Простое моделирование физики в Java не работает. - PullRequest
3 голосов
/ 04 октября 2010

Я хотел бы реализовать физику мяча, и, как я новичок, я адаптирую код в учебнике http://adam21.web.officelive.com/Documents/JavaPhysicsTutorial.pdf.

Я стараюсь следовать этому столько, сколько могу, но я не в состоянииПримените все физические явления в коде, кто-нибудь, пожалуйста, скажите мне, где я ошибаюсь или я все еще делаю какую-то глупую ошибку программирования.

Шары движутся, когда я не вызываю метод отскока и не могу использовать метод отскока, и мяч движется влево вместо падения / окончания на пол **,

Может ли какой-нибудь орган порекомендовать мне какой-нибудь лучший способ или аналогичный простой и компактный способ выполнения этой задачи применения физики на двух или более шарах с интерактивностью.

вот код;

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

}

с использованием 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);
            }
        });
    }

}   

* РЕДАКТИРОВАТЬ: * нормально разделение кода с использованием нового подхода для гравитации из этого форума: этот код также не работаетмяч не идет по полу:

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;

    }
}

большое спасибо за любые исправления и помощь.

jibby

Ответы [ 2 ]

5 голосов
/ 04 октября 2010

В настоящее время я не могу запустить Java, поэтому я не могу протестировать ваш код, но я заметил пару вещей:

  1. У вас есть два независимых набора переменных для (почти) одного и того же:{dx, dy} и {m_velocityX, m_velocityY}.В результате ваши getSpeed ​​и setSpeed ​​являются независимыми , равно как и getDirection и Setdirection.Я не могу поверить, что это будет работать так, как вы ожидаете.
  2. Ваши координаты кажутся немного запутанными (возможно, поэтому мяч "падает" влево).Вы, кажется, измеряете угол по часовой стрелке от направления X, что не является стандартным. РЕДАКТИРОВАТЬ: Plínio Pantaleão определил причину падения влево.
  3. Ваш код, кажется, включает в себя простые линейные движения, подпрыгивание, гравитацию и трение.Вы должны реализовать и протестировать их по одному.Сначала я предлагаю движение, затем добавляю отскок, затем трение и гравитацию отдельно (в любом порядке) и, наконец, объединяю их.

РЕДАКТИРОВАТЬ:
Этот код для гравитации неверен:

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

Сначала вы используете 400 в качестве "магического числа";Я не могу сказать, что это представляет.Затем вы ограничиваете эффект областью в верхней части экрана по непонятным причинам.В конце функции вы изменяете m_y таким образом, что не имеет смысла.И (возможно), что хуже всего, у вас есть гравитация , изменяющая и умножающая вертикальная скорость, а это не то, как работает гравитация.

Попробуйте вместо этого:

// 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;
2 голосов
/ 04 октября 2010

Хорошо, проблема еще не решена.Но несколько вещей, которые могут помочь:

1 - Math.sin / cos принять угол в радианах.(это может помочь немного).- AdobeBall

2 - Вы должны рассчитывать gravDir для каждого вызова move (), поскольку m_velocityX / Y может изменить направление - AdobeBall

3 - Ваш основной цикл в runball () выполняетодин и тот же шар два раза и сравнивая с собой ... Используйте j = i + 1 во втором цикле

4 - Вы вызываете runball () в цикле потока.Так что я ожидаю, что шары все равно будут двигаться ... Не только если вы вызовете bounce ().Я прав?

Вы можете исправить свой код и попробовать еще раз.И размещать новости!:)

...