Skip to main content
GameDev.net gamedev.net
🔒 Locked

"Dipping" physics: flying object swooping and then returning to previous height

Started by PiCroft Oct 27, 2011 at 3:16 PM 13 replies 4k views
Original Post
PiCroft
PiCroft
Hello,

I'm trying to create a simple 2D game where an object is flying at a particular height at constant velocity. When I press a button, the object starts to dive, the dive getting steeper the longer you hold the button. When you release the button, the object levels out, then starts to climb back up to its original height.

Could someone give me some math pointers for making this mechanic?
Imgelling
Imgelling

Hello,

I'm trying to create a simple 2D game where an object is flying at a particular height at constant velocity. When I press a button, the object starts to dive, the dive getting steeper the longer you hold the button. When you release the button, the object levels out, then starts to climb back up to its original height.

Could someone give me some math pointers for making this mechanic?


Have your object have 2 velocities, horizontal and vertical, that do not interact with each other (as in real life).

Have the horizontal velocity stay the same. When you press the button accelerate the vertical velocity so that it starts going down. That will need to be incremented each frame the button is held down. When the button is released, just have the vertical velocity decelerate to 0.

if (button.ispresssed())
{
vertical.velocity += 10; // this could be -= all depends on how to set it up
}
else
{
vertical.velocity -= 10; // this is opposite of the first one
if (vertical.velocity < 0) vertical.velocity = 0;
}

Edit: Not sure if you wanted to decrease horizontal velocity during "diving". Doing so would make the dive even steeper. if so, it would change to something like...
if (button.ispresssed())
{
vertical.velocity += 10; // this could be -= all depends on how to set it up
horizontal.velocity -= 5; //this could be += all depends on set up
if (horizontal.velocity < 0) horizontal.velocity = 0;
}
else
{
vertical.velocity -= 10; // this is opposite of the first one
if (vertical.velocity < 0) vertical.velocity = 0;
horizontal.velocity += 5;
if (horizontal.velocity > MAX_HORIZONTAL_VELOCITY) horizontal.velocity = MAX_HORIZONTAL_VELOCITY;
}
my blog contains ramblings and what I am up to programming wise.
PiCroft
PiCroft
Thanks, that's useful!

I need to make the object rotate correctly too, I'm using a second object hovering slightly in front of the main object thats invisible, so the object always rotates to face it. It doesn't look right atm, but Its a good stop-gap until I can make a movement algorithm that correctly applies physics to it.
Imgelling
Imgelling

Thanks, that's useful!

I need to make the object rotate correctly too, I'm using a second object hovering slightly in front of the main object thats invisible, so the object always rotates to face it. It doesn't look right atm, but Its a good stop-gap until I can make a movement algorithm that correctly applies physics to it.


Not sure if you are doing this already but it will be a smoother curve if instead of using constants for acceleration, the += -= 5's and 10's, is to make it time based. Like so...

float VERTICAL_ACCELERATION_PER_SECOND 10
if (button.ispresssed())
{
vertical.velocity += (int)( VERTICAL_ACCELERATION_PER_SECOND * Timer.MillisecondsElapsed / 1000.0f);
}
where Timer.MillisecondsElapsed is the amount of time taken since the last frame.

This is the method I use in my 2D tile engine testing to give my character the ability to jump in a smooth curve which can be seen here. He is a bit "floaty" but that is because I haven't gotten the gravity number down just right.

Basically, there is a constant gravity pulling down on him adding to his velocity, 32 pixels per second per frame. When he stands on a block, the block is pushing him back up and resetting his vertical velocity to 0 pixels per second. To jump I add a force to him by setting his vertical acceleration to -1000 pixels per second and let the gravity that is applied every frame do the work for me.
Horizontal movement is just adding/subtraction a horizontal acceleration and when left/right is not pressed, the acceleration rapidly returns to 0.

I know it is not exactly what you are trying to achieve, but maybe it will give ya some ideas.
my blog contains ramblings and what I am up to programming wise.
hupsilardee
hupsilardee
How about using an upside bell curve for the y-coordinate of the object?
TomKQT
TomKQT

Hello,

I'm trying to create a simple 2D game where an object is flying at a particular height at constant velocity. When I press a button, the object starts to dive, the dive getting steeper the longer you hold the button. When you release the button, the object levels out, then starts to climb back up to its original height.

Could someone give me some math pointers for making this mechanic?


I wouldn't go with splitting the velocity into horizontal and vertical. In fact, if you keep horizontal as it is and increse the vertical part, the total velocity will have higher magnitude, which probably won't be what you want.

I would solve your problem by having a velocity vector v (which will be horizontal during the initial flying at a constant height).
When you hold a dive button, I would simply rotate the vector down. The longer you hold the button, the bigger the overall rotation, but with a limit at some defined angle (for example 70 degrees to not let it dive too steep)
When you don't hold the button, I would gradually rotate the vector back to the initial horizontal orientation, then compare the current height with the target height and if it is smaller, rotate the vector further upwards to make the object ascend to the required target height.

Your actual position is then simply updated every frame as
p = p + v * dt;
where dt is the timestep between frames, p is a position vector (2D) and v is the velocity vector (2D).

If you always change the rotation gradually (so not for example from 0 to 40 degrees in one step), the resulting movement will be nicely smooth (the object's central point would draw a smooth curve).

Please let me know if this verbal explanation isn't clear and/or if you would prefer some equations.

Btw, it of course all depends on what kind of movement are you trying to get, what kind of object it is etc. Maybe you really want it to dive at higher overall velocity than when it flies horizontal?The solution with rotating velocity vector would suit something like an airplane, where the rotation even can be nicely visualised (the whole airplane rotates).
PiCroft
PiCroft

[quote name='PiCroft' timestamp='1319728613' post='4877578']
Hello,

I'm trying to create a simple 2D game where an object is flying at a particular height at constant velocity. When I press a button, the object starts to dive, the dive getting steeper the longer you hold the button. When you release the button, the object levels out, then starts to climb back up to its original height.

Could someone give me some math pointers for making this mechanic?


I wouldn't go with splitting the velocity into horizontal and vertical. In fact, if you keep horizontal as it is and increse the vertical part, the total velocity will have higher magnitude, which probably won't be what you want.

I would solve your problem by having a velocity vector v (which will be horizontal during the initial flying at a constant height).
When you hold a dive button, I would simply rotate the vector down. The longer you hold the button, the bigger the overall rotation, but with a limit at some defined angle (for example 70 degrees to not let it dive too steep)
When you don't hold the button, I would gradually rotate the vector back to the initial horizontal orientation, then compare the current height with the target height and if it is smaller, rotate the vector further upwards to make the object ascend to the required target height.

Your actual position is then simply updated every frame as
p = p + v * dt;
where dt is the timestep between frames, p is a position vector (2D) and v is the velocity vector (2D).

If you always change the rotation gradually (so not for example from 0 to 40 degrees in one step), the resulting movement will be nicely smooth (the object's central point would draw a smooth curve).

Please let me know if this verbal explanation isn't clear and/or if you would prefer some equations.

Btw, it of course all depends on what kind of movement are you trying to get, what kind of object it is etc. Maybe you really want it to dive at higher overall velocity than when it flies horizontal?The solution with rotating velocity vector would suit something like an airplane, where the rotation even can be nicely visualised (the whole airplane rotates).
[/quote]

Thatnks, this is closer to what I want.

The idea is that the object will have 2 heights: at default, the object will move towards the upper height (default behaviour) and when diving, it will move towards the lower height.

I have the velocity and I'm adding it to the position as you suggested, and I am getting movement forward (because the default velocity is forwards, but I'm having difficulty correctly calculating the rotation.

//if diving, set target y to lower limit
zVec2f target;

target.x = getPosition().x;
target.x += 5.0f;

if(diving)
target.y = baseline_y_lower;
else
target.y = baseline_y_upper;

zVec2f delta = (getPosition()-target);

float TurnDir = delta.getAngle();

float rotDif = zRadRelative(TurnDir-physOrientatiation.xa.getAngle());
physOrientatiation.xa.rotate(rotDif);

//set final velocity
zVec2f velocity = physOrientatiation.xa;
velocity.normalise();
setPosition(getPosition() + velocity * ev.getTime().dt);

//rotate sprite
mainr->setRotation(physOrientatiation.xa.getAngle());


The above code makes my object fly in weird directions. I'm not entirely sure why though :/

Edit: physOrientatiation.xa.rotate(rotDif); rotates to an absolute value in radians I believe, so when it calculates the difference in angle between the current heading and the target point, the value returned is the total angle needed to turn, not the angle needed to turn this frame.

That being said, I'm wondering why this is causing such odd behaviour since, if the object turns directly towards the target in 1 frame, the next frame the difference should be tiny or non-existant, meaning that it should snap to facing the right direction immediately and then continue correctly, but instead it floats off in odd directions.
alvaro
alvaro

I wouldn't go with splitting the velocity into horizontal and vertical. In fact, if you keep horizontal as it is and increse the vertical part, the total velocity will have higher magnitude, which probably won't be what you want.


Actually, that's exactly what I would expect. By dipping you convert potential energy into kinetic energy, which is why you get faster.

Kestrels use this to their advantage when hunting: They hover above the ground at some height and, when they figure out what they want to catch, they take advantage of the extra speed that the drop gives them.
TomKQT
TomKQT

[quote name='Tom KQT' timestamp='1320671819' post='4881384']
I wouldn't go with splitting the velocity into horizontal and vertical. In fact, if you keep horizontal as it is and increse the vertical part, the total velocity will have higher magnitude, which probably won't be what you want.


Actually, that's exactly what I would expect. By dipping you convert potential energy into kinetic energy, which is why you get faster.

Kestrels use this to their advantage when hunting: They hover above the ground at some height and, when they figure out what they want to catch, they take advantage of the extra speed that the drop gives them.
[/quote]

Of course, but for a proper simulation of this you would need to use gravity vector (acceleration vector) and increase the velocity using this acceleration. Simply increasing the vertical velocity component by a constant number would lead to a weird effect. We don't know what's PiCroft really doing, but he didn't mention gravity.
TomKQT
TomKQT
The code doesn't seem right to me, provided I understand well what you really want to achieve.
Try something like this. I don't know what physOrientation.xa is, so you'll need to adapt this code a bit, it is partly a pseudo-code. In fact I didn't use physOrienation.xa at all, I don't see when (and if at all) it should be used:


float angle = 0;
if (diving && getPosition().y > baseline_y_lower) {
// we are diving and we are still above the desired depth => we must descend
angle = descend_angle_value; // descend_angle_value can be a constant now to make it easier to get it working
}
else if (!diving && getPosition().y < baseline_y_upper) {
// we are not diving and we are still below the desired depth => we must ascend
angle = ascend_angle_value; // ascend_angle_value can be a constant now to make it easier to get it working
}

// Now give your object the 'angle' absolute orientation, dunno how your engine works so I'll guess:
mainr->setRotation(angle);

// Calculate the velocity vector anyhow, given its orientation ('angle') and magnitude (depends on how fast you want it to move).
// For example even something as simple as this could work too:
zVec2f velocity;
velocity.x = magnitude * cos(angle);
velocity.y = magnitude * sin(angle);
// ... but a care must be taken about signs (in which direction you measure the angle, which direction does y have etc.)
// Note that you don't want to normalize the velocity, in general case the velocity magnitude won't be 1.

setPosition(getPosition() + velocity * ev.getTime().dt);


Warning - it's just a code to get started, it has some simplifications - the rotation changes abruptly, the object will move in lines, not in curves. The final code should change the angle gradually until it reaches the desired ascend/descent value. And when approaching the target height, you would have to start leveling your object in advance to make smooth transition again.
alvaro
alvaro

[quote name='alvaro' timestamp='1320684727' post='4881454']
Actually, that's exactly what I would expect. By dipping you convert potential energy into kinetic energy, which is why you get faster.


Of course, but for a proper simulation of this you would need to use gravity vector (acceleration vector) and increase the velocity using this acceleration. Simply increasing the vertical velocity component by a constant number would lead to a weird effect. We don't know what's PiCroft really doing, but he didn't mention gravity.
[/quote]

Well, he didn't mention gravity by name but, if you reread the first post, what he describes sounds exactly like acceleration from gravity to me.

EDIT: Increasing the vertical velocity component by a constant number every frame is precisely what gravity does..., isn't it?
PiCroft
PiCroft
Thanks guys, this is a lot of help!

I think I know why my object isn't behaving as I thought - the rotate() function is relative to the current position, so when it gets and angle of, say, 4.1 radians, its rotating that amount every frame which may be why its flying about all over the place.

I'm going to try resetting the rotation back to a specific default value every frame and rotating from there and see if it fixes the problem.
TomKQT
TomKQT

Well, he didn't mention gravity by name but, if you reread the first post, what he describes sounds exactly like acceleration from gravity to me.

The first post of this thread? I don't think there's any hint on gravity


EDIT: Increasing the vertical velocity component by a constant number every frame is precisely what gravity does..., isn't it?


You are right, it is. It represents some force (acceleration) pushing the object down and if you change the vertical velocity each frame by delta_time * gravity, then it represents gravitation force (gravity = 9.81on Earth).
The problem is that we really don't know what kind of behaviour is PiCroft trying to get. Because keeping the horizontal velocity intact and increasing the vertical by some number every frame would simulate something like a gravity or other similar force (if the acc value would differ from gravity), which would be like a free fall. Like an airplane flying forward and suddently losing its wings (with acc = gravity) or suddenly being pushed down/up by some magnet or something or just losing part of the wings lift (with acc != gravity).
Not exactly what I personaly imagined by "diving" and "climbing". That sounds to me rather like if the object (airplane? submarine? spaceship?) tilts up/down and flies that direction. Yes, maybe with the added grafity acceleration, I don't say he certainly doesn't want to have gravity. But when something flies straight at a constant velocity propelled by some engine (needed against air/water/xxx drag) and then tilts down to descend, you must tilt also the propelling force.
Doing it the other way isn't WRONG, it just isn't what I GUESSED PiCroft was trying to achieve

This really is complicated to get right when we don't know what are we doing
TomKQT
TomKQT

Thanks guys, this is a lot of help!

I think I know why my object isn't behaving as I thought - the rotate() function is relative to the current position, so when it gets and angle of, say, 4.1 radians, its rotating that amount every frame which may be why its flying about all over the place.

I'm going to try resetting the rotation back to a specific default value every frame and rotating from there and see if it fixes the problem.


If you are working on your original code, you should maybe also consider whether you have the correct direction in this code:
zVec2f delta = (getPosition()-target);

That gives you a vector from the target to your position, not the other way around which would give more sense IMHO. It then affects the calculation of the angle in delta.getAngle();
PiCroft
PiCroft
I was right, the rotations were being added every frame, resetting the rotation each time works

Sorry for being mysterious , to clear things up: there's no gravity required, the object in question is an insect that bobs up and down at a certain height and when a button is pressed, it swoops down to a lower height and bobs up and down at that height.

I am in fact looking to make the insect speed up during dives/rises, but at the moment I'm just kind of experimenting with ways of doing things and seeing what feels right, so for the time being there is no real "right" way to do it

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.