I need to develop cannon game using box2d and cocos2dx. Cannon is divided into two parts
Base which is fixed in the ground and doesn't move.
b2WeldJointDef basePlatformWeldJointDef;
basePlatformWeldJointDef.Initialize(base->getBody(), weaponPlatform->getBody(),weaponPlatform->getBody()->GetWorldCenter());
basePlatformWeldJointDef.collideConnected = false;
basePlatformWeldJoint = m_world->CreateJoint(&basePlatformWeldJointDef);
Arm which is fixed in the base with a RevoluteJoint.
b2RevoluteJointDef armJointDef;
armJointDef.Initialize(base->getBody(), arm->getBody(), m_loader->pointsToMeters(ccp(armPosition.x-(arm->getContentSize().width*WeaponScale/4),armPosition.y)));
armJointDef.enableMotor = true;
armJointDef.enableLimit = true;
armJointDef.motorSpeed = 0;
armJointDef.lowerAngle = CC_DEGREES_TO_RADIANS(0);
armJointDef.upperAngle = CC_DEGREES_TO_RADIANS(0);
armJointDef.maxMotorTorque = 2;
armJointDef.collideConnected = false;
cannonRevoluteJoint = (b2RevoluteJoint*)m_world->CreateJoint(&armJointDef);
The cannon should calculate the angle that will fire to, and this is calculated correctly. Using the revolutJointObject->setLimits(lowerAngle, higherAngle) here i use the lowerAngle and the higherAngle both are the desired angle so the arm moves to desired angle directly without motion.
Then i needed to move the arm not just change its angle, so i set the lowerAngle and higherAngle with the old angle and desired angle depending which will be the lower and the which will the higher, and changed the motor speed of the RevoluteJoint
The problem is that i need a callback method which fires when the revolute joint reaches to a certain angle or when the motor speed reaches Zero assuming that when the arm reaches the limit angle will stop and the motor speed will be Zero.
I have searching in SO and i found This Solution which calculates the angle each step, this can be used but it needs more calculations that i feel lazy to do.
Does the callback method for notifying motor speed or certain angle has been reached exists ?
Schedule a function to check your conditions on each frame. When you don't need the checks any more - unschedule the selector, then reschedule when needed again.
As far as I know there are no callbacks for your exact task.
All a callback would do behind the scenes is check the angle each frame and then call the callback function when the joint angle is within a certain range.
There's no built in callbacks for this use case. You could make your own to hide what's going on, or you could just put the if statement in the update function. The performance of this will be fine.
Related
I'm currently building a simplified Reaction Control System for a Satellite game, and need a way to use the system to align the satellite to a given unit direction in world-space coordinates. Because this is a game simulation, I am faking the system and just applying a torque force around the objects epicenter.
This is difficult because in my case, the Torque cannot be varied in strength, it is either on or off. It's either full force or no force. Calculating the direction that the torque needs to be applied in is relatively easy, but I'm having trouble getting it to align perfectly without spinning out of control and getting stuck in a logical loop. it needs to apply the opposing force at precisely the right 'time' to land on the target orientation with zero angular velocity.
What I've determined so far is that I need to calculate the 'time' it will take to reach zero velocity based on my current angular velocity and the angle between the two vectors. If that exceeds the time until I reach angle zero, then it needs to apply the opposing torque. In theory this will also prevent it from 'bouncing' around the axis too much. I almost have it working, but in some cases it seems to get stuck applying force in one direction, so I'm hoping somebody can check the logic. My simulation does NOT take mass into account at the moment, so you can ignore the Inertia Tensor (unless it makes the calculation easier!)
For one axis, I'm currently doing it this way, but I figure someone will have a far more elegant solution that can actually compute both Yaw and Pitch axes at once (Roll is invalid).
Omega = Angular Velocity in Local-Space (Degrees Per Second)
Force = Strength of the Thrusters
// Calculate Time Variables
float Angle = AcosD(DotProduct(ForwardVector, DirectionVector));
float Time1 = Abs(Angle / Omega.Z); // Time taken to reach angle 0 at current velocity
float Time2 = Abs(DeltaTime * (Omega.Z / Force); // Time it will take to reach Zero velocity based on force strength.
// Calculate Direction we need to apply the force to rotate toward the target direction. Note that if we are at perfect opposites, this will be zero!
float AngleSign = Sign(DotProduct(RightVector, DirectionVector));
float Torque.Z = 0;
if (Time1 < Time2)
{
Torque.Z = AngleSign * Force;
}
else
{
Torque.Z = AngleSign * Force * -1.0f
}
// Torque is applied to object as a change in acceleration (no mass) and modified by DeltaSeconds for frame-rate independent force.
This is far from elegant and there are definitely some sign issues. Do you folks know a better way to achieve this?
EDIT:
If anybody understands Unreal Engine's Blueprint system, this is how I'm currently prototyping it before I move it to C++
Beginning from the "Calculate Direction" line, you could instead directly compute the correction torque vector in 3D, then modify its sign if you know that the previous correction is about to overshoot:
// Calculate Direction we need to apply the force to rotate toward the target direction
Torque = CrossProduct(DirectionVector, ForwardVector)
Torque = Normalize(Torque) * Force
if (Time2 < Time1)
{
Torque = -Torque
}
But you should handle the problematic cases:
// Calculate Direction we need to apply the force to rotate toward the target direction
Torque = CrossProduct(DirectionVector, ForwardVector)
if (Angle < 0.1 degrees)
{
// Avoid divide by zero in Normalize
Torque = {0, 0, 0}
}
else
{
// Handle case of exactly opposite direction (where CrossProduct is zero)
if (Angle > 179.9 degrees)
{
Torque = {0, 0, 1}
}
Torque = Normalize(Torque) * Force
if (Time2 < Time1)
{
Torque = -Torque
}
}
Okay well what i take from the pseudocode above is that you want to start braking when the time needed to break exceeds the time left till angle 0 is reached. Have you tried to slowly start breaking (in short steps because of the constant torque) BEFORE the time to break exceeds the time till angle 0?
When you do so and your satellite is near angle 0 and the velocity very low, you can just set velocity and angle to 0 so it doesn't wobble around anymore.
Did you ever figure this out? I'm working on a similar problem in UE4. I also have a constant force. I'm rotating to a new forward vector. I've realized time can't be predicted. Take for example you're rotating on Z axis at 100 degrees/second and a reverse force in exactly .015 seconds will nail your desired rotation and velocity but the next frame takes .016 seconds to render and you've just overshot it since you aren't changing your force. I think the solution is something like cheating by manually setting the forward vector once velocity is zeroed out.
I'm trying to simulate some real jump physics with setVelocity using Box2d in Cocos2d x C++.
My commands are like:
switch (keyCode){
case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
physicsBody->setVelocity(Vec2(75, 0));
mySprite1->setPhysicsBody(physicsBody3);
break;
case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
physicsBody3->setVelocity(Vec2(-75,0));
mySprite1->setPhysicsBody(physicsBody3);
break;
case EventKeyboard::KeyCode::KEY_UP_ARROW:
physicsBody3->setVelocity(Vec2(0,200));
mySprite1->setPhysicsBody(physicsBody3);
break;
}
However, as it is clear to me, whenever i change the velocity in one axis, the other axis gets one.
The problem is: i'm unable to run and jump (the jump stops the running).
I need some way to change the velocity in only one axis at a time, so that my jump don't interfere with my run. That or another way to do tat exact same thing. I'm open to ideas regarding the physics since i'm a newbie in game programming.
You should use the ApplyLinearImpulse to get the effect that you are looking for.
// Apply linear impulse only in x-direction
physicsBody->ApplyLinearImpulse(b2Vec(75, 0), physicsBody->GetPosition(), true);
// Apply the jump impulse
physicsBody->ApplyLinearImpulse(b2Vec(0, 200), physicsBody->GetPosition(), true);
The above code will apply impulse and add to the current velocity. Which means that when you jump you will keep moving in the x-direction. This is code from one of my projects so I can confirm that it works.
I want to limit maximum speed a body can travel with.
The problem is, even if I do something like this answer suggests:
/* after applying forces from input for example */
b2Vec2 vel = body->GetLinearVelocity();
float speed = vel.Normalize();//normalizes vector and returns length
if ( speed > maxSpeed )
body->SetLinearVelocity( maxSpeed * vel );
What if, for example, right before clamping the velocity I am applying some huge force to the body?
Even if linear velocity is capped to maxSpeed for the moment, in the next timestep Box2D will take the b2Body::m_force value into account and effectively move my body faster than maxSpeed.
So I came up with this (had to move b2Body::m_force to public):
if ( speed > maxSpeed ) {
body->SetLinearVelocity( maxSpeed * vel );
body->m_force = b2Vec2(0, 0)
}
Yet this still doesn't handle the problem properly.
What if the velocity is slightly smaller than maxSpeed so the condition will not be hit, but still the m_force value will be big enough to increase velocity too much?
The point is I can't make accurate predictions as to how force will impact the velocity as I am stepping using delta accumulator and I don't know how many physics steps will be required for the moment.
Is there any way to handle this other than just to limit the velocity directly before integrating position in Box2D source code?
My first attempt to solve this problem was by simply executing above pieces of code not every loop, but every physics substep, which means that if my delta accumulator tells me I have to perform n b2World::Step's, I also cap the velocity n times:
// source code taken form above link and modified for my purposes
for (int i = 0; i < nStepsClamped; ++ i)
{
resetSmoothStates_ ();
// here I execute whole systems that apply accelerations, drag forces and limit maximum velocities
// ...
if ( speed > maxSpeed )
body->SetLinearVelocity( maxSpeed * vel );
// ...
singleStep_ (FIXED_TIMESTEP);
// NOTE I'M CLEARING FORCES EVERY SUBSTEP to avoid excessive accumulation
world_->ClearForces ();
}
Now while this gives me constant speed regardless of frame rate (which was my primary concern as my movement was jittery), it is not always <= maxSpeed. The same scenario: imagine a huge force applied just before capping the velocity and exceuting b2World::Step.
Now, I could simply calculate the actual force to be applied according to the current velocity, as I know the force will be applied only once until next validation, but there's another simple solution that I've already mentioned and eventually sticked with:
Go to Box2D\Dynamics\b2Body.h
Add float32 m_max_speed public member and initialize it with -1.f so initially we don't limit velocities for any body.
Go to Box2D\Dynamics\b2Island.cpp.
Locate line number 222.
Add following if condition:
m_positions[i].c = c;
m_positions[i].a = a;
if (b->m_max_speed >= 0.f) {
float32 speed = v.Normalize();
if (speed > b->m_max_speed)
v *= b->m_max_speed;
else v *= speed;
}
m_velocities[i].v = v;
m_velocities[i].w = w;
This will work even without substepping that I've described above but keep in mind that if you were to simulate air resistance, applying drag force every substep guarantees correctness of the simulation even with varying framerates.
First, answer for yourself, who can apply force to a body. Box2D itself can impact bodies via contacts and gravity. Contacts are not using forces, but impulses. To manage them setup contact listener and modify normalImpulses and tangentImpulses . Gravity I think cant impact body a lot, but it also can be controlled via b2BodyDef::gravityScale.
If your code aplying some manual forces, it maybe usefull to introduce some proxy interface to manage them.
I cant see some easy way, because at each step box2d makes several velocity and position iterations. So, forces and impulses applied to it at begin of step will cause change of position accordingly.
I cant imagine the way, how strict velocity without hacking box2d source code. By the way, I think it is not bad variant. For example, insert restriction in Dynamics/b2Island.cpp:219 (b2Island::Solve) to w and v variables.
I looked at a bunch of similar questions, and I cannot seem to find one that particularly answers my question. I am coding a simple 3d game, and I am trying to allow the player to pick up and move entities around my map. I essentially want to get a velocity vector that will "push" the physics object a distance from the player's eyes, wherever they are looking. Here's an example of this being done in another game (the player is holding a chair entity in front of his eyes).
To do this, I find out the player's eye angles, then get the forward vector from the angles, then calculate the velocity of the object. Here is my working code:
void Player::PickupOtherEntity( Entity& HoldingEntity )
{
QAngle eyeAngles = this->GetPlayerEyeAngles();
Vector3 vecPos = this->GetEyePosition();
Vector3 vecDir = eyeAngles.Forward();
Vector3 holdingEntPos = HoldingEntity.GetLocation();
// update object by holding it a distance away
vecPos.x += vecDir.x * DISTANCE_TO_HOLD;
vecPos.y += vecDir.y * DISTANCE_TO_HOLD;
vecPos.z += vecDir.z * DISTANCE_TO_HOLD;
Vector3 vecVel = vecPos - holdingEntPos;
vecVel = vecVel.Scale(OBJECT_SPEED_TO_MOVE);
// set the entity's velocity as to "push" it to be in front of the player's eyes
// at a distance of DISTANCE_TO_HOLD away
HoldingEntity.SetVelocity(vecVel);
}
All that is great, but I want to convert my math so that I can apply an impulse. Instead of setting a completely new velocity to the object, I want to "add" some velocity to its existing velocity. So supposing I have its current velocity, what kind of math do I need to "add" velocity? This is essentially a game physics question. Thank you!
A very simple implementation could be like this:
velocity(t+delta) = velocity(t) + delta * acceleration(t)
acceleration(t) = force(t) / mass of the object
velocity, acceleration and force are vectors. t, delta and mass scalars.
This only works reasonably well for small and equally spaced deltas. What you are essentially trying to achieve with this is a simulation of bodies using classical mechanics.
An Impulse is technically F∆t for a constant F. Here we might want to assume a∆t instead because mass is irrelevant. If you want to animate an impulse you have to decide what the change in velocity should be and how long it needs to take. It gets complicated real fast.
To be honest an impulse isn't the correct thing to do. Instead it would be preferable to set a constant pick_up_velocity (people don't tend to pick things up using an impulse), and refresh the position each time the object rises up velocity.y, until it reaches the correct level:
while(entPos.y < holdingEntPos.y)
{
entPos.y += pickupVel.y;
//some sort of short delay
}
And as for floating in front of the player's eyes, set an EyeMovementEvent of some sort that also sends the correct change in position to any entity the player is holding.
And if I missed something and that's what you are already doing, remember that when humans apply an impulse, it is generally really high acceleration for a really short time, much less than a frame. You wouldn't see it in-game anyways.
basic Newtonian/D'Alembert physics dictate:
derivate(position)=velocity
derivate(velocity)=acceleration
and also backwards:
integrate(acceleration)=velocity
integrate(velocity)=position
so for your engine you can use:
rectangle summation instead of integration (numerical solution of integral). Define time constant dt [seconds] which is the interval between updates (timer or 1/fps). So the update code (must be periodically called every dt:
vx+=ax*dt;
vy+=ay*dt;
vz+=az*dt;
x+=vx*dt;
y+=vy*dt;
z+=vz*dt;
where:
a{x,y,z} [m/s^2] is actual acceleration (in your case direction vector scaled to a=Force/mass)
v{x,y,z} [m/s] is actual velocity
x,y,z [m] is actual position
These values have to be initialized a,v to zero and x,y,z to init position
all objects/players... have their own variables
full stop is done by v=0; a=0;
driving of objects is done only by change of a
in case of collision mirror v vector by collision normal
and maybe multiply by some k<1.0 (0.95 for example) to account energy loss on impact
You can add gravity or any other force field by adding g vector:
vx+=ax*dt+gx*dt;
vy+=ay*dt+gy*dt;
vz+=az*dt+gz*dt;
also You can add friction and anything else you need
PS. the same goes for angles just use angle/omega/epsilon/I instead of x/a/v/m
to be clear by angles I mean rotation (pitch,yaw,roll) around mass center
I have recently been getting into OpenGL/SDL and playing around with objects in 2D/3D Space and as i'm sure most newbies to this area do, have a few queries, about the 'best' way to do something. I quote best, because i'm assuming there isn't a best way, it's personal preference.
So, I have an entity, a simple GL_QUAD, which I want to move around. I have keyboard events setup, i can get the keypress/release events, not a problem.
I have an entity class, which is my GL_QUAD, pseudo implementation....
class Entity
{
void SetVelocity(float x, float y);
}
I then have this event handler code...
if theEvent.Key = UPARROW AND theEvent.State = PRESSED
Entity.SetVelocity(0.0f, -1.0f);
else if theEvent.Key = UPARROW AND theEvent.State = RELEASED
Entity.SetVelocity(0.0f, 0.0f);
My question is, is this the best way to move my entity? This has led me to thinking that we could make it a little more complex, by having a method for adjusting the X/Y Velocity, seperately. As SetVelocity would forget me X velocity if i started moving left? So i could never travel diagonally.
For Example...
class Entity
{
void SetXVelocity(float x);
void SetYVelocity(float y);
}
if theEvent.Key = UPARROW AND theEvent.State = PRESSED
Entity.SetYVelocity(-1.0f);
else if theEvent.Key = UPARROW AND theEvent.State = RELEASED
Entity.SetYVelocity(0.0f);
if theEvent.Key = LEFTARROW AND theEvent.State = PRESSED
Entity.SetXVelocity(-1.0f);
else if theEvent.Key = LEFTARROW AND theEvent.State = RELEASED
Entity.SetXVelocity(0.0f);
This way, if I have an XVelocity and I then press the UPARROW, I will still have my XVelocity, as well as a new YVelocity, thus moving diagonally.
Is there a better way? Am I missing something very simple here?
I am using SDL 1.2, OpenGL, C++. Not sure if there is something in SDL/OpenGL which would help?
Thanks in advance for your answers.
The question is really general since it depends on how you want to model the movement of your objects in your world.
Usually every object has its velocity which is calculated basing on an acceleration and capped to a maximum. This means that a key press alters the acceleration of the object for the specified frame which is then calculated and applied to the current velocity of the object.
This is done through an update phase which goes through all the objects and calculates the velocity change according to the object acceleration. In this way you don't bother to modify the velocity itself but you let your engine to do its calculations depending on the state of every object..
acceleration is applied over a period of time, so in the example by #jack, you would apply an acceleration 10m/s^2 over a time period of one second.
you should also modify your application to make it time based, not frame based.
have a look at this basic game physics introduction, and I would also really have a look at the GameDev.net Physics Tutorials
I assume the way you want movement to work is that you want the player to move only when a key is held.
In short: your solution is fine.
Some potential gotchas to take consideration of: What happens if both left and right is pressed?
Well, what you describe here is a simple finite state machine. You have the different directions in which you can move (plus no movement at all) as the states, and the key-events as transitions. This can usually be implemented quite well using the state pattern, but this is often quite painful in C++ (lots of boilerplate code), and might be over the top for your scenario.
There are of course other ways to represent speed and direction of your entity, e.g. as a 2D-vector (where the length gives the speed). This would enable you to easily represent arbitrary directions and velocities.