Java-Gaming.org Hi !
 Featured games (90) games approved by the League of Dukes Games in Showcase (754) Games in Android Showcase (229) games submitted by our members Games in WIP (842) games currently in development
 News: Read the Java Gaming Resources, or peek at the official Java tutorials
Pages: [1]
 ignore  |  Print
 Assistance with Simple Euler Physics Integration  (Read 5310 times) 0 Members and 1 Guest are viewing this topic.
E.R. Fleming

Senior Newbie

Exp: 4-6 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

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
E.R. Fleming

Senior Newbie

Exp: 4-6 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!
Roquen

JGO Kernel

Medals: 517

 « Reply #3 - Posted 2014-07-29 05:38:55 »

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

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

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.

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! 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 valuesfinal 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!
Roquen

JGO Kernel

Medals: 517

 « Reply #5 - Posted 2014-07-29 09:19:58 »

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

Senior Newbie

Exp: 4-6 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 stateMachine;      float ACCEL_CONST = 20f;   float DAMP =  0.95f;   float MAX_SPEED = 100f;   float dt = 1/60;//rest omitted for claritypublic 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.

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.
basil_

« JGO Bitwise Duke »

Medals: 418
Exp: 13 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
Pages: [1]
 ignore  |  Print

 DesertCoockie (33 views) 2018-05-13 18:23:11 nelsongames (75 views) 2018-04-24 18:15:36 nelsongames (70 views) 2018-04-24 18:14:32 ivj94 (752 views) 2018-03-24 14:47:39 ivj94 (82 views) 2018-03-24 14:46:31 ivj94 (622 views) 2018-03-24 14:43:53 Solater (98 views) 2018-03-17 05:04:08 nelsongames (179 views) 2018-03-05 17:56:34 Gornova (405 views) 2018-03-02 22:15:33 buddyBro (1065 views) 2018-02-28 16:59:18
 Java Gaming Resourcesby philfrei2017-12-05 19:38:37Java Gaming Resourcesby philfrei2017-12-05 19:37:39Java Gaming Resourcesby philfrei2017-12-05 19:36:10Java Gaming Resourcesby philfrei2017-12-05 19:33:10List of Learning Resourcesby elect2017-03-13 14:05:44List of Learning Resourcesby elect2017-03-13 14:04:45SF/X Librariesby philfrei2017-03-02 08:45:19SF/X Librariesby philfrei2017-03-02 08:44:05
 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