• Rise/Run java
    8 replies, posted
Goal: make a ball move directly from point A to point B, incrementaly. As in not instantly. I want it to be visible. Problem: I know it has something to do with rise/run, and I know that I want x to increment every frame by rise * speed and y to increment every frame by run*speed, but rise and run are usually large numbers... I wrote some code that kind of sort of partially works. Could someone help me by either fixing it, or explaining this stupidly simple 8th grade math to me? I feel so dumb... [code] import java.applet.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class BallApplet extends Applet implements Runnable, MouseListener { int x,y,radius,tx,ty; int direction = 1; private Image dbImage; private Graphics dbg; public void init() { this.setBackground(Color.BLACK); radius = 10; x = 10; y = 10; tx = 50; ty = 100; this.addMouseListener(this); } public void start() { Thread th = new Thread(this); th.start(); } public void stop() { } public void destroy() { } public void run () { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); int xinterval = 1; //speed while (true) { //"game" loop boolean cont = true; //ignore if(x<tx){// if x is less than tx then increment x by interval, and dont continue to decrement it again. x+=xinterval; cont = false; } if(x>tx&&cont!=false){ x-=xinterval; } cont = true; //reset if(java.lang.Math.abs(ty-y)<2){ //if y is closer than 2 units away from target y, set it so i dont get div by 0 errors y = ty; cont = false; } if(java.lang.Math.abs(tx-x)<2){ //same with x x = tx; cont = false; } if(cont==true){ //if the circle is farther away than 2 units, move y by rise/run*speed. I think this part is wrong... y = y+((ty-y)/(tx-x))*(xinterval); } System.out.println("("+x+","+y+")"); //debug repaint(); try { Thread.sleep (5); } catch (InterruptedException ex) { } Thread.currentThread().setPriority(Thread.MAX_PRIORITY); } } public void update (Graphics g) { // initialize buffer if (dbImage == null) { dbImage = createImage (this.getSize().width, this.getSize().height); dbg = dbImage.getGraphics (); } // clear screen in background dbg.setColor (getBackground ()); dbg.fillRect (0, 0, this.getSize().width, this.getSize().height); // draw elements in background dbg.setColor (getForeground()); paint (dbg); // draw image on the screen g.drawImage (dbImage, 0, 0, this); } public void paint (Graphics g) { g.setColor (Color.red); g.fillOval (x - radius, y - radius, 2 * radius, 2 * radius); g.drawLine(x, y, tx, ty); } @Override public void mouseClicked(MouseEvent arg0) { System.out.println("User clicked at ("+arg0.getX()+","+arg0.getY()+")"); tx = arg0.getX(); ty = arg0.getY(); } @Override public void mouseEntered(MouseEvent arg0) { // TODO Auto-generated method stub } @Override public void mouseExited(MouseEvent arg0) { // TODO Auto-generated method stub } @Override public void mousePressed(MouseEvent arg0) { // TODO Auto-generated method stub } @Override public void mouseReleased(MouseEvent arg0) { // TODO Auto-generated method stub } } [/code] The interesting part that you want is in the run method. I just gave the whole thing if someone wants to run it themselves to see what I mean. It seems to partially work if the target x is greater than the current x, otherwise it spazes out... Thanks in advance, and I now see why I should have paid much more attention in 8th grade math. Theres no [i]math[/i] post icon?
May be a stupid question, why are you moving x by 1 each time but moving y by a value that depends on the difference in x divided by difference in y multiplied by 1 and added to y? Also why aren't you moving y when x moves? If I am understanding your goal correctly I would change the if statements to make the ball move in various directions. Could easily be done with a bit of trig, you will have the angle the ball needs to move in since x and y are just difference in x and tx and difference in y and ty. From there you could say that: Movement on x = cos(a) and y = sin(a) if a is the angle between the direction and x axis. I think anyway, been a while since I used trig. To work out a I think it is difference in y/diff in x. Sorry I couldn't help with your code but that is how I would work out the travel.
[quote] Also why aren't you moving y when x moves? [/quote] Huh? Am I not? I think I may be doing something completely wrong. Could you elatorate on your trig idea? I am terrible at trig, as I am at most other math. -snip im an idiot- - unsnip no im not- Could you explain the part about what A is? what is the angle between the direction and x axis? Im confused. Thanks for the responce :)
All you need to do, if I understand your assignment correctly, is calculate the total difference between x1 and x2 and y1 and y2, which will give you a vector pointing from point 1 to point 2. Then all you do is add this vector, multiplied by the seconds since last frame, to the position of the ball. (optionally, you can multiply the vector by a speed, 1 unit per sec is what my example uses) [editline]16th November 2010[/editline] Rise/run is unnecessary because you can treat x and y separately.
I have just looked through it again and realised it was actually my mistake, didn't see the ! in the second if statement. With the trig idea I am basically just making a triangle: [img]http://i7.photobucket.com/albums/y266/jasongillan/trig.png[/img] Red is where you are and black is where you need to be. Sin(a) = adj/hyp Cos(a) = opp/hyp Tan(a) = opp/adj Lets say you want to move distance p along the hyp, using the above definitions you can work out that: x = hyp*cos(a) y = hyp*sin(a) Does that make any more sense?
No need for trig because you're not doing anything with angles, you're working entirely with points in the Cartesian plane. RyanDv3 is right about doing it with vectors, but vector terminology is a bit beyond 8th-grade math. Bob, forget Y for a moment and imagine that you want to move the ball straight along the X axis. Suppose it's at x=3 initially, and you want it to move to x=7 over the course of ten seconds. That's a distance of 4, over the course of 10 seconds, so its movement rate has to be (4/10)=0.4 units per second. To animate it, each time you redraw the picture you'd take the number of seconds elapsed so far — this doesn't have to be a whole number, it can be fractional — multiply by 0.4, and add 3 (the starting point): x = 0.4t + 3 That'll put the ball at x=3 when t=0, and x=7 when t=10. Doing it in both X and Y works exactly the same; you just calculate the X position and Y position separately. The ball has both an X-speed and a Y-speed, and the two are independent of each other.
Wow, thank you for all your help! Sorry for not responding sooner. This really helped me a lot! Oh, and when I said 8th grade math, I didn't mean this was an assignment for 8th grade math, i just ment that what I didn't understand was probably covered in 8th grade math, in which I didn't pay much attention. I have a problem. Wyzard, your idea worked to some extent. Firstly, it dosent work exactly, maby this is because of loss of precision in transitioning between int and double. Anyway, it works the first time i run it, but when I click somewhere, it resets x and y to 0 and it either overshoots or dosent work right. Here's the code if you want to see it, ill keep looking for what im doing wrong. [code]import java.applet.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class BallApplet extends Applet implements Runnable, MouseListener { double x,y,tx,ty; int radius; int direction = 1; private Image dbImage; private Graphics dbg; int Speed; int TimeInSeconds; double ElapsedTime; double StartTime; double xNet; double yNet; double xMovement; double yMovement; boolean Break; public void init() { this.setBackground(Color.BLACK); radius = 10; x = 10; y = 10; tx = 50; ty = 100; this.addMouseListener(this); } public void start() { Thread th = new Thread(this); th.start(); } public void stop() { } public void destroy() { } public void SetUpRun(){ Speed = 3; //speed TimeInSeconds = 10; ElapsedTime = 0; StartTime = System.currentTimeMillis(); xNet = java.lang.Math.abs(x-tx); yNet = java.lang.Math.abs(y-ty); xMovement = xNet/TimeInSeconds; yMovement = yNet/TimeInSeconds; Break = false; System.out.println("Speed: "+Speed+" TimeInSeconds: "+TimeInSeconds+" ElapsedTime: "+ElapsedTime+" StartTime: "+StartTime+ "xNet: "+xNet+" yNet: "+yNet+" xMovement: "+xMovement+" yMovement: "+yMovement); } public void run () { Thread.currentThread().setPriority(Thread.MIN_PRIORITY); while (true) { //"game" loop if(Break==false){ ElapsedTime = (System.currentTimeMillis()-StartTime)/1000; x = (ElapsedTime*xMovement)*Speed; y = (ElapsedTime*yMovement)*Speed; } else{ ElapsedTime = 0; StartTime = 0; xNet = 0; yNet = 0; xMovement = 0; yMovement = 0; Break = true; } if(java.lang.Math.abs(x-tx)<Speed+1&java.lang.Math.abs(y-ty)<Speed+1){ Break = true; x=tx; y=ty; } //System.out.println(ElapsedTime); //System.out.println("("+x+","+y+")"); //debug repaint(); try { Thread.sleep (5); } catch (InterruptedException ex) { } Thread.currentThread().setPriority(Thread.MAX_PRIORITY); } } public void update (Graphics g) { // initialize buffer if (dbImage == null) { dbImage = createImage (this.getSize().width, this.getSize().height); dbg = dbImage.getGraphics (); } // clear screen in background dbg.setColor (getBackground ()); dbg.fillRect (0, 0, this.getSize().width, this.getSize().height); //lol Herp // draw elements in background dbg.setColor (getForeground()); paint (dbg); // draw image on the screen g.drawImage (dbImage, 0, 0, this); } public void paint (Graphics g) { g.setColor (Color.blue); g.fillOval ((int) x - radius, (int)y - radius, 2 * radius, 2 * radius); g.setColor(Color.red); g.drawLine((int) x, (int) y, (int) tx, (int)ty); } @Override public void mouseClicked(MouseEvent arg0) { System.out.println("User clicked at ("+arg0.getX()+","+arg0.getY()+")"); tx = arg0.getX(); ty = arg0.getY(); this.SetUpRun(); } @Override public void mouseEntered(MouseEvent arg0) { // TODO Auto-generated method stub } @Override public void mouseExited(MouseEvent arg0) { // TODO Auto-generated method stub } @Override public void mousePressed(MouseEvent arg0) { // TODO Auto-generated method stub } @Override public void mouseReleased(MouseEvent arg0) { // TODO Auto-generated method stub } } [/code] Interesting bits are in the beginning where i init the variables, in the method SetUpRun, and in the run method.
It's just a couple of small errors: Don't take the absolute value of the difference between the current position and the target, otherwise the circle will be incapable of moving backwards (note that Movement, Speed, and ElapsedTime are all positive). Also, you want to subtract the initial position from the final position so that when the initial position is smaller than the final position, you get a positive value for Net and thus start moving toward the final position. [code]xNet = tx - x; yNet = ty - y;[/code] Instead of determining the absolute position every time, just change the current position by a certain amount. DO this by getting rid of "speed" and just use Movement to determine the velocity. Thus xMovement and yMovement would be the (rectangular) components of velocity. "ElapsedTime" also isn't necessary, because the next position will always be relative to the last one. [code]x += ElapsedTime * xMovement; y += ElapsedTime * yMovement;[/code] Note that this method of changing position by adding the velocity (called the [url=http://en.wikipedia.org/wiki/Euler_method]Euler Method[/url]) becomes very inaccurate once the velocity starts changing due to acceleration, drag force, simple harmonic motion, etc. When you use Thread.sleep(), just measure the amount of time that it took to do the calculations and sleep for the amount of time left over, that way your frames last a constant amount of time.
Sorry, you need to Log In to post a reply to this thread.