Ich hab vor ein paar Tagen auf Facebook so ein Spiel mit Bällen die man zu paltzen bringen muss gespielt.. hab mir geadacht.. das könnte ich ja mal in Java probieren...
Ich mach eigentlich sonst nichts mit Spielprogrammierung, ich arbeite eher im Web und Datenbankbereich.
Also hab ich mir Quxlis Tutorial geschnappt und hab das geschrieben....
Ziel ist es theoritisch durch klicks alle Bälle zu zerstören... ist noch nicht fertig...
1. Grundlegend hab ich jetzt ein Problem mit ConcurrentModificationException.
Passiert weil ich die Liste veränder sie aber gleichzeitig von einem anderen Thread (EDT??) gelesen wird.. oder?
Was mach ich dagegen?
2. Wie kann ich das ganze einwenig "sauberer" zeichnen, das scheint mir noch ein wenig unsauber und nicht so "smooth" wie ich es gerne hätte... Gibts da was in Richtung Antialiasing?
Danke für eure Tipps....
Ich mach eigentlich sonst nichts mit Spielprogrammierung, ich arbeite eher im Web und Datenbankbereich.
Also hab ich mir Quxlis Tutorial geschnappt und hab das geschrieben....
Java:
package bouncing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Bouncing extends JPanel implements Runnable, MouseListener{
private static final long serialVersionUID = -2897573490118370605L;
boolean running = true;
Random rnd = new Random();
//zur Berechnung der FPS und Animation
long delta = 0;
long last = 0;
long fps = 0;
//Anzahl der Bälle
int numBalls = 200;
//Liste mit den Bällen
ArrayList<Ball> balls = new ArrayList<Ball>();
public static void main(String[] args) {
new Bouncing(800,600);
}
public Bouncing(int w, int h){
this.setPreferredSize(new Dimension(w,h));
JFrame frame = new JFrame("Bouncing");
frame.setLocation(100, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.pack();
frame.setVisible(true);
this.addMouseListener(this);
init();
}
private void init(){
last = System.nanoTime();
setBackground(Color.black);
//Bälle erzeugen
while(balls.size()<numBalls)
createBall();
Thread t = new Thread(this);
t.start();
}
/**
* Methode erzeugt einen zufälligen Ball und fügt ihn in die Liste der Bälle ein
*/
public void createBall(){
int x = rnd.nextInt(this.getWidth());
int y = rnd.nextInt(this.getHeight());
int r = rnd.nextInt(255);
int g = rnd.nextInt(255);
int b = rnd.nextInt(255);
int dx = rnd.nextInt(200)-100;
int dy = rnd.nextInt(200)-100;
Ball ball = new Ball(x,y, 7, 7,this, new Color(r,g,b));
ball.setDx(dx);
ball.setDy(dy);
balls.add(ball);
}
public void run() {
while(running){
computeDelta();
doLogic();
moveObjects();
repaint();
try {
Thread.sleep(10);
} catch (InterruptedException e) {}
}
System.out.println("Spiel zu Ende....");
}
private void doLogic() {
try {
for(Ball move: balls)
move.doLogic(delta);
//zusammen gestoßene Bälle sterben lassen
ArrayList<Ball> trash = new ArrayList<Ball>();
for(int i = 0; i < balls.size(); i++){
for(int j = i+1; j < balls.size(); j++){
if(balls.get(i).colidedWith(balls.get(j))){
trash.add(balls.get(i));
trash.add(balls.get(j));
}
}
}
for(Ball s: trash)
s.die();
//Bälle die wir löschen können, die löschen wir aus der Liste
for(Ball s: balls){
if(s.isCanDelete())
balls.remove(s);
}
if(balls.size()<1)
running = false;
} catch (ConcurrentModificationException e) {
e.printStackTrace();
}
}
/**
* Bälle bewegen
*/
private void moveObjects() {
for(Ball move: balls)
move.move(delta);
}
/**
* zeichnen
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.drawString("FPS: "+Long.toString(fps), 20, 10);
g.drawString("Balls: "+balls.size(), 100, 10);
try {
for(Ball draw: balls)
draw.drawObject(g);
} catch (ConcurrentModificationException e) {
e.printStackTrace();
}
}
/**
* delta und fps berechnen
*/
private void computeDelta() {
delta = System.nanoTime() - last;
last = System.nanoTime();
fps = ((long) 1e9)/delta;
}
public void mouseClicked(MouseEvent e) {
Ball ball = new Ball(e.getX(),e.getY(), 7, 7,this, Color.WHITE);
ball.setDead(true);
balls.add(ball);
}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
}
Java:
package bouncing;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
/**
* Spielball
*
*/
public class Ball extends Rectangle2D.Double {
private static final long serialVersionUID = -6285058019006719750L;
Bouncing p;
//Richtung
double dx;
double dy;
//kann dieser Ball gelöscht werden
private boolean canDelete;
//Fortschritt der explusion
private int dieStatus =0;
private boolean dead;
Color color;
public Ball(double x, double y, double w, double h, Bouncing p, Color color) {
this.x = x;
this.y = y;
this.height = h;
this.width = w;
this.p = p;
this.color = color;
}
public void drawObject(Graphics g) {
Color old = g.getColor();
g.setColor(color);
g.drawOval((int)x, (int)y, (int)width, (int)height);
g.setColor(old);
}
/**
* Kollisionsdetection mit den Wänden
* @param delta
*/
public void doLogic(long delta) {
//Wenn wir an den wänden anstoßen, wechseln wir die Richtung
if(x<0 || (x+width)>p.getWidth())
dx *=-1;
if(y<0 || (y+height)>p.getHeight())
dy *=-1;
}
/**
* Bewegung und Animation
* @param delta
*/
public void move(long delta) {
//sind wir tot, explodieren wir...
if(dead){
double expansion = 40*(delta/1e9);
width = width+expansion;
height = height+expansion;
x = x-expansion/2;
y = y-expansion/2;
dieStatus++;
if(dieStatus==250)
setCanDelete(true);
}else{ // sonst bewegen wir uns
if(dy!=0)
y += dy*(delta/1e9);
if(dx!=0)
x += dx*(delta/1e9);
}
}
/**
* wir sind können nur zusammenstoßen wenn wir tot sind
* @param s
* @return
*/
public boolean colidedWith(Ball s){
return (this.intersects(s) && (this.isDead() || s.isDead()));
}
public void die() {
if(!dead){
setDead(true);
}
}
//Getter und Setter
public double getDx() {
return dx;
}
public void setDx(double dx) {
this.dx = dx;
}
public double getDy() {
return dy;
}
public void setDy(double dy) {
this.dy = dy;
}
public boolean isCanDelete() {
return canDelete;
}
public void setCanDelete(boolean canDelete) {
this.canDelete = canDelete;
}
public boolean isDead() {
return dead;
}
public void setDead(boolean dead) {
this.dead = dead;
}
}
Ziel ist es theoritisch durch klicks alle Bälle zu zerstören... ist noch nicht fertig...
1. Grundlegend hab ich jetzt ein Problem mit ConcurrentModificationException.
Passiert weil ich die Liste veränder sie aber gleichzeitig von einem anderen Thread (EDT??) gelesen wird.. oder?
Was mach ich dagegen?
2. Wie kann ich das ganze einwenig "sauberer" zeichnen, das scheint mir noch ein wenig unsauber und nicht so "smooth" wie ich es gerne hätte... Gibts da was in Richtung Antialiasing?
Danke für eure Tipps....