Bewegung eines Charakters auf Canvas

  • 16 Antworten
  • Letztes Antwortdatum
S

SocietyGraz

Neues Mitglied
0
Hallo. Ich habe folgendes Problem:
Ich möchte einen Spieler (Bitmap) auf einem Canvas bewegen. Mein Problem ist, dass das alte Bild immer gelöscht werden sollte, sodass nur noch die aktuelle Bitmap angezeigt wird. Derzeit wird bei jeder bewegung ein neues Bild hinzugefügt und alle alten behalten. Wie kann ich diese bevor ich die neue Bitmap auf das Canvas zeichne, löschen?

GameScreen class:

private void updateRunning(List<TouchEvent> touchEvents, float deltaTime) {
Graphics g = game.getGraphics();
int len = touchEvents.size();
for (int i = 0; i < len; i++) {
TouchEvent event = touchEvents.get(i);
if (event.type == TouchEvent.TOUCH_DOWN) {
if(event.x < 100 && event.y < 100)
{
player.goUp();
g.drawPlayerUp(player.currentImageUp, player.x, player.y);
}
if(event.x > 700 && event.y < 200)
{
player.goRight();
g.drawPlayerRight(player.currentImageRight, player.x, player.y);

}
if(event.x > (GameImpl.displayWidth - 100) && event.y > (GameImpl.displayHeight - 100))
{
player.goDown();
g.drawPlayerDown(player.currentImageDown, player.x, player.y);

}
if(event.x < 100 && event.y > (GameImpl.displayHeight - 100))
{
player.goLeft();
g.drawPlayerLeft(player.currentImageLeft, player.x, player.y);

}
}
}

}

Player class:

public class Player {

public int x;
public int y;

public int currentImageUp = 2;
public int currentImageRight = 2;
public int currentImageLeft = 2;
public int currentImageDown = 2;

public static final int MOVE_SPEED = (int) (GameImpl.displayWidth / 60);

public Player(int x, int y) {
this.x = x;
this.y = y;
}

public void goUp() {
if (currentImageUp < 2)
currentImageUp++;
else
currentImageUp = 0;
this.y -= MOVE_SPEED;

}

public void goDown() {
if (currentImageDown < 2)
currentImageDown++;
else
currentImageDown = 0;
this.y = this.y + MOVE_SPEED;

}

public void goLeft() {
if(currentImageLeft < 2)
currentImageLeft++;
else
currentImageLeft = 0;
this.x -= MOVE_SPEED;
}

public void goRight() {
if (currentImageRight < 2)
currentImageRight++;
else
currentImageRight = 0;
this.x += MOVE_SPEED;
}
}

GraphicImpl class with one of the moving methods:

@Override
public void drawPlayerRight(int image, int x, int y) {
switch(image)
{
case 0:
canvas.drawBitmap(((PixmapImpl) Assets.player_new_right).bitmap, x, y, null);
break;
case 1:
canvas.drawBitmap(((PixmapImpl) Assets.player_new_right_left).bitmap, x, y, null);
break;
case 2:
canvas.drawBitmap(((PixmapImpl) Assets.player_new_right_right).bitmap, x, y, null);
break;
}
}
 
Canvas.drawColor()
 
canvas.drawColor() löscht ja das gesamte Canvas. Ich hab jedoch eine Map im Hintergrund und möchte nur den Player immer wieder neu zeichnen. Brauch ich ein zweites Canvas dazu?
 
Du musst den Canvas immer wieder komplett neu zeichnen. Also erst mal canvas.drawColor(), dann deine Map und dann den Spieler.
 
das ist doch zu aufwendig.. gibts da wirklich keine bessere lösung? :glare:
 
Nein, der Canvas funktioniert halt einfach so.

Aber wieso aufwendig? Ob du deinen Canvas nur einmal, oder immer zeichnest macht doch kaum Unterschied im Code..
 
Aufwendig im Sinne von den Ressourcen am Handy und Smartphone. Dauernd die komplette Map mit vielen Images zu zeichnen ist sicher sehr Ressourcen aufwendig.
 
Nicht wirklich. Die Bitmaps müssen sowieso in den RAM geladen werden, egal wie oft sie gezeichnet werden. Das zeichnen auf den Canvas selbst ist dann nicht mehr viel Arbeit.

Wie gesagt, der Canvas funktioniert halt einfach so, daran kann man nichts ändern.
 
Man kann auch Bitmaps übereinanderlegen und seine Figur in einen transparenten Canvas malen. Dann muss man diesen mit drawColor(0x00,PorterDuff.CLEAR) löschen. Dann macht der Grafikprozessor die Arbeit für einen :D
 
Ich zeichne die Map jetzt immer neu.. Hat bisher von der Performance her noch funktioniert sodass es so aussieht als würde der Spieler die Map entlang gehen.

Jetzt habe ich das erste Problem mit der Performance. Hab gerade die Collision detection gemacht. Habe das so gelöst, dass ich alle Bitmaps und Wände in eine List<Rect> gebe und mit folgender Methode darüber iteriere:

public boolean collisionDetection()
{
Rect player = new Rect(this.player.x, this.player.y, this.player.x + 21, this.player.y + 72);
int y = bitmapsCollision.size();

for(int i = 0; i < bitmapsCollision.size(); i++)
{
Rect npc = new Rect(bitmapsCollision.get(i));

if(Rect.intersects(player, npc))
{
return true;
}
}
return false;
}

Jetzt läuft das ganze nicht mehr so flüssig und bei schnellerem Gehen des Spielers (häufiges Button drücken) kommt dieser ins stocken und wird manchmal nicht gezeichnet, sondern ausgelassen. Die Methode collisionDetection() wird bei jedem Gehversuch aufgerufen. Die Liste beinhaltet 380 Rects. Gibts hier eine performantere Lösung? Ich teste das Spiel auf einem Nexus 7 2013.

Vielen Dank für Eure Hilfe
 
Du erzeugst in der Schleife bei jeder Playerbewegung neu 380 Rechtecke. Das kann man doch sicher irgendwie cachen - oder vllt. die Suche nach Abstand zum Player ausdünnen.
 
Werd dem Tipp mit dem cachen nachgehen. Danke erstmal für die ständige schnelle Antwort.

Was meinst du mit dem ausdünnen des Abstands?
 
Was man schon mal nicht macht, ist jedes mal alle Rechtecke neu zu erstellen. Leg sie doch einmal an und verändere sie immer wieder.

Die nächste Frage wäre: Wieso 380 Rechtecke? Mich würde interessieren, warum das so viele sein müssen. Das kann man sicher anders lösen.

PS: Das Nexus 7 ist fast zu gut, um darauf zu entwickeln. Besser ist, wenn man mit schwächeren Geräten entwickelt.
 
380 rechtecke ergeben sich aus ca. 100 Wänden, 10 npcs und ca. 270 dekorations objekten.. ich leg um jedes objekt ein rechteck damit ich Rect.intersects () aufrufen kann.

Ich weiß dass es zu stark ist falls die app verbreitet wird, aber es wird nur auf einem device präsentiert und danach ad acta gelegt.
 
Nach Abständen vorfiltern?

Zum Beispiel: man sortiere die Rechtecke nach der kleinsten x Koordinate.
Dann muss man sein Array nur bis zum ersten Rechteck mit einer x0 > x1 vom Player durchlaufen.

Oder man nimmt statt Rechtecken Intervall-Bäume.

Oder man teilt seinen Level in "Räume" also große Rechtecke ein, wobei dann jedes Objekt max. in zwei dieser Räume sein kann.

Oder ...

Aber das wiederholte Erzeugen der Rechtecke sollte man auf jeden Fall nach Möglichkeit vermeiden.
 
Zuletzt bearbeitet:
Bei zB 270 Deko-Objekten, die wird man doch auf ein Bitmap zusammenfassen können oder ähnliches..

Es gibt da so viele Möglichkeiten das anders zu machen..
 
erli2909 schrieb:
Bei zB 270 Deko-Objekten, die wird man doch auf ein Bitmap zusammenfassen können oder ähnliches..

Es gibt da so viele Möglichkeiten das anders zu machen..

Wenn man alles auf eine Bitmap zusammenfasst funktioniert die collision detection denk ich nicht mehr.. oder ich versteh nicht wie du das meinst..

werd mal paar sachen probieren. danke für eure hilfe!
 
Zurück
Oben Unten