Accelerate to X velocity in Y seconds - c++

How can I get something to go from X to Xgoal velocity in Y seconds?
The goalVelocity is set to (100, 100) and it does approach it but it takes way too long to get there.
I can multiply frameDelta by some number like 20 or 100 but I want to find out what to multiply frameDelta by to get it to reach goalVelocity in some number of seconds.
velocity, goalVelocity and origin are all Vec2f and frameDelta is a float
Right now I have this code:
velocity = approach(goalVelocity, velocity, frameDelta);
origin = origin + velocity * frameDelta;
The code for approach is:
inline float approach(float flGoal, float flCurrent, float dt)
{
float flDifference = flGoal - flCurrent;
if (flDifference > dt)
return flCurrent + dt;
if (flDifference < -dt)
return flCurrent - dt;
return flGoal;
}
inline Vec2f approach(Vec2f flGoal, Vec2f flCurrent, float dt)
{
return Vec2f(approach(flGoal.x, flCurrent.x, dt), approach(flGoal.y, flCurrent.y, dt));
}

Maybe I misunderstood your Question, but acceleration is just speed difference divided by time, so just multiply dt with X/Y.

A basic physics engine should look something like
Vec2f position, velocity, acceleration;
while (true)
{
acceleration = button ? thrust : 0;
velocity += acceleration * timeDelta;
position += velocity * timeDelta
redraw space ship at position;
sleep (timeDelta);
}
if you want to go from 0 to X velocity in Y seconds, then thrust = X/Y.

Related

Smooth movement of player SFML

void update(RenderWindow& window)
{
if (Keyboard::isKeyPressed(Keyboard::W))
{
dy = -0.3;
}
if (Keyboard::isKeyPressed(Keyboard::A))
{
dx = -0.3;
}
if (Keyboard::isKeyPressed(Keyboard::S))
{
dy = 0.3;
}
if (Keyboard::isKeyPressed(Keyboard::D))
{
dx = 0.3;
}
x += dx;
y += dy;
dx = dy = 0;
EntitySprite.setPosition(x, y);
window.draw(EntitySprite);
}
When the movement is described in such a code, the player moves angularly: either to the left, or up, or to the right, or down, or diagonally at an angle of 45 degrees by pressing two buttons together, for example S and D. Can this angle be made smoother so that the movement itself was carried out not only to the left, right, diagonally, etc.? My knowledge of geometry is not enough here, so I ask for your help).
In your code, the user input directly modifies the player position. This is probably the reason why the player movement looks so abrupt to you. Technically, in your code, the user input is what is determining the player velocity at any given moment.
A more realistic approach would be to let the player have a velocity property instead –
that represents the player position's rate of change – and then have the player position updated only through this velocity, not directly from the user input. Instead, the velocity would be what is directly modified by the input, but not entirely determined by the current input as it will also depend on its previous value.
Following this approach, the user input is used to calculate the player acceleration in each call to update(). This acceleration – the rate of change of the velocity – is used to update the player velocity directly. Finally, the player velocity is, in turn, used to update the player position.
The following code implements this approach by introducing the velocity_ data member and the acceleration local variable:
void update(RenderWindow& window) {
sf::Vector2f acceleration;
// adjust this at will
const float dAcc = 0.3f;
// set acceleration
if (Keyboard::isKeyPressed(Keyboard::W))
acceleration.y -= dAcc;
if (Keyboard::isKeyPressed(Keyboard::A))
acceleration.x -= dAcc;
if (Keyboard::isKeyPressed(Keyboard::S))
acceleration.y += dAcc;
if (Keyboard::isKeyPressed(Keyboard::D))
acceleration.x += dAcc;
// update velocity through acceleration
velocity_ += acceleration;
// update position through velocity
x += velocity_.x;
y += velocity_.y;
// apply damping to the velocity
velocity_ = 0.99f * velocity_;
EntitySprite.setPosition(x, y);
window.draw(EntitySprite);
};
This way, the player possesses some kind of inertia, and its movement looks smoother.
Note that you may want to have some damping for the velocity as in:
velocity_ = 0.99f * velocity_;
This will resemble the effect of drag forces.
with help of that man I did it like this, but some better)
void update(RenderWindow& window)
{
float decceleration = 0.3;
if (Keyboard::isKeyPressed(Keyboard::W))
{
accelerationY -= decceleration;
}
if (Keyboard::isKeyPressed(Keyboard::S))
{
accelerationY += decceleration;
}
if (Keyboard::isKeyPressed(Keyboard::A))
{
accelerationX -= decceleration;
}
if (Keyboard::isKeyPressed(Keyboard::D))
{
accelerationX += decceleration;
}
dx += accelerationX;
dy += accelerationY;
speed = sqrt(dx * dx + dy * dy);
if (speed > maxSpeed)
{
dx *= maxSpeed / speed;
dy *= maxSpeed / speed;
}
x += dx;
y += dy;
dx *= 0.9;
dy *= 0.9;
accelerationX = 0;
accelerationY = 0;
EntitySprite.setPosition(x, y);
window.draw(EntitySprite);
}

Code about a particle bouncing on a curved surface

I'm supposed to write a code that simulates an inelastic particle bouncing within a wall and a semicircle (radius 30, center # (50,0). The particle loses 3% of its original velocity every time it hits a wall and/or the semicircle.
I'm also using graphics.h library
I have made most of the program already, but the particle does not properly bounce on the semicircle.
I used the reflection matrix:
\begin{bmatrix}
cos 2\theta & sin2\theta \
sin2 \theta & -cos2\theta
\end{bmatrix}
here is the this snippet of the code containing the conditions when the particle hits the semicircle:
//initial conditions
x = 0;
y = 100;
Vx = 15.0;
Vy = 0.0;
double dt = 0.0001; //initial time step and increment
for(double t = 0; t < 50; t += dt)
{
Vy = Vy + grav*dt;
//Conditions when the particle hits a wall or the floor and retaining only 97% of its speed
if (y<0.0)
{
Vy = -Vy + grav*dt;
}
if(x >100.0 || x < 0.0)
{
Vx = -Vx;
}
//condition when the particle hits the semicircle
//semicircle equation: y = sqrt(30^2 - (x-50)^2)
if(y < sqrt((30*30)-((x-50)*(x-50))) )
{
Vxnew = ((Vx)*(cos(2.0*theta)) + (Vy*(sin(2.0*theta))));
Vy = (Vy*(cos(2.0*theta)) - ((Vx)*(sin(2.0*theta))));
Vx = Vxnew;
}
x = x + Vx*dt;
y = y + Vy*dt;
putpixel(conx(x), cony(y), 15);
}
I'm not sure if this reflection matrix applies on curved surfaces and I should use something else or my implementation is wrong.
For the losing the velocity part, I can probably just multiply the new x and y velocities by 0.97.
For context, this function that I made converts the calculated value in the loop to pixel values
//convert to pixel value (scale of 6)
double conx(double x)
{
return x * (600/100) + 50;
}
double cony(double y)
{
return -y * (600/100) + 650;
}

How to rotate a point every second

I have a point that I want to rotate that corresponds to every second in time like a second hand in a clock, it should rotate 6 degrees every second but i tried timing it and it does not take a minute to make a full rotation, here is the code
void rotate(const float& ox, const float& oy, float &x, float &y, const float& rotation) {
float tx = x-ox;
float ty = y-oy;
float nx = tx*cos(rotation) - ty*sin(rotation);
float ny = tx*sin(rotation) + ty*cos(rotation);
x = nx+ox;
y = ny+oy;
}
float origx = 1280/2, origy = 720/2, pntx = origx, pnty = origy-300, rotation=6; // variables
rotate(origx, origy, pntx, pnty, rotation*timer.delta); // update point, timer is an object that gets the delta time between frames of the main loop
Need to update the values for your variables like:
your origx should be 90 deg which is 0.5π rad
your origy should also be 90 deg which is 0.5π rad
every second step (rotation) is 6 deg which is 0.033333333333π rad
For sin and cos takes radians in the argument and not degrees.

How do I keep the jump height the same when using delta time?

I'm using delta time so I can make my program frame rate independent.
However I can't get the jump height it be the same, the character always jumps higher on a lower frame rate.
Variables:
const float gravity = 0.0000000014f;
const float jumpVel = 0.00000046f;
const float terminalVel = 0.05f;
bool readyToJump = false;
float verticalVel = 0.00f;
Logic code:
if(input.isKeyDown(sf::Keyboard::Space)){
if(readyToJump){
verticalVel = -jumpVel * delta;
readyToJump = false;
}
}
verticalVel += gravity * delta;
y += verticalVel * delta;
I'm sure the delta time is correct because the character moves horizontally fine.
How do I get my character to jump the same no matter the frame rate?
The formula for calculating the new position is:
position = initial_position + velocity * time
Taking into account gravity which reduces the velocity according to the function:
velocity = initial_velocity + (gravity^2 * time)
NOTE: gravity in this case is not the same as the gravity.
The final formula then becomes:
position = initial_position + (initial_velocity + (gravity^2 * time) * time
As you see from the above equation, initial_position and initial_velocity is not affected by time. But in your case you actually set the initial velocity equal to -jumpVelocity * delta.
The lower the frame rate, the larger the value of delta will be, and therefore the character will jump higher. The solution is to change
if(readyToJump){
verticalVel = -jumpVel * delta;
readyToJump = false;
}
to
if(readyToJump){
verticalVel = -jumpVel;
readyToJump = false;
}
EDIT:
The above should give a pretty good estimation, but it is not entirely correct. Assuming that p(t) is the position (in this case height) after time t, then the velocity given by v(t) = p'(t)', and the acceleration is given bya(t) = v'(t) = p''(t)`. Since we know that the acceleration is constant; ie gravity, we get the following:
a(t) = g
v(t) = v0 + g*t
p(t) = p0 + v0*t + 1/2*g*t^2
If we now calculate p(t+delta)-p(t), ie the change in position from one instance in time to another we get the following:
p(t+delta)-p(t) = p0 + v0*(t+delta) + 1/2*g*(t+delta)^2 - (p0 + v0*t + 1/2*g*t^2)
= v0*delta + 1/2*g*delta^2 + g*delta*t
The original code does not take into account the squaring of delta or the extra term g*delta*t*. A more accurate approach would be to store the increase in delta and then use the formula for p(t) given above.
Sample code:
const float gravity = 0.0000000014f;
const float jumpVel = 0.00000046f;
const float limit = ...; // limit for when to stop jumping
bool isJumping = false;
float jumpTime;
if(input.isKeyDown(sf::Keyboard::Space)){
if(!isJumping){
jumpTime = 0;
isJumping = true;
}
else {
jumpTime += delta;
y = -jumpVel*jumpTime + gravity*sqr(jumpTime);
// stop jump
if(y<=0.0f) {
y = 0.0f;
isJumping = false;
}
}
}
NOTE: I have not compiled or tested the code above.
By "delta time" do you mean variable time steps? As in, at every frame, you compute a time step that can be completely different from the previous?
If so, DON'T.
Read this: http://gafferongames.com/game-physics/fix-your-timestep/
TL;DR: use fixed time steps for the internal state; interpolate frames if needed.

Wave vector in 2 dimensions

So I'm trying to make the player shoot a bullet that goes towards the mouse in a wavey pattern. I can get the bullet to move in a wavey pattern (albeit not really how I predicted), but not towards the mouse.
Vector2 BulletFun::sine(Vector2 vec) {
float w = (2 * PI) / 1000; // Where 1000 is the period
float waveNum = (2 * PI) / 5; // Where 5 is the wavelength
Vector2 k(0.0F, waveNum);
float t = k.dot(vec) - (w * _time);
float x = 5 * cos(t); // Where 5 is the amplitude
float y = 5 * sin(t);
Vector2 result(x, y);
return result;
}
Right now the speed isn't much of a concern, that shouldn't be too much of a problem once I have this figured out. I do get some angle change, but it seems to be reversed and only 1/8th a circle.
I'm probably miscalculating something somewhere. I just kind of learned about wave vectors.
I've tried a few other things, such as 1 dimensional travelling waves and another thing involving adjusting a normal sine wave by vec. Which had more or less the same result.
Thanks!
EDIT:
vec is the displacement from the player's location to the mouse click location. The return is a new vector that is adjusted to follow a wave pattern, BulletFun::sine is called each time the bullet receives and update.
The setup is something like this:
void Bullet::update() {
_velocity = BulletFun::sine(_displacement);
_location.add(_velocity); // add is a property of Tuple
// which Vector2 and Point2 inherit
}
In pseudocode, what you need to do is the following:
waveVector = Vector2(travelDistance,amplitude*cos(2*PI*frequency*travelDistance/unitDistance);
cosTheta = directionVector.norm().dot(waveVector.norm());
theta = acos(cosTheta);
waveVector.rotate(theta);
waveVector.translate(originPosition);
That should compute the wave vector in a traditional coordinate frame, and then rotate it to the local coordinate frame of the direction vector (where the direction vector is the local x-axis), and then translate the wave vector relative to your desired origin position of the wave beam or whatever...
This will result in a function very similar to
Vector2
BulletFun::sine(Bullet _bullet, float _amplitude, float _frequency, float _unitDistance)
{
float displacement = _bullet.getDisplacement();
float omega = 2.0f * PI * _frequency * _displacement / _unitDistance;
// Compute the wave coordinate on the traditional, untransformed
// Cartesian coordinate frame.
Vector2 wave(_displacement, _amplitude * cos(omega));
// The dot product of two unit vectors is the cosine of the
// angle between them.
float cosTheta = _bullet.getDirection().normalize().dot(wave.normalize());
float theta = acos(cosTheta);
// Translate and rotate the wave coordinate onto
// the direction vector.
wave.translate(_bullet.origin());
wave.rotate(theta);
}