2D Kollision -> Abstossung

Status
Nicht offen für weitere Antworten.

Verjigorm

Top Contributor
Hallo,

ich hab da nen kleines Programm mit 2 (oder mehr) Kreisen,
die sich über ein JPanel bewegen

Die Kollisionserkennung an sich funktioniert gut, aber ich verstehe nicht genau, wieso sich die Kreise nach der Kollision nicht abstossen, so wie geplant, sondern sich ineinander verkeilen

Vielleicht blickt jemand im Code durch, ist nicht toll, war eigentlich nur ne kleine Spielerei, die ausgeartet ist :)

Relevant sollten die Zeilen 103-120 sein, die prüfen die Kollision, wie gesagt, das funktioniert eigentlich gut.
Ab 228 ist die Steuerung für die Richtungen, da liegt wohl der Fehler, aber ich erkenne ihn nicht.
x_collision_possible auf false gesetzt, verhindert die Kollisionserkennung

Weiss jemand Rat?

mfg Verjigorm

Code:
package dots;

import java.awt.*;
import java.util.Random;

import javax.swing.*;


public class Dots extends JPanel {

	private static final long serialVersionUID = -252486986571082924L;
	//Anzahl Kreise
	private int anz = 2, speed_x = 5, speed_y = 5;
	private int[] x = new int[anz];
	private int[] y = new int[anz];
	private Color[] colors = {Color.WHITE, /*Color.LIGHT_GRAY, Color.DARK_GRAY,*/ Color.GRAY, Color.BLACK,
			Color.RED, Color.PINK, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.MAGENTA,
			Color.CYAN, Color.BLUE};
	private Color[] c = new Color[anz];
	
	private boolean[] x_collision = new boolean[anz]; 
	private boolean[] y_collision = new boolean[anz];
	
// x bzw y- Richtung nach Kollision ändern
	private boolean x_collision_possible = true;
	private boolean y_collision_possible = false;
	
	private Dots td;
	private int durchmesser = 50;
	
	private int refresh = 10, sleeptime = 15;
	private Random r = new Random();

	/*
	 * Main
	 */
	public static void main(String[] args) 
	{
	   new Dots();
	}
   
	/*
	 * Konstruktor
	 */
   public Dots()
   {
	   td = this;
	   
	   JFrame frame = new JFrame("Dots");
	   frame.setLocation(100,100);
	   frame.setSize(500,550);
	   frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	   frame.add(this);
	   
	   x[1] = 200;
	   //x[2] = 200;
	   //x[3] = 300;
	   //x[4] = 400;
	   
	   //initialisieren
	   for(int i=0; i<anz; i++)
	   {
		   c[i] = colors[r.nextInt(colors.length)];
		   x_collision[i] = false;
		   y_collision[i] = false;
		   new MyThread(i, r.nextInt(speed_x)+1, r.nextInt(speed_y)+1, x[i], y[i]).start();
	   }
       
	   //repaint-thread
	   new Thread(new Runnable(){

		@Override
		public void run() 
		{
			while(true)
			try {
				Thread.sleep(refresh);
				td.repaint();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		   
	   }).start();
	   
	   //Thread zur Kollisionsabfrage
	   new Thread(new Runnable(){

			@Override
			public void run() 
			{
				while(true)
				try {
					Thread.sleep(2*refresh);
					
					for(int i = 0; i < x.length; i++)
					{
						for(int j = 0; j < x.length; j++)
						{

							if(Math.abs((x[i]+durchmesser/2) - (x[j]+durchmesser/2)) <= 2*durchmesser 
								&& Math.abs((y[i]+durchmesser/2) - (y[j]+durchmesser/2)) <= 2*durchmesser
								&& i != j && x[i] != 0 && y[i] != 0)
							{
								//System.out.println("Kollision: " +
									//	x_positive[i] + " <-> " + x_positive[j] + " und " +
										//y_positive[i] + " <-> " + y_positive[j]);
								if(x_collision_possible)
								{
									x_collision[i] = true;
									x_collision[j] = true;
								}
								
								if(y_collision_possible)
								{
									y_collision[i] = true;
									y_collision[j] = true;
								}
							}
						}
					}
					
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			   
		   }).start();
	   
	   
	   frame.setVisible(true);
   }

   @Override
   public void paintComponent(Graphics g) 
   {
	      super.paintComponent(g);
	      
	      for(int i = 0; i<anz; i++)
	      { 
	    	  g.setColor(c[i]);
	    	  g.fillOval(x[i], y[i] , 2*durchmesser, 2*durchmesser);
	      }
   }
   
   
   
   class MyThread extends Thread
   {
	   	private int nr;
	   	private int x_mod, y_mod;
	   	boolean rechts = true;
	   	boolean runter = true;
		int x_int, y_int;
		
	   public MyThread(int nr, int x_mod, int y_mod, int x_start, int y_start)
	   {
		   this.nr = nr;
		   this.x_mod = x_mod;
		   this.y_mod = y_mod;
		   x_int = x_start;
		   y_int = y_start;
	   }
	   
		public void run() 
		{
			
			while(true)
			{
				//System.out.println("Thread: " + x1 + " <= " + 
					//	(getWidth()-2*durchmesser) + "," + rauf);
				if(x_int < getWidth()-2*durchmesser && x_int >= 0)
				{
					if(rechts)
					{
						rechts();
					}
					else
					{
						links();
					}
				}
				else 
				{
					if(x_int > 0)
					{
						links();
					}
					else
					{
						rechts();
					}
				}
				
				
				//Hoch-Runter
				if(y_int < getHeight()-2*durchmesser && y_int >= 0)
				{
					if(runter)
					{
						runter();
					}
					else
					{
						hoch();
					}
				}
				else 
				{
					if(y_int > 0)
					{
						hoch();
					}
					else
					{
						runter();
					}
				}
				
				x[nr] = x_int;
				y[nr] = y_int;		
			}
		}
		
		private synchronized void rechts()
		{
			if(x_collision[nr])
			{
				x_collision[nr] = false;
				links();
				return;
			}
			rechts = true;
			x_int+=x_mod;
			x_int+=x_mod;
			try {
				Thread.sleep(sleeptime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		private synchronized void links()
		{
			if(x_collision[nr])
			{
				x_collision[nr] = false;
				rechts();
				
				return;
			}
			
			rechts = false;
			x_int-=x_mod;
			x_int-=x_mod;
			try {
				Thread.sleep(sleeptime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		private void runter()
		{
			if(y_collision[nr])
			{
				y_collision[nr] = false;
				hoch();
				return;
			}
			
			runter = true;
			y_int+=y_mod;
			y_int+=y_mod;
			try {
				Thread.sleep(sleeptime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		private void hoch()
		{
			if(y_collision[nr])
			{
				y_collision[nr] = false;
				runter();
				return;
			}
			
			runter = false;
			y_int-=y_mod;
			y_int-=y_mod;
			try {
				Thread.sleep(sleeptime);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
   }//class
  
}
 

Marco13

Top Contributor
:shock: wo-ho ... die Bewegung jedes einzelnen Kreises und der Kollisionserkennung jeweils(!) mit einem eigenen Thread zu machen, ohne einen Hauch von synchronisation ist schonmal SEHR gewagt... ich würde dir (sofern kein driftiger Grund besteht, das nicht zu machen) dazu raten, die Bewegung und die Kollisionserkennung in EINEM Thread zu machen... So weiß man nie, wann eine Kollision erkannt wird, und welche Auswirkungen die hat. Im Kollisionsthread werden bei
Code:
               for(int i = 0; i < x.length; i++)
               {
                  for(int j = 0; j < x.length; j++)
                  {
                     if(Math.abs((x[i]+durchmesser/2)... <- unschöne if-Abfrage....
ja die Kollisionen jeweils ZWEI mal geprüft (Also "Kugel0 mit Kugel1" und "Kugel1 mit Kugel0"). Und sie bewirken damit vielleicht auch zwei mal einen Reichtungswechsel, weil die Bewegungs-Threads ja munter weiterlaufen, und vielleicht zwischendurch die x_collision-Variable abfragen und ggf. zurücksetzen.

Das auf
for(int j = i+1; j < x.length; j++)
zu ändern löst das Problem zwar nicht, aber ... Schadet wohl auch nicht.

Es werden da ja sozusagen Quadrate auf Kollisionen getestet...!? Ob die "unschöne" if-Abfrage wirklich so passt, hab ich jetzt aber nicht nachvollzogen. Aber so wie das "Verhaken" aussieht, KÖNNTE eine Ursache dafür auch sein, dass die Kollision zwei mal hintereinander erkannt wird, also .. sinngemäß: Die Rechtecke bewegen sich aufeinander zu, und überschneiden sich dann auf einmal - dann wird (irgendwann, wenn der KollisionsThread gerade dazu kommt :roll: ) eine Kollision erkannt, und die Bewegungsrichtung von einem (oder beiden) Rechtecken umgedreht. Dann bewegen sie sich einmal voneinander weg, aber VIELLEICHT wird NACH diesem Schritt, in dem sie sich schon voneinander weg bewegen, NOCHMAL ein Kollsion erkannt.... (Hab's jetzt aber nicht sooo auseinaderklamüsert .... es sieht halt so aus, kannst ja mal schauen, ob sowas passieren könnte)
 

Verjigorm

Top Contributor
Gut, das alles zu synchronisieren war schonmal ne Idee von mir ...

das mit der doppelten Kollision könnte der Grund sein, da hab ich noch garnicht dran gedacht, muss ich mal nachprüfen.

Soweit schonmal danke für die Mühe, werde nachher nochmal drüberschauen.

mfg Verjigorm
 

Verjigorm

Top Contributor
Hab mal nen bissl dran rumgespielt, vorallem an den Aktualisierungszeiten
Nicht gut, aber gefällt mir schonmal soweit :)
Weitere Verbesserungsvorschläge sind natürlich gern gesehen

Code:
//package dots;

import java.awt.*;
import java.util.Random;

import javax.swing.*;


public class Dots extends JPanel {

   private static final long serialVersionUID = -252486986571082924L;
   //Anzahl Kreise
   private int anz = 20, speed_x = 4, speed_y = 3;
   private int[] x = new int[anz];
   private int[] y = new int[anz];
   private Color[] colors = {Color.WHITE, /*Color.LIGHT_GRAY, Color.DARK_GRAY,*/ Color.GRAY, Color.BLACK,
         Color.RED, Color.PINK, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.MAGENTA,
         Color.CYAN, Color.BLUE};
   private Color[] c = new Color[anz];
   
   private boolean[] x_collision = new boolean[anz];
   private boolean[] y_collision = new boolean[anz];
   
// x bzw y- Richtung nach Kollision ändern
   private boolean x_collision_possible = true;
   private boolean y_collision_possible = true;
   
   private Dots td;
   private int durchmesser = 20;
   
   private int refresh = 75, sleeptime = 10, collision_time = 150;
   private Random r = new Random();

   /*
    * Main
    */
   public static void main(String[] args)
   {
      new Dots();
   }
   
   /*
    * Konstruktor
    */
   public Dots()
   {
      td = this;
      
      JFrame frame = new JFrame("Dots");
      frame.setLocation(100,100);
      //frame.setSize(500,550);
      frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.add(this);
      
      
      //initialisieren
      for(int i=0; i<anz; i++)
      {
         c[i] = colors[r.nextInt(colors.length)];
         x_collision[i] = false;
         y_collision[i] = false;
         x[i] = i * 5 * durchmesser;
         new MyThread(i, r.nextInt(speed_x)+1, r.nextInt(speed_y)+1, x[i], y[i]).start();
         //new MyThread(i, 2, 2, x[i], y[i]).start();
      }
       
      //repaint-thread
      new Thread(new Runnable(){

      @Override
      public void run()
      {
         while(true)
         try {
            Thread.sleep(refresh);
            td.repaint();
         } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
         
      }).start();
      
      //Thread zur Kollisionsabfrage
      new Thread(new Runnable(){

         @Override
         public void run()
         {
            while(true)
            try {
               Thread.sleep(collision_time);
               
               for(int i = 0; i < x.length; i++)
               {
                  for(int j = i+1; j < x.length; j++)
                  {

                      if(Math.abs(x[i] - x[j]) <= 2*durchmesser
                              && Math.abs(y[i] - y[j]) <= 2*durchmesser
                              && i != j && x[i] != 0 && y[i] != 0)
                     /*if(Math.abs((x[i]+durchmesser/2) - (x[j]+durchmesser/2)) <= 2*durchmesser
                        && Math.abs((y[i]+durchmesser/2) - (y[j]+durchmesser/2)) <= 2*durchmesser
                        && i != j && x[i] != 0 && y[i] != 0)*/
                     {
                        //System.out.println("Kollision: " +
                           //   x_positive[i] + " <-> " + x_positive[j] + " und " +
                              //y_positive[i] + " <-> " + y_positive[j]);
                        if(x_collision_possible)
                        {
                           x_collision[i] = true;
                           x_collision[j] = true;
                        }
                        
                        if(y_collision_possible)
                        {
                           y_collision[i] = true;
                           y_collision[j] = true;
                        }
                     }
                  }
               }
               
            } catch (InterruptedException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
            }
         }
            
         }).start();
      
      
      frame.setVisible(true);
   }

   @Override
   public void paintComponent(Graphics g)
   {
         super.paintComponent(g);
        
         for(int i = 0; i<anz; i++)
         {
        	 g.setColor(Color.BLACK);
        	 g.fillOval(x[i], y[i] , 2*durchmesser+2, 2*durchmesser+2);
            g.setColor(c[i]);
            g.fillOval(x[i], y[i] , 2*durchmesser, 2*durchmesser);
         }
   }
   
   
   
   class MyThread extends Thread
   {
         private int nr;
         private int x_mod, y_mod;
         boolean rechts = true;
         boolean runter = true;
      int x_int, y_int;
      
      public MyThread(int nr, int x_mod, int y_mod, int x_start, int y_start)
      {
         this.nr = nr;
         this.x_mod = x_mod;
         this.y_mod = y_mod;
         x_int = x_start;
         y_int = y_start;
      }
      
      public void run()
      {
    	  rechts();
    	  runter();
         while(true)
         {
            //System.out.println("Thread: " + x1 + " <= " +
               //   (getWidth()-2*durchmesser) + "," + rauf);
            if(x_int < getWidth()-2*durchmesser && x_int >= 0)
            {
               if(rechts)
               {
                  rechts();
               }
               else
               {
                  links();
               }
            }
            else
            {
               if(x_int > 5)
               {
                  links();
               }
               else
               {
                  rechts();
               }
            }
            
            
            //Hoch-Runter
            if(y_int < getHeight()-2*durchmesser && y_int >= 5)
            {
               if(runter)
               {
                  runter();
               }
               else
               {
                  hoch();
               }
            }
            else
            {
               if(y_int > 5)
               {
                  hoch();
               }
               else
               {
                  runter();
               }
            }
            
            x[nr] = x_int;
            y[nr] = y_int;      
         }
      }
      
      private synchronized void rechts()
      {
    	  //System.out.println("rechts " + nr);
         if(x_collision[nr])
         {
        	 System.out.println("wechsle nach links " + x_collision[nr]);
            x_collision[nr] = false;
            System.out.println(x_collision[nr]);
            links();
            return;
         }
         rechts = true;
         x_int+=x_mod;
         x_int+=x_mod;
         try {
            Thread.sleep(sleeptime);
         } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
      
      private synchronized void links()
      {
    	  
    	  //System.out.println("links: " + nr);
         if(x_collision[nr])
         {
        	 System.out.println("wechsle nach rechts " +  x_collision[nr]);
            x_collision[nr] = false;
            System.out.println(x_collision[nr]);
            rechts();
            
            return;
         }
         
         rechts = false;
         x_int-=x_mod;
         x_int-=x_mod;
         try {
            Thread.sleep(sleeptime);
         } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
      
      private synchronized void runter()
      {
         if(y_collision[nr])
         {
            y_collision[nr] = false;
            hoch();
            return;
         }
         
         runter = true;
         y_int+=y_mod;
         y_int+=y_mod;
         try {
            Thread.sleep(sleeptime);
         } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
      
      private synchronized void hoch()
      {
         if(y_collision[nr])
         {
            y_collision[nr] = false;
            runter();
            return;
         }
         
         runter = false;
         y_int-=y_mod;
         y_int-=y_mod;
         try {
            Thread.sleep(sleeptime);
         } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
         }
      }
   }//class
 
}
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen

Neue Themen


Oben