- Home /
How to move an object relative to another moving object?
Hi, I am making a sign that moves up and down above a player's head while the player is in a zone that pops the sign over their head. My problem is that every time I try to get the sign to move in its local space, it keeps returning to the same position that I have specified in my Update() function - which is an offset from the player's current position. What should I change/use in my code to make this happen?
Ok, I finally got it figured out. It feels like there has to be some better way to do this with Unity, but this is the only working way I figured out to get a sign bouncing over the player's head as they moved around inside a zone.
This is the full source in case anyone else wants to figure out how to do something similar.
using UnityEngine;
using System.Collections;
public class TriggerForest : MonoBehaviour {
//private variables
private bool playerInBounds;
private bool bCreated;
private GameObject signObj; //displays the text
private GameObject floatTextObj; //displays instructions to interact
private static float initDuration = 0.8f; //controls duration that sign moves in a direction until switching
private static float duration = initDuration;
private static float speed = 0.5f; //controls speed that sign moves
private Vector3 move = new Vector3(0.0f, 0.0f, 0.5f); //controls direction that sign moves in
private bool bDone = false;
//public variables
public GameObject player;
public GameObject playerPosition; //always center on the player
public GameObject forestSign;
public GameObject floatText;
public Vector3 signOffset = new Vector3(0.0f, 0.5f, 3.0f); //set the default offset for displaying sign above player
public Vector3 fTextOffset = new Vector3(0.0f, 0.5f, -1.5f);
// Use this for initialization
void Start () {
}
//check if player is insider trigger
void OnTriggerEnter(Collider other) {
if (other.gameObject.tag == "Player") {
playerInBounds = true;
//Debug.Log(playerInBounds); //test
Debug.Log ("Entering forest.");
}
}
void OnTriggerExit(Collider other) {
if (other.gameObject.tag == "Player") {
playerInBounds = false;
//Destroy (other.gameObject); //test
Debug.Log ("Leaving forest.");
}
}
// Update is called once per frame
void Update () {
//alternative way to reference player
//var player = GameObject.FindWithTag("Player");
if (playerInBounds) {
//check if user pressed the key to enter level (using e for now)
//GetKeyDown occurs only once per press, compared to GetKey which continues to occur as long as button is pressed
if(Input.GetKeyDown(KeyCode.E)) {
//reference documentation for the line below: http://docs.unity3d.com/ScriptReference/Application.LoadLevel.html
//switch the scene to forest level
Application.LoadLevel("testSceneLoad");
}
//ensures we do not continue making objects; also init run once things for sign here
if(!bCreated) {
//create objects from prefabs
signObj = (GameObject) Instantiate(forestSign, transform.position, transform.rotation);
floatTextObj = (GameObject) Instantiate(floatText, transform.position, transform.rotation);
//set the intial position of sign
signObj.transform.position = player.transform.position + signOffset;
//parent the sign to the player's position; this updates its position automatically
signObj.transform.parent = playerPosition.transform;
bCreated = true;
}
/* THE SIGN */
//update position of sign
//moves sign down
if(!bDone) {
if(duration > 0.0f) {
signObj.transform.Translate(move * speed * Time.deltaTime, Space.Self);
duration -= Time.deltaTime;
if(duration <= 0.001f) {
duration = initDuration;
bDone = true;
}
}
}
//moves sign up
if(bDone) {
if(duration > 0.0f) {
signObj.transform.Translate(-move * speed * Time.deltaTime, Space.Self);
duration -= Time.deltaTime;
if(duration <= 0.001f) {
duration = initDuration;
bDone = false;
}
}
}
//update rotation of sign
var newRot = transform.rotation.eulerAngles;
newRot.x = 0.0f; newRot.y = 180.0f; newRot.z = 0.0f;
signObj.transform.rotation = Quaternion.Euler(newRot); //this sits the sign upright
/* THE FLOATING TEXT */
//update position of floating text
floatTextObj.transform.position = player.transform.position + fTextOffset;
//update rotation of floating text
var newRot2 = transform.rotation.eulerAngles;
newRot2.x = 90.0f; newRot2.y = 0.0f; newRot2.z = 0.0f;
floatTextObj.transform.rotation = Quaternion.Euler(newRot2); //this sits the text upright
}
else {
Destroy(signObj);
Destroy (floatTextObj);
bCreated = false;
}
}
}
Is there a reason your not just parenting it to your player?
Answer by jkpenner · Oct 13, 2014 at 04:11 AM
So for moving an object relative to another object, one of the best ways of doing that would be to parent it to the object you want it to move relative to. Then to animate or to move it around relative to that object you would adjust the localPosition of the child object. I modified a bit of your code to reflect some of these ideas. (Note: I haven't tested any of this in Unity.)
if(!bCreated) {
signObj = (GameObject) Instantiate(forestSign, transform.position, transform.rotation);
signObj.transform.parent = player.transform; // Parent the signObj to the player
signObj.transform.localPosition = Vector3.up * textOffset; // Set the local position of the signObj
bCreated = true;
}
// Updates the signObj's position
signObj.transform.localPosition = Vector3.up * textOffset;
//update rotation of sign
var newRot = transform.rotation.eulerAngles;
newRot.x = 0.0f; newRot.y = 180.0f; newRot.z = 0.0f;
signObj.transform.rotation = Quaternion.Euler(newRot); //this sits the sign upright
// Update the textOffset to move the signObj up and down
textOffset += moveSpeed * moveDirection * Time.deltaTime;
// Restrict the textOffset between the maxHeight and minHeight
// and reverse the direction it moves
if(textOffset > maxHeight) {
textOffset = maxHeight;
moveDirection *= -1;
} else if (textOffset < minHeight) {
textOffset = minHeight;
moveDirection *= -1;
}
Answer by jheard901 · Oct 13, 2014 at 08:35 PM
Using "signObj.transform.localPosition = Vector3.up * textOffset;" after I have parented the object to the player centers the sign on the player and its position doesn't change from the player's current position. I nearly have it working now though.
So I parented the sign to the player and then I move it in local space which almost does exactly what I am looking to make it do. However, the sign rotates whenever the player rotates, instead of keeping the same position overhead. Is there a way to parent an object to just the position of another object?
I think you could do this by using a dummy object. Assign both the sign & the player to the dummy object. Set transforms on the dummy object, but rotation to the player.