Freezing Rotation and Joints (Swing / Rope) Physics Issues

Hey there, thank you for dropping by my question.
Are you in need of freezing a rotation, this code might work:

using UnityEngine;
using System.Collections;

public class DenyRotation : MonoBehaviour {

    Quaternion origRotation;
    Transform mTransform;

	void Awake () {
        mTransform = transform;
        origRotation = mTransform.rotation;
    }
	
	void LateUpdate () {
        mTransform.rotation = origRotation;
    }
}

However, for me it didn’t.
I’m stuck with a bit trickier problem.

This problem happened during the creation of a RopeSwing. Freezing the Z rotation makes sure my player stays upstraight, but it influences the swing physic.
Unfreezing it makes the player go ham.
Hardcoding it with the code above makes the player go even more ham.

The issue is explained below with Images!
[32153-main+issue.png|32153]

Well, if Freezing Z is the devil, why not turn it off? Well:[32154-main+issue+part+2.png|32154]

The hierarchy is shown in the picture above, in case the idea wasn’t clear yet. :slight_smile:
Also, yes there are grammar faults, no I didn’t want to repaint them for this post when I found out, my apologies.

My Question is:
How can I Freeze the Rotation of PhotonPlayer without it influencing the Swing Physics?

Alternatively:
How can I Freeze the Rotation of PhotonPlayer’s Childs or Set them to be the inverted delta of their parent rotation, to give the illusion they’re not rotating

Note, I’ve tried the following code already for the alternative option, which doesn’t seem to work :confused:

using UnityEngine;
using System.Collections;

public class DenyRotation : MonoBehaviour {

    Quaternion origRotation, origRotationParent;
    Transform mTransform, mParentTransform;

	void Awake () {
        mTransform = transform;
        mParentTransform = transform.parent;
        origRotation = transform.rotation;
        origRotationParent = transform.parent.rotation;
    }
	
	void LateUpdate () {
        mTransform.rotation = Quaternion.Euler(
            origRotation.eulerAngles.x - origRotationParent.eulerAngles.x + mParentTransform.rotation.eulerAngles.x,
            origRotation.eulerAngles.y - origRotationParent.eulerAngles.y + mParentTransform.rotation.eulerAngles.y,
            origRotation.eulerAngles.z - origRotationParent.eulerAngles.z + mParentTransform.rotation.eulerAngles.z);
    }
}

If you have any ideas, I would really really appreciate it :slight_smile:
Fire away! <3

CONCLUSIONAL EDIT:

The feature hasn’t been entirely resolved, however, the rotation inversion wasn’t all that hard.
For those out there seeking specific similar answers, here’s the updated code for the rotation inversion.

using UnityEngine;
using System.Collections;

public class DenyRotation : MonoBehaviour {

// Private variables for the transforms (Why? Normally .transform acts as a GetComponent, ieuw!!)
Transform m_Transform, m_ParentTransform;

void Awake () 
{
    // Store the transforms in our private variables
    m_Transform = transform;
    m_ParentTransform = transform.parent;
}

void LateUpdate() 
{
    // Apply inverse rotation of the parent
    m_Transform.localRotation = Quaternion.Inverse(m_ParentTransform.localRotation);
}

That code will work just fine for the rotation inversion, note that you’ll need to seperate the parent object and it’s childs by a single object in between which holds the DenyRotation script, that way you only have to apply this script once.

In the end, the grapple system worked quite well aside from the fact that there wasn’t any pulling up towards the grapple point. Many such as myself believe that having a pull towards the grapple point will allow for more flexibilty and increasal of speed with well timed grapples, which is kind of what we wanted.

My most accurate guess, along with the well written answer by scribe below would be to use the anchor system correctly instead of the current Hinge and fixed joint system that I have now.
I had some tryouts with the anchor system which actually worked quite well too, but I didn’t come to find how to implement this with a configurable joint before I had to get back to my multiplayer networking duties for my internship.

In the end the grapple system was scrapped in order to restore a more balanced movement system.
Even though I will miss it, I’m sure you can pull off making a proper grapple system if you Really know what you’re doing with Anchors.

If time allows me to, I’ll make a tutorial in the future.

For now I’ll honor scribe’s attempt at solving my issue by accepting his answer, because surely for others in some cases his solution should have perfect outcomes. :slight_smile:

Thank you very much for reading, I hope this article will help you with your own programming journeys. :slight_smile:

Hey there!

So here is some code, and below I will try to run through it briefly, though it is not particularly difficult to understand and if you are doing a coding internship it should look pretty simple!

public Transform hingeObj;
HingeJoint hinge;
float hingeLength = 0f;
public float transitionLength = 1f;
float transitionStartTime = 0f;
Rigidbody rb;

void Start(){
	if(GetComponent<Rigidbody>()){
		rb = GetComponent<Rigidbody>();
	}else{
		rb = gameObject.AddComponent<Rigidbody>();
	}
	rb.isKinematic = false;
	rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationZ;
}

void Update(){
	if(Input.GetKeyDown(KeyCode.Z)){
		hinge = gameObject.AddComponent<HingeJoint>();
		hinge.anchor = transform.InverseTransformPoint(hingeObj.position);
		hingeLength = hinge.anchor.magnitude;
		hinge.axis = transform.InverseTransformDirection(Vector3.forward);
		hinge.autoConfigureConnectedAnchor = false;
		transitionStartTime = Time.time;
	}
	if(Input.GetKeyUp(KeyCode.Z)){
		Destroy(hinge);
		transitionStartTime = Time.time;
	}
}
void FixedUpdate(){
	rb.AddForce(new Vector3(Input.GetAxis("Horizontal")*10f, 0, 0));
	if(hinge){
		hinge.anchor = transform.InverseTransformPoint(transform.position-(transform.position-hingeObj.position).normalized*hingeLength);
		transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.forward, hingeObj.position - transform.position), (Time.time-transitionStartTime)/transitionLength);
	}else{
		transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Vector3.forward), (Time.time - transitionStartTime)/transitionLength);
	}
}

So this code would be attached to your uppermost (hierarchy-wise) component of your player.

The start function simply makes sure you have a rigidbody attached and sets kinematic to false and makes sure your rotations are properly constrained!

You will need to change around update as at the moment I have it set-up to simply attach a hinge joint when I press Z which would obviously be strange behaviour in your game, but it looks like you have already sorted how you choose your grapple point.

So once you have your grapple point set up the rest of the Update function should run similarly to attach a hinge joint with correct setting on z down, and destroy the joint on z up.

Then Fixed Update:

the first line was simply for my testing purposes to enable me to move my object.

Then the if statement checks if there is a hinge at that point in time, if there is then we have to make sure we keep recalculating our relative anchor point to stop errors over time adding up and making our object further or closer to the pivot position than we began.

We also begin a rotation lerp which overrides the rotation constraints set on the rigidbody and transitions our object to have it’s up axis facing the pivot point.

If we don’t have a hinge joint attached then we transition back to upright!

Important things to note:

One, this code is set-up for movement in the x and y axis where the objects forward direction is along the z axis, If this is not the case then in the two Quaternion.LookRotation methods, rather than using Vector3.forward you will have to calculate the perpendicular angle to transform.up.

Vector3 perpDir = new Vector3(transform.up.y, -transform.up.x, 0); will maybe, probably, sometimes work? (not tested)

Two, and probably more importantly! It would be much easier to do this with some parenting, where you have your ‘physics parent’ with locked rotationson it’s rigidbody and simply rotate the child when you are hinged, this way you can completely avoid recalculating the anchor points etc and will be far more efficient, but that is easy to do and I like challenges, so this is how to do it the hard way :wink:

Hope that helps, I am happy to answer any questions you have about that code!

Scribe.

P.S

There was a recent meta question about bumping (here) Though I myself don’t feel it’s really an issue in most cases I do share the opinion of what seems to be the majority that excessive bumping is bad, excessive is up for interpretation but personally I would say that 5 bumps in one day is definitely towards excessive, maybe keep it to one bump a day to keep the mods at bay ya know :smiley: at least your username is fitting!