I have a sphere and I am trying to control a cube moving around the surface of the sphere. So far everything is working perfectly, the only thing I can’t figure out is when it gets to the top and bottom of the sphere, the cube rotates left and right by itself and fights my horizontal input.
I think it has to do with how i’m calculating the surface normal. I only want to rotate the cube along the local x-axis and z-axis and I thought Lerping between the surface normal and cube normal would be an easy solution.
When the cube is moving to the right in a straight line following sphere surface. Perfect.
Now if I turn left to the top, it gets weird…
Blue line is the intended direction I have pointed the cube in, the Red line is the direction it is forcing me to go in. Almost following the lines on the sphere.
Update:
Basically what i’m trying to do is get the GameObject normal to align with the surfaceNormal from the Raycast, without rotating around the y-axis.
I’m trying to get the the red line (myNormal) to align with the green line (surfaceNormal) without causing the cube to turn left or right (rotate around the y-axis).
void MyRaycast(GameObject other)
{
RaycastHit hit;
Ray ray;
Vector3 myNormal = other.transform.up;
ray = new Ray(other.transform.position, -myNormal);
if (Physics.Raycast(ray, out hit))
{
surfaceNormal = hit.normal;
}
//lerp between cube normal and sphere surface normal
myNormal = Vector3.Lerp(myNormal, surfaceNormal, lerpSpeed*Time.deltaTime);
//find the target forward direction
Vector3 myForward = Vector3.Cross(other.transform.right, myNormal);
//get quaternion target rotation
Quaternion targetRotation = Quaternion.LookRotation(myForward, myNormal);
//rotate cube
other.transform.rotation = Quaternion.Lerp(other.transform.rotation, targetRotation, lerpSpeed*Time.deltaTime);
if(hit.distance > playerDistance)
{
//if cube is leaving sphere apply small force to keep along the surface
other.rigidbody.AddForce(-gravity * surfaceNormal);
}
}
I tried a whole bunch of different combinations of code and tried getting the angle between myNormal and surfaceNormal but I can’t get it to work right.
Am I missing something obvious? I’m kind of stuck now. Any help would be greatly appreciated as I am very new to Unity.
I’m confused about your code, so I may be missing something critical. But to move an object around a sphere, I’d make the object a child of a game object at the same position as the sphere, then I’d use Quaternion.AngleAxis() to rotate the object at the center. Here is an example script. In order to make it work, the cube must have a correct rotation to start (i.e. forward must be tangent to the sphere). Attach the script to the cube and drag and drop the sphere on the ‘sphere’ variable.
using UnityEngine;
using System.Collections;
public class BlockWalker : MonoBehaviour {
public Transform sphere;
public float turnSpeed = 45.0f;
public float moveSpeed = 45.0f;
private Transform center;
void Start () {
center = new GameObject().transform;
center.parent = sphere;
transform.parent = center;
}
void Update() {
if (Input.GetKey(KeyCode.LeftArrow)) {
transform.Rotate (0.0f, -turnSpeed * Time.deltaTime, 0.0f);
}
if (Input.GetKey(KeyCode.RightArrow)) {
transform.Rotate (0.0f, turnSpeed * Time.deltaTime, 0.0f);
}
else if (Input.GetKey (KeyCode.UpArrow)) {
Vector3 v3Axis = -Vector3.Cross (center.position - transform.position, transform.forward);
center.rotation = Quaternion.AngleAxis(moveSpeed * Time.deltaTime, v3Axis) * center.rotation;
}
else if (Input.GetKey (KeyCode.DownArrow)) {
Vector3 v3Axis = Vector3.Cross (center.position - transform.position, transform.forward);
center.rotation = Quaternion.AngleAxis(moveSpeed * Time.deltaTime, v3Axis) * center.rotation;
}
}
}