In short - Moving a rigidbody by ForceMode.Impulse behaves inconsistently between two objects: one snaps to a new vector3, other (with a navmeshAgent) gets an impulse and then jitters (this is in a non-kinematic case use). Each needs different amounts of force to move roughly the same distance.
Now to the Long version:
I’m working on a direction based ‘GetHit’ method, that moves the object (player or enemy) to a different location. The enemy is moved by a navMeshAgent, and the player by an input based script (a pretty standard rb mover script). Anyway, both classes have the same type of Get Hit function, that in the enemy’s case looks like this:
public void GetHit(HitPoint hitPoint)
{
//disables the navMeshAgent for a certain amount of time - this doesn't work actually
agent.enabled = false;
//calls a method that calculates the hit direction
MoveByHitDirection(hitPoint);
//starts a timer for the duration of the agent being disabled, timer ticks down in update as long as it's above 0
hitTimer = hitCooldown;
if(hitTimer >= 0)
{
//re-enables the agent.
agent.enabled = true;
}
}
//Gets called after calculating the direction of the hit
private void MoveRigidboyByImpulse(Vector3 direction)
{
//moves the rb away from that direction, multiplying the direction with the value of hitForce
rb.AddRelativeForce(direction * hitForce.Value, ForceMode.Impulse);
}
In this scenario, the enemy gets recoiled nicely, but then he keeps on colliding with the player and gets “pushed back”, and it seems like the impulse is conflicting with the NavMeshAgent - it isn’t able to move towards it’s target anymore. The NavMeshAgent never actually gets disabled.
The Players case is much simpler, since no agent needs to be disabled. It simply receives an impulse from the direction of the hit.
private void MoveRigidboyByImpulse(Vector3 direction)
{
//called from a hit direction calculator
//moves the rb towards that direction
rb.AddRelativeForce(direction * moveForce.Value, ForceMode.Impulse);
}
The results of this, is that the player barely moves. When it does (when hitForce.value is really high), it snaps into the new vector. When the player’s attacking, the same MoveRigidboyByImpulse method is being called, and if the player is jumping (i.e not grounded) - the .impulse is added like an actual inpulse, instead of like a snap function. I’m guessing it has something to do with the angular drag (which is 0.05)?
On both objects, the rb has x and z rotation constraints, uses gravity, and isKinematic is set to false. If I set isKinematic inside the enemy’s method for the duration of GetHit, it won’t move at all (even if it’s arranged so that it’s set to false before receiving the impulse). GetHit() is called by a collision that’s based on an attack animation event. the player and the enemy have both a collider on them, and child objects with colliders that register the hit themselves, and they send the information about where the hit took place.
What am I missing here, and what else should I do?
Thanks for reading, this was long!