问题
i have a question about a body, which follows a specific path. First of all here the method to move the body to a target point:
const float destinationControl = 0.3f;
b2Vec2 targetPosition = path[counter];
b2Vec2 missilePosition = _physicalBody->GetPosition();
b2Vec2 diff = targetPosition - missilePosition;
float dist = diff.Length();
if (dist > 0)
{
if(dist < destinationControl){
++counter;
return;
}
// compute the aiming direction
b2Vec2 direction = b2Vec2(diff.x / dist, diff.y / dist);
// get the current missile velocity because we will apply a force to compensate this.
b2Vec2 currentVelocity = _physicalBody->GetLinearVelocity();
// the missile ideal velocity is the direction to the target multiplied by the max speed
b2Vec2 desireVelocity = b2Vec2(direction.x * maxSpeed, direction.y * maxSpeed);
// compensate the current missile velocity by the desired velocity, based on the control factor
b2Vec2 finalVelocity = control * (desireVelocity - currentVelocity);
// transform our velocity into an impulse (get rid of the time and mass factor)
float temp = (_physicalBody->GetMass() / normalDelta);
b2Vec2 finalForce = b2Vec2(finalVelocity.x * temp, finalVelocity.y * temp);
_physicalBody->ApplyForce(finalForce, _physicalBody->GetWorldCenter());
}
The array path
represent as the name implies a specific path which the body follow when the user trigger a touch event.
My problem is that the variable maxSpeed is not constant. So when the path is very short and the maxSpeed
is very high the body moves over the current target point. With my method above the body return to the current target point and does not focus the next point.
At the moment i have a constant destinationControl
which controls if the distance between the body and the current target point is short enough to focus the next target point.
The focus is to increase a counter which represent the index of the target points.
So my final question is: Can you imagine another possible solution, because mine is not very safe. Is there a way to figure out if the body moves over the current target point?
thank you in advance and sorry for my bad english.
回答1:
I had a similar problem in a path following demonstration I was putting together(here is the project and here is the just the video).
I found the most workable solution was to use a combination of 2 functions. The first detects if the entity is "close" to the next point they want to get to.
bool MovingEntity::IsNearTarget()
{
Vec2 toTarget = GetTargetPos() - GetBody()->GetPosition();
if(toTarget.LengthSquared() < GetMinSeekDistanceSquared())
{
return true;
}
return false;
}
This entity is using a "seek" operation to move from point to point. If it is close to the point, the function returns true. It uses the square of the distance to avoid square roots for length.
The second function is the path following function executed every update:
void MovingEntity::ExecuteNavigateToPoint()
{
vector<Vec2>& path = GetPath();
bool isNearTarget = IsNearTarget();
bool isNearNavTarget = IsNearTarget(_navigatePos,5.0);
/* If the state tick timer expires, it means we
* have spent too long trying to reach the next waypoint
* and we need to replan on how to get to it.
*/
if(IsStateTickTimerExpired())
{
CCLOG("Tick Timer Expired!!!");
ChangeState(ST_NAVIGATE_TO_POINT);
}
/* If we are close to the navigation target point,
* just seek to it.
*/
if(isNearNavTarget || path.size() == 0)
{ // Must be really close...just seek to it.
CommandSeek(_navigatePos);
}
else if(!IsNodePassable(GetTargetPos(),false))
{
ChangeState(ST_NAVIGATE_TO_POINT);
}
else
{ // If we are near the target and there are more points
// on the list, pop the next point and navigate to it.
if(isNearTarget && path.size() > 0)
{ // Still more points on the list.
GetTargetPos() = path.back();
path.pop_back();
ResetStateTickTimer(2*TICKS_PER_SECOND);
/* If we can't get past the current nodes, replan.
*/
if(path.size() > 0 && !IsNodePassable(path.back(),false))
{
ChangeState(ST_NAVIGATE_TO_POINT);
}
}
ApplyThrust();
ApplyTurnTorque();
}
}
This one is a bit harrier, but what it comes down to is checking for whether the entity has reached the final target (_navigatePos), reached the next path point, or unable to approach the target point for some reason, so it times out and replans the path to it.
This is part of a simulation of a ship flying through a moving asteroid field, so the scenery was changing and the ship could get "stuck" in certain situations, so it had to replan every now and then.
The code base for this is located on github.
Was this helpful?
回答2:
What I think you might want to do is to compare your maxSpeed to the distance possible to move. When moving farther than the distance available, set the misslePosition to the targetPosition and retrieve the next target position in the path, and subtract the distance already moved from maxSpeed.
if (maxSpeed > dist)
{
maxSpeed -= dist;
misslePosition = targetPosition;
targetPosition = path[counter + 1];
}
Another possible solution would be to make smaller steps and perform a loop while totalDistanceCovered < maxSpeed, this might be a little easier to capture more edge cases, although more CPU time is used.
const float stepDistance(0.1f); //Some relatively small value depending on your units.
float totalDistance(0.0f);
while (totalDistance < maxSpeed)
{
totalDistance += stepDistance;
//Perform the same movement logic you already have.
}
--- My original answer below ---
You may need to set the definition of the _physicalBody to be a bullet if you are attempting to collide with a dynamic target.
By default, Box2D uses continuous collision detection (CCD) to prevent dynamic bodies from tunneling through static bodies. This is done by sweeping shapes from their old position to their new positions. The engine looks for new collisions during the sweep and computes the time of impact (TOI) for these collisions. Bodies are moved to their first TOI and then halted for the remainder of the time step.
Normally CCD is not used between dynamic bodies. This is done to keep performance reasonable. In some game scenarios you need dynamic bodies to use CCD. For example, you may want to shoot a high speed bullet at a stack of dynamic bricks. Without CCD, the bullet might tunnel through the bricks.
From box2d.org/manual
来源:https://stackoverflow.com/questions/23157562/ios-box2d-body-follows-a-specific-path-based-on-an-array-of-points-with-fluctu