so I am working on an AI system with C++ and SFML in which I want the enemies to follow the player. Im going to create it so the enemies are moving towards the point at which the player was 30 frames ago (so it will constantly updating). But my question is simple, what is the math behind getting the enemy to move to a specific point? Like let's say the player is at (230, 400) and the enemy is at (100, 200) how do I get the enemy (using the .move() function with a speed of 3) to move to that point? Any help would be fantastic!
---UPDATED BELOW WITH CURRENT CODE FOR HANDLING MOVEMENT-----
float angle = atan2(v2iEnemyPos[1].y - rsPlayer.getPosition().y, v2iEnemyPos[1].x - rsPlayer.getPosition().x);
angle =angle * 180 / (atan(1) * 4);
sf::Vector2f newpos((cos(angle))*2, (sin(angle))*2);
std::cout << newpos.x << " " << newpos.y << std::endl;
rsEnemy[1].move(newpos.x, newpos.y);
rwWinOne.draw(rsPlayer);
rwWinOne.display();
rwWinOne.clear();
The direction to move your enemy into is simply the difference between the player position and the enemy position. However, you want the enemies to move with constant speed, so you need to normalize the result. This will give you the direction as a vector of length 1.
Vector2u direction = normalize(player.getPosition() - enemy.getPosition());
You can now multiply this direction by the speed constant of that enemy's type. The result is a vector with it's length depending on the speed factor instead of the distance to the player. Just use the result to move your enemy.
enemy.move(speed * direction);
However, you perform that once a frame and framerates can vary between machines and configurations. Therefore, you should add a the elapsed time since the last move call, which might be your frame time, as factor to the equation. This way, if a frame takes a longer than usual, the enemy will be moved further to comprehend this, and vice versa.
// Initialize a timer
sf::Clock clock;
// Get elapsed time at the beginning of a frame
// I multiply this by target framerate to get a value around one
float delta = clock.restart().asSeconds() * 60;
// Move all objects based on elapsed time
Vector2u direction = normalize(player.getPosition() - enemy.getPosition());
enemy.move(delta * speed * direction);
By the way, basic knowledge of linear algebra is needed very often in game development, so you might pay out to attend an online course.
You should consider the elapsed time (since last frame) - dt - in your calculation.
The enemy has a given speed: enemy_velocity.
I won't use the move() function, but the SetPosition().
You have to calculate the new position of the enemy:
enemy.x += dt * enemy_velocity * cos(angle);
enemy.y += dt * enemy_velocity * sin(angle);
And affect it with SetPosition().
Related
I have m_dynamicsWorld with 1 static object and 1 dynamic.
I trying control dynamic rigid body in bullet physics.
I change position every frame while button pressed:
btTransform t;
t.setOrigin(btVector3(pos.x, pos.y, pos.z));
t.setRotation(btQuaternion(rot.x, rot.y, rot.z, rot.w));
rb->setWorldTransform(t);
rb->getMotionState()->setWorldTransform(t);
for (int i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; --i)
m_dynamicsWorld->getCollisionObjectArray()[i]->activate(true); // for all rb in m_dynamicsWorld
then simulate
m_dynamicsWorld->stepSimulation(m_timeStep, 1 + 1, m_timeStep); // timeStep < maxSubSteps * fixedTimeStep
Dynamic object is moving but gravity does not apply for it and it does not collide with walls.
Seems like i control object, not bullet.
Then i increase fixedTimeStep and simulate:
m_dynamicsWorld->stepSimulation(m_timeStep, 4 + 1, m_timeStep / 4); // timeStep < maxSubSteps * fixedTimeStep
With 2 or more (4 in example) fixedTimeSteps bullet apply gravity and collisions good. But simulation time is increased. On phone every millisecond is important.
I dont remove object from m_dynamicsWorld when transform, dont change collision flag to CF_KINEMATIC_OBJECT, dont set mass to 0 and then set back to positive.
Why bullet dont apply gravity and collisions well with 1 fixedTimeStep?
How is better move dynamic object without increase fixedTimeStep?
Please dont advice me use kinematic object, maybe i control car which should be affected by gravity and collisions with other dynamics objects.
I have started working in Unreal Engine 4 and opened up the most basic tutorial with c++ on their web site. So this is the code they provided
void AFloatingActor::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
FVector NewLocation = GetActorLocation();
float DeltaHeight = (FMath::Sin(RunningTime + DeltaTime) - FMath::Sin(RunningTime));
NewLocation.Z += DeltaHeight * 20.0f; //Scale our height by a factor of 20
RunningTime += DeltaTime;
SetActorLocation(NewLocation);
}
And this is the explanation of what it should do:
The code we've just written will cause FloatingActors to bob up and down smoothly, using the RunningTime variable we created to keep track of our movement over time.
And when you compile it it does that, but it doesn't tell me anything about how or why it works. The thing that bugs me is as the title say the movement equation :
DeltaHeight = sin(RunningTime + DeltaTime) - sin(RunningTime)
If anyone could explain this to me it would be greatly appreciated. What I'm asking would be Mathematical/Physical explanation behind this equation or the explanation where does this equation come from. Why is it like that.
This function controls the movement (height specifically) of the character such that the amount of movement is controlled via a sine wave over time. That is, at time 0 it starts moving upwards relatively quickly, then slows down upwards movement until it stops moving up and then starts moving down, speeds up downwards eventually slowing down and moving up again. It continues periodically moving up and down in this manner.
So, how this functions works, is that it's called periodically and then time change between this call and the last is DeltaTime. The last time it was called was RunningTime. So compute the new position:
FMath::Sin(RunningTime + DeltaTime)
and the old position:
FMath::Sin(RunningTime)
then calculate the change in position by taking the difference:
float DeltaHeight = (FMath::Sin(RunningTime + DeltaTime) - FMath::Sin(RunningTime));
I'm trying to make my asteroid keep moving once I press a button.
void Ship::applyThrust()
{
_v.setX(_v.getX() - sin(2 * M_PI * (_angle / 360)) * 2.5);
_v.setY(_v.getY() + cos(2 * M_PI * (_angle / 360)) * 2.5);
}
This is the formula I have to help my ship move.
The _v.setX and _vsetY updates the X and Y position
The M_PI is just 3.14.
The _angle is how much of a rotation I set with my left and right arrow keys and
The 2.5 is how many frames per I want it to move
My ship is moving just fine, the problem is that I'm trying to simulate space inertia and have my ship continue moving.
Any ideas on how would be the logic for this?
Thanks,
Inside of your game loop, you'll need a function that updates the position of the ship based on its x and y velocity. You're close in getting the new x and y coordinates of your ship, but you don't account for the velocity of the ship. When you apply thrust, get the x and y components of your velocity, not your new position. You'll have an additional function to update position which should be called within the game loop at a timed interval - e.g. every time you update the frame. So your applyThrust function should actually update your ship's velocity. That means you'll need to add variables to your Ship class for your ship's position and your ship's velocity if you don't already have them. I'm breaking out the components of position and velocity for simplicity, but you'll probably want to store them in a vector for clarity:
class Ship
{
private float xpos, ypos; // current position of your ship
private float velocityX, velocityY; // current velocity of your ship
}
Then, when you apply thrust, you change the velocity, and remember that applyThrust is only called when the thrust button is pushed, not every frame as the position update is:
void Ship::applyThrust()
{
/*
Assume 1 total unit of thrust is applied each time you hit the thrust button
so you break down the velocity into x and y components depending on the direction
your ship is facing.
*/
// thrustUnit is how much thrust each thrust button press gets you, it's arbitrary
// and can be the 2.5 multiplier you're using in your question
float thrustUnit = 1.0;
// now get the x and y thrust components of velocity based on your ship's direction
// assuming 0 degrees is pointing to the right
float newVX, newVY = 0.0;
newVX = thrustUnit * cos(_angle);
newVY = thrustUnit * sin(_angle); // radian conversion left out to save space
// Update your ship's velocity
updateVelocity(newVX, newVY);
}
updateVelocity will look something like: (note that the velocity is additive so it continues to drift unless a thrust is applied in the opposite direction - the same as if it were in a frictionless medium such as space)
void Ship::updateVelocity(newVX, newVY)
{
// update the x component
velocityX += newVX;
velocityY += newVY;
}
So now you'll also need an updatePosition function that takes into account your ship's velocity. This gets called with each frame update:
void Ship::updatePosition()
{
// add the x component of velocity to the ship's x position
// assuming xpos and ypos are variables in the Ship class for tracking position
xpos += velocityX;
ypos += velocityY;
}
Now the position of the ship changes incrementally according to each velocity component at each frame update. You can also make thrustUnit a member variable to allow for power-ups that can either boost or decrease your thrust component for your ship's speed and being able to control it better with a smaller thrustUnit or giving it hyperspeed with a large thrustUnit.
Good luck with your game!
I'm making a vertical-scroll platformer game, and I want to create sprites that move left-to-right (or right-to-left) and when they're out of the screen, they appear on the other side.
I have an implementation that is mostly working, the only problem is that the sprites on a single floor keeps getting closer and closer in every loop.
I'm really not good in describing things, so please check this video.
I'm using the following code to calculate the new position of the nodes:
pos.x = fmodf(size.width + pos.x + this->currentDir * this->speed * delta, this->len + size.width) - size.width;
len is the width after which the sprite gets repositioned to 0 (actually -size.width, which is the width of the sprite), currentDir is either 1 or -1 and delta is the time from the update() method.
Every sprite is positioned in it's own update(), but I already tried doing everything in the Scene's update() method, but the result was the same.
If your delta variable is increasing over time, then I believe that your pos.x would also increase in the same proportion, this is why the distance from the floors would change.
Have you tried to reset the delta value each time the floor goes offscreen?
I'm building up a 2D physics engine in c++ based on the Cyclone Physics Engine, http://procyclone.com, and I'm trying to figure out why the code uses a gravity vector multiplied by the mass to add force to an object,
void psiclone::Gravity::addForce(Body* body, double seconds) {
body->addForce(gravity * body->mass);
}
instead of
body->addForce(gravity * seconds);
Granted, the code does provide an update() including
velocity.mX += acceleration.getX() * seconds;
but with 2 objects being effected by gravity, shouldn't they both hit the ground at the same time even if they have different masses??
From physics, we know that force = mass * acceleration. Thus to calculate acceleration, they just divide force by mass. They are just sticking with physics definitions of the terms. gravity * seconds would be velocity.
Thank you for the replies; Upon further investigation I was missing a line in my update function ( cyclone's particle::integrate() ) multiplying the acceleration vector by the body's inverseMass:
acceleration *= inverseMass;
velocity += acceleration * seconds;
position += velocity * seconds;
This allowed two body's of differing mass to both fall to the bottom of the screen and hit at the same time.