Simple physical simulation in Java does not work properly
I want to achieve ball physics, as a novice, I adjust the code in the tutorial.
I try to do my best, but I can't apply all physical phenomena in the code. Someone can tell me that I'm wrong or I'm still making some stupid programming mistakes
When I didn't call the bounce method and I couldn't use the bounce method and the ball moved to the left instead of falling / ending on the floor, the ball was moving * *,
Some bodies can recommend me some better or similar simple ways to accomplish this task, applying physics to the interaction of two or more balls
This is the 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 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; } }
Using Adobe ball:
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[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(),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(),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(),b1 .getY()); double origangle = b1.getDirection(); b1.setDirection(angle + origangle); angle = pointDirection(tmp.getX(),tmp.getY(),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: * make sure to split the code from this forum using the new gravity method: this code does not work, and the ball is not present:
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; } }
Thank you very much for any correction and help
jibby
Solution
At present, I can't run Java, so I can't test your code, but I noticed some things:
>For (almost) the same thing, you have two sets of independent variables: {DX, Dy} and {m_velocityx, m_velocityy} Therefore, getspeed and setspeed are independent, as are getdirection and setdirection I can't believe it will work the way you expect. > Your coordinates look a little confused (which may be why the ball "falls" to the left) You seem to measure the angle clockwise from the X direction, which is not standard Editor: PL í niopantale ã o has determined the reason for the tilt to the left. > Your code seems to involve simple linear motion, bouncing, gravity and friction You should implement and test these at once I first suggest motion, then add bounce, friction and gravity (in any order), and finally combine them
Edit: this gravity code is wrong:
if (m_y + m_bottomBound > 400) { m_veLocityY *= -0.981; // setY(400 - m_bottomBound); m_y = 400 - m_bottomBound; }
First, you use 400 as the "magic number"; I don't know what it stands for Then, you limit the effect to the area near the top of the screen for unclear reasons At the end of the function, you change m in a meaningless way_ y. And (perhaps) worst of all, you have gravity reversal and doubling vertical velocity, which is not the way gravity works
Try this:
// 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;