- Home /
Parent/Player teleports but its children dont teleport aswell
Recently I started attempting to make a teleporting mechanic which creates a red and blue portal if Q or E is pressed.
When the player enters this portal he gets teleported to the other portal as expected. However when the Player teleports, its children/attached objects don't teleport aswell. I'm sure there is a simple solution like adding an if statement to an Update function that constantly repositions the children but I am unable to figure it out fully. If anybody has any suggestions I'd greatly appreciate it!
The code that teleports the character is as follows:
(This code is attached to each portal)
(collision = The Player/Parent Object)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class telePortal : MonoBehaviour {
private Transform destination;
public bool isOrange;
private void Start()
{
if (!isOrange)
{
destination = GameObject.FindGameObjectWithTag("OrangePortal").GetComponent<Transform>();
}
else
{
destination = GameObject.FindGameObjectWithTag("BluePortal").GetComponent<Transform>();
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (Vector2.Distance(transform.position, collision.transform.position) > 0.5f)
{
collision.transform.position = new Vector2(destination.position.x, destination.position.y);
}
}
}
What you describe is weird, the children of a transform are always moved together when the parent transform moves, this is very fundamental to Unity. So the only thing I can think of is that the children do get teleported to the other side, but maybe then they "touch" the portal on the other side, and are teleported back, disrupting the positions... but this is just a hunch. You can check if this is what happens if you can see the children as children in the Hierarchy move, and if your character moves, they also moves, but displaced.
If this is the case, a solution would be to only ever move teleport by using the topmost parent object, children always notifying this root when any touches a portal. You can probably do this with GetComponentInParent<>()
call. Also make sure that the parent only accepts one teleport request at a time.
Answer by Captain_Pineapple · Jun 21, 2018 at 10:01 AM
Hey there,
if i understand your setup correctly you can not guarantee that the collider that hits the portals collider is your player-parent-objects collider.
So it might be good to check if the object that hits your portal is actually the one you are expecting. Something like Debug.Log("Transform entering Portal: " + collision.transform.name);
If this actually is a problem you might be able to fix it by changing your code to:
collision.root.transform.position = new Vector2(destination.position.x, destination.position.y);
though this will only work if your player object is actually the root of the moving player.
Hey Captain_Pineapple, Its is true that I cannot guarantee that the collider that hits the portal collider is my player parent objects collider through code unless using tags. However upon colliding with the teleporter, the player is visibly teleported, the sprite of the player is placed on the parent therefore I assume that its children would follow as its evident that the parent collider collided. I cannot use tags as I want to have any other rigidbody2d objects to teleport similarly as well when colliding with the teleporter.
I'm sorry if i'm unclear or suggest nonsensical points, I'm extremely new to c# but I greatly appreciate the reply so soon.
Can you edit your OP and include the hierarchie of your player object including colliders?
Answer by aardappel156 · Jun 21, 2018 at 10:03 AM
Maybe an alternative would be destroying and Instantiate your gameobject
public class telePortal : MonoBehaviour
{
private Transform destination;
public bool isOrange;
public GameObject Thingyouwanttoteleport;
private void Start()
{
if (!isOrange)
{
destination = GameObject.FindGameObjectWithTag("OrangePortal").GetComponent<Transform>();
}
else
{
destination = GameObject.FindGameObjectWithTag("BluePortal").GetComponent<Transform>();
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (Vector2.Distance(transform.position, collision.transform.position) > 0.5f)
{
Destroy(collision.gameObject);
Instantiate(Thingyouwanttoteleport, destination.transform.position , Quaternion.identity);
}
}
}
Something like this? This could work as long as there isn't any important data in the said Game object. If there is you could store the data on something else.
Hey aardappel156, This method would only work for the player however as Id have to supply the Thingyouwanttoteleport gameObject with the player/parent game object. Also I believe the same issue would exist as the children wouldn't know where to go after the parent is re instantiated. Sorry if i'm incorrect or unclear, i'm extremely knew to unity and c#. Thank you for your quick reply.
This should work if the prefab does have the children in it. But I never destroyed a game object and Instantiate the same object so you might be right.
Answer by RetroGeek46 · Jun 21, 2018 at 10:09 AM
Your script is checking not checking if the collision is happening with parent or child object. It could be that a child object (if you have sprite as a child of the player gameobject) is the one colliding. I'd suggest adding a "Player" tag to the player and check collision based on that.
On the parent object, change tag to Player, then use this code inside onTriggerEnter2D
private void OnTriggerEnter2D(Collider2D collision) {
if (collison.gameobject.tag == "Player") {
collision.transform.position = new Vector2(destination.position.x, destination.position.y);
}
}
Hey RetroGeek46, The sprite of the player is on the parent therefore meaning the parent is the one who collides with the portal as I get visual confirmation by seeing him teleport and also I'm aware tags work but want this to work for any rigidbody2d that collides with the portal. This solution is probably the cleanest way though. Thank you for the quick reply as well.
$$anonymous$$ake an empty gameobject a child of all the things you want teleportable. Add a collider with trigger enabled
Then, just tag that object as "teleportable" and check in portal script. This will also enable you to easily set the boundary around the object.
In the movement line, change it to collision.transform.parent.transform so that you move the parent and not just the collider.
Answer by Aaron9699 · Jun 22, 2018 at 07:02 AM
One method that works but I feel isn't the best solution is that I found a way of storing the local position of the players children to its parent in a Start() function and constantly making sure that the children stay there by using an Update() that's on the player.
public Vector3 child1;
public Vector3 child2;
private void Start()
{
ledgeDetector = gameObject.GetComponent<BoxCollider2D>();
coinSound = Resources.Load<AudioClip>("CoinPickupSound");
myrigidbody2D = this.GetComponent<Rigidbody2D>();
anim = gameObject.GetComponent<Animator>();
gravityStore = myrigidbody2D.gravityScale;
child1 = this.transform.GetChild(0).transform.position - this.transform.position;
//Local position to parents
child2 = this.transform.GetChild(1).transform.position - this.transform.position;
}
void Update()
{
if (facingRight)
{
this.transform.GetChild(0).transform.position = this.transform.position + child1;
this.transform.GetChild(1).transform.position = this.transform.position + child2;
}
else if(!facingRight)
{
this.transform.GetChild(0).transform.position = new Vector3(this.transform.position.x - child1.x, this.transform.position.y + child1.y, child1.z);
this.transform.GetChild(1).transform.position = new Vector3(this.transform.position.x - child2.x, this.transform.position.y + child2.y, child2.z);
}
This solution makes everything work perfectly yet I feel like this is not the intended way or most efficient way.
As i commented above it'd be nice if you could provide the hierarchy setup of your player so that we can see the relation between your playerscript/object and the colliders.