Variablen Mathematik - Vektorielle Geschwindigkeit

Feeder

Bekanntes Mitglied
Hey, folgender Code soll den Abstand zwischen Spieler und Maus errechnen und dann die Position des Spielers immer mehr dem der Maus annäheren.
Meine Formel möchte ich hier noch herleiten:
vy = Geschwindigkeit in y Richtung
vy = Geschwindigkeit in x Richtung
Betrag(v) = Wurzel(vx^2 + vy^2)
Es gilt (um sich direkt zur Maus zu bewegen), dass
x/y (Abstände Maus Spieler) = vx/vy, demnach ergibt sich
vx = vy*(x/y)

Einsetzen:
Betrag(v) = Wurzel(vy*(x/y)^2 + vy^2)
(Betrag von v) ^2 = (vy*x/y)^2 + (vy)^2 {bx + nx = (b+n)x}
(Betrag von v)^2 = (1+x/y)vy
vy = (Betrag von v)^2/(1+x/y)
vx = vy*x/y

Dieser Code sollte eigentlich genau das machen, klappt aber nicht ;D
Java:
    public void calculate() {
        // Player p; 
        PointerInfo mi = MouseInfo.getPointerInfo();
        //speedbetrag = 1pix/tick
        double vx =  mi.getLocation().getX() - p.getX(); //Werte der Vektoren
        double vy =  mi.getLocation().getY() - p.getY();
        double yspeed = (Math.pow(1, 2)/(1 + vy/vx)); // y speed = geschwindigkeitsbetrag zum Quadrat/(1+yvonvector/xvonvector)
    
        double  xspeed = vy/vx*yspeed;

        yspeed = Math.round(yspeed * 1000)/1000; //rundet 4 Kommastellen
        xspeed = Math.round(xspeed * 1000)/1000;

        p.setX(p.getX() + (xspeed)); // in jedem Tick wird xspeed addiert (v*t = s)
        p.setY(p.getY() + (yspeed));
        System.out.println("Sys:" + yspeed + " " + xspeed + " " + Math.pow((xspeed*xspeed + yspeed*yspeed), 0.5)); //3 Ergebnis muss näherungsweise speedbetrag sein
    }

Der rastet mir da total aus. Bei einigen Grenzfällen kommt hin und wieder jedoch Sinnvolles zum Vorschein, beispielweise bei hohen speedbetrag und niedriger refrehsrate
 

Enceladus271

Bekanntes Mitglied
1. Math.pow(1,2) ist immer gleich 1. In deiner Rechnung ist daher yspeed = 1 / (1 + vy/vx) = vx / (vx+vy). Was willst du dort berechnen?
2. Wieso rundest du auf 4 Stellen? Möchtest du kein möglichst exaktes Ergebnis haben?
3. Du hast nirgendwo die Fälle berücksichtigt, bei denen durch 0 geteilt wird.
 

Feeder

Bekanntes Mitglied
1. Math.pow(1,2) ist immer gleich 1. In deiner Rechnung ist daher yspeed = 1 / (1 + vy/vx) = vx / (vx+vy). Was willst du dort berechnen?
2. Wieso rundest du auf 4 Stellen? Möchtest du kein möglichst exaktes Ergebnis haben?
3. Du hast nirgendwo die Fälle berücksichtigt, bei denen durch 0 geteilt wird.

3. ja das stimmt, dass muss ich noch ändern.
2. Das war ein versuch sinnvolle Ergebnisse zu erhalten, ich werde es mal mit BigDecimal probieren.
1. Wie in der Herleitung gezeigt, sollten das die Werte der vektoriellen Geschwindigkeit sein. V(vx|vy)
 

Feeder

Bekanntes Mitglied
Java:
    public void calculate() {
       //Player p
        PointerInfo mi = MouseInfo.getPointerInfo();
//p.getX; p.getY liefert BigDecimal
        double vx =  mi.getLocation().getX() - (p.getX().doubleValue());
        double vy =  mi.getLocation().getY() - (p.getY().doubleValue());
        BigDecimal yspeed;
        BigDecimal  xspeed;
        if(1+vx/vy == 0) {
            yspeed = new BigDecimal(0);
            xspeed = new BigDecimal(0);
        } else {
         yspeed = new BigDecimal((Math.pow(0.01, 2)/(1 + vy/vx))); // y speed = geschwindigkeitsbetrag zum Quadrat/(1+yvonvector/xvonvector)
         xspeed = yspeed.multiply(new BigDecimal(vx/vy));
        }
 

JCODA

Top Contributor
Kannst du nochmal erklären, warum du durch irgendwas teilen musst? Das sieht mir irgendwie sehr unnatürlich aus. Wie schnell soll sich der Spieler bewegen? in abh. der Entfernung oder hat er eine konstante Geschwindigkeit?

BigDecimal o.A scheinen mir nicht wirklich zielführend. (Hier geht ja es explizit um einzelnen Pixelpositionen, nicht um die Nachkommastellen von pi. )
 

Feeder

Bekanntes Mitglied
Verdammt :D Ich muss das Quadrat übernehmen. Danke, probiere es gleich aus:

(Betrag von v)^2 = (vy*x/y)^2+ vy^2
--->
(Betrag von v)^2 = (x^2/y^2)*vy^2 + 1*vy^2 {bx+nx = (b+n)x}
--->
(Betrag von v)^2 = (1+x^2/y^2)vy^2
vy^2 = (Betragvonv)^2 / (1+x^2/y^2)
vy = n/Wurzel(1+(x^2/y^2))
 

Feeder

Bekanntes Mitglied
Java:
    public void calculate() {
        PointerInfo mi = MouseInfo.getPointerInfo();
        double vx =  mi.getLocation().getX() - p.getX();
        double vy =  mi.getLocation().getY() - p.getY();
        double yspeed;
        double  xspeed;
        if(1+vx*vx/vy*vy == 0) {
            yspeed = 0;
            xspeed = 0;
        } else {
         if(vy < 0) {
         yspeed = ((Math.pow(0.1, 2)/-Math.pow((1 + vy*vy/vx*vx), 0.5))); // y speed = geschwindigkeitsbetrag zum Quadrat/(1+yvonvector/xvonvector)
         } else {
         //um richtige Lösung der Lösungsmenge der Wurzel(n) zu verwenden (negative Wurzelergebnisse)
         yspeed = ((Math.pow(0.1, 2)/Math.pow((1 + vy*vy/vx*vx), 0.5))); // y speed = geschwindigkeitsbetrag zum Quadrat/(1+yvonvector/xvonvector)
       
         }
         if(vy!=0) {
         xspeed = yspeed*((vx/vy));
         } else {
             xspeed = 0;
         }

        }

Dieser Code funktioniert schon besser, bugt jedoch leider :(

Bugbeschreibung:
nach 1-2 Sekunden rast der mich in die linke, obere Ecke meines Frames und bleibt dort für immer...
Ich glaube das liegt daran, dass er mir für Werte gegen Unendlich nicht gewachsen ist.:eek:
Kann es sein, dass ich den paint in ein anderes Thread auslagern sollte, habe ich schließlich ne while(true) Schleife?

Java:
    private class GamePanel extends JPanel{
        public void paint(Graphics g) {
            g.setColor(Color.RED);
            g.fillOval((int)(p.getX()), (int)(p.getY()), p.getRadius(),p.getRadius());
          
        }
Danke für eure Verbesserungen !!! Habt ihr noch mehr o_O
 

JCODA

Top Contributor
Leider hast du meine Frage nicht beantwortet, naja ...
Könntest du ein kurzes Beispiel erstellen, in dem dein Problem ausführbar und sichtbar wird?
 

JCODA

Top Contributor
Erstelle ein Programm, welches so wenig wie möglich code beinhaltet, aber so viel wie nötig, sodass wir das Problem anhand von dem Code sehen können.
 

Feeder

Bekanntes Mitglied
Java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.PointerInfo;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class KSKB {
    JFrame frame;
    GamePanel panel;
    double px,py;
    public static void main(String[] args) {
        new KSKB();

    }
    public KSKB() {
        init();
        while(true) {
        calculate();
        draw();
        }
    }
private void draw() {
        panel.repaint();
        frame.repaint();
       
    }
private void calculate() {
    PointerInfo mi = MouseInfo.getPointerInfo();
    double vx =  mi.getLocation().getX() - px;
    double vy =  mi.getLocation().getY() - py;
    double yspeed;
    double  xspeed;
    if(1+vx*vx/vy*vy == 0) {
        yspeed = 0;
        xspeed = 0;
    } else {
     if(vy < 0) {
     yspeed = ((Math.pow(0.1, 2)/-Math.pow((1 + vy*vy/vx*vx), 0.5))); // y speed = geschwindigkeitsbetrag zum Quadrat/(1+yvonvector/xvonvector)
     } else {
     //um richtige Lösung der Lösungsmenge Wurzel(n) zu verwenden (negative Wurzelergebnisse)
     yspeed = ((Math.pow(0.1, 2)/Math.pow((1 + vy*vy/vx*vx), 0.5))); // y speed = geschwindigkeitsbetrag zum Quadrat/(1+yvonvector/xvonvector)
    
     }
     if(vy!=0) {
     xspeed = yspeed*((vx/vy));
     } else {
         xspeed = 0;
     }
     px = px + xspeed; //gemäß: v = s*t
     py = py + yspeed;
        }
    }
private void init() {
    frame = new JFrame();
    frame.setSize(600, 600);
    frame.setResizable(false);
    panel = new GamePanel();
    panel.setBounds(0, 0, 600, 600);
    frame.add(panel);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
       
    }
private class GamePanel extends JPanel{
    public void paint(Graphics g) {
        g.setColor(Color.BLUE);
        g.fillOval((int)px, (int)py, 20, 20);
    }
    }
}

Ich hoffe das ist das gewollte Beispiel (abgespeckt, viel unnötiges gibt es noch nicht) :)
 

Feeder

Bekanntes Mitglied
IDEE!!!
Java:
     double vx =  mi.getLocation().getX() - px;
    double vy =  mi.getLocation().getY() - py;

Der Code funktioniert env. nur, wenn man EINEN Bildschirm besitzt...

Ebenso könnte es sein, das das ändern der Maus Position zwischen dem Berechnungen von vx und vy einen Fehler hervorruft, verändere also:

Java:
private void calculate() {
    PointerInfo mi = MouseInfo.getPointerInfo();
    Point p = mi.getLocation();

    if(p.getX()>= 0 && p.getY() >= 0) {
        double vx =  p.getX() - px;
        double vy = p.getY() - py;
        double yspeed;
        double  xspeed;
        if(1+vx*vx/vy*vy == 0) {
            yspeed = 0;
            xspeed = 0;
        } else {
         if(vy < 0) {
         yspeed = ((Math.pow(0.1, 2)/-Math.pow((1 + vy*vy/vx*vx), 0.5))); // y speed = geschwindigkeitsbetrag zum Quadrat/(1+yvonvector/xvonvector)
         } else {
         //um richtige Lösung der Lösungsmenge Wurzel(n) zu verwenden (negative Wurzelergebnisse)
         yspeed = ((Math.pow(0.1, 2)/Math.pow((1 + vy*vy/vx*vx), 0.5))); // y speed = geschwindigkeitsbetrag zum Quadrat/(1+yvonvector/xvonvector)
    
         }
         if(vy!=0) {
         xspeed = yspeed*((vx/vy));
         } else {
             xspeed = 0;
         }
         px = px + xspeed; //gemäß: v = s*t
         py = py + yspeed;
            }
    }
    if(px<100000) {
    System.out.println(mi.getLocation().getX() + " " + mi.getLocation().getY());
    System.out.println(px + " " + py);
    }
    }

Ich stelle zudem fest, das das Programm ausrastet, wenn der Kreis links unter dem Mauszeiger ist. Ebenso wird mein Ergebnis unendlich, wenn sich der Mauszeiger und der Kreis zu nahe kommen (der Kreis springt dann immer hin und her)

129.00000000000003 101.99999917050971 // spielerwert
129.0 102.0 // mauswert
128.99999999965738 102.0099991705097 //spielerwert
129.0 102.0 // mauswert
129.0 101.99999967038927 //spielerwert

der nächste Spielerwert ist folglich größer 100000(siehe calculate())

Ich vermute also, das "Hüpfen des Kreises" um die Maus ist das Problem...

EDIT: Script läuft immer dann schief, wenn der x oder y Wert von der Maus "übergangen" wird
 
Zuletzt bearbeitet:

JCODA

Top Contributor
Hier ein Beispiel, um flüssige Animation sicherzustellen, berechnet man die Zeit zwischen den einzelnen Frames. Schau es dir mal an, frag ruhig gezielt, wenn etwas unklar ist.

Java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class KSKB {

    JFrame frame;
    GamePanel panel;
    double px, py;
    long lastTime;

    boolean constantSpeed = true;
  
    public static void main(String[] args) {
        new KSKB().startLoop();
    }

    public KSKB() {
        init();
    }

    public void startLoop() {
        lastTime = System.currentTimeMillis();
        while (true) {
            // Berechne Delta zwischen einzelnen Frames, um
            // Geschwindigkeitsberechnung in abh. der Zeit zu machen.
            long before = System.currentTimeMillis();
            double delta = (System.currentTimeMillis() - lastTime);
            calculate(delta);
            lastTime = before;
            panel.repaint();
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private void calculate(double t) {
        //Hier wäre ein MouseListener wohl schöner.
        PointerInfo mi = MouseInfo.getPointerInfo();
        Point m = mi.getLocation();
        SwingUtilities.convertPointFromScreen(m, panel);
        double dx = m.getX() - px;
        double dy = m.getY() - py;
        double len = Math.pow(dx * dx + dy * dy, 0.5);
        double vx = 0;
        double vy = 0;
        if (len > 10) {
            double ux = dx / len;
            double uy = dy / len;
            if (constantSpeed) {
                vx = ux * t / 4;
                vy = uy * t / 4;
            }else{              
                // Geschwindigkeit in Abh. der Entfernung, nicht physikalisch, aber
                // zum zeigen auch ok
                vx = ux * t / 4 * len / 100.0;
                vy = uy * t / 4 * len / 100.0;
            }
        }
        px += vx;
        py += vy;

    }

    private void init() {
        frame = new JFrame();
        frame.setSize(600, 600);
        frame.setResizable(false);
        panel = new GamePanel();
        panel.setBounds(0, 0, 600, 600);
        frame.add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);

    }

    private class GamePanel extends JPanel {
        // Bei Swing immer paintComponent überschreiben und super.paintComponent
        // muss ebenfalls aufgerufen werden
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.BLUE);
            g.fillOval((int) px - 10, (int) py - 10, 20, 20);
        }
    }
}
 

Feeder

Bekanntes Mitglied
Hey, dein Code funktioniert ja super :) Danke.
Mir ist jedoch nicht bewusst, wie du auf die Formel der calculate() Methode gekommen bist, wärst du so nett mir es noch einmal zu erklären ;)
Explizit verstehe ich:
Java:
            double ux = dx / len;
            double uy = dy / len;

dieses Konstrukt nicht. (Ganze Erklärung wäre mir wohl hilfreicher :p )

Edit: Ach das ist der Sinus und Kosinus !!!
Edit: Wie du dann auf:

Java:
            if (constantSpeed) {
                vx = ux * t / 4;
                vy = uy * t / 4;
            }else{           
                // Geschwindigkeit in Abh. der Entfernung, nicht physikalisch, aber
                // zum zeigen auch ok
                //Edit Abh.?
                vx = ux * t / 4 * len / 100.0;
                vy = uy * t / 4 * len / 100.0;
            }

Ist mir aber unklar, warum sollte : cos(ywinkel) und sin(ywinkel) * t eine Länge ergeben und warum multiplizierst du bei else:

mit len/100 ?

Edit:

Ach alles klar, ich habs !!!
Du rechnest mit Hilfe der sini die beiden vx/vy über die gesamtlänge aus.

Würdest du mir zuletzt bitte noch erklären, warum du bei nicht konstanter geschwindigkeit len / 100 multiplizierst?
 
Zuletzt bearbeitet:

JCODA

Top Contributor
Java:
            double ux = dx / len;
            double uy = dy / len;
In Vektorsprache bedeutet das, dass ich den Vektor normiere (er hat dann Länge 1) und wie du schon richtig gesehen hast, entspricht dass dann gerade einem Punkt auf dem Einheitskreis (deshalb die Darstellung mit sin/cos).
Würdest du mir zuletzt bitte noch erklären, warum du bei nicht konstanter geschwindigkeit len / 100 multiplizierst?

Naja, das war einfach so eine "Heuristik". Ich wollte, dass die momentane Geschwindigkeit von der Entfernung abhängt, in dem Fall ist also die Geschwindigkeit gerade Entfernung /100. Die 100 habe ich durch Ausprobieren gefunden. (einfach ein Wert, der gut aussieht.)
 

Feeder

Bekanntes Mitglied
Vektor Rechnung habe ich nächstes Jahr ausgiebig im Matheleistungskurs. Kann mir aber vorstellen, was du meinst.

Danke dir !!!

- Thread closed-
 

Ähnliche Java Themen

Neue Themen


Oben