run-Methode läuft immer schneller? // bestimmte Position überprüfen

  • Antworten:19
  • OffenNicht stickyNicht beantwortet
  • Forum-Beiträge: 71

25.01.2014, 10:53:33 via Website

ERSTES PROBLEM ERLEDIGT, BITTE NACH UNTEN SCROLLEN!

Hallo,

ich habe eigentlich gleich 2 Probleme:
und zwar entwickle ich gerade eine App, bei der man auf einem Boden laufen kann, und immer wieder unten als Boden Lava auftaucht, sprich ein Jump&Run, wo man über Lava auf dem Boden drüber springen muss.

Nun die 2 Probleme,
das erste: Ich habe das Runnable Interface implementiert, und die run-Methode ruft immer wieder eine Funktion zeitZaehlen() auf, welche die x-Position des Spielers bewegt, und die Punkte aktualisiert und die y-Position übernimmmt (wenn gesprungen wird). Jetzt habe ich folgendes Problem: sobald das Spiel startet, funktioniert alles wunderbar, man kann springen usw, allerdings anfangs nur vielleicht über ein viertel des Bildschirms, so wie auch eigentlich sein soll. Jetzt wird im Laufe des Spiels die Figur aber immer schneller (sprich eigentlich müsste das daran liegen, dass die Funktion zeitZaehlen immer schneller aufgerufen wird(warum auch immer)) und man kann nach geschätzten 20 Sekunden schon "über den ganzen Bildschirm springen". An was könnte das liegen? Hier noch Quelltext-Ausschnitte:

1public class GameActivity extends Activity implements OnClickListener, java.lang.Runnable{
2
3 private int round;
4 private int points;
5
6 private Handler handler=new Handler();

1private void startRound()
2 {
3 round++;
4 bildschirmAktualisieren();
5 handler.postDelayed(this, 30);
6 }
7
8 private void bildschirmAktualisieren()
9 {
10 TextView tvround=(TextView)findViewById(R.id.round_view);
11 tvround.setText(Integer.toString(round));
12 TextView tvpoints=(TextView)findViewById(R.id.points_view);
13 tvpoints.setText(Integer.toString(points));
14 }
15
16 private void zeitzaehlen()
17 {
18 xPos=xPos+9;
19 yPos=Sprung.sprungposition;
20 points++;
21 pruefeRundenende();
22 pruefeSpielende();
23 bildschirmAktualisieren();
24 draw();
25 handler.postDelayed(this,30);
26 }

1@Override
2 public void run()
3 {
4 zeitzaehlen();
5 }

Ich hoffe, ihr könnt mir hier vielleicht helfen.


Nun noch das zweite Problem, was eigentlich eher eine Frage ist, bzw, wobei ich eher eine Hilfestellung brauche.

Und zwar kann man zwar schon springen und alles, allerdings passiert noch 0 wenn man in die Lava schnurstracks reinläuft. Jetzt wollte ich euch fragen, wie ihr das möglichst effizient machen würdet. Das Programm bzw. Layout ist letztendlich so aufgebaut:
Ich habe 2*14 ImageViews, die immer aktualisiert werden, das heißt ich habe 14 ImageViews in der ersten Reihe nebeneinander, und dann drüber nochmal 14 ImageViews. Diese sind ganz am Anfang mit Steinen belegt, und dann kommt nach und nach Lava dazu. Dieses "dazukommen" der Lava habe ich so gelöst: durch die Methode zeitZaehlen werden immer die Punkte hochgezählt und ich sage nun einfach in meiner Draw-Methode, dass wenn zum Beispiel 90 Punkte oder 180 Punkte erreicht sind, dass dann z.B ImageView 5 oder ImageView 18 oder welche auch immer Lava anzeigen soll, Beispiel:
1switch(points)
2 {
3 case 90:
4 xPos=-42;
5 bild19.setImageDrawable(getResources().getDrawable(R.drawable.volcano_lava_big));
6 bild20.setImageDrawable(getResources().getDrawable(R.drawable.volcano_lava_big));
7 bild21.setImageDrawable(getResources().getDrawable(R.drawable.volcano_lava_big));
8 break;
9
10 case 180:
11 xPos=-42;
12 bild19.setImageDrawable(getResources().getDrawable(R.drawable.volcano_stone_big));
13 bild20.setImageDrawable(getResources().getDrawable(R.drawable.volcano_lava_big));
14 bild21.setImageDrawable(getResources().getDrawable(R.drawable.volcano_lava_big));
15 bild23.setImageDrawable(getResources().getDrawable(R.drawable.volcano_stone_big));
16 bild24.setImageDrawable(getResources().getDrawable(R.drawable.volcano_stone_big));
17 bild25.setImageDrawable(getResources().getDrawable(R.drawable.volcano_stone_big));
18 bild26.setImageDrawable(getResources().getDrawable(R.drawable.volcano_stone_big));
19 break;

Nun will ich eben eine Funktion machen, die das Spielende überprüft. Jetzt ist das Problem, dass die Lava ja immer an einer anderen Stelle ist, habt ihr da eine Idee wie ich das abprüfen kann? Klar wäre es möglich dann in der pruefeSpielende()-Funktion zu schauen, wie viele Punkte erreicht sind, und dann über die Draw-Methode schauen, wo gerade die Lava ist, dann irgendwie die x-Positionen der Lava herausfinden, und wenn an der x-Position der Lava die y-Position der Spielfigur noch gleich ist, wie auf dem Boden, dann den Game-Over-Screen anzeigen. Allerdings wäre das viel zu viel Arbeit, nicht nur für mich zum schreiben, sondern selbst mein Handy würde dann wahrscheinlich schon extrem belastet werden, denn es würde schließlich immer erst jedesmal die Punkte abgeprüft und was weiß ich was noch alles. Also fällt die Möglichkeit aus.
Also habt ihr da vielleicht eine Idee, wie ich das am geschicktesten lösen kann? Also im Prinzip, dass man sobald man die Lava berührt, bzw versucht "darüberzulaufen" der Game-Over-Screen erscheint?
Bei Fragen gerne fragen, ist mein erster Beitrag, hoffe alles ist ok.
Wenn ihr sonst noch Tipps habt, könnt ihr sie auch gerne loswerden.

Schon mal im Vorhinein vielen vielen Dank für die Antworten.

Lg
Florian

Ps: das ganze sieht dann so aus (ohne Lava)
Jeder von diesen Steinen ist also eine einzelne ImageView.

— geändert am 28.01.2014, 12:47:09

Antworten
  • Forum-Beiträge: 71

26.01.2014, 10:46:09 via Website

Hat keiner eine Idee?

Wäre mir wirklich wichtig und würde mir sehr helfen.

Danke!

Antworten
  • Forum-Beiträge: 359

27.01.2014, 09:54:29 via Website

Hast du schonmal den Ablauf gedebuggt ?
Vielleicht. ist irgend ein delay von einer Variable abhängig die noch flasch ist oder ....

Antworten
  • Forum-Beiträge: 71

27.01.2014, 14:20:04 via Website

Danke.
Ich glaube ich weiß jetzt konkret woran es liegt,
und zwar habe ich ja ein Runnable implementiert, und dann mache ich immer bei StarteRunde dieses handler.postDelayed();
Und zwar einmal eben beim StarteRunde und dann eben beim zeitzaehlen(). Beim zeitzaehlen ist alles ok, das verzögert einfach nur irgendwie das ganze, aber ich bin mir jetzt ziemlich sicher, dass es an dem postDelayed in der Funktion StarteRunde() liegen muss, denn es wird tatsächlich immer wenn eine neue Runde beginnt schneller. Woran liegt das genau bzw. vielmehr hat jemand ne Idee wie ich dem entgegenwirken kann?

PS: wenn ich das Handler.PostDelayed in StarteRunde rausnehm funktioniert gar nichts mehr, bzw. es wird nicht mehr in die run-Methode gesprungen und dadurch bewegt sich meine Figur auch nicht mehr.

Ich hoffe auf Hilfe.

Gruß Florian

Antworten
  • Forum-Beiträge: 71

27.01.2014, 14:52:33 via Website

Also Sleep funktioniert nicht, ich habe jetzt versucht anstatt postDelayed einfach nur das direkte *,post zu benutzen, aber auch hier wird es jede Runde schneller, ich kanns mir nicht erklären.

1private void startRound()
2 {
3 round++;
4 bildschirmAktualisieren();
5 handler.post(this);
6 }

— geändert am 27.01.2014, 14:52:47

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.174

27.01.2014, 15:01:05 via Website

Wieso funktioniert sleep nicht.
In deine Funktion einfach mal in eine Try ein Thread. Sleep reinmachen, oder zeitdifferenz zwischen start und Ende in LogCat ausgeben, dann solltest du genau sehen ob es und um wie viel es schneller wird.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
  • Forum-Beiträge: 71

27.01.2014, 15:06:00 via Website

Ich habe es jetzt endlich geschafft es zu lösen, zwar auf die sehr einfache Art, aber die Hauptsache ist, es funktioniert. Ich habe jetzt einfach das Handler.post(this) in die StartSpiel()-Funktion reingepackt und die StarteRunde()-Funktion einfach gelöscht. Die Runden werden jetzt direkt in der Funktion in der das Rundenende überprüft wird hochgezählt.

Danke für die Hilfe!

Antworten
  • Forum-Beiträge: 71

28.01.2014, 12:46:40 via Website

Jetzt habe ich das nächste Problem, also ich habe es geschafft, dass auf die "Kollission" mit der Lava reagiert wird.
Jetzt habe ich aber ein vermeintliches Problem mit einer Activity, und zwar der game_over_activity, die nicht mehr machen soll, als das Game_Over_Layout anzuzeigen.
Jetzt wird die Activity aber aus unerklärlichen Gründen nicht nur einmal sondern sehr oft aufgerufen. Ich habe es versucht, einfach anstatt der Activity zu starten die Runden hochzuzählen, das funktioniert und wird auch nur einmal ausgeführt. Was aber nicht funktioniert, ist ein anderes Layout in der Activity zu laden, das heißt es liegt zweifelsfrei (für mich zumindest) an der Activity und auch nicht am Layout.
Hier einmal der Ausschnitt, wo ich die Activity aufrufe:
1Intent intent = new Intent(this,game_over_activity.class);
2 startActivity(intent);
3 finish();

Und dann hier die komplette game_over_activity:
1package de.ftProductions.volcanoJump;
2
3import android.app.Activity;
4import android.content.Intent;
5import android.os.Bundle;
6import android.view.KeyEvent;
7import android.view.Window;
8
9public class game_over_activity extends Activity {
10
11
12 @Override
13 protected void onCreate(Bundle savedInstanceState)
14 {
15 requestWindowFeature(Window.FEATURE_NO_TITLE);
16 super.onCreate(savedInstanceState);
17 setContentView(R.layout.game_over);
18 }
19
20 @Override
21 public boolean onKeyDown(int keyCode,KeyEvent event)
22 {
23 if(keyCode==KeyEvent.KEYCODE_BACK)
24 {
25 finish();
26 Intent intent= new Intent(this,StartScreenActivity.class);
27 startActivity(intent);
28 }
29 return true;
30 }
31}

Danke im Vorhinein.

Antworten
  • Forum-Beiträge: 359

28.01.2014, 13:14:20 via Website

Das ist eindeutig ein Logik Fehler!

Wenn du hingehst und eine globale Variable public boolean isGameOverStartet = false;

und dann an der entsprechenden Stelle:
1if (!isGameOverStartet){
2
3 Intent intent= new Intent(this,StartScreenActivity.class);
4 startActivity(intent);
5 isGameOverStartet = true;
6 finish();
7}

Fang an zu Debuggen !!!
Gruß
Fabian

— geändert am 28.01.2014, 13:14:46

Antworten
  • Forum-Beiträge: 71

28.01.2014, 14:49:29 via Website

Wow, tatsächlich, es funktioniert dadurch. Vielen Dank.
Kannst du mir aber auch noch erklären warum das so ist?
Weil es wundert mich wirklich denn eigentlich rufe ich die Funktion zwar immer wieder durch das Runnable auf, aber sobald einmal die Bedingung erfüllt ist, wird doch meine Funktion aufgerufen und ich sage finish(), was die Activity doch eigentlich komplett schließt. Daher dachte ich, dass es dann nicht mehr möglich ist, dass die Funktion nochmals aufgerufen wird (weil sie eben schon geschlossen ist). Kannst du mir das also vielleicht erklären, warum das nötig ist?

Gruß
Florian

Antworten
  • Forum-Beiträge: 359

28.01.2014, 15:40:56 via Website

Es liegt vermutlich am java.lang.Runnable
Mit finish wird zwar die 2 Beendet aber Thread die nicht das Activity sind, werden trotzdem weiter ausgeführt.
Ich vermute somit das der Asyncrone Thread dies immerwieder aufgerufen hat.

Gruß
Fabian

Antworten
  • Forum-Beiträge: 71

28.01.2014, 15:53:17 via Website

Aber eigentlich sollte die Methode run() dann doch nicht mehr aufgerufen werden, wodurch dann die zeitZaehlen()-Methode (und sie ist die einzige in der pruefeSpielende() aufgerufen wird!) auch nicht mehr aufgerufen wird. Deswegen wundert es mich eben..

Antworten
  • Forum-Beiträge: 71

28.01.2014, 20:50:44 via Website

Okay, wieder was gelernt :)
Aber gibt es denn dann auch eine Möglichkeit wirklich die komplette Activity zu beenden?

Antworten
  • Forum-Beiträge: 1.525

28.01.2014, 23:52:46 via Website

Florian S.
Okay, wieder was gelernt :)
Aber gibt es denn dann auch eine Möglichkeit wirklich die komplette Activity zu beenden?

Mit
1finish();
soweit ich weiß.
Sollte ein Thread trotzdem noch irgendwie laufen, dann dazu
1DeinenThread.stop();


LG

— geändert am 28.01.2014, 23:56:05

Antworten
  • Forum-Beiträge: 1.793

29.01.2014, 21:13:05 via App

Finish() alleine ist oft schon zu viel des Guten (Beenden-Knöpfe in einer App sind einfach in 99% sinnlos), bei deinem Fall musst du einfach mal Handler.removeCallbacks() bemühen.

Die Activity wird ja durch finish() beendet. Im UI-Thread (der die Callbacks des Handlers bearbeitet) laufen aber ALLE Activities, Services und Broadcastreceiver.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten

Empfohlene Artikel