我有一个我无法弄清楚的错误。我尝试了很多次,碰撞检测和计算新的速度似乎很好,但有些球似乎互相困住我不知道。可以请你帮忙我出去了。
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.util.Random;
import javax.swing.JFrame;
public class ElasticCollision extends Canvas implements Runnable {
private static final int WIDTH = 300;
private static final int HEIGHT = WIDTH / 16 * 9;
private static final int SCALE = 3;
private static final String TITLE = "Elastic collision";
private boolean running = false;
private JFrame frame;
private Thread thread;
private Random random = new Random();
private Color color;
private int a, b, c;
private Ball[] ball;
private int x = 0, y = 0;
private int radius = 0;
private int speedX = 0, speedY = 0;
private int noOfBalls = 25;
private double newVelX1 = 0, newVelY1 = 0;
private double newVelX2 = 0, newVelY2 = 0;
private double angle1 = 0, angle2 = 0, angle3 = 0;
private int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
public ElasticCollision() {
Dimension size = new Dimension(WIDTH * SCALE, HEIGHT * SCALE);
setPreferredSize(size);
frame = new JFrame();
ball = new Ball[noOfBalls];
}
public void start() {
for (int i = 0; i < noOfBalls; i++) {
x = random.nextInt(getWidth());
y = random.nextInt(getHeight());
radius = 25 + random.nextInt(25);
speedX = 1 + random.nextInt(2);
speedY = 1 + random.nextInt(2);
ball[i] = new Ball(x, y, radius, speedX, speedY);
}
running = true;
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false;
}
public void run() {
long lastTime = System.nanoTime();
double unprocessed = 0;
double nsPerTick = 1000000000.0 / 60;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
while (running) {
long now = System.nanoTime();
unprocessed += (now - lastTime) / nsPerTick;
lastTime = now;
while (unprocessed >= 1) {
ticks++;
update();
unprocessed -= 1;
}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < noOfBalls; i++) {
for (int j = i + 1; j < noOfBalls; j++) {
if (ball[i].inCollision != true
|| ball[j].inCollision != true)
checkCollision(ball[i], ball[j]);
}
}
frames++;
render();
if (System.currentTimeMillis() - lastTimer > 1000) {
lastTimer += 1000;
frame.setTitle(TITLE + " | " + ticks + " ticks, " + frames
+ " fps");
frames = 0;
ticks = 0;
}
}
stop();
}
public void update() {
for (int i = 0; i < noOfBalls; i++) {
ball[i].x += ball[i].speedX;
ball[i].y += ball[i].speedY;
if (ball[i].x >= getWidth() - ball[i].radius && ball[i].speedX > 0)
ball[i].speedX = -ball[i].speedX;
if (ball[i].x <= ball[i].radius && ball[i].speedX < 0)
ball[i].speedX = -ball[i].speedX;
if (ball[i].y >= getHeight() - ball[i].radius && ball[i].speedY > 0)
ball[i].speedY = -ball[i].speedY;
if (ball[i].y <= ball[i].radius && ball[i].speedY < 0)
ball[i].speedY = -ball[i].speedY;
}
}
public void render() {
BufferStrategy bs = getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.yellow);
g.fillRect(0, 0, getWidth(), getHeight());
for (int i = 0; i < noOfBalls; i++)
ball[i].paint(g);
g.dispose();
bs.show();
}
public void checkCollision(Ball ball1, Ball ball2) {
double distance;
if (ball1.x + ball1.radius + ball2.radius > ball2.x
&& ball1.x < ball1.x + ball1.radius + ball2.radius
&& ball1.y + ball1.radius + ball2.radius > ball2.y
&& ball1.y < ball2.y + ball1.radius + ball2.radius) {
distance = Math.sqrt(((ball1.x - ball2.x) * (ball1.x - ball2.x))
+ ((ball1.y - ball2.y) * (ball1.y - ball2.y)));
if ((int) distance < ball1.radius + ball2.radius) {
ball1.collision = true;
ball2.collision = true;
ball1.inCollision = true;
ball2.inCollision = true;
ball1.collisionX = ((ball1.x * ball2.radius) + (ball2.x * ball1.radius))
/ (ball1.radius + ball2.radius) + ball1.radius;
ball1.collisionY = ((ball1.y * ball2.radius) + (ball2.y * ball1.radius))
/ (ball1.radius + ball2.radius) + ball1.radius;
ball2.collisionX = ((ball1.x * ball2.radius) + (ball2.x * ball1.radius))
/ (ball1.radius + ball2.radius) + ball2.radius;
ball2.collisionY =
((ball1.y * ball2.radius) + (ball2.y * ball1.radius))
/ (ball1.radius + ball2.radius) + ball2.radius;
/*
* x1 = (ball1.x - getWidth()) / 2; y1 = (ball2.y - getHeight())
* / 2; angle1 = Math.toDegrees(Math.atan2(y1, x1));
*
* x2 = (ball1.x - getWidth()) / 2; y2 = (ball2.y - getHeight())
* / 2; angle2 = Math.toDegrees(Math.atan2(y2, x2));
*/
double colision_angle = Math.toDegrees(Math.atan2(
(ball2.y - ball1.y), (ball2.x - ball1.x)));
double speed1 = Math.sqrt(ball1.speedX * ball1.speedX
+ ball1.speedY * ball1.speedY);
double speed2 = Math.sqrt(ball2.speedX * ball2.speedX
+ ball2.speedY * ball2.speedY);
double direction1 = Math.atan2(ball1.speedY, ball1.speedX);
double direction2 = Math.atan2(ball2.speedY, ball2.speedX);
double vx_1 = speed1 * Math.cos(direction1 - colision_angle);
double vy_1 = speed1 * Math.sin(direction1 - colision_angle);
double vx_2 = speed2 * Math.cos(direction2 - colision_angle);
double vy_2 = speed2 * Math.sin(direction2 - colision_angle);
double final_vx_1 = ((ball1.radius - ball2.radius) * vx_1 + (ball2.radius + ball2.radius)
* vx_2)
/ (ball1.radius + ball2.radius);
double final_vx_2 = ((ball1.radius + ball1.radius) * vx_1 + (ball2.radius - ball1.radius)
* vx_2)
/ (ball1.radius + ball2.radius);
double final_vy_1 = vy_1;
double final_vy_2 = vy_2;
newVelX1 = (int) (Math.cos(colision_angle) * final_vx_1 + Math
.cos(colision_angle + Math.PI / 2) * final_vy_1);
newVelY1 = (int) (Math.sin(colision_angle) * final_vx_1 + Math
.sin(colision_angle + Math.PI / 2) * final_vy_1);
newVelX2 = (int) (Math.cos(colision_angle) * final_vx_2 + Math
.cos(colision_angle + Math.PI / 2) * final_vy_2);
newVelY2 = (int) (Math.sin(colision_angle) * final_vx_2 + Math
.sin(colision_angle + Math.PI / 2) * final_vy_2);
ball1.speedX = (int) newVelX1;
ball1.speedY = (int) newVelY1;
ball2.speedX = (int) newVelX2;
ball2.speedY = (int) newVelY2;
ball1.x = ball1.x + (int) newVelX1;
ball1.y = ball1.y + (int) newVelY1;
ball2.x = ball2.x + (int) newVelX2;
ball2.y = ball2.y + (int) newVelY2;
}
}
}
public static void main(String[] args) {
ElasticCollision balls = new ElasticCollision();
balls.frame.setResizable(false);
balls.frame.add(balls);
balls.frame.pack();
balls.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
balls.frame.setVisible(true);
balls.start();
}
}
class Ball {
protected int x = 0, y = 0;
protected int radius;
protected int speedX = 0, speedY = 0;
protected boolean collision = false;
protected int collisionX = 0, collisionY = 0;
protected boolean inCollision = false;
public Ball(int x, int y, int radius, int speedX, int speedY) {
this.x = x + radius;
this.y = y + radius;
this.radius = radius;
this.speedX = speedX;
this.speedY = speedY;
}
public void paint(Graphics g) {
if (!collision) {
g.setColor(Color.red);
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
} else {
g.setColor(Color.green);
g.fillOval(x - radius, y - radius, radius * 2, radius * 2);
g.setColor(Color.blue);
g.fillOval(collisionX - radius, collisionY - radius, 20, 20);
g.setColor(Color.black);
g.drawOval(collisionX - radius, collisionY - radius, 20, 20);
collision = false;
inCollision = false;
}
g.setColor(Color.black);
g.drawOval(x - radius, y - radius, radius * 2, radius * 2);
}
}
答案 0 :(得分:0)
我的猜测是,一旦检测到碰撞,你的逻辑就不会让球分开。只改变运动方向一次而不是每次球都彼此靠近。