# Algorithmus für bessere Kollisionsabfragen



## Feeder (17. Jun 2017)

Hey, in folgendem Programm soll eine zufällige Anzahl an 2D-Bällen erstellt werden, diese sollen wenn sie mit anderen Bällen kollidieren mit diesen verschmelzen und im Falle, das sie am Rand der Frame kommen, abprallen. 

Vor allen Dingen die korrekte Kollisionsabfrage am Rand ist mir wichtig, leider geschieht es nicht selten, dass die Bälle am Rande "kleben" bleiben, da sie nicht mehr die Grenze in das Spielfeld überschreiten.

Dafür suche ich bessere Kollisionabfragen. Könnte jemand Code- oder theoretische Vorschläge geben?


```
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;

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

public class TheWalkerAI {
    JFrame frame;
    AIPanel panel;
    JLabel label;
    ArrayList<Walker> was;
    long lastTime;
    public TheWalkerAI() {
        init();
        while(true) {
        long before = System.currentTimeMillis();
        double delta = (System.currentTimeMillis() - lastTime)*0.001;
        calculate(delta);
        lastTime = before;
        repaint();
   
//        try {
//            Thread.sleep(1);
//        } catch (InterruptedException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }
        label.setText( was.size() + " Walkers initialized," + " running by " + Math.round((1/delta)) + " FPS");

        }
    }
    private void calculate(double deltatime) {
        for(int i = 0; i < was.size(); ++i) {
        was.get(i).checkObjectCollision(was, i);
        was.get(i).step(deltatime);
   
        }
    }
    private void repaint() {
        label.repaint();
        panel.repaint();
        frame.repaint();
       
    }
    private void init() {
        lastTime = System.currentTimeMillis();
        frame = new JFrame();
        frame.setBounds(0, 0, 1000, 1000);
        frame.setResizable(false);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setBackground(Color.BLACK);
        frame.setResizable(true);
        frame.setTitle("Ellipses rolling...");
        panel = new AIPanel();
        frame.add(panel);
        frame.addComponentListener(new ComponentListener() {
           
            @Override
            public void componentShown(ComponentEvent e) {
                // TODO Auto-generated method stub
               
            }
           
            @Override
            public void componentResized(ComponentEvent e) {
                label.setLocation(0, frame.getHeight()-60);
               
            }
           
            @Override
            public void componentMoved(ComponentEvent e) {
                // TODO Auto-generated method stub
               
            }
           
            @Override
            public void componentHidden(ComponentEvent e) {
                // TODO Auto-generated method stub
               
            }
        });
        label = new JLabel();
        label.setBounds(0, frame.getHeight()-60, 280, 20);
        label.setForeground(Color.WHITE);
        label.setBackground(Color.BLACK);
        label.setOpaque(true);
        panel.add(label);
        panel.setLayout(null);
        createWalkers(600, 1000, 1000,40);
    }
    public void createWalkers(int max, double maxspeedy, double maxspeedx, double maxradius) {
        long length = (Math.round((max)*Math.random()));
        was = new ArrayList<Walker>();
        for(int i = 0; i < length; ++i) {
            double xspeed = maxspeedx * Math.random() - 0.5*maxspeedx;
            double yspeed = maxspeedy * Math.random() - 0.5*maxspeedy;
            double radius = maxradius * Math.random() + 10;
            was.add(new Walker(frame,new Vector(xspeed, yspeed), radius, new Vector(frame.getWidth() * Math.random(), frame.getHeight()*Math.random())));
        }
       
    }
    public static void main(String[] args) {
        new TheWalkerAI();
   
       
    }
    public class AIPanel extends JPanel {
         public void paintComponent(Graphics g) {
            for(int i = 0; i < was.size(); ++i) {
                was.get(i).display(g);

            }
         }
    }

}
```


```
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.JFrame;

public class Walker {
    JFrame motherframe;
    Vector pos;
    double radius;
    Vector speed;
    Color color;
    public Walker(JFrame frame, Vector speed, double radius) {
        double x = frame.getWidth()/2;
        double y = frame.getHeight() / 2;
        pos = new Vector(x, y);
        this.radius = radius;
        motherframe = frame;
        Random ra = new Random();
        int r = ra.nextInt(256);
        int cg = ra.nextInt(256);
        int b = ra.nextInt(256);
        color = new Color(r, cg, b);
    }
    public Walker(JFrame frame, Vector speed, double radius, Vector position) {
        this.speed = speed;
        this.radius = radius;
        motherframe = frame;
        this.pos = position;
        Random ra = new Random();
        int r = ra.nextInt(256);
        int cg = ra.nextInt(256);
        int b = ra.nextInt(256);
        color = new Color(r, cg, b);
    }
    public void step(double time) {
        double posaddx = speed.getX()*time;
        double posaddy = speed.getY()*time;

        if(pos.getX() + posaddx + radius < motherframe.getWidth() && pos.getX() + posaddx > 0 ) {
            pos.setX(pos.getX()+posaddx);
   
        }
        else {
            //Abstand zu Ende berechnen
            //Addieren Teil von posaddx hinzu
            //Subtrahieren den rest hinzu
            //Negieren der Geschwindigkeit
                if (speed.getX() > 0){
                    double r = motherframe.getWidth() - (pos.getX() + radius);
                    pos.setX(pos.getX()+r);
                    posaddx = posaddx - r; //Übriger Teil
                    pos.setX(pos.getX()+posaddx);
                    speed.setX(-speed.getX());
            }     else {
               
                    double r = pos.getX() - radius;
                    pos.setX(pos.getX()+r);
                    posaddx = posaddx - r; //Übriger Teil
                    pos.setX(pos.getX()+posaddx);
                    speed.setX(-speed.getX());
                   
            }
        }
       
        if(pos.getY() + posaddy + radius < motherframe.getHeight() && pos.getY() + posaddy > 0) {
            pos.setY(pos.getY()+posaddy);
        } else {
            //Abstand zu Ende berechnen
            //Addieren Teil von posaddx hinzu
            //Subtrahieren den rest hinzu
            //Negieren der Geschwindigkeit
                if(speed.getY() >= 0) {
                    double r = motherframe.getHeight() - (pos.getY() + radius);
                    pos.setY(pos.getY()+r);
                    posaddy = posaddy - r; //Übriger Teil
                    pos.setY(pos.getY()+posaddy);
                    speed.setY(-speed.getY());
            }      else {
                double r = pos.getY() - radius;
                pos.setY(pos.getY()+r);
                posaddy = posaddy - r; //Übriger Teil
                pos.setY(pos.getY()+posaddy);
                speed.setY(-speed.getY());
   
            }
        }

    }
    public void display(Graphics g) {
        g.setColor(color);
        g.fillOval((int)Math.round(pos.getX()-radius*0.5), (int)Math.round(pos.getY()-radius*0.5), (int)radius, (int)radius);

    }
    public void checkObjectCollision(ArrayList<Walker> was, int himself) {
        for(int i = himself+1; i < was.size(); ++i) {
            if(i != himself){
                if((this.pos.distance(was.get(i).pos) <= this.radius + was.get(i).radius)) {
                    Walker wa = was.get(i);
                    was.remove(i);
                    int g = (int) Math.round((wa.color.getGreen() + this.color.getGreen()) * 0.5);
                    int r = (int) Math.round((wa.color.getRed() + this.color.getRed()) * 0.5);
                    int b = (int) Math.round((wa.color.getBlue() + this.color.getBlue()) * 0.5);
                    color = new Color(r,g,b);
                    this.radius = Math.pow(this.radius*this.radius + wa.radius*wa.radius, 0.5);
                    this.pos.setX((this.pos.getX()+wa.pos.getX())*0.5);
                    this.pos.setY((this.pos.getY()+wa.pos.getY())*0.5);
                    this.speed.setX((this.speed.getX()+wa.speed.getX())*0.5);
                    this.speed.setY((this.speed.getY()+wa.speed.getY())*0.5);
                }
            }
        }
       
    }
}
```


```
public class Vector extends java.awt.Point{

    private static final long serialVersionUID = 5704073610770567171L;
    public void setX(double x) {
        this.x = x;
    }
    public void setY(double y) {
        this.y = y;
    }
    double x,y;
    public Vector(double x, double y) {
        this.x = x;
        this.y = y;
    }
    @Override
    public double getX() {
        // TODO Auto-generated method stub
        return x;
    }

    @Override
    public double getY() {
        // TODO Auto-generated method stub
        return y;
    }

    @Override
    public void setLocation(double x, double y) {
        this.x = x;
        this.y = y;
       
    }
    public void rotate(double angle) {
            double rx = (this.x * Math.cos(angle)) - (this.y * Math.sin(angle));
            double ry = (this.x * Math.sin(angle)) + (this.y * Math.cos(angle));
            x = rx;
            y = ry;
       
    }
    public void add(Vector v) {
        this.y += v.getY();
        this.x += v.getX();
    }
   

}
```


----------



## Hellosager (17. Jun 2017)

Könntest mal sagen wo du den Fehler vermutest, ich hab nicht so Lust mir alles durchzulesen, Sorry.


----------



## Feeder (18. Jun 2017)

Hellosager hat gesagt.:


> Könntest mal sagen wo du den Fehler vermutest, ich hab nicht so Lust mir alles durchzulesen, Sorry.



Der Fehler; 

Thread arbeitet durch äußere Einflüsse WhileSchleife länger ab. Position ist außerhalb der Grenzen. Der Nächste Durchlauf ist schneller, Position wird nicht wieder in die Grenzen gesetzt...


----------



## mrBrown (18. Jun 2017)

Dann fang genau den Fall ab. Wenn sie außerhalb der Grenzen sind, werden sie wieder rein gesetzt. 


Deine Vector-Klasse ist btw völliger Unsinn.


----------



## Feeder (18. Jun 2017)

mrBrown hat gesagt.:


> Dann fang genau den Fall ab. Wenn sie außerhalb der Grenzen sind, werden sie wieder rein gesetzt.
> 
> 
> Deine Vector-Klasse ist btw völliger Unsinn.



Ich probiers mal aus. Danke!

Wie soll den die Vector Klasse aussehen? Hatte sie mittlerweile abgeändert:


```
public class Vector extends java.awt.Point{

    public void setX(double x) {
        this.x = x;
    }
    public void setY(double y) {
        this.y = y;
    }
    double x,y;
    public Vector(double x, double y) {
        this.x = x;
        this.y = y;
    }
    @Override
    public double getX() {
        // TODO Auto-generated method stub
        return x;
    }

    @Override
    public double getY() {
        // TODO Auto-generated method stub
        return y;
    }

    @Override
    public void setLocation(double x, double y) {
        this.x = x;
        this.y = y;
       
    }
    public void rotate(double angle) {
            double rx = (this.x * Math.cos(angle)) - (this.y * Math.sin(angle));
            double ry = (this.x * Math.sin(angle)) + (this.y * Math.cos(angle));
            x = rx;
            y = ry;
       
    }
    public Vector add(Vector v) {
        double y = this.y + v.getY();
        double x = this.x + v.getX();
        return new Vector(x, y);
    }
    public Vector sub(Vector v) {
        double y = this.y - v.getY();
        double x = this.x - v.getX();
        return new Vector(x, y);
    }
    public Vector multiply(double d) {
        Vector v = new Vector(getX()*d, getY()*d);
        return v;
    }
   

}
```


----------



## thecain (18. Jun 2017)

In welche Richtung zeigt denn dein vektor? Was ist sein skalar?


----------



## mrBrown (18. Jun 2017)

Feeder hat gesagt.:


> Wie soll den die Vector Klasse aussehen? Hatte sie mittlerweile abgeändert:


Du solltest *kein* `extends Point` nutzen. Das ist nur eine riesen Fehlerquelle.



thecain hat gesagt.:


> In welche Richtung zeigt denn dein vektor? Was ist dein skalar?


Bezieht sich das auf die Vektor-Klasse oder auf den gesamten Code?


----------



## Feeder (18. Jun 2017)

mrBrown hat gesagt.:


> Du solltest *kein* `extends Point` nutzen. Das ist nur eine riesen Fehlerquelle.
> 
> 
> Bezieht sich das auf die Vektor-Klasse oder auf den gesamten Code?



Ich stehe stets offen für jeden Verbesserungsvorschlag


----------



## Feeder (18. Jun 2017)

thecain hat gesagt.:


> In welche Richtung zeigt denn dein vektor? Was ist sein skalar?


Hmm, benötigte ich bis jetzt noch nicht... Ich werde es mal einschreiben...


----------



## Feeder (18. Jun 2017)

Habe die Vector Klasse erstmal überschrieben...


```
public class Vector {
    double x,y;
    public Vector(double x, double y) {
        this.x = x;
        this.y = y;
    }
    public void setX(double x) {
        this.x = x;
    }
    public void setY(double y) {
        this.y = y;
    }

    public double getX() {
        // TODO Auto-generated method stub
        return x;
    }

    public double getY() {
        // TODO Auto-generated method stub
        return y;
    }

    public void setLocation(double x, double y) {
        this.x = x;
        this.y = y;
       
    }
    public void rotate(double angle) {
            double rx = (this.x * Math.cos(angle)) - (this.y * Math.sin(angle));
            double ry = (this.x * Math.sin(angle)) + (this.y * Math.cos(angle));
            x = rx;
            y = ry;   
    }
    public void add(Vector v) {
        y = this.y + v.getY();
        x = this.x + v.getX();
   
    }
    public void sub(Vector v) {
        y = this.y - v.getY();
        x = this.x - v.getX();
   
    }
    public void multiply(double d) {
        x = x*d;
        y = y*d;
    }
    public void div(double d) {
        x = x/d;
        y = y/d;
    }
    public double mag() {
          return Math.pow((x*x + y*y), 0.5);
        }
    public void normalize() {
        double m = mag();
        div(m);
    }
    public double distance(Vector b) {
        Vector c = this.clone();
        c.sub(b);
        double x = this.mag();
        return x;
       
    }
    public Vector clone() {
        Vector v = new Vector(this.getX(), this.getY());
        return v;
       
    }
   
   

}
```


----------



## mrBrown (18. Jun 2017)

Ich würde uU sogar trennen zwischen Vektor als Richtungsvektor und Vektor als Punkt, das macht's manchmal übersichtlicher.
Und (ist aber persönliche Präferenz) die Klasse immutable machen


----------

