1
\$\begingroup\$

I hit Space to make the Capsule jump into a Cube above it.

Expected results: Upon Collision between Capsule and Cube, a HingeJoint is created with the Capsule's rigidbody connected to it. Capsule remains stable and in place.

Actual results: A HingeJoint is indeed created with the Capsule rigidbody connected, but the Capsule goes wildly flying everywhere! Here's a .gif showing the issue (also hosted here):

animation of problem

Note that this flying all over the place only happens when I am holding a movement key (WASD) at time of collision. Otherwise, it does behave in a stable manner.

This is the Capsule's rigidbody-based controller script Smoothy.cs

using System;
using UnityEngine;
using Color = UnityEngine.Color;
using System.Collections;
using System.Collections.Generic;

public class Smoothy : MonoBehaviour
{
    public Transform cameraTransform;
    public Quaternion targetRotation;
    public int rotDegPerSecond = 720;
    public LayerMask _layerMaskEverythingButPlayer;

    [Header("General Config")]
    [SerializeField] MyKeyInput _input;

    [Header("General Debug")]
    [SerializeField] Vector3 _playerMoveInput = Vector3.zero;
    [SerializeField] Vector3 _playerCalculatedForce = Vector3.zero;

    [Header("General")]
    Rigidbody _rigidbody = null;
    CapsuleCollider _capsuleCollider = null;

    [Header("Movement Config")]
    [SerializeField] float _movementMultiplier = 30.0f;
    [SerializeField] float _notGroundedMovementMultiplier = 1.25f;
    [SerializeField] float _crouchSpeedMultiplier = 0.5f;
    [SerializeField] float _runMultiplier = 2.5f;
    [SerializeField] float _minimumVelocityMagnitude = 0.25f;


    [Header("Ground Check Config")]
    [SerializeField][Range(0.0f, 1.8f)] float _groundCheckRadiusMultiplier = 0.9f;
    [SerializeField][Range(-0.95f, 1.05f)] float _groundCheckDistanceTolerance = 0.05f;

    [Header("Ground Check Debug")]
    [SerializeField] bool _playerIsGrounded = true;
    [SerializeField] float _colliderCenterToGroundDistance = 0.0f;
    [SerializeField] float _playerCenterToGroundDistance = 0.0f;

    [Header("Ground Check")]
    RaycastHit _groundCheckHit = new RaycastHit();

    private void Awake()
    {
        _rigidbody = GetComponent<Rigidbody>();
        _capsuleCollider = GetComponent<CapsuleCollider>();

    }

    private void Update()
    {        
        if (Input.GetKeyDown(KeyCode.Space))
        {
            _rigidbody.AddForce(Vector3.up * 30f, ForceMode.Impulse);
        }
    }

    private void FixedUpdate()
    {
        _playerMoveInput = GetMoveInput();
        _playerCalculatedForce = _playerMoveInput;      
        _playerCalculatedForce = PlayerMove();       

        //Rotation        
        if (_input.moveDirectionRaw != Vector3.zero && _input.moveDirection != Vector3.zero)
        {
            targetRotation = Quaternion.LookRotation(_input.moveDirection); //or moveDirectionRaw
            targetRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotDegPerSecond * Time.deltaTime);
            _rigidbody.MoveRotation(targetRotation);
        }

        _playerCalculatedForce *= _rigidbody.mass; 
        _rigidbody.AddForce(_playerCalculatedForce, ForceMode.Force);
    }

    private Vector3 GetMoveInput()
    {
        return _input.moveDirection;
    }   

    private Vector3 PlayerMove()
    {
        return ((_playerIsGrounded) ? (_playerCalculatedForce * _movementMultiplier) : (_playerCalculatedForce * _movementMultiplier * _notGroundedMovementMultiplier));
    }
}

MyKeyInput.cs grabs keyboard input

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MyKeyInput : MonoBehaviour
{
    public Smoothy zc;

    //vars
    public float horizontalInput;
    public float verticalInput;
    public Vector3 moveDirection;
    public Vector3 moveDirectionRaw;
    public bool MoveIsPressed;

    public void Update()
    {
        horizontalInput = Input.GetAxis("Horizontal");
        verticalInput = Input.GetAxis("Vertical");

        moveDirection = new Vector3(horizontalInput, 0.0f, verticalInput).normalized;
        moveDirection = (Quaternion.AngleAxis(zc.cameraTransform.rotation.eulerAngles.y, Vector3.up) * moveDirection).normalized;

        moveDirectionRaw = new Vector3(Input.GetAxisRaw("Horizontal"), 0.0f, Input.GetAxisRaw("Vertical")).normalized;
        moveDirectionRaw = (Quaternion.AngleAxis(zc.cameraTransform.rotation.eulerAngles.y, Vector3.up) * moveDirectionRaw).normalized;

        if (moveDirectionRaw != Vector3.zero && moveDirection != Vector3.zero)
        {
            MoveIsPressed = true;
        }
        else 
        {
            MoveIsPressed = false;
        }
    }
}

^ -- these are the only two scripts on the Capsule

BarLogic.cs is the script on the Cube that the Capsule collides with before Capsule goes crazy

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class BarLogic : MonoBehaviour
{
    public GameObject smoothPlayer;
    RigidbodyConstraints originalConstraints;
    RigidbodyConstraints barConstraints;

    private void Awake()
    {
        originalConstraints = smoothPlayer.GetComponent<Rigidbody>().constraints;
        barConstraints = RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("TopOfHead"))
        {
            if (this.GetComponent<HingeJoint>() == false)
            {
                smoothPlayer.GetComponent<Smoothy>().enabled = false;
                smoothPlayer.GetComponent<Rigidbody>().freezeRotation = false;
                smoothPlayer.GetComponent<Rigidbody>().constraints = barConstraints;

                this.AddComponent<HingeJoint>();
                this.GetComponent<HingeJoint>().connectedBody = smoothPlayer.GetComponent<Rigidbody>();              
            }
        }
    }
}

Any ideas what the cause of Capsule flying around could be?

I'm noticing that if I remove the //Rotation code block in Smoothy.cs that the flying around doesn't consistently happen anymore, but since I'm already telling the code via BarLogic.cs to "Disable Smoothy.cs upon colliding with Cube", I don't what more I can do to fix this. Shouldn't (because I wrote that script disable line in BarLogic) no code from Smoothy.cs be active anymore as soon as the collision between Cube and Capsule occurs?

\$\endgroup\$
5
  • \$\begingroup\$ What happens if you comment out the call to MoveRotation? Any difference? This can create very large effective torques, which might be interacting poorly with the hinge constraint. \$\endgroup\$
    – DMGregory
    Feb 9 at 14:39
  • \$\begingroup\$ Hi, yes, that does stop the issue from happening. But I'm not sure what to do-- The MoveRotation is important to make my CharacterController (Smoothy.cs) work properly. If I comment it out, then it would break the CharacterController functionality for the seconds leading up to Capsule (my character) colliding with the cube to make the HingeJoint. How might you suggest preserving the 'MoveRotation' in the frames before collision, but still have it successfully create the HingeJoint upon collision without glitchiness? My idea was making OnTriggerEnter disable Smoothy.cs but that didn't work. \$\endgroup\$
    – mango
    Feb 9 at 15:42
  • \$\begingroup\$ Can you tell us a bit about the intended behaviour of this rotation, and of the hinge (e.g. what axis/pivot do you want the object to hinge around), and how you want them to interact? Once we understand the desired behaviour, we can better target answers to achieve it. \$\endgroup\$
    – DMGregory
    Feb 9 at 18:11
  • \$\begingroup\$ Oh, yes. Smoothy.cs MoveRotation is meant to rotate player Capsule to the direction of movement input which takes keyboard input and Cinemachine camera direction into account. The HingeJoint is meant to let player rock backwards and forward on it along X axis (swinging forward and backward on 'bar' cube like a gymnast). Once connected to 'bar' cube via HingeJoint, the player Capsule does not need ability to rotate on any axis except that X axis. But problem is just that at time of HingeJoint creation (upon collision), that rotation code causes the Capsule to fly everywhere, shown in gif. \$\endgroup\$
    – mango
    Feb 9 at 19:46
  • \$\begingroup\$ By the way, I want to mention that I was able to 'solve' the problem by changing the BarLogic.cs line of barConstraints = RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ; to this instead: barConstraints = RigidbodyConstraints.None; but I don't understand how/why that 'solved' it. In other words, player Capsule no longer erratically bounces around the screen & game now seems stable, when I changed this line of code. Does this seem like the solution to you? (I'm just concerned it's only 'half-solved' from this and that a physics issue will still show up later) \$\endgroup\$
    – mango
    Feb 9 at 19:59

0

You must log in to answer this question.

Browse other questions tagged .