球的弹性碰撞

时间:2013-11-26 17:58:59

标签: java

我有一个我无法弄清楚的错误。我尝试了很多次,碰撞检测和计算新的速度似乎很好,但有些球似乎互相困住我不知道。可以请你帮忙我出去了。

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);
    }

}

1 个答案:

答案 0 :(得分:0)

我的猜测是,一旦检测到碰撞,你的逻辑就不会让球分开。只改变运动方向一次而不是每次球都彼此靠近。