AWT Bälle

florian1995

Aktives Mitglied
ich wollte heute ein app programmieren das eine bestimmte anzahl von bällen in einem raum "herumschießt".(auch gegenseitige berührung soll möglich sein)
nun habe ich hier das app jedoch bewegen sich die bälle so gar nicht nach meinem geschmack^^:lol:

Java:
package ballphysic;

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;

public class BallPhysic extends Applet implements Runnable{

    private Image dbImage;
    private Graphics dbg;

    private int appletsize_x=350;
    private int appletsize_y=200;
    private int radius=30;

    Ball [] b;

    private int number_Balls=2;

    public void start(){
        b=new Ball[number_Balls];
        for(int i=0;i<b.length;i++){
            b[i]=new Ball();
            b[i].init(appletsize_x, appletsize_y, radius);
        }
        Thread th=new Thread(this);
        th.start();
    }

    public void run() {
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
        while(true){
            try{
                Thread.sleep(10);
            }catch(Exception e){
                System.out.print(e);
            }
            for(int i=0;i<b.length;i++){
                //bewegen
                b[i].moveBall();
            }
            for(int i=0;i<b.length;i++){
                
                //randabfrage
                int y=b[i].get_y_Pos();
                int x=b[i].get_x_Pos();

                if(x<0){
                    b[i].rejectX();
                    b[i].resetX(false);
                }else if(x>appletsize_x-radius){
                    b[i].rejectX();
                    b[i].resetX(true);
                }else if(y<0){
                    b[i].rejectY();
                    b[i].resetY(false);
                }else if(y>appletsize_y-radius){
                    b[i].rejectY();
                    b[i].resetY(true);
                }
                //ballabfrage
                for(int j=0;j<b.length;j++){
                    int x2=b[j].get_x_Pos();
                    int y2=b[j].get_y_Pos();
                    if(j==i){
                        continue;
                    }
                    if((x+radius>=x&&x2<=x+radius)){
                        b[i].rejectX();
                        b[j].rejectX();
                    }
                    if(y2+radius>=y&&y2<=y+radius){
                        b[i].rejectY();
                        b[j].rejectY();
                    }
                }
                //repaint
                repaint();
            }
            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
        }
    }

    public void paint(Graphics g){
        for(int i=0;i<b.length;i++){
            g.fillOval(b[i].get_x_Pos(),b[i].get_y_Pos(),radius,radius);
        }
    }

    public void update (Graphics g){

      // Initialisierung des DoubleBuffers
      if (dbImage == null)
      {
            dbImage = createImage (this.getSize().width, this.getSize().height);
            dbg = dbImage.getGraphics ();
      }

      // Bildschirm im Hintergrund löschen
      dbg.setColor (getBackground ());
      dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);

      // Auf gelöschten Hintergrund Vordergrund zeichnen
      dbg.setColor (getForeground());
      paint (dbg);

      // Nun fertig gezeichnetes Bild Offscreen auf dem richtigen Bildschirm anzeigen
      g.drawImage (dbImage, 0, 0, this);

    }



}

----------------------------------------------------------------------------------------------

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ballphysic;

/**
 *
 * @author Flo
 */
class Ball {
    private double x_speed,y_speed;
    private int x_pos,y_pos;
    private int appletsize_x,appletsize_y;

    public void init(int x,int y,int r){
        appletsize_x=x;
        appletsize_y=y;
        //while(x_speed==0||y_speed==0){
            x_speed=(int)(Math.random()*8-4);
            y_speed=(int)(Math.random()*8-4);
        //}

        x_pos=(int)(Math.random()*(appletsize_x-r)+10);
        y_pos=(int)(Math.random()*(appletsize_y-r)+10);
    }

    public void resetX(boolean choose){
        if(!choose){
            x_pos=0;
        }else{
            x_pos=appletsize_x;
        }
    }

    public void resetY(boolean choose){
        if(!choose){
            y_pos=0;
        }else{
            y_pos=appletsize_y;
        }
    }

    public void rejectX(){
        x_speed=-x_speed;
    }

    public void rejectY(){
        y_speed=-y_speed;
    }

    public void moveBall(){
        x_pos+=x_speed;
        y_pos+=y_speed;
    }

    public int get_x_Pos(){
        return x_pos;
    }

    public int get_y_Pos(){
        return y_pos;
    }
}

hoffe ihr könnt mir sagen welchen fehler ich gemacht habe. :):)

schon im voraus danke ;)
 

florian1995

Aktives Mitglied
soll eine reine übung zu awt sein.
es sollen <number_balls> bälle in einem raum herumfliegen.
wenn sie auf eine wand oder einen anderen ball treffen sollen sie zurückgestoßen werden(mit rejectX() oder rejectY())
 

Volvagia

Top Contributor
Schaue dir mal das an:

Java:
package ballphysic;
 
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
 
public class BallPhysic extends Applet
{
	private static final long serialVersionUID = 1L;
	
	private static final byte BALL_COUNT = 20;
	private Image doubleBuffer;

    public void init()
    {
    	doubleBuffer = createImage(getWidth(), getHeight());
    	Ball.createBalls(this, BALL_COUNT);
    }
    public void start()
    {
    	Ball.startBalls();
    }
    public void paint(Graphics g)
    {
        Ball.paintBalls(g);
    }
    public void update(Graphics g)
    {
    	Graphics bufferG = doubleBuffer.getGraphics ();
    	
    	bufferG.setColor(getBackground());
    	bufferG.fillRect(0, 0, getWidth(), getHeight());
 
    	bufferG.setColor(g.getColor());
    	paint(bufferG);
 
    	g.drawImage(doubleBuffer, 0, 0, this);
    	g.dispose();
    }
}
///////////////////////////////////////////////////////
package ballphysic;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

class Ball implements Runnable
{
	private static final double RADIUS = 5.0d;
	private static final double DIAMETER = RADIUS * 2;
	private static final List<Ball> BALL_LIST = new ArrayList<Ball>();
	
	private static Component component;
	
	private int x;
	private int y;
	
	private double realX;
	private double realY;
	
	private Ball()
	{
		super();
	}
	public void run()
	{
		double angle = (Math.PI * -1) + (Math.random() * (Math.PI - Math.PI * -1)) + 1;
		double sinus = Math.sin(angle);
		double coSinus = Math.cos(angle);
		
		do
		{
			if(checkWalls() || checkOtherBalls())
			{
				angle = angle = (Math.PI * -1) + (Math.random() * (Math.PI - Math.PI * -1)) + 1;
				sinus = Math.sin(angle);
				coSinus = Math.sin(angle);
			}
			
			realX = realX + sinus;
			realY = realY + coSinus;
			
			x = (int)realX;
			y = (int)realY;

			component.repaint();
			try
			{
				TimeUnit.MILLISECONDS.sleep(10L);
			}
			catch (InterruptedException e) {}
		}
		while(true);
	}
	private boolean checkWalls()
	{
		boolean b = false;
		if(x <= 0 || y <= 0 || x + DIAMETER >= component.getWidth() || y + DIAMETER >= component.getHeight())
			b = true;
		return(b);
	}
	private boolean checkOtherBalls()
	{
		boolean b = false;
		for(byte c = 0; c < BALL_LIST.size() && !b; c++)
		{
			Ball otherBall = BALL_LIST.get(c);
			if(otherBall != this)
				if(getBounds().intersects(otherBall.getBounds()))
					b = true;
		}
		return(b);
	}
	
    
    private void setX(int newX)
    {
    	x = newX;
    }
    private void setY(int newY)
    {
    	y = newY;
    }
    private void setRealX(double newX)
    {
    	realX = newX;
    }
    private void setRealY(double newY)
    {
    	realY = newY;
    }
    
    private int getX()
    {
    	return(x);
    }
    private int getY()
    {
    	return(y);
    }
    private Rectangle getBounds()
    {
    	return(new Rectangle(x, y, (int)DIAMETER, (int)DIAMETER));
    }
    
    static void createBalls(Component c, byte count)
    {
    	int compWidth = c.getWidth();
    	int compHeight = c.getHeight();
    	component = c;
    	for(byte b = 0; b < count; b++)
    	{
    		Ball ball = new Ball();

    		double randX = Math.random() * compWidth;
    		double randY = Math.random() * compHeight;
    		
    		ball.setX((int)randX);
    		ball.setY((int)randY);
    		
    		ball.setRealX(randX);
    		ball.setRealY(randY);
    		
    		BALL_LIST.add(ball);
    	}
    }
    static void startBalls()
    {
    	for(Ball b:BALL_LIST)
    		new Thread(b, "Ball").start();
    }
    static void paintBalls(Graphics g)
    {
    	Color currentColor = g.getColor();
    	
    	g.setColor(Color.BLACK);
    	for(Ball b:BALL_LIST)
    		g.fillOval(b.getX(), b.getY(), (int)DIAMETER, (int)DIAMETER);
    	
    	g.setColor(currentColor);
    }
}

Habe ich zwar jetzt nur so runtergetippt, aber ich denke es wird seinen Job schon irgendwie erledigen.
 
Zuletzt bearbeitet:

Volvagia

Top Contributor
Warum nicht die update(Graphics) überschreiben? Beim zeichnen wäre das neben der BufferStrategy der einzige Weg den ich kenne, um einen Doublepuffer zu verwenden. Und die wird von einen Applet ja leider nicht unterstützt. (Zumindest existiert keine createBufferStrategy(int))

Eine ArrayList enthält ein Array, welches bei Bedarf vergrößert wird. Der einzig nennswerte Unterschied hier ist das nicht per eckige Klammer sondern der Methode add(T) und get(int) zugegriffen wird, aber das ist schon alles. Ließ dich besser in Collections ein, du wirst warscheinlich nicht sehr lange um die herumkommen. (Zumindest ohne soetwas selbst zu schreiben)

Java ist auch eine Insel – 11 Datenstrukturen und Algorithmen
 

florian1995

Aktives Mitglied
ok danke für diese zahlreichen antworten. ;)
werde mich mal in collections einlesen scheint ja nicht so schwer zu sein.
aber weiß jetzt jemand was der fehler an meinem programm ist?
das mit dem fixen bestimmen der bälle hilft nix.
 

Quaxli

Top Contributor
Ich hab' auch mal dran rum gepfrimmelt ;)
Guck mal, was Du noch erkennst :D:D:D

Java:
import java.applet.Applet;
import java.awt.*;
import java.awt.geom.Rectangle2D;

public class BallPhysic extends Applet implements Runnable {

	private static final long	serialVersionUID	= 1L;
	private Image							dbImage;
	private Graphics					dbg;
	private int								radius						= 20;
	Ball[]										b;
	private int								number_Balls			= 10;

	public void start() {

		this.setSize(400,400);

		//Arrays habe ich mal gelassen
		b = new Ball[number_Balls];
		for (int i = 0; i < b.length; i++) {
			b[i] = new Ball(radius, this);
		}

		Thread th = new Thread(this);
		th.start();
	}

	public void run() {

		long delta = 0;
		long last = System.nanoTime();

		while (true) {

			//Zeit des letzten Schleifendurchlaufs
			delta = System.nanoTime() - last;
			last = System.nanoTime();

			//alle Bälle bewegen
			for (int i = 0; i < b.length; i++) {
				// bewegen in Abhängigkeit von der für den Loop benötigten Zeit
				b[i].moveBall(delta);
			}

			//Kollision mit der Wand prüfen
			for (int i = 0; i < b.length; i++) {
         b[i].checkFrameCollision();
			}

			
			//Kollision mit den anderen prüfen - sehr einfach gestrickt
			//Aber Du sollst ja auch noch was zu tun haben  ;-)
			for (int i = 0; i < b.length; i++) {
				
				if(i==b.length-1){
					continue;
				}
				
        for(int n = i+1;n<b.length;n++){
        	if(b[i].intersects(b[n])){
        		b[i].rejectX();
        		b[i].rejectY();
        		b[n].rejectX();
        		b[n].rejectY();
        	}
        }
			}
			

			try {
				Thread.sleep(10);
			} catch (Exception e) {
				System.out.print(e);
			}

			repaint();
		}
	}

	public void paint(Graphics g) {
    super.paint(g);
    g.setColor(Color.RED);

    //Mal-Methode für alle Bälle aufrufen - GraphicsObject übergeben
		for (int i = 0; i < b.length; i++) {
		  b[i].paintBall(g);
		}
	}

	public void update(Graphics g) {

		// Initialisierung des DoubleBuffers
		if (dbImage == null) {
			dbImage = createImage(this.getSize().width, this.getSize().height);
			dbg = dbImage.getGraphics();
		}

		// Bildschirm im Hintergrund löschen
		dbg.setColor(getBackground());
		dbg.fillRect(0, 0, this.getSize().width, this.getSize().height);

		// Auf gelöschten Hintergrund Vordergrund zeichnen
		dbg.setColor(getForeground());
		paint(dbg);

		// Nun fertig gezeichnetes Bild Offscreen auf dem richtigen Bildschirm
		// anzeigen
		g.drawImage(dbImage, 0, 0, this);

	}

}


/*
 * Ball erbt von Rectangle2D. Damit haben wir double Genauigkeit und auch
 * sonst noch ein paar praktische Methoden
 * 
 */
class Ball extends Rectangle2D.Double {

	private static final long	serialVersionUID	= 1L;
	private double						x_speed;
	private double						y_speed;
	BallPhysic parent;
	Color col;

	public Ball(int r, BallPhysic p) {

		super(0,0,r,r);  //super-Konstruktor (Rectangle2D.Double mit 0,0 - wird ja unten geändert
		parent = p;
		
		//Zufallsfarbe
		col = new Color((int)(Math.random()*255),(int)(Math.random()*255),(int)(Math.random()*255));
		
		//Zufallsgeschwindigkeit 
		x_speed = (int) (Math.random() * 100);
		y_speed = (int) (Math.random() * 100);

		//Zu langsam sieht blöd aus
		if(x_speed<30){
			x_speed = 30;
		}
		
		if(y_speed<30){
			y_speed = 30;
		}
		
		//Zufallsposition
		x = Math.random() * (p.getWidth()) ;
		y = Math.random() * (p.getHeight());
	}

	
	// Hier wird gemalt
	public void paintBall(Graphics g) {
		g.setColor(col);
		g.fillOval((int)getX(),(int)getY(),(int)getWidth(),(int)getHeight());
	}

	
	//Kollission mit der Wand prüfen unter Zuhilfenahme geerbter Methoden
	public void checkFrameCollision() {
		
		if(getX()<=0){
			x = 0;
			rejectX();
		}
		
		if(getY()<=0){
			rejectY();
			y = 0;
		}
		
		if(getX()+getWidth()>=parent.getWidth()){
			rejectX();
			x = parent.getWidth() - getWidth();
		}
		
		if(getY()+getHeight()>=parent.getHeight()){
			rejectY();
		  y = parent.getHeight()-getHeight();
		}
		
	}

	public void rejectX() {
		x_speed *= -1;
	}

	public void rejectY() {
		y_speed *= -1;
	}

	//Ball in Abhängigkeit der Zeit für den letzten Schleifendurchlauf berechnen
	//Genauigkeit durch System.nanoTime() - ergibt gleichmäßigere Bewegung
	public void moveBall(long delta) {

		if (x_speed != 0) {
			x += x_speed * (delta / 1e9);
		}

		if (y_speed != 0) {
			y += y_speed * (delta / 1e9);
		}
	}

}
 

florian1995

Aktives Mitglied
aah. das ergibt sinn :)

frage:

-nanotime ist dafür das jede schleife gleich lange braucht??
-was zum teufel ist super() ????? (hab mir programmieren größtenteils selbst beigebracht^^ also nicht blöd melden)
-was macht .intersects() ?
 

Volvagia

Top Contributor
Nein, um die Geschwindigkeit der Ballbewegungen anzupassen. Aber soweit ich weiß ist System.nanoTime() seeeehr ungenau. Ich denke, ein TimerTask statt Thread würde mehr bringen.

Super ist lateinisch, und bedeutet "über". Super() ruft einfach einen Konstruktor der Superclass auf.

Intersects prüft, ob sich 2 Rectangle überschneiden.
 

Quaxli

Top Contributor
1. Nein, die Schleifen brauche unterschiedlich lange (kannst ja mal delta ausgeben lassen) Daher erfolgt die Bewegung in Abhängigkeit der benötigten Zeit. Das soll eine gleichmäßigere Bewegung ergeben.

2. "super" ist der Aufruf der Vaterklasse (die, vond er geerbt wird). super(0,0,r,r) ist damit der Aufruf des Konstruktors von Rectangle2D.Double. super.paint(g) ruft die paint-Methode des Applets auf und sorgt dafür, daß auch alles andere gezeichnet wird. Bei einem Applet macht das vermutlich keinen großen Unterschied, in Swing aber z. B. durchaus.

3. Einfach mal in die API gucken. :D:D:D intersects() erbt Rectangle2D von RectangluarShape. Kurz gesagt wird hier geprüft, ob sich die beiden Rechtecke überschneiden. Falls ja, wird das als Kollision interpretiert. Das ist zwar nicht 100% genau, dafür aber bequem und in diesem Fall wohl auch ausreichend - wenn 2 Bälle genau im 45° Winkel aufeinander treffen, dürfte es aber auffallen, daß die sich gar nicht berühren. Wenn Du es genauer haben willst, mußt Du den Teil ersetzen.
 

Oben