当前位置:  开发笔记 > 小程序 > 正文

如何用三角学而不是向量来处理球与球的碰撞?

如何解决《如何用三角学而不是向量来处理球与球的碰撞?》经验,为你挑选了1个好方法。

我正在制作这个SO问题的球物理应用程序的简化版本.我通过阅读该问题提供的代码和链接获得了很多,但是在我的程序中我不使用向量,我只是更新我的球的坐标(每个都有一个随机的角度和速度)和三角函数撞到了墙上.

有关如何在没有三角测量的情况下处理球与球的碰撞的信息,但是我没有找到解释如何三角函数完成的信息.

--EDIT 9/13/2010--

成功......有点......我完成了我想做的事,但我无法按照自己的意愿去做.如果有一种方法可以在不使用矢量的情况下计算球与球之间的碰撞,那么我就无法实现.即便如此,矢量确实是处理所有类型碰撞的一种更简单的方法......我只是希望我知道当我开始我的程序时...会节省我两三天的工作:)所有的我(完整?)程序的代码如下.我添加了一些简洁的功能,如阴影和减小的球半径,这可以让你看到当一个大球击中一个小球时两个球的质量差异.总共有五个类文件,AddLogic.java,Ball.java,BallBuilder.java,MouseEventHandler.java,和Vector2D.java.

AddLogic.java

import java.awt.*;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;

public class AddLogic implements Runnable {//Make AddLogic a runnable task.

    private BallBuilder ballBuilder;
    private BufferStrategy strategy;
    private static ArrayList objectsToDraw = new ArrayList();
    private int floorHeight = 33;

    public AddLogic(BallBuilder ballBuilder, BufferStrategy strategy) {
        this.ballBuilder = ballBuilder;
        this.strategy = strategy;
    }

    private void logic(BallBuilder ballBuilder, BufferStrategy strategy) {
        this.ballBuilder = ballBuilder;
        this.strategy = strategy;

        while (true) {//Main loop. Draws all objects on screen and calls update methods.
            Graphics2D g = (Graphics2D) strategy.getDrawGraphics();//Creates the Graphics2D object g and uses it with the double buffer.
            g.setColor(Color.gray);
            g.fillRect(0, 0, ballBuilder.getWidth(), ballBuilder.getHeight());//Draw the wall.
            g.setColor(Color.lightGray);
            g.fillRect(0, ballBuilder.getHeight() - floorHeight, ballBuilder.getWidth(), floorHeight);//Draw the floor.
            g.setColor(Color.black);
            g.drawLine(0, ballBuilder.getHeight() - floorHeight, ballBuilder.getWidth(), ballBuilder.getHeight() - floorHeight);//Draw the line between the wall and floor.

            if (objectsToDrawIsEmpty() == true) {//If no balls have been made display message telling users how to make new ball.
                g.setColor(Color.red);
                g.drawString("Click Mouse For New Ball", (ballBuilder.getWidth() / 2) - 70, ballBuilder.getHeight() / 2);
            }

            for (int i = 0; i < objectsToDraw.size(); i++) {//Draw shadows for all balls.
                Ball ball = (Ball) objectsToDraw.get(i);
                g.setColor(Color.darkGray);
                g.fillOval(
                        (int) ball.ballPosition.getX() - (int) ((ball.ballPosition.getY() / (350 / ball.getBallRadius())) / 2),
                        ballBuilder.getHeight() - (floorHeight / 2) - (int) ((ball.ballPosition.getY() / (1250 / ball.getBallRadius())) / 2),
                        (int) ball.ballPosition.getY() / (350 / ball.getBallRadius()),
                        (int) ball.ballPosition.getY() / (1250 / ball.getBallRadius()));
            }

            for (int i = 0; i < objectsToDraw.size(); i++) {//Draw all balls by looping through them and checking for any vector or collision updates that need to be made.
                Ball ball = (Ball) objectsToDraw.get(i);
                g.setColor(ball.getBallColor());
                g.fillOval(
                        (int) ball.ballPosition.getX() - ball.getBallRadius(),
                        (int) ball.ballPosition.getY() - ball.getBallRadius(),
                        ball.getBallRadius() * 2,
                        ball.getBallRadius() * 2);

                vectorUpdate(ball);//Update ball vector coordinates.

                collisionCheck(ball);//Check ball to ball and ball to wall collisions.

            }

            if (MouseEventHandler.mouseEventCheck() == true) {// Creates a new ball when mouse is clicked.
                Ball ball = new Ball(ballBuilder);
                objectsToDraw.add(ball); //Adds the new ball to the array list.
                MouseEventHandler.mouseEventUpdate(); //Resets the mouse click event to false.

            }

            g.dispose();//To aid Java in garbage collection.
            strategy.show();//Show all graphics drawn on the buffer.

            try {//Try to make thread sleep for 5ms.  Results in a frame rate of 200FPS.
                Thread.sleep(5);
            }

            catch (Exception e) {//Catch any exceptions if try fails.

            }
        }
    }

    private void vectorUpdate(Ball ball) {//Update the ball vector based upon the ball's current position and its velocity.

        ball.ballPosition.setX(ball.ballPosition.getX() + ball.ballVelocity.getX());
        ball.ballPosition.setY(ball.ballPosition.getY() + ball.ballVelocity.getY());

    }

    private void collisionCheck(Ball ball) {//Check for ball to wall collisions. Call check for ball to ball collisions at end of method.

        if (ball.ballPosition.getX() - ball.getBallRadius() < 0) {//Check for ball to left wall collision.
            ball.ballPosition.setX(ball.getBallRadius());
            ball.ballVelocity.setX(-(ball.ballVelocity.getX()));
            ball.decreaseBallRadius(ball);//Decrease ball radius by one pixel. Called on left, top, and right walls, but not bottom because it looks weird watching shadow get smaller during bottom bounce.

        }

        else if (ball.ballPosition.getX() + ball.getBallRadius() > ballBuilder.getWidth()) {//Check for ball to right wall collision.
            ball.ballPosition.setX(ballBuilder.getWidth() - ball.getBallRadius());
            ball.ballVelocity.setX(-(ball.ballVelocity.getX()));
            ball.decreaseBallRadius(ball);//Decrease ball radius by one pixel. Called on left, top, and right walls, but not bottom because it looks weird watching shadow get smaller during bottom bounce.
        }

        if (ball.ballPosition.getY() - ball.getBallRadius() < 0) {//Check for ball to top wall collision.
            ball.ballPosition.setY(ball.getBallRadius());
            ball.ballVelocity.setY(-(ball.ballVelocity.getY()));
            ball.decreaseBallRadius(ball);//Decrease ball radius by one pixel. Called on left, top, and right walls, but not bottom because it looks weird watching shadow get smaller during bottom bounce.
        }

        else if (ball.ballPosition.getY() + ball.getBallRadius() + (floorHeight / 2) > ballBuilder.getHeight()) {//Check for ball to bottom wall collision.  Floor height is accounted for to give the appearance that ball is bouncing in the center of the floor strip.
            ball.ballPosition.setY(ballBuilder.getHeight() - ball.getBallRadius() - (floorHeight / 2));
            ball.ballVelocity.setY(-(ball.ballVelocity.getY()));
        }

        for (int i = 0; i < objectsToDraw.size(); i++) {//Check to see if a ball is touching any other balls by looping through all balls and checking their positions.
            Ball otherBall = (Ball) objectsToDraw.get(i);

            if (ball != otherBall && Math.sqrt(Math.pow(ball.ballPosition.getX() - otherBall.ballPosition.getX(), 2.0) + Math.pow(ball.ballPosition.getY() - otherBall.ballPosition.getY(), 2.0)) < ball.getBallRadius() + otherBall.getBallRadius()) {
                resolveBallToBallCollision(ball, otherBall);//If the ball is hitting another ball calculate the new vectors based on the variables of the balls involved.
            }

        }

    }

    private void resolveBallToBallCollision(Ball ball, Ball otherBall) {//Calculate the new vectors after ball to ball collisions.
        Vector2D delta = (ball.ballPosition.subtract(otherBall.ballPosition));//Difference between the position of the two balls involved in the collision.
        float deltaLength = delta.getLength();//The (x, y) of the delta squared.

        Vector2D minimumTranslationDistance = delta.multiply(((ball.getBallRadius() + otherBall.getBallRadius()) - deltaLength) / deltaLength);//The minimum distance the balls should move apart once they.

        float ballInverseMass = 1 / ball.getBallMass();//half the ball mass.
        float otherBallInverseMass = 1 / otherBall.getBallMass();//half the other ball mass.

        ball.ballPosition = ball.ballPosition.add(minimumTranslationDistance.multiply(ballInverseMass / (ballInverseMass + otherBallInverseMass)));//Calculate the new position of the ball.
        otherBall.ballPosition = otherBall.ballPosition.subtract(minimumTranslationDistance.multiply(otherBallInverseMass / (ballInverseMass + otherBallInverseMass)));//Calculate the new position of the other ball.

        Vector2D impactVelocity = (ball.ballVelocity.subtract(otherBall.ballVelocity));//Find the veloicity of the impact based upon the velocities of the two balls involved.
        float normalizedImpactVelocity = impactVelocity.dot(minimumTranslationDistance.normalize());//

        if (normalizedImpactVelocity > 0.0f) {//Returns control to calling object if ball and other ball are intersecting, but moving away from each other.
            return;
        }

        float restitution = 2.0f;//The constraint representing friction. A value of 2.0 is 0 friction, a value smaller than 2.0 is more friction, and a value over 2.0 is negative friction.

        float i = (-(restitution) * normalizedImpactVelocity) / (ballInverseMass + otherBallInverseMass);
        Vector2D impulse = minimumTranslationDistance.multiply(i);

        ball.ballVelocity = ball.ballVelocity.add(impulse.multiply(ballInverseMass));//Change the velocity of the ball based upon its mass.
        otherBall.ballVelocity = otherBall.ballVelocity.subtract(impulse.multiply(otherBallInverseMass));//Change the velocity of the other ball based upon its mass.
    }

    public static boolean objectsToDrawIsEmpty() {//Checks to see if there are any balls to draw.
        boolean empty = false;
        if (objectsToDraw.isEmpty()) {
            empty = true;
        }

        return empty;

    }

    public void run() {//Runs the AddLogic instance logic in a new thread.
        logic(ballBuilder, strategy);
    }
}

Ball.java

import java.awt.*;

public class Ball {

    private int ballRadius;
    private float ballMass;
    public Vector2D ballPosition = new Vector2D();
    public Vector2D ballVelocity = new Vector2D();
    private Color ballColor;

    public Ball(BallBuilder ballBuilder) {//Construct a new ball.
        this.ballRadius = 75;//When ball is created make its radius 75 pixels.
        this.ballMass = ((float)(4 / 3 * Math.PI * Math.pow(ballRadius, 3.0)));//When ball is created make its mass that the volume of a sphere the same size.
        this.ballPosition.set(ballRadius, ballBuilder.getHeight() - ballRadius);//When ball is created make its starting coordinates the bottom left hand corner of the screen.
        this.ballVelocity.set(randomVelocity(), randomVelocity());//When ball is created make its (x, y) velocity a random value between 0 and 2.

        if (AddLogic.objectsToDrawIsEmpty() == true) {//If the ball being created is the first ball, make it blue, otherwise pick a random color.
            this.ballColor = Color.blue;
        } else {
            this.ballColor = randomColor();
        }

    }

    public void decreaseBallRadius(Ball ball){//Decrease the ball radius.
        if(ball.getBallRadius() <= 15){//If the ball radius is less than or equal to 15 return control to calling object, else continue.
            return;
        }

        ball.setBallRadius(ball.getBallRadius() - 1);//Decrease the ball radius by 1 pixel.
        ball.setBallMass((float)(4 / 3 * Math.PI * Math.pow(ballRadius, 3.0)));//Recalcualte the mass based on the new radius.

    }

    public int getBallRadius() {
        return ballRadius;
    }

    public float getBallMass(){
        return ballMass;
    }

    public Color getBallColor() {
        return ballColor;
    }

    private void setBallRadius(int newBallRadius) {
        this.ballRadius = newBallRadius;
    }

    private void setBallMass(float newBallMass){
        this.ballMass = newBallMass;
    }

    private float randomVelocity() {//Generate a random number between 0 and 2 for the (x, y) velocity of a ball.
        float speed = (float)(Math.random() * 2);
        return speed;
    }

    private Color randomColor() {//Generate a random color for a new ball based on the generation of a random red, green, and blue value.
        int red = (int) (Math.random() * 255);
        int green = (int) (Math.random() * 255);
        int blue = (int) (Math.random() * 255);
        ballColor = new Color(red, green, blue);
        return ballColor;
    }

}

BallBuilder.java

import java.awt.*;
import java.awt.image.*;
import java.util.concurrent.*;
import javax.swing.*;

public class BallBuilder extends Canvas{
    private int frameHeight = 600;
    private int frameWidth = 800;

    private static BufferStrategy strategy;//Create a buffer strategy named strategy.

    public BallBuilder(){
        setIgnoreRepaint(true);//Tell OS that we will handle any repainting manually.
        setBounds(0,0,frameWidth,frameHeight);

        JFrame frame = new JFrame("Bouncing Balls");
        JPanel panel = new JPanel();

        panel.setPreferredSize(new Dimension(frameWidth, frameHeight));
        panel.add(this);

        frame.setContentPane(panel);
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        addMouseListener(new MouseEventHandler());

        createBufferStrategy(2);//Create a double buffer for smooth graphics.
    strategy = getBufferStrategy();//Apply the double buffer to the buffer strategy named strategy.

    }

    public static void main(String[] args) {
        BallBuilder ballBuilder = new BallBuilder(); // Creates a new ball builder.
        ExecutorService executor = Executors.newSingleThreadExecutor();//Creates a thread executor that uses a single thread.
        executor.execute(new AddLogic(ballBuilder, strategy));//Executes the runnable task AddLogic on the previously created thread.

    }

}

MouseEventHandler.java

import java.awt.event.*;

public class MouseEventHandler extends MouseAdapter{

    private static boolean mouseClicked = false;

    public void mousePressed(MouseEvent e){//If either of the mouse buttons is pressed the mouse clicked variable is set to true.
        mouseClicked = true;
    }

    public static void mouseEventUpdate(){//When called, sets the mouse clicked variable back to false.
        mouseClicked = false;
    }

    public static boolean mouseEventCheck(){//Returns the state of the mouse clicked variable.
        if(mouseClicked){
            return true;
        }

        else{
            return false;
        }

    }

}

的Vector2D

public class Vector2D {//A class that takes care of ball position and speed vectors.

    private float x;
    private float y;

    public Vector2D() {
        this.setX(0);
        this.setY(0);
    }

    public Vector2D(float x, float y) {
        this.setX(x);
        this.setY(y);
    }

    public void set(float x, float y) {
        this.setX(x);
        this.setY(y);
    }

    public void setX(float x) {
        this.x = x;
    }

    public void setY(float y) {
        this.y = y;
    }

    public float getX() {
        return x;
    }

    public float getY() {
        return y;
    }

    public float dot(Vector2D v2) {//Speciality method used during calculations of ball to ball collisions.
        float result = 0.0f;
        result = this.getX() * v2.getX() + this.getY() * v2.getY();
        return result;
    }

    public float getLength() {
        return (float) Math.sqrt(getX() * getX() + getY() * getY());
    }

    public Vector2D add(Vector2D v2) {
        Vector2D result = new Vector2D();
        result.setX(getX() + v2.getX());
        result.setY(getY() + v2.getY());
        return result;
    }

    public Vector2D subtract(Vector2D v2) {
        Vector2D result = new Vector2D();
        result.setX(this.getX() - v2.getX());
        result.setY(this.getY() - v2.getY());
        return result;
    }

    public Vector2D multiply(float scaleFactor) {
        Vector2D result = new Vector2D();
        result.setX(this.getX() * scaleFactor);
        result.setY(this.getY() * scaleFactor);
        return result;
    }

    public Vector2D normalize() {//Speciality method used during calculations of ball to ball collisions.
        float length = getLength();
        if (length != 0.0f) {
            this.setX(this.getX() / length);
            this.setY(this.getY() / length);
        } else {
            this.setX(0.0f);
            this.setY(0.0f);
        }

        return this;
    }

}

Dr. belisari.. 5

当球反弹时,速度角度会发生变化,每次弹跳后都应该改变它.

替代文字

此外,正如您稍后将看到的,当两个球碰撞时,速度VALUE(称为"模数")也会发生变化.

编辑:::

在我看来,你正在加速球

int x = (int) (ball.getBallTempX() + 
              (ball.getBallPathLength() * Math.cos(ball.getBallAngle())));  

似乎对应

int x = (int) (ball.getBallTempX() + 
              (ball.getBallSpeed() * Math.cos(ball.getBallAngle())));  

对于"y"也一样

我对吗?

编辑2 ::

实际上,您也不需要TempX,TempY,PreviousCenterX和PreviousCenterY.

试试这些方法

private int xCoordinateUpdate(Ball ball) {

   int x = (int) (ball.getBallCenterX()+ (ball.Speed() 
                                      * Math.cos(ball.getBallAngle())));

return x;

(Y相同)

编辑3 ::

多一个 ... :)

你需要的是代码就是这个公式(当你试图碰撞球时,任何其他都会失败):

伪代码>

BallCenterX = BallCenterX + BallSpeed*Math.cos(角度)

BallCenterY = BallCenterY + BallSpeed*Math.sin(角度)

忘记任何"临时"和"旧"价值观.它们会削弱你的球碰撞功能.



1> Dr. belisari..:

当球反弹时,速度角度会发生变化,每次弹跳后都应该改变它.

替代文字

此外,正如您稍后将看到的,当两个球碰撞时,速度VALUE(称为"模数")也会发生变化.

编辑:::

在我看来,你正在加速球

int x = (int) (ball.getBallTempX() + 
              (ball.getBallPathLength() * Math.cos(ball.getBallAngle())));  

似乎对应

int x = (int) (ball.getBallTempX() + 
              (ball.getBallSpeed() * Math.cos(ball.getBallAngle())));  

对于"y"也一样

我对吗?

编辑2 ::

实际上,您也不需要TempX,TempY,PreviousCenterX和PreviousCenterY.

试试这些方法

private int xCoordinateUpdate(Ball ball) {

   int x = (int) (ball.getBallCenterX()+ (ball.Speed() 
                                      * Math.cos(ball.getBallAngle())));

return x;

(Y相同)

编辑3 ::

多一个 ... :)

你需要的是代码就是这个公式(当你试图碰撞球时,任何其他都会失败):

伪代码>

BallCenterX = BallCenterX + BallSpeed*Math.cos(角度)

BallCenterY = BallCenterY + BallSpeed*Math.sin(角度)

忘记任何"临时"和"旧"价值观.它们会削弱你的球碰撞功能.

推荐阅读
赛亚兔备_393
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有