- Home /
Using collision with Vector3.MoveTowards
I have a simple top-down control scheme that checks whenever the left mouse button is pressed, and then uses Vector3.MoveTowards to move the player to that location. However, I cannot get collision to work with this method - in other words, the player walks straight through everything.
I tried scripting it with OnCollisionEnter, making the player stop and move slightly outside the object he collides with, every time he collides with something - but it doesn't seem to detect the collision whatsoever, despite both objects having colliders. What am I doing wrong?
Have you tried using a custom function that manipulates the object a tiny bit every tick while detecting collision? It's not that complicated and should do the same exact thing that you want.
I tried that, but the collision detection didn't seem to work at all, neither with colliders nor triggers - not sure why...
Answer by aldonaletto · Dec 25, 2012 at 04:07 AM
Simple objects aren't constrained by collisions, only CharacterControllers or Rigidbodies. Since Rigidbodies are too complicate to control, you should add a CharacterController to the object and move it with Move or SimpleMove.
If your current code is something like this:
transform.position = Vector3.MoveTowards(transform.position, targetPos, speed * Time.deltaTime);
you can convert it to use a CharacterController with a code like this:
// find the target position relative to the player:
var dir: Vector3 = targetPos - transform.position;
// calculate movement at the desired speed:
var movement: Vector3 = dir.normalized * speed * Time.deltaTime;
// limit movement to never pass the target position:
if (movement.magnitude > dir.magnitude) movement = dir;
// move the character:
GetComponent(CharacterController).Move(movement);
The CharacterController is constrained by collisions. If there's an obstacle between it and targetPos, this code will make the CharacterController slip along the obstacle looking for the smaller distance to the targetPos, what may make it avoid round or inclined obstacles - but an obstacle big enough or perpendicular enough to the trajectory can stop it.
NOTE: The CharacterController is a special capsule collider aligned to the Y axis. You can reduce its height to make it spherical, but there's no way to transform it in a cubic collider, nor rotate it to become horizontal. This restriction may complicate using it in cars, boats or other objects that can't fit reasonably into a capsule or sphere.
Thank you! This works almost perfectly - I have one last issue though. I want the player object to stick to the terrain beneath it while moving, but I'm not sure how to do this. Any ideas? I'm using ScreenToWorldPoint(Input.mousePosition) to detect the target position.
Update: I have partly solved the problem with these code segments:
height = Terrain.activeTerrain.SampleHeight(transform.position) + Terrain.activeTerrain.transform.position.y;
Vector3 dir = new Vector3 (targetPosition.x, height, targetPosition.z) - transform.position;
transform.position = new Vector3(transform.position.x, height, transform.position.z);
The last one being run at the very end.
However, this causes the player to stutter a bit - is there a more elegant solution than this?
The code above tried to imitate Vector3.$$anonymous$$oveTowards. If you just want the player to go to some target position while being affected by gravity, things may become simpler:
// find the target position relative to the player:
var dir: Vector3 = targetPos - transform.position;
// ignore any height difference:
dir.y = 0;
// calculate velocity limited to the desired speed:
var velocity: Vector3 = Vector3.Clamp$$anonymous$$agnitude(dir * speed, speed);
// move the character including gravity:
GetComponent(CharacterController).Simple$$anonymous$$ove(velocity);
Simple$$anonymous$$ove takes care of the gravity, and we must pass to it the velocity vector (Y component is ignored). The velocity is clamped to the speed value, and falls gradually to zero when the character gets too close to the target point.
Answer by Jamster · Dec 25, 2012 at 05:17 PM
I had this problem last week, for me it was a case of moving too fast so it was being moved to the other side of the wall and effectively "going through" the wall. I think it'll work if you use a slower speed to move the object or if you use Quaternion.LookRotation(x-y) and add a force to the rigidbody on it.
As a side note, I gave up on the game because I couldn't get useful data out of the mouse position (using Camera.ScreenToWorldPoint) so I would be really gratefull if you could give me some code for that bit :)
To get the mouse position code to work correctly, I've created a new camera for that purpose being entirely top-down and orthographic (Culling mask set to nothing) - then parented it to follow the other camera and positioned it so that the player's in the middle. I've used that camera for ScreenToWorldPoint, and it tracks the position correctly.
Answer by gameanax.com · Dec 25, 2012 at 05:16 PM
If you want a simple solution than use a rigidBody on the player... Colliders will never detect collision without a rigidbody or a Character Controller
The other method is by using CharacterController but you have to use OnControllerColliderHit() function to detect collision...
Gud Luck...
Your answer
Follow this Question
Related Questions
Change Direction on Collision 6 Answers
get angular velocity change from collision 0 Answers
Collision with no contact? 2 Answers
Unparent object on collision? 3 Answers
onCollisionEnter function called from another object. 1 Answer