Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (133)
games submitted by our members
Games in WIP (603)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Assistance with Simple Euler Physics Integration  (Read 1479 times)
0 Members and 1 Guest are viewing this topic.
Offline E.R. Fleming

Junior Newbie


Exp: 1-3 months



« Posted 2014-07-29 01:20:38 »

So, I've been picking my brain for a couple days on this problem, and I haven't come up with a solution as of yet. I need your help!

I'm using LibGDX and am trying to create VERY simple physics for smooth, 8-direction player movement, using acceleration, velocity, and position vectors. I set up my physics equations (according to the Euler method) in my "isRunning" boolean, and my input works fine, but the physics are wonky and send my "player" accelerating infinitely in the positive y direction. I would post a gif of the program running, but I'm unsure as to whether or not that is actually allowed on the forum.

Could you guys assist? Thanks in advance!

http://pastebin.java-gaming.org/ce500034f0317

Also, on an unrelated note, this is my first post on the forum! =D

Offline tkausl

Junior Devvie


Medals: 3
Exp: 5 years



« Reply #1 - Posted 2014-07-29 01:55:11 »

I would post a gif of the program running, but I'm unsure as to whether or not that is actually allowed on the forum.
Would be great, or a little Video on YouTube.

What i see is, that you accelerate without any limit. Thats not good. Also, you accellerate backwards if W is not pressed, better would be if you scale down velocity. (velocity = velocity * 0.99 or something like that).

My English isnt that great. Correct me, if you want, im still learning this Language Smiley
Offline E.R. Fleming

Junior Newbie


Exp: 1-3 months



« Reply #2 - Posted 2014-07-29 02:14:57 »

Thank you for your reply! As per your request, here's a gif containing the behavior of my "player" object. I hope the quality is okay.

https://i.imgflip.com/aojps.gif

The words in the console read "W IS NOT PRESSED" and "W IS PRESSED".

Thanks again!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Roquen
« Reply #3 - Posted 2014-07-29 05:38:55 »

Use fixed time steps for the simulation.
Offline Screem
« Reply #4 - Posted 2014-07-29 08:26:42 »

Gah, I accidentally hit appreciate on your comment, Roquen. No harm done. Cheesy

Anyways, I have time to spare so I'll explain this as best as I can.

Adding to what Roquen said, you only calculate the delta time once when you instantiate your Player class. Delta time is the time between the last frame and the current frame, so saving the value is useless. In your isRunning() method, add store the current delta time and use that. Also you can shorten your if statements. Instead of
if(statement == true)
, you could simply write
if(statement)
. Last thing, avoid creating new objects in methods called repeatedly. libGDX's Vector2 class has a method called
set(float x, float y)
so it's better to call that method than create a new Vector each time. Now onto the actual physics. Cheesy

If I understand correctly, you want the player to accelerate to a maximum speed, and 'drift' to a stop. Here's my usual approach:

Lets define some values first. Suppose our object accelerates at 20 pixels per second. And our maximum speed (otherwise known as terminal velocity) for both the x and y axis is 200 pixels per second.

Check which movement keys are pressed. If up is pressed, set acceleration.y to our acceleration value. If up is not pressed, set acceleration.y to zero. For down, set acceleration.y to the negative of our acceleration value or zero if not pressed. Repeat for left and right, but on the x-axis instead.

After the acceleration vector has the correct components, multiply it by deltaTime. This will normalize the acceleration values based on the time elapsed so the player moves at the same rate regardless of frame rate.

Then, add the acceleration to the velocity. Now, we need to cap the velocity in case it exceeds our maximum speed (otherwise known as terminal velocity). Add a couple if statements to check if the x and y axis of the velocity exceed our maximum speed, and cap them if they do. Viola, our player moves smoothly! But how do we stop?

When a key is released, it's acceleration component is set to zero. Newton's first law of physics states objects move with a constant velocity (or stay at rest) until acted upon by an outside force. To stop our object, we have to simulate friction (the outside force). Don't worry, this is really simple.

Before, when we checked if each key was pressed, we set it's respective acceleration value to zero if it was released. So if up was released, acceleration.y would be set to zero. This means our object should start slowing down on the y axis. Use a simple if statement to check if acceleration.y == 0, then multiply velocity.y by some friction or damping value. The higher the value the more gradually an object will slow down. I usually use 0.95, but you can play around with different values to find what you like.

Lastly, add our velocity to our position and reset our acceleration back to normal by multiplying it by the inverse of delta (1 / delta). This is important, otherwise you'll keep multiplying the acceleration by delta until it reaches zero.

Now we're done! Cheesy Your object will accelerate to a maximum speed and slow down when you let go of the movement keys. Here's some really basic pseudo code you can use:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
// I should probably have used pastebin for this... I didn't realize how long it'd be.

// Our constant values
final float ACCELERATION = 20F;
final float MAX_SPEED = 200F;
final float DAMP = 0.95F;
float deltaTime = 0;

Vector2 acceleration, velocity, position;

public void update() {
   // I usually pass the delta time as a parameter to the update() method,
   // but you can do whatever you want.
   deltaTime = Gdx.graphics.getDeltaTime();

   // Step one: Check each key.
   if(up.isPressed()) acceleration.y = ACCELERATION;
   else acceleration.y = 0;

   if(down.isPressed()) acceleration.y = -ACCELERATION;
   else acceleration.y = 0;

   if(left.isPressed()) acceleration.x = -ACCELERATION;
   else acceleration.x = 0;

   if(right.isPressed()) acceleration.x = ACCELERATION;
   else acceleration.x = 0;

   acceleration.scl(deltaTime); // normalize the acceleration.

   velocity.add(acceleration); // Add the acceleration to the velocity.

   // Check if the velocity is greater than the maximum speed
   //
   // By using the absolute value, we can avoid two clauses as we will not
   // need to check if the velocity is less than the negative maximum speed
   // since absolute value returns the distance a number is from zero.
   //
   // Signum returns 1 if the value passed in is positive, zero if it's zero, or -1 if it's negative.
   // This preserves the direction of the velocity.
   if(Math.abs(velocity.x) > MAX_SPEED) velocity.x = MAX_SPEED * Math.signum(velocity.x);
   if(Math.abs(velocity.y) > MAX_SPEED) velocity.y = MAX_SPEED * Math.signum(velocity.y);

   // Dampen our velocity to drift to a stop.
   if(acceleration.x == 0) velocity.x *= DAMP;
   if(acceleration.y == 0) velocity.y *= DAMP;

   position.add(velocity);

   acceleration.scl(1 / delta);

   // Tada! We're done. :D
}


Also, welcome to the forum! Wink
Offline Roquen
« Reply #5 - Posted 2014-07-29 09:19:58 »

That using a variable time step.  Run simulations at a fixed rate.
Offline E.R. Fleming

Junior Newbie


Exp: 1-3 months



« Reply #6 - Posted 2014-07-29 15:05:31 »

I appreciate you guys coming and answering my questions!

As per your suggestions, I gave my code a fixed time step and added the "DAMP" float, and the "MAX_SPEED" cap. Here's the code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
public class Player extends MovingEntity {
   
   ShapeRenderer shape;
   Rectangle bounds;
   public StateMachine<Player> stateMachine;
   
   float ACCEL_CONST = 20f;
   float DAMP =  0.95f;
   float MAX_SPEED = 100f;
   float dt = 1/60;

//rest omitted for clarity

public void move(){
     
     
     
      velocity.x += acceleration.scl(dt).x;
      velocity.y += acceleration.scl(dt).y;
     
     
      if(Math.abs(velocity.x) >= MAX_SPEED) velocity.x = MAX_SPEED * Math.signum(velocity.x);
      if(Math.abs(velocity.y) >= MAX_SPEED) velocity.y = MAX_SPEED * Math.signum(velocity.y);
     
      if (acceleration.x == 0) velocity.x *= DAMP;
      if (acceleration.y == 0) velocity.y *= DAMP;
     
      position.x += velocity.scl(dt).x;
      position.y += velocity.scl(dt).y;
     

     
      if(Gdx.input.isKeyPressed(Input.Keys.W)){
         acceleration.y = ACCEL_CONST;
         System.out.println("W IS PRESSED");
      }
      else acceleration.y = 0;
     
      isRunning();
      stateMachine.update();
      //Gdx.app.log(HunterGame.log, "Current state is " + stateMachine.getCurrentState());
   
   }


As you can see, I moved my physics code out of the "isRunning" boolean, because in truth, it's only used by the stateMachine to determine what state the player is in. My "move()" function is called by the "update()" function in my WorldRenderer class.

And my player object is behaving differently... it's just not the behavior I want. When I press my W key, it instantly moves up in position ( most likely to 20f, my acceleration constant), only to return to (0, 0) when the key is released.

Again, I appreciate your help!

EDIT:

...Wow. Just realized a silly mistake I made. Changing now.

EDIT 2: My change didn't help much. For some reason or another, my code is equating my change in velocity with my change in position.
Offline basil_

« JGO Bitwise Duke »


Medals: 99
Exp: 12 years



« Reply #7 - Posted 2014-07-29 22:15:13 »

keep in mind that capping/limiting the velocity component-wise can result in a bit weird behaviour. basicly it is manhattan distance.

it is fine to start and get a grip on the topic ..

but you might want to try capping the velocity based on its vector-magnitude later. maybe i'm totally of tho' and you got that already Wink
Pages: [1]
  ignore  |  Print  
 
 

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

rwatson462 (37 views)
2014-12-15 09:26:44

Mr.CodeIt (31 views)
2014-12-14 19:50:38

BurntPizza (62 views)
2014-12-09 22:41:13

BurntPizza (99 views)
2014-12-08 04:46:31

JscottyBieshaar (60 views)
2014-12-05 12:39:02

SHC (74 views)
2014-12-03 16:27:13

CopyableCougar4 (77 views)
2014-11-29 21:32:03

toopeicgaming1999 (138 views)
2014-11-26 15:22:04

toopeicgaming1999 (127 views)
2014-11-26 15:20:36

toopeicgaming1999 (38 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!