Hello, I’m trying to move an object (let’s say a character) on the surface of another object. I know that this subject has been dealt with in a lot of other posts, but I still couldn’t find a fully working solution.
I’ve seen different approaches and tried them all with some good results, but I can’t really be satisfied because there are still some problems and glitches.
So I’ve decided to break the whole thing into smaller tasks, hoping to find the final solution to this.
Here’s what I have so far:
void Update ()
{
// Input translation
float inputTranslation = Input.GetAxis("Vertical") * moveSpeed * Time.deltaTime;
transform.position += transform.forward * inputTranslation;
RaycastHit hit;
if (Physics.Raycast (transform.position, -transform.up, out hit, Mathf.Infinity))
{
// Stick on surface
transform.position = hit.point;
// Align to surface normal
Quaternion fro = Quaternion.FromToRotation(transform.up, hit.normal) * transform.rotation;
transform.rotation = Quaternion.Lerp(transform.rotation, fro, Time.deltaTime * 5.0f);
}
// Inpput heading rotation
float headingDeltaAngle = Input.GetAxis("Horizontal") * Time.deltaTime * headingRotSpeed;
Quaternion headingDelta = Quaternion.AngleAxis(headingDeltaAngle, transform.up);
transform.rotation = headingDelta * transform.rotation;
}
First task: placing the object (character) onto another object’s surface.
Here it looks like pretty much easy stuff: cast a ray downwards from the character, get the hit point and update the character’s position.
Also, I need the caracter to move through user input.
This kinda works, but it depends on the surface of the object: sometimes the characters get stuck and won’t move anymore; other times it will just go through the object’s mesh and pass on the other side (because the raycast gets another hit.point) or even better, it will keep travelling in the outer space…Off course this is not good: I need to find a more generic solution that will work (hopefully) with any arbitrary mesh.
So the first question is: is this a right approach to make the character stick on the object’s surface, while also allowing user input to move it? Is it right to set the position of the character to hit.point or does it conflict with the input translation?
Also, how can I add a little offset between the character’s transform and the object’s surface? I already put the pivot below the character, but I guess I also need to offset the Y position a bit.
Second task: orient the character to the surface normal
This is kinda tricky for me, my vector and quaternion math is lame (to say the least). Anyway, from what I can see and read on Unity docs, Quaternion.FromToRotation rotates the transfom from “fromDirection” to “toDirection”. In this case, it rotates the transform from it’s up direction to the direction of the hit.normal. Seems legit to me.
Then all this stuff is being interpolated with Quaternion.Lerp, going from the current object’s rotation to the desired one (according to the surface normal) in a given amount of time.
I’ve seen different examples to do this (at least 4 different ways), but this one seems to me the one which is working better. Again, it’s not perfect. Is there a way to improve it, or maybe is better to accomplish this task in a different way?
Third task: changing character’s direction with right/left arrow keys
I don’t know if this is the right approach; it seems to work fine but I’m not sure if it is causing any of the problems stated above.