- Home /
Keep rotation when changing parent in Unity 3D
Hello, I'm trying to implement arrows. Every frame the arrow changes its rotation depending on its velocity, but when it hits something and I try to attach the arrow to the object rotation goes wrong. I'm sure that the problem occurs when changing parent and I tried everything without result. This is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Arrow : MonoBehaviour
{
private Rigidbody rb;
private bool hit;
private Quaternion startingRot;
void Start()
{
rb = GetComponent<Rigidbody>();
hit = false;
startingRot = transform.rotation;
}
void FixedUpdate()
{
if (!hit && rb.velocity.magnitude>0)
{
transform.localRotation = Quaternion.LookRotation(rb.velocity);
}
}
private void OnTriggerEnter(Collider other)
{
hit = true;
rb.constraints = RigidbodyConstraints.FreezeRotation;
transform.SetParent(other.transform, true);
rb.isKinematic = true;
rb.velocity = Vector3.zero;
}
}
Have you tried saving the arrows rotation right before parenting and then setting it back immediately after?
Yes, but it makes no difference:
private void OnTriggerEnter(Collider other)
{
startingRot = transform.rotation;
hit = true;
transform.SetParent(other.transform, true);
rb.isKinematic = true;
rb.velocity = Vector3.zero;
transform.rotation = startingRot;
}
You could try using a raycast off of the arrow and at a certain distance grab the arrows rotation and then set it back after parenting. Something like:
RaycastHit hit;
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, distanceToObject, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Collide))
{
startingRot = transform.rotation;
}
Then you could play around a bit with distanceToObject
to make it more precise. If that doesn't work could you post an image of what the arrow is actually doing? I'm kind of assu$$anonymous$$g it angles the arrow but if not an image might help.
Maybe I misunderstand your problem since the code works for me. However, first I had an unwanted effect since I forgot to set the collider to be a trigger and then the object rotated weirdly and moved away. As a trigger, it is nicely parented and stops rotating.
Answer by AndBje · Apr 13, 2021 at 09:07 PM
This was an interesting problem (the video-clip was a very good demonstration). It seems like you can't re-parent a rigid body without getting some weird behavior. I tried several things, like disable the rigid body and re-parent first in the next frame, and so on, but it still didn't work.
The only solution that works for me is to remove the rigid body before re-parenting.
Destroy(rb);
transform.SetParent(other.transform, true);
If you don't like the idea of removing behaviors in run-time you could have a second copy of the arrow, without the rigid body and simply replace the original arrow with the copy.
Good hunting!
Quite interesting indeed. Noticed in the video that the collider is doing exactly what is expected but the actual mesh is rotating so the transform.rotation doesn't actually change anything since it's separated from it's collider. I tested this with a simple drop test and got the exact same result.
Still not working with this code:
private void OnTriggerEnter(Collider other)
{
hitted = true;
//rb.constraints = RigidbodyConstraints.FreezeRotation;
//rb.isKinematic = true;
//rb.velocity = Vector3.zero;
Destroy(rb);
transform.SetParent(other.transform, true);
}
The result is: Clip I tried uncommenting those lines and I get the same result no matter what settings I tweek. Just in case, this is the code for the bow that affects the arrow: PasteBin
No matter what, thanks a lot for all the help!!
Nah it's not your code, I'm still messing around and getting nowhere, even something like this:
public class Arrow : MonoBehaviour
{
private Rigidbody rb;
RaycastHit rayHit;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
if (Physics.Raycast(transform.position, Vector3.down, out rayHit, 1f, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Collide))
{
Destroy(rb);
StartCoroutine(ParentArrow());
}
}
IEnumerator ParentArrow()
{
yield return new WaitForSeconds(1);
transform.SetParent(rayHit.transform);
}
}
will produce the same behavior. The arrow will sit in the correct position right up until it's parented. A clear view of what's going on
As you can see the collider is still where it belongs but the Mesh has moved for some strange reason and all I'm doing is dropping the object, no other code.
On a side note, I have no idea how to make my images clickable links lol. Got it =)
Your answer
Follow this Question
Related Questions
How to Prevent Rolling Cube from Climbing Up Walls 0 Answers
CONTROL RIGIDBODY MOVEMENT 2 Answers
Hockey Game collider objects going through objects 0 Answers
Rigidbody doesn't rotate after collision 3 Answers
How to prevent a thrown object from rotating but not effect the physics of its collision? 0 Answers