How can I reattach the player transform after using DetachChildren() to flip the parent?
I want my player to "ride' the moving object (which has a definite front and back) so I'm making him a child of the object with OnCollisionEnter2D. Before flipping the object, I am using DetachChildren() but need to attach him again once the object is flipped (since OnCollisionExit2D will not be called until the player leaves the object). Any suggestions would be greatly appreciated!
I have only an assumptions, that's why I write a comment ins$$anonymous$$d of an answer, but try it with FixedUpdate() or LateUpdate() ins$$anonymous$$d of Update(). That's at least what helped me sometimes when an Object had a janky movement to it, since Update() is frame-dependent it can lead to such problems.
Answer by Danao · Mar 20, 2017 at 02:32 AM
The solution was much more simple and elegant than I was originally trying to make it. All I needed to do was add a bool to check if "colliding" was true during the change of direction, if so, then use SetParent to reattach the player:
using UnityEngine;
public class: MovingObject : MonoBehaviour {
public float speed;
public float distance;
private float xStartPosition;
private Transform PlayerAttach;
private bool colliding = false;
void Start()
{
xStartPosition = transform.position.x;
}
void FixedUpdate()
{
if ((speed < 0 && transform.position.x < xStartPosition) || (speed > 0 && transform.position.x > xStartPosition + distance))
{
transform.DetachChildren();
speed *= -1;
// Multiply the object's x local scale by -1
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
transform.position = new Vector3(transform.position.x + speed * Time.deltaTime, transform.position.y, transform.position.z);
if(colliding = true)
{
PlayerAttach.SetParent(gameobject.transform);
}
void OnCollisionEnter2D(Collision2D other)
{
other.transform.SetParent(gameObject.transform);
PlayerAttach = other.transform;
colliding = true;
}
private void OnCollisionExit2D(Collision2D other)
{
colliding = false;
transform.DetachChildren();
}
}
Answer by justDeek · Mar 18, 2017 at 01:35 PM
The SmoothFollow.cs script:I tried to replicate your setting and came to the following suggestions: When the player is a child of the moving object it should be recentered (a position of (0,0,0)) so that it's previous position doesn't get affected by the flip (wich is probably what causes the erratical movement).
Other Solutions would be to set the moving object a child of the player, then the player follows the moving object but with an undampened offset. A better approach would be to unparent the moving object from the player (have them both separate) and add the SmoothFollow script from the Standard Assets to the player, wich you can enable when OnCollisionEnter and disable when OnCollisionExit.
Another problem could be that you use OnCollision instead of OnTrigger and set the Collider of either the player, the moving object or both to "is Trigger", so that they don't collide constantly, wich could also be the source of your problem.
using UnityEngine;
namespace UnityStandardAssets.Utility
{
public class SmoothFollow : MonoBehaviour
{
// The target we are following
[SerializeField]
private Transform target;
// The distance in the x-z plane to the target
[SerializeField]
private float distance = 0f;
// the height we want the camera to be above the target
[SerializeField]
private float height = 0.5f;
[SerializeField]
private float rotationDamping;
[SerializeField]
private float heightDamping;
// Use this for initialization
void Start() { }
// Update is called once per frame
void LateUpdate()
{
// Early out if we don't have a target
if (!target)
return;
// Calculate the current rotation angles
var wantedRotationAngle = target.eulerAngles.y;
var wantedHeight = target.position.y + height;
var currentRotationAngle = transform.eulerAngles.y;
var currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;
// Set the height of the camera
transform.position = new Vector3(transform.position.x ,currentHeight , transform.position.z);
// Always look at the target
transform.LookAt(target);
}
}
}
@pik$$anonymous$$36 I found the answer I needed. I appreciate your help looking into the problem and sent a reward point your way!