Kreis von einem Punkt zu einem anderen bewegen

  • 5 Antworten
  • Letztes Antwortdatum
N

Nono

Neues Mitglied
1
Hallo zusammen,

ich habe eine SurfaceView Klasse, in der erstmal nur ein Kreis gezeichnet wird. Wenn man auf den Bildschirm tippt, soll aus diesem Kreis ein neuer Kreis entstehen und sich in die Richtung des Punktes bewegen, wo man hingetippt hat. Ich habe das bis jetzt wie folgt gelöst:

Code:
@Override
    public boolean onTouchEvent(MotionEvent event){
        synchronized(getHolder()){
            if(spielfigur.getRadius() >= 30){
                Point ziel = new Point((int)event.getX(), (int)event.getY());
                int diffx = ziel.x - (int)spielfigur.getX();
                int diffy = ziel.y - (int)spielfigur.getY();
                Ball schuss = new Ball(this, spielfigur.getX(), spielfigur.getY(), diffx/10, diffy/10, Color.RED);
                baelle.add(schuss);
                spielfeld.setBaelle(baelle);
            }
        }
        return true;
    }

Also im wesentlichen wird hier die Differenz von der Position der Spielfigur und dem Touchpunkt berechnet und dieser Wert geteilt durch 10 als Bewegungsgeschwindigkeit für den neuen Ball übergeben. Also dieses diffx/10 und diffy/10 stehen für die Pixel, die sich der Ball pro Frame bewegen soll. Das klappt auch soweit. Das Problem ist nur, dass die Bewegungsgeschwindigkeit sich stark unterscheidet, je nachdem ob man nah an der Spielfigur tippt, also ob die Differenz gering ist, oder weiter weg, also das die Differenz groß ist. Die Geschwindigkeit soll aber ungefähr gleich bleiben. Mir fällt leider nichts dazu ein. Hat jemand eine Idee?

Viele Grüße
 
Hab ne Lösung gefunden:

Code:
@Override
    public boolean onTouchEvent(MotionEvent event){
            synchronized(getHolder()){
                if(spielfigur.getRadius() >= 30 && (event.getX() != spielfigur.getX() || event.getY() != spielfigur.getY())){
                    float xSpeed;
                    float ySpeed;
                    float speed = 10;
                    float zielx = event.getX();
                    float ziely = event.getY();
                    float diffx = zielx - spielfigur.getX();
                    float diffy = ziely - spielfigur.getY();
                   
                    double winkel = Math.toDegrees(Math.atan2(diffy, diffx));
                   
                    xSpeed = (float) (Math.cos(Math.toRadians(winkel))*speed);
                    ySpeed = (float) (Math.sin(Math.toRadians(winkel))*speed);
                   
                    Ball schuss = new Ball(this, spielfigur.getX(), spielfigur.getY(), xSpeed, ySpeed, Color.RED);
                    baelle.add(schuss);
                    spielfeld.setBaelle(baelle);
                    spielfigur.raiseRadius(-10);
                }
            }
        }
        return true;
    }
 
Du musst schon etwas mehr rechnen

DOT - vidme guck ab 0:40 so mache ich das in meiner App:

Geschwindigkeit ist ein Konstanter wert sagen wir 10 dp pro sekunde also:

ballVel=10;

Zu deinem Fall:

Der User klickt und dein eventobjekt hat die koordinaten.
Damit errechnest du erstmal mit Pythagoras den Abstand

delPosX=event.x-ball.x;
delPosY=event.y-ball.y;

-> delPos=(delPosX*delPosX+delPosY*delPosY)^(1/2)

Damit errechnest du den Cosinus der jeweiligen Richtungen

cos(delPosX)=delPosX/delPos;
cos(delPosY)=delPosY/delPos;

du setzt mit diesen Werten die Geschwindigkeiten des Balles dann in die jeweiligen Richtungen:

ball.velX=ballVel*delPosX/delPos;
ball.velY=ballVel*delPosY/delPos;

Rendere die Geschwindigkeit dann und fertig ist:)

PS: gehört aber eher in den Spieleentwickler bereich ;)


Hier dein Code dazu(you're welcome):

PHP:
@Override
    public boolean onTouchEvent(MotionEvent event){
        synchronized(getHolder()){
            if(spielfigur.getRadius() >= 30){
                Point ziel = new Point((int)event.getX(), (int)event.getY());
                float velocity=*********;//Wert eingeben
                int diffx = ziel.x - (int)spielfigur.getX();
                int diffy = ziel.y - (int)spielfigur.getY();
                float diffPos=Math.sqrt(diffx*diffx+diffy*diffy);
                Ball schuss = new Ball(this, spielfigur.getX(), spielfigur.getY(), (int)(velocity*diffx/diffPos), (int)(velocity*diffy/diffPos), Color.RED);
                baelle.add(schuss);
                spielfeld.setBaelle(baelle);
            }
        }
        return true;
    }


Ich hab ncoh eine Variable is MovingUp und isMovingRight wegen Kollisionserkennung ich weiß nciht wie du das löst mit dem feststellen dass er den Punkt erreicht hat da ja Tunneleffekte entstehen können wenn mal ein frame zu lange dauert aber das ist ein anderes Thema.

edit: deine Lösung ist zu umständlich arbeite mit dem Kosinus aus meiner Lösung der braucht keine sehr rechenintensiven Konversionen oder Sinus berechnungen. Glaub mir die kosten dich sehr viele CPU clocks!!!!
 
  • Danke
Reaktionen: Nono
Alles klar ich glaube dir, kenne mich mit den CPU Kosten nicht aus :) Danke !! :)
 
Hab nochmal ein Anliegen zu dem Thema. Also als ich gefragt hatte musste ich nur den Kreis in die Richtung des Zielpunktes laufen lassen. Er musste nicht stehen bleiben. Das hat ja ganz gut geklappt. Aber jetzt hab ich auch einen Fall, wo der Kreis dann wirklich an dem Punkt stehen bleiben soll. Weiß grad nicht genau wie ich das machen soll. Was genau meintest du mit dieser isMovingUp bzw isMovingRight Variable? Bzw wie setzt du die ein?

Hab es probiert mit einer if Abfrage, ob der Punkt dann genau auf dem Zielpunkt liegt, also dass er dann nichts mehr macht, aber das klappt irgendwie nicht.

Wäre cool wenn du nochmal helfen könntest.

Viele Grüße
 
Jo das ist sehr schwer den Zeitpunkt abzufangen wo der Ball genau auf dem Punkt ist vor allem wenn mehrere ms zwischen zwei frames liegen. Das ist der Tunneleffekt von dem ich sprach zuvor.
Früher hatte es mir gereicht dass das Objekt in einem bestimmten bereich ist aber das war sehr komisch und bei entsprechenden geschwindigkeiten kommt dann trotzdem der tunneleffekt.

Ich löse das inzwischen indem ich zwei variablen habe:

boolean isMovingUp;
boolean isMovingRight;

Beim setzen der Geschwindigkeit ermittle ich dann eben wie er sich bewegen wird:

Geht er nach rechts setze ich isMovingRight eben auf True ansonsten auf false. Das gleiche mit isMovingUp.

Dann ist die Abfrage easy ob er den Punkt erreicht hat:
2 variablen tarX und tarY für die zielkoordinaten

if (isMovingRight&&ball.X>=tarX||
!isMovingRight&&ball.X<=tarX||
isMovingUp&&ball.Y <=tarY||
!isMovingUp&&ball.Y >=tarY)
{
ball.X=tarX;
ball.Y=tarY;
}

Aber man sollte immer mit floats rechnen damit keine ru sungsfehler entstehen bei der Beweging so klappt das sonst sehr gut aber
 
Zuletzt bearbeitet:
Zurück
Oben Unten