开发者

Simple Physics Simulation in java not working.

I wanted to implement ball physics and as i m newbie, i adapt the code in tutorial http://adam21.web.officelive.com/Documents/JavaPhysicsTutorial.pdf .

i try to follow that as i much as i can, but i m not able to apply all physical phenomenon in code, can somebody please tell me, where i m mistaken or i m still doing some silly programming mistake.

The balls are moving when i m not calling bounce method and i m unable to avail the bounce method and ball are moving towards left side instead of falling/ending on floor**,

Can some body recommend me some better way or similar easy compact way to accomplish this task of applying physics on two ball or more balls with interactivity.

here is code ;

    import java.awt.*;
    public class AdobeBall {

    protected int radius = 20;
    protected Color color;

    // ... Constants
    final static int DIAMETER = 40;

    // ... Instance variables
    private int m_x; // x and y coordinates upper left
    private int m_y;

    private double dx = 3.0; // delta x and y 
    private double dy = 6.0;

    private double m_velocityX; // Pixels to move each time move() is called.
    private double m_velocityY;

    private int m_rightBound; // Maximum permissible x, y values.
    private int m_bottomBound;

    public AdobeBall(int x, int y, double velocityX, double velocityY,
            Color color1) {
        super();
        m_x = x;
        m_y = y;
        m_velocityX = velocityX;
        m_velocityY = velocityY;
        color = color1;
    }

    public double getSpeed() {
        return Math.sqrt((m_x + m_velocityX - m_x) * (m_x + m_velocityX - m_x)
                + (m_y + m_velocityY - m_y) * (m_y + m_velocityY - m_y));
    }

    public void setSpeed(double speed) {
        double currentSpeed = Math.sqrt(dx * dx + dy * dy);
        dx = dx * speed / currentSpeed;
        dy = dy * speed / currentSpeed;
    }

    public void setDirection(double direction) {
        m_velocityX = (int) (Math.cos(direction) * getSpeed());
        m_velocityY = (int) (Math.sin(direction) * getSpeed());
    }

    public double getDirection() {
        double h = ((m_x + dx - m_x) * (m_x + dx - m_x))
                + ((m_y + dy - m_y) * (m_y + dy - m_y));
        double a = (m_x + dx - m_x) / h;
        return a;
    }

    // ======================================================== setBounds
    public void setBounds(int width, int height)  {
        m_rightBound = width - DIAMETER;
        m_bottomBound = height - DIAMETER;
    }

    // ============================================================== move
    public void move()  {

        double gravAmount = 0.02;
        double gravDir = 90; // The direction for the gravity to be in.
        // ... Move the ball at the give velocity.
        m_x += m_velocityX;
        m_y += m_velocityY;

//       ... Bounce the ball off the walls if necessary.
        if (m_x < 0) { // If at or beyond left sid开发者_如何学编程e
            m_x = 0; // Place against edge and
            m_velocityX = -m_velocityX;

        } else if (m_x > m_rightBound) { // If at or beyond right side
            m_x = m_rightBound; // Place against right edge.
            m_velocityX = -m_velocityX;
        }

        if (m_y < 0) { // if we're at top
            m_y = 0;
            m_velocityY = -m_velocityY;

        } else if (m_y > m_bottomBound) { // if we're at bottom
            m_y = m_bottomBound;
            m_velocityY = -m_velocityY;
        }

     //   double speed = Math.sqrt((m_velocityX * m_velocityX)
     //         + (m_velocityY * m_velocityY));

        // ...Friction stuff 
        double fricMax = 0.02; // You can use any number, preferably less than 1
        double friction = getSpeed();
        if (friction > fricMax)
            friction = fricMax;
        if (m_velocityX >= 0) {
            m_velocityX -= friction;
        }
        if (m_velocityX <= 0) {
            m_velocityX += friction;
        }
        if (m_velocityY >= 0) {
            m_velocityY -= friction;
        }
        if (m_velocityY <= 0) {
            m_velocityY += friction;
        }

        // ...Gravity stuff

        m_velocityX += Math.cos(gravDir) * gravAmount;
        m_velocityY += Math.sin(gravDir) * gravAmount;

    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color newColor)  {
        color = newColor;
    }

    // ============================================= getDiameter, getX, getY
    public int getDiameter() {
        return DIAMETER;
    }

  public double getRadius() {
        return radius; // radius should be a local variable in Ball.
    }

    public int getX() {
        return m_x;
    }

    public int getY() {
        return m_y;
    }

}

using adobeBall:

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;

    public class AdobeBallImplementation implements Runnable {

    private static final long serialVersionUID = 1L;

    private volatile boolean Play;
    private long mFrameDelay;
    private JFrame frame;
    private MyKeyListener pit;

    /** true means mouse was pressed in ball and still in panel. */
    private boolean _canDrag = false;

    private static final int MAX_BALLS = 50; // max number allowed
    private int currentNumBalls = 2; // number currently active
    private AdobeBall[] ball = new AdobeBall[MAX_BALLS];

    public AdobeBallImplementation(Color ballColor) {

        frame = new JFrame("simple gaming loop in java");
        frame.setSize(400, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pit = new MyKeyListener();
        pit.setPreferredSize(new Dimension(400, 400));
        frame.setContentPane(pit);

        ball[0] = new AdobeBall(34, 150, 7, 2, Color.YELLOW);
        ball[1] = new AdobeBall(50, 50, 5, 3, Color.BLUE);
        frame.pack();
        frame.setVisible(true);
        frame.setBackground(Color.white);
        start();
        frame.addMouseListener(pit);
        frame.addMouseMotionListener(pit);

    }

    public void start() {
        Play = true;
        Thread t = new Thread(this);
        t.start();
    }

    public void stop() {
        Play = false;
    }

    public void run() {

        while (Play == true) {
            // bounce(ball[0],ball[1]);
            runball();
            pit.repaint();
            try {
                Thread.sleep(mFrameDelay);
            } catch (InterruptedException ie) {
                stop();
            }
        }
    }

    public void drawworld(Graphics g) {

        for (int i = 0; i < currentNumBalls; i++) {
            g.setColor(ball[i].getColor());
            g.fillOval(ball[i].getX(), ball[i].getY(), 40, 40);
        }
    }

    public double pointDistance (double x1, double y1, double x2, double y2) {
        return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    }

    public void runball() {

        while (Play == true) {
            try {

                for (int i = 0; i < currentNumBalls; i++) {
                    for (int j = 0; j < currentNumBalls; j++) {

                        if (pointDistance(ball[i].getX(), ball[i].getY(),
                                ball[j].getX(), ball[j].getY()) < ball[i]
                                                                       .getRadius()
                                                                       + ball[j].getRadius() + 2) {
                            // bounce(ball[i],ball[j]);
                            ball[i].setBounds(pit.getWidth(), pit.getHeight());
                            ball[i].move();

                            pit.repaint();

                        }
                    }
                }

                try {
                    Thread.sleep(50);
                } catch (Exception e) {
                    System.exit(0);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static double pointDirection(int x1, int y1, int x2, int y2) {
        double H = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); // The
        // hypotenuse
        double x = x2 - x1; // The opposite
        double y = y2 - y1; // The adjacent
        double angle = Math.acos(x / H);
        angle = angle * 57.2960285258;
        if (y < 0) {
            angle = 360 - angle;
        }
        return angle;
    }

    public static void bounce(AdobeBall b1, AdobeBall b2) {
        if (b2.getSpeed() == 0 && b1.getSpeed() == 0) {
            // Both balls are stopped.
            b1.setDirection(pointDirection(b1.getX(), b1.getY(), b2.getX(), b2
                    .getY()));
            b2.setDirection(pointDirection(b2.getX(), b2.getY(), b1.getX(), b1
                    .getY()));
            b1.setSpeed(1);
            b2.setSpeed(1);
        } else if (b2.getSpeed() == 0 && b1.getSpeed() != 0) {
            // B1 is moving. B2 is stationary.
            double angle = pointDirection(b1.getX(), b1.getY(), b2.getX(), b2
                    .getY());
            b2.setSpeed(b1.getSpeed());
            b2.setDirection(angle);
            b1.setDirection(angle - 90);
        } else if (b1.getSpeed() == 0 && b2.getSpeed() != 0) {
            // B1 is moving. B2 is stationary.
            double angle = pointDirection(b2.getX(), b2.getY(), b1.getX(), b1
                    .getY());
            b1.setSpeed(b2.getSpeed());
            b1.setDirection(angle);
            b2.setDirection(angle - 90);
        } else {
            // Both balls are moving.
            AdobeBall tmp = b1;
            double angle = pointDirection(b2.getX(), b2.getY(), b1.getX(), b1
                    .getY());
            double origangle = b1.getDirection();
            b1.setDirection(angle + origangle);
            angle = pointDirection(tmp.getX(), tmp.getY(), b2.getX(), b2.getY());
            origangle = b2.getDirection();
            b2.setDirection(angle + origangle);
        }
    }

    public static void main(String[] args) {

        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new AdobeBallImplementation(Color.red);
            }
        });
    }

}   

*EDIT:*ok splitting the code using new approach for gravity from this forum: this code also not working the ball is not coming on floor:

public void mymove() {

    m_x += m_velocityX;
    m_y += m_velocityY;

    if (m_y + m_bottomBound > 400) {
        m_velocityY *= -0.981;
    //  setY(400 - m_bottomBound);
        m_y = 400 - m_bottomBound;

    }

    // ... Bounce the ball off the walls if necessary.
    if (m_x < 0) { // If at or beyond left side
        m_x = 0; // Place against edge and
        m_velocityX = -m_velocityX;

    } else if (m_x > m_rightBound) { // If at or beyond right side
        m_x = m_rightBound - 20; // Place against right edge.
        m_velocityX = -m_velocityX;
    }

    if (m_y < 0) { // if we're at top
        m_y = 1;
        m_velocityY = -m_velocityY;

    } else if (m_y > m_bottomBound) { // if we're at bottom
        m_y = m_bottomBound - 20;
        m_velocityY = -m_velocityY;

    }
}

thanks a lot for any correction and help.

jibby


At the moment I cannot run java, so I cannot test your code, but I notice a couple of things:

  1. You have two independent sets of variables for (almost) the same thing: {dx, dy} and {m_velocityX, m_velocityY}. As a result, your getSpeed and setSpeed are independent, and so are getDirection and Setdirection. I cannot believe that this will work the way you expect.
  2. Your coordinates seem a little confused (which is probably why the ball "falls" to the left). You seem to be measuring angle clockwise from the X direction, which is not standard. EDIT: Plínio Pantaleão has identified the reason for falling to the left.
  3. Your code seems to involve simple linear motion, bouncing, gravity and friction. You should implement and test these one at a time. I suggest the motion first, then add bouncing, then friction and gravity separately (in either order) and finally combine them.

EDIT:
This code for gravity is wrong:

if (m_y + m_bottomBound > 400) {
    m_velocityY *= -0.981;
    //  setY(400 - m_bottomBound);
    m_y = 400 - m_bottomBound;
}

First you are using 400 as a "magic number"; I can't tell what it represents. Then you are restricting the effect to a region near the top of the screen, for reasons that are not clear. At the end of the function you change m_y in a way that makes no sense. And (maybe) worst of all, you have gravity reversing and multiplying vertical velocity, which is not how gravity works.

Try this instead:

// You will have to adjust this. Start with a small value and increase it until
// you see an effect.
final static double GRAVITY = 0.1;

// Note that +y is down, so accelerating downward means increasing vY
m_velocityY += GRAVITY;


Ok, not solving the problem yet. But a few things that may help:

1 - Math.sin/cos take angle in radians. (that may help a litle). - AdobeBall

2 - You have to calculate gravDir for each invoke of move() since m_velocityX/Y may have change direction- AdobeBall

3 - Your main loop in runball() are taking the same ball two times and comparing to itself... Use j=i+1 in second loop

4 - You call runball() in your thread loop. So I would expect the balls to move anyway.... Not just if you call bounce(). I'm correct?

You may correct your code and try again. And post the news! :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜