- Home /
Issue moving Object around surface of sphere
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.
It looks like you're trying to implement gravity mechanics similar to those in Super $$anonymous$$ario Galaxy:- have you searched existing posts for implementations of that? e.g.
Omg you are a genius! Never even thought of that. Thanks I'll look at the links tomorrow morning!
Could it be that hit.normal is not calculatin its values very well? Have you debugged looking at hit.normal values? Also, near to the top of the sphere there are many triangles, that could be a reason but I´m not quite sure of it.
Hi,
Have been wanting to have good scripts to do this properly for about a year or more now. $$anonymous$$ost of the scripts have been incomplete and didn't include a way to jump to another object.
Can post the final complete scripts?
Thanks in advance!
Answer by cameo24 · Dec 10, 2013 at 09:02 AM
Hi everyone, thanks for the answers and sorry for the lack of updates. I checked out the links and I noticed in this answer http://forum.unity3d.com/threads/8873-Faux-Gravity-making-my-brain-spin-Help!
It checked to see if r.freezeRotation was set
I copied some of the code and set
other.rigidbody.freezeRotation = true;
And then used:
if(hit.distance > playerDistance)
{
other.rigidbody.AddForce(-gravity * surfaceNormal);
}
Quaternion q = Quaternion.FromToRotation(myNormal, surfaceNormal);
q = q*other.transform.rotation;
other.transform.rotation = Quaternion.Slerp(other.transform.rotation, q, lerpSpeed*Time.deltaTime);
And it worked!
I was curious about the freezeRotation property so I tried that with my original code above and it worked as well!
So the only thing I was missing was this freezeRotation property of the rigidbody. http://docs.unity3d.com/Documentation/ScriptReference/Rigidbody-freezeRotation.html
I tried freezing the axis in the inspector of the cube, but that caused my cube/snake to not rotate on arrow key input.
Can post complete scripts that include jumping from object to object? Thanks in advance!
Answer by robertbu · Nov 09, 2013 at 01:59 AM
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;
}
}
}
Please see my update. I am trying to get an object to move around any surface, not just a perfect sphere so I don't want to hardcode it a certain distance away from the center of the sphere. thanks
I've see two approaches to the problem of walking on arbitrary meshes. Both have issues. The first is to move the object on its local forward, raycast the direction of the local down of the object, then realign and reposition the object with the underlying mesh. The problem with this solution is transitions. As you cross a peak, your object often loses contact with the mesh and heads off into space (drawing). The other approach is to raycast towards some center of the object. This works well for sphere-like objects, but fails for many arbitrary meshes. There are ways of mitigating both problems, but I don't know of a perfect fix. In theory, you could align your character with the nearest triangle, but Unity does not give you built-in support for this calculation.
Your answer
Follow this Question
Related Questions
Is it better to make the Player in FPS be a Rigidbody or a characterController? 1 Answer
Object Rotating around center from Mouse Movement 1 Answer
Object rotating around object at two levels 1 Answer
Rotate a spawned object whith onmousedrag and move it with onmousedown 0 Answers
Two problems One code 1 Answer