Moving a rigidbody in local space with transform.TransformPoint has unexpected results.
Hey all,
This is the first time I've ever used transform.TransformPoint and I am not sure if I am using it incorrectly, but it's definitely not working as I intended.
This script should be extremely simple. All it does is take a gameObject that I have assigned in the editor, get the rigidbody component to it (which is a Kinematic rigidbody so the elevator doesn't fall), then if the elevator bool is set to rise in another script, it moves the elevator up.
I am attempting to accomplish this by calculating the position I want to move the elevator's gameObject to in local space and then using the transform.TransformPoint function to convert that to world space. Once I do, I am using MovePosition.
instead of working, when I activate the elevator, it goes crazy and flies off in a random direction before giving me a ton of errors.
NOTES: I NEED the elevator to move in its local y because I use "elevators" for other things besides rising up, such as to push blocks sideways. This is why I am not just using the world space position of the rigidbody when determing where to move it.
Here is my code.
public float riseSpeed;
public float riseDistance;
public bool rise;
public GameObject elevatorObject;
Rigidbody elevator;
private Vector3 startPosition;
//Elevators rise and take things on top of them with them.
void Start () {
startPosition = elevatorObject.transform.localPosition;
elevator = elevatorObject.GetComponent<Rigidbody>();
}
void Update()
{
//Elevator should be rising.
if(rise==true)
{
//Find elevator's current position.
Vector3 currentPos = elevatorObject.transform.localPosition;
//Add to the y
currentPos.y+=riseSpeed*Time.deltaTime;
//Make sure we haven't gone past the height limit.
if(currentPos.y >= (startPosition.y+riseDistance))
{
currentPos.y = startPosition.y+riseDistance;
}
//THIS IS THE STEP I AM CONFUSD BY. Because I want to move a rigidbody instead of the transform I need to convert to worldspace
currentPos = transform.TransformPoint(currentPos);
//Now move the elevator.
elevator.MovePosition(currentPos);
}
}
I am sure I'm doing something I'm not supposed to be here somewhere, I just don't know what it is.
Answer by OncaLupe · Nov 12, 2015 at 04:11 AM
transform.localPosition
, when used on an object without a parent, just returns the world position. It's meant to move child objects relative to its parent without needing to convert between world coordinates. TransformPoint() may work in that situation, however to just move an object along an axis is actually very easy. Each object's transform component has variables that point along each of it's local axis. transform.up
points in world space where it's local Y axis is. Multiply the distance you want to travel to that and add to the start position.
using UnityEngine;
using System.Collections;
public class MoveInLocalY : MonoBehaviour
{
public float riseSpeed;
public float riseDistance;
public bool rise;
public GameObject elevatorObject;
Rigidbody elevator;
Vector3 startPosition;
float currentRiseOffset = 0f;
void Start()
{
startPosition = elevatorObject.transform.position;
elevator = elevatorObject.GetComponent<Rigidbody>();
}
void Update()
{
if(rise)
{
//Add intended movement to current offset
currentRiseOffset += riseSpeed * Time.deltaTime;
//If we reached (or passed) the end position, set exact value
if(currentRiseOffset >= riseDistance)
{
currentRiseOffset = riseDistance;
//Turn off the bool, no need to keep trying to move once we reach the end
rise = false;
}
//Move elevator. Takes the local Y axis, multiples by currentRisePos to get total offset, then adds to startPosition.
elevator.MovePosition(startPosition + (elevatorObject.transform.up * currentRiseOffset));
}
}
}
You may notice the if() check changed slightly also. if(rise==true)
is redundant since 'rise' is a bool already. If you need to check if a bool variable is false, use if(!rise)
. !
means 'not'.
So I actually solved this a different way, by changing one line of code from:
currentPos = transform.TransformPoint(currentPos);
to
currentPos = transform.parent.TransformPoint(currentPos);
I asked a friend for help and that's what we came up with. It ended up working perfectly. I didn't get a chance to post it as a solution here until just now.
The reason why the above change works is still very confusing to me, it has something to do with trying to use its own reference point when its position is reliant on its parent as a reference point. Still, it works now and I figured I'd put that here in case someone else has the exact same issue.
Your solution does look like it would work as well, based on the information I provided, I haven't tested it but I'll accept it as an answer since you took the effort to respond and I don't see any problems with it at first glance.