Bitmap durch klick auf den Screen an Koordinate x,y steuern

  • 14 Antworten
  • Letztes Antwortdatum
C

coreytaylor211

Fortgeschrittenes Mitglied
5
Hallo zusammen,

wie der Titel schon sagt bekomme ich diese wahrscheinlich recht einfache Sache nicht hin.
Ich habe eine Bitmap mit x und y Koordinaten.
Wenn ich mir jetzt mit
Code:
event.getAction() == MotionEvent.ACTION_DOWN{
     Variable=event.getX();
     Variable=event.getY();
die neuen Koordinaten hole, springt die Bitmap direkt dorthin. Ich möchte aber Sie schön dahin fährt :)
Ich habe schon alles mögliche mit Schleifen durch, ich komme einfach nicht auf die Lösung.
Vielleicht stehe ich auch dem Schlauch.
Daher bitte ich euch um Hilfe.
 
Zuletzt bearbeitet:
Ich versuche es kurz und verständlich zu machen:

Entwerfe eine Klasse Drawable mit folgenden Variablen:

float velocity,velX,velY,posX,posY,tarPosX,tarPosY;
boolean isMovingUp,isMovingRight;

Was sollte passieren wenn du jetzt auf den Bildschirm klickst:

die positionen tarPosX und tarPosY sollten auf diesen Punkt gesetzt werden.
Es werden die richtungs geschwindigkeiten velX und velY ausgerechnet und zwar so:

Code:
velX=velocity*(tarPosX-posX)*(tarPosX-posX)/Math.sqrt((tarPosX-posX)*(tarPosX-posX)+(tarPosY-posY)*(tarPosY-posY));
isMovingRight=velX>=0?true:false;

velY=velocity*(tarPosY-posY)*(tarPosY-posY)/Math.sqrt((tarPosX-posX)*(tarPosX-posX)+(tarPosY-posY)*(tarPosY-posY));
isMovingUp=velY>=0?true:false;

velocity ist ein Wert der angibt wie schnell sich das Bild bewegen soll

Wann sollte die Berechnung erfolgen: einfach in deiner Schleife abfragen ob posX!=tarPosX und posY!=tarPosY ist UND gleichzeitig noch velX==0 und velY==0 ist dann sollte alles berechnet werden...

ansonsten führst du dann in deiner Schleife ganz einfach die Berechnungnen durch:

posX+=velX*delTime;
posY+=velY*delTime;

delTime ist die Zeit für die Berechnung

isMovingRight und isMovingUp werden gesetzt um zu testen wann der Bild sein Ziel erreicht hat. Das prüfst du einfach indem du abfragst falls das Bild sich nach Rechts bewegt und dessen position aber schon über dem Ziel ist dann hat er sein Ziel koordinate schon erreicht und ist sogar dadrüber weg also: zurücksetzen auf die Zielkoordinate und velX=0 machen. Dasselbe fragst du bei Bewegung in y-Richtung ab.


Ok war doch länger ich hoffe das kann dir helfen
 
  • Danke
Reaktionen: coreytaylor211
Vielen dank für deine Hilfe werde es nachher ausprobieren.

So ich habe das jetzt so gut es geht umgesetzt. Nur nochmal zum Verständnis die Variablen posX und posY bekommen die alten Koordinaten und tarPosX und tarPosY (tar für target nehme ich mal an) die neuen Koordinaten.
Das Problem was ich gerade habe ist das ich mit der delTime und velocity gerade nicht zurecht komme ? Wie ermittel ich denn die optimalen Werte für diese beiden Variablen.
Vielen Dank schonmal für die Hilfe.
 
Zuletzt bearbeitet:
posX und posY sind einfach die positionen der Bitmap.

delTima ist delta time diese ermittelst du indem du die Differenz zwischen diesem schleifendurchgang und dem letzten berechnest:

Hier mal ein Codeschnipsel wie ich das mache:

Code:
/**
     * sets the time between two frames
     */
    public void setDeltaTime()
    {
        if(oldTime!=0)
            delTime=System.currentTimeMillis()-oldTime;
        if(delTime<30)
        {
            try
            {
                sleep(30-delTime);
            }
            catch (InterruptedException e)
            {
                return;
            }
            delTime=System.currentTimeMillis()-oldTime;
        }
        if(delTime>50l)delTime=50l;
        oldTime=System.currentTimeMillis();
    }

Dieser Code sorgt dafür das jeder Schleifendurchgang 30 ms dauert MINDESTENS. Also begrenzt einfach die Frames...
Falls oldTime nicht gesetzt wurde vorher schläft er einfach 30 ms. Ist der letzte frame weniger als 30 ms her schläft er ebenfalls bis die 30 ms vorbei sind danach wird die Zeit seit dem letzten Frame nochmals berechnet da man sich nciht sicher sein kann dass ein sleep exakt die Zeit schläft die man angegeben hat ;)

weiterhin berechne ich nichts was über 50 ms ist da lasse ich dann lieber alles etwas langsamer ablaufen anstatt dass die gesamte Logik aufeinmal gerendert wird wenn der Abstand zu groß ist zwischen frames

Dieser Code wird dann einfach ind er Schleife aufgerufenbevor alles berechnet wird:

Code:
/**
     * this is the run method of the main thread
     */
    @Override
    public void run()
    {
       while(isRunning)
        {
            delTime=0;
            oldTime=System.currentTimeMillis();
           ...
           
            while(!isPaused)
            {
                ...
                mView.doDraw();
                ...
                setDeltaTime();
                ...
                updatePosition(delTime);
                ...
            }
           ...
        }
    }


So das zur Zeit....


deine Geschwindigkeit gibts du am besten abhängig von der Bildschirmgröße an(entweder von der Höhe oder der Breite oder so)

sagen wir mal du gibts die velocity so an:


velocity=screenWidth/1000;

dann würde das einfach bedeuten dein Bild hat die Geschwindigkeit um in einer sekunde von einer seite des Bildschirm zur nächsten zu gelangen...

So setze ich das in meiner App ein nur sind da auch noch beschleunigungen mit einberechnet damit das ganze geschmeidiger startet anstatt von 0 auf 100.
 
  • Danke
Reaktionen: coreytaylor211
Vielen Dank ich habe erste Erfolge zu berichten, die Bitmap folgt mir jetzt wenn Sie oben am Bildschirmrand ist und wenn ich diagonal von oben links nach unten rechts drücke.
Nur wenn die Bitmap wieder nach oben und nach links soll springt Sie noch.
Nächster Punkt ist egal wo ich velX und velX auf null setzte die Bitmap hält nicht an.
Was mir bei logCat aufgefallen ist bleibt immer ein ganz kleiner wert der Geschwindigkeit vorhanden.

Es wäre super wenn du noch einen kleinen Denkanstoß für mich hättest KEINE LÖSUNG das muss ich selber hingekommen ;)

Vielen Dank schonmal
 
Dann empfehle ich dir mal deinen Code, wo alle Berechnungen durchgeführt werden, einmal zu posten. Es ist nicht gut wenn man im Dunkeln rumstochert ^^
Es scheint wohl nur ein kleiner Logikfehler zu sein...
 
  • Danke
Reaktionen: coreytaylor211
Ok, da ich Anfänger bin bitte nicht über dieses Chaos meckern.^^ Ich weiß ich muss mir das schöne Programmieren noch beibringen :)

So hier der Code
Code:
                velX= (float) (velocity*(tarPosX-posX)*(tarPosX-posX)/Math.sqrt((tarPosX-posX)*(tarPosX-posX)+(tarPosY-posY)*(tarPosY-posY)));
                isMovingRight= velX >= 0;
                Log.d("Test","velX  "  + velX);


                velY= (float) (velocity*(tarPosY-posY)*(tarPosY-posY)/Math.sqrt((tarPosY-posY)*(tarPosY-posY)+(tarPosX-posX)*(tarPosX-posX)));
                isMovingUp= velY >= 0;
                Log.d("Test","velY  "  + velY);

                if ( isMovingRight== true &&(posX) >= tarPosX){
                    vectorX1= velX;
                    velX=0;
                    x1 = tarPosX;
                    Log.d("Test","tarPosX  "  + tarPosX);
                }
                if( isMovingUp ==true && (posY) >= tarPosY){
                    vectorY1 = velY;
                    velY=0;
                    y1 = tarPosY;
                    Log.d("Test","tarPosY  "  + tarPosY);
                }
                if (!isMovingRight && posX >= tarPosX){
                    vectorX1 = velX;
                    velX=0;
                    x1 = tarPosX;
                }
                if(!isMovingUp && posY >= tarPosY){
                    vectorY1 = velY;
                    velY=0;
                    y1 = tarPosY;
                }

                while(posX!=tarPosX && posY!=tarPosY && velX==0 && velY ==0){
                    posX+=velX*delTime;
                    posY+=velY*delTime;
                    Log.d("Test","posX  "  + posX);
                    Log.d("Test","posY  "  + posY);
                    break;
                }
 
Ok.

1. Guck dir deine If-Anweisungen genau an merkst du was bei den 2. Argumenten? die sehen sich verdammt ähnlich ;)

2. x1 und y1 sind also die positionen der Bitmap? Wozu dann posX und posY benutzen?

3. posX und posY werden nciht auf tarX und tarY gesetzt deßhalb denkt das Programm deine Bitmap ist nicht am Ziel
->Vorsicht du ergreifst keine Maßnahmen bei der Berechnung der Geschwindigkeiten : deswegen droht eine Division durch 0!(Du möchtest sicher keine Schwarzen Löcher erschaffen bei dieser Aktion:))


Code:
public void updatePosition(long delTime)
{

     //Neue Geschwindigkeit nur Berechnen falls das Bild still steht und die Zielkoordinaten ungleich der Position sind
     if(velX==0&&velY==0&&(tarPosX!=posX||tarPosY!=posY))
     {
          float delPosX=tarPosX-posX;
          float delPosY=tarPosY-posY;
          float delPos=(float)(Math.sqrt(delPosX*delPosX+delPosY*delPosY));
          if(tarPosX!=posX)
          {    
               velX= velocity*delPosX/delPos;
                     isMovingRight= velX >= 0;
          }

          if(tarPosY!=posY)
          {
              velY= velocity*delPosY/delPos;
                isMovingUp= velY >= 0;
           }
     }

     //Position rendern
     posX+=velX*delTime;
     posY+=velY*delTime;

     //Und gleich darauf die Kollisionserkennung durchführen
     if(isMovingRight&&posX>tarPosX||!isMovingRight&&posX<tarPosX)
     {
          velX=0;
          posX=tarPosX;
     }

     if(isMovingUp&&posY>tarPosY0||!isMovingUp&&posY<tarPosY)
     {
          velY=0;
          posY=tarPosY;
     }

}


Ps: die While Schleife ist im Grunde genommen eine If Abfrage :biggrin:

PPS: habe isMovingUp verwechselt in Wahrheit ist da jetzt ein isMovingDown daraus geworden ändert aber nichts am richtigen Ablauf der Berechnung
 
Zuletzt bearbeitet von einem Moderator:
  • Danke
Reaktionen: coreytaylor211
So ich habe alles versucht ohne die Lösung anzuschauen aber habe es nicht geschafft.
Jetzt kommt aber der Witz :) es geht immer noch nicht.
Ich poste hier nochmal den Code vielleicht siehst du ja den Fehler.
Nochmals vielen Dank
Code:
velX= (float) (velocity*(tarPosX-posX)*(tarPosX-posX)/Math.sqrt((tarPosX-posX)*(tarPosX-posX)+(tarPosY-posY)*(tarPosY-posY)));
                isMovingRight= velX >= 0?true:false;
                Log.d("Test","velX  "  + velX);


                velY= (float) (velocity*(tarPosY-posY)*(tarPosY-posY)/Math.sqrt((tarPosY-posY)*(tarPosY-posY)+(tarPosX-posX)*(tarPosX-posX)));
                isMovingUp= velY >= 0?true:false;
                Log.d("Test","velY  "  + velY);
                if (velX==0&&velY==0&&(tarPosX!=posX||tarPosY!=posY)){

                    float delPosX = tarPosX-posX;
                    float delPosY = tarPosY-posY;
                    float delPos = (float)(Math.sqrt(delPosX*delPosX+delPosY*delPosY));


                    if (tarPosX!=posX){
                        velX = velocity*delPosX/delPos;
                        isMovingRight = velX >=0;

                    }
                    if(tarPosY != posY){
                        velY= velocity*delPosY/delPos;
                        isMovingUp = velY >=0;
                    }


                }
                posX+=velX*delTime;
                posY+=velY*delTime;
                if (isMovingRight && posX > tarPosX||!isMovingRight&&posX<tarPosX){
                    velX=0;
                    posX=tarPosX;
                    Log.d("Test","tarPosX  "  + tarPosX);
                }
                if(isMovingUp && posY > tarPosY||!isMovingUp&&posY<tarPosY){
                    velY=0;
                    posY=tarPosY;
                    Log.d("Test","tarPosY  "  + tarPosY);
                }
 
Löschen einfach mal die erste Berechnung der Geschwindigkeiten ganz oben. Mit dieser kommst du nie in die richtige Berechnung der Geschwindigkeiten weil velX und velY nie 0 sind und wenn doch dann würdest du durch 0 dividieren.

Btw: Verstehst du worauf die Berechnungen beruhen :)

Und wenn du dabei bist ändere mal isMovingUp

Setzte es auf True wenn velY kleiner 0 und bei der Anfrage ganz unten die < und > umkehren.
 
  • Danke
Reaktionen: coreytaylor211
Huhu danke für die Hilfe, habe es so gemacht wie du gesagt hast aber es geht leider nicht :(
Code:
        @Override
        public boolean onTouchEvent(MotionEvent event){
            if(event.getAction()== MotionEvent.ACTION_DOWN){
                tarPosX= event.getX();
                tarPosY= event.getY();
                Log.d("Test","velX  "  + velX);
                Log.d("Test","velY  "  + velY);
                isMovingRight  = velX >= 0?true:false;
                isMovingDown = velY>=0?true:false;
                if (velX==0&&velY==0&&(tarPosX!=posX||tarPosY!=posY)){


                    float delPosX = tarPosX-posX;
                    float delPosY = tarPosY-posY;
                    float delPos = (float)(Math.sqrt(delPosX*delPosX+delPosY*delPosY));


                    if (tarPosX!=posX){
                        //velX = (float) (velocity*(tarPosX-posX)*(tarPosX-posX)/Math.sqrt((tarPosX-posX)*(tarPosX-posX)+(tarPosY-posY)*(tarPosY-posY)));
                        velX = velocity*delPosX/delPos;
                        isMovingRight = velX >=0;


                    }
                    if(tarPosY != posY){
                        //velY = (float) (velocity*(tarPosY-posY)*(tarPosY-posY)/Math.sqrt((tarPosY-posY)*(tarPosY-posY)+(tarPosX-posX)*(tarPosX-posX)));
                        velY= velocity*delPosY/delPos;
                        isMovingDown = velY <=0;          // Hier habe ich velY auf true gemacht wenn es kleiner 0.


                    }


                }
                posX+=velX*delTime;
                posY+=velY*delTime;


                if (isMovingRight && posX > tarPosX || !isMovingRight && posX < tarPosX ){
                    velX=0;
                    posX=tarPosX;
                    Log.d("Test","tarPosX  "  + tarPosX);
                }
                if(isMovingDown && posY < tarPosY || !isMovingDown && posY > tarPosY ){       // Hier habe ich die < > geändert wie gewünscht.
                    velY=0;
                    posY=tarPosY;
                    Log.d("Test","tarPosY  "  + tarPosY);
                }
Ich möchte dich ja auch nicht nerven aber ich bekomme es einfach nicht hin.
 
Ja warum ist denn der Code auch in der onClick.
Du nervst schon nicht....

Pack das in eine schleife die ständig ausgeführt wird und in onClick setzt du einfach nur die target positionen (wenn tarPosX==posX und auch tarPosX ==posY)

Nicht in OnClick!
 
  • Danke
Reaktionen: coreytaylor211
Jaiel schrieb:
(wenn tarPosX==posX und auch tarPosX ==posY)

meinst du hier wirklich tarPosX == posY ?

Ich habe das die Berechnung in eine eigende Methode gepackt, weil wenn ich das in eine Schleife packe hängt sich das Handy auf.

meine onClick sieht jetzt so aus :
Code:
        public boolean onTouchEvent(MotionEvent event){
            if(event.getAction()== MotionEvent.ACTION_DOWN){
                tarPosX= event.getX();
                tarPosY= event.getY();
                updatePos();
                }
            return true;

        }

und die Berechnung sieht so aus
Code:
        public void updatePos(){


                Log.d("Test", "velX  " + velX);
                Log.d("Test","velY  "  + velY);
                isMovingRight  = velX >= 0?true:false;
                isMovingDown = velY>=0?true:false;
                if (velX==0&&velY==0&&(tarPosX!=posX||tarPosY!=posY)){


                    float delPosX = tarPosX-posX;
                    float delPosY = tarPosY-posY;
                    float delPos = (float)(Math.sqrt(delPosX*delPosX+delPosY*delPosY));


                    if (tarPosX!=posX){
                        velX = (float) (velocity*(tarPosX-posX)*(tarPosX-posX)/Math.sqrt((tarPosX-posX)*(tarPosX-posX)+(tarPosY-posY)*(tarPosY-posY)));
                        //velX = velocity*delPosX/delPos;
                        isMovingRight = velX >=0;


                    }
                    if(tarPosY != posY){
                        velY = (float) (velocity*(tarPosY-posY)*(tarPosY-posY)/Math.sqrt((tarPosY-posY)*(tarPosY-posY)+(tarPosX-posX)*(tarPosX-posX)));
                        //velY= velocity*delPosY/delPos;
                        isMovingDown = velY <=0;          // Hier habe ich velY auf true gemacht wenn es kleiner 0.


                    }





                }
                posX+=velX*delTime;
                posY+=velY*delTime;


                if (isMovingRight && posX > tarPosX || !isMovingRight && posX < tarPosX ){
                    velX=0;
                    posX=tarPosX;
                    Log.d("Test","tarPosX  "  + tarPosX);
                }
                if(isMovingDown && posY > tarPosY || !isMovingDown && posY < tarPosY ){       // Hier habe ich die < > geändert wie gewünscht.
                    velY=0;
                    posY=tarPosY;
                    Log.d("Test","tarPosY  "  + tarPosY);
                }

                Log.d("Test","posX  "  + posX);
                Log.d("Test","posY  "  + posY);


                Log.d("Test","x1  "  + x1);
                Log.d("Test","y1  "  + y1);


                Log.d("Test"," Ende x1  "  + x1);
                Log.d("Test"," Ende y1  "  + y1);
                Log.d("Test"," Ende tarPosX  "  + tarPosX);
                Log.d("Test"," Ende tarPosY  "  + tarPosY);
                Log.d("Test"," Ende posX  "  + posX);
                Log.d("Test"," Ende posY  "  + posY);
                Log.d("Test"," Ende velX  "  + velX);
                Log.d("Test"," Ende velY  "  + velY);




        }


Wenn ich diese Berechnung hier nehme
Code:
velX = velocity*delPosX/delPos;
velY= velocity*delPosY/delPos;
dann bewegt sich die Kugel ganz langsam aber kann nicht gesteuert werden.

Wenn ich die andere nehme dann bewegt lässt sich die Kugel wieder nur diagonal nach rechts unten und ganz nach rechts steuern, aber Sie hält nicht an.
Bewegungen nach links oder diagonal nach oben links springt Sie nur.
 
Juhu habe es hinbekommen aus irgendeinem Grund musste ich
Code:
posX=tarPosX  in tarPosX = posX ändern und mit posY genau das selbe.
[DOUBLEPOST=1440007757,1440004587][/DOUBLEPOST]Eigentlich ist das Thema hier ja durch aber :) aber wenn das ok ist würde ich dich gerne über eine Formel fragen. (weil du in Mathe ja voll drin bist wie ich sehe )

Wie bekomme ich das jetzt hin das sich die Bitmap oder das Canvas sich genau in die Richtung dreht in die man gerade fährt ?
Das musste dir wie einen Pfeil vorstellen der immer in die Richtung zeigen soll in die er fährt.
Wenn das jetzt zu kompliziert ist, dann reicht auch einfach nur ein Hinweis auf was ich mein Augen richten sollte.

Vielen Dank
 
Ja im onClick solltest du sie Zielkoordinaten nur ändernn wenn das Bitmap sich gerade nicht bewegt sprich auf den jetzigen target Positionen ruht.(edit: war ein Verschreiben. ...Natürlich meinte ich tarPosY==posY)
Sonst wird es so sein dass du mitten drin in der Bewegung die Koordinaten änderst und das Bild bewegt sich entweder weiter oder springt zu dieser Stelle urplötzlich...

Eine Drehung erreichst du mit Hilfe einer dreh Matrix. ..schaue dir dazu einfach die Canvas klasse in den docs an...Da gibt es ein paar Methoden die das machen können.

Dieser Ausdruck hier delPosX/delPos ist zum Beispiel der Cosinus des Winkels zwischen x Achse und deinem object bzw. der Sinus des Winkels zwischen Y Achse und dem Objekt. ...umgekehrt ist ist delPosY/delPos der Kosinus zwischen Y und Objekt und Sinus zw. X und Objekt. ..

Daraus kannst du den Drehwinkel berechnen ;)
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: coreytaylor211
Zurück
Oben Unten