What is the best way to move KinematicBody towards a target with collisions ?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By VirgilusGalacticus

Hi,
I’ve been searching for a good way to move my npc (it’s a fish) to a position Vector3() with collisions detection.

First, I tried to use Tween :

public Vector3 Destination;
public float Time = 5.0f;


tween = GetNode<Tween>("Tween");
	
tween.InterpolateProperty(this,"translation",Translation,Destination,Time);

This solution was very accurate and easy to use but collision detection doesn’t work: my fish pass through the ground, and IsOnWall() function return nothing.

The second solution was with MoveAndSlide():

public override void _PhysicsProcess(float delta)
{
	Vector3 velocityAngle = Destination-Translation;
    Vector3 movement = MoveAndSlide(velocityAngle.Normalized()*speed);
}

It was a good solution, I’ve got my collisions but I don’t really know how to stop the movement precisely except with:

 if(Translation.DistanceTo(Destination)<0.1f){
  }

And lastely, I tried with LinearInterpolate() function:

Translation = _beginPosition.LinearInterpolate(Destination,_currentTranslationTime/Time);

The result was the same as with Tween.

I think I missed something, I thought it was an easy thing to move object linearly between two positions.

Thanks for your help.

Hi,
If you modify position directly (with linear interpolation or twin) you wont get colision stop the movement. You’ll have to implement your own mechanism. I think MoveAndSlide is the way to go. If you want to instead stop on any collision withous sliding, you could use MoveAndCollide instead.

Note that in your code you assigned the return value of MoveAndSlide to a Vector3 called “movement”. But the result from that function is the linear velocity vector. I think it should be more like:

public override void _PhysicsProcess(float delta)
{
    Vector3 velocity = (Destination-Translation).normalized()*speed;
    velocity = MoveAndSlide(velocity);
}

It wont affect to the code you have right now, because you are updating the velocity before move and slide and not doing anything after move and slide. But that way you can check the resultant velocity for other calculations afterwards. You could even check if the velocity changed, that means a collision was present.

p7f | 2020-07-24 18:22

Hi,
Thanks for your advice. I changed my code to use MoveAndSlide like you say:

public override void _PhysicsProcess(float delta)
{
	if(isMoving) 
     {
		Vector3 velocity = (Destination-Translation).Normalized()*Speed;
		velocity = MoveAndSlide(velocity);
		if(Translation.DistanceTo(Destination)<=0.05f){
			isMoving=false;
			Translation = Destination;
			SetDestinationRoutine();

		}
	}
    if(IsOnWall()) SetDestinationRoutine();
	
}

I use IsOnWall() to know when my character collide with floor, and it seems to work perfectly.
There is another issue with Translation.DistanceTo(destination)<=minDistancewhen I increase the speed: my character goes to fast, pass the destination point, try to go back to destination point, and oscilate between two positions.
The solution was to increase the minDistance value.
Is there a better solution (more accurate) to stop my character at a position with MoveAndSlide? Thanks.

VirgilusGalacticus | 2020-07-25 11:57