1
\$\begingroup\$

I've been working on a 2D RPG game in Unity, and for some reason, whenever my character runs into a wall, the camera begins to shake violently. I have a RigidBody2D and a BoxCollider2D connected to him and a TilemapCollider connected to my Tilemap. The RigidBody component is Dynamic with a gravity scale of 0 (because it's a top-down game). Also, the camera is a child of the player. Here's the script to my character controller:

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

public class PlayerController : MonoBehaviour
{
    // Variable for the player speed and animation
    float speed = 2f;
    private Animator animator;
    private Vector3 change;
    
    // Called before the first frame is loaded
    void Start()
    {
        // Gets animator component
        animator = GetComponent<Animator>();
    }
    
    // Update is called once per frame
    void Update()
    {
        // Detects change in the player's coordinates
        change = Vector2.zero;
        change.x = Input.GetAxisRaw("Horizontal");
        change.y = Input.GetAxisRaw("Vertical");
        if (change != Vector3.zero)
        {
            // Detects whether the player's animation should play or not
            MoveCharacter();
            animator.SetFloat("moveX", change.x);
            animator.SetFloat("moveY", change.y);
            animator.SetBool("moving", true);
        }

        else
        {
            animator.SetBool("moving", false);
        }
    }

    void MoveCharacter()
    {
        //  Allows movement on the X axis and calculations to allow the player to move
        if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
        {
            transform.Translate(Vector2.right * speed * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
        {
            transform.Translate(-Vector2.right * speed * Time.deltaTime);
        }

        // Allows movement on the Y axis
        if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
        {
            transform.Translate(Vector2.up * speed * Time.deltaTime);
        }
        if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
        {
            transform.Translate(-Vector2.up * speed * Time.deltaTime);
        }
    }
}
\$\endgroup\$
5
  • \$\begingroup\$ As I'm sure you found when researching past questions here about similar topics, you should not use transform.translate to move a rigidbody. Treat the transform as read-only, and move the object only via the properties and methods of the rigidbody instead. \$\endgroup\$
    – DMGregory
    Jan 13 at 21:18
  • \$\begingroup\$ I'd rather not put camera as player child, can't say that it will fix the problem, but you will have more ways to resolve it in that case. \$\endgroup\$
    – Sergio
    Jan 13 at 21:20
  • \$\begingroup\$ @DMGregory Do you mean declare a RigidBody2D and change the ‘.transform’ to ‘.MovePosition’? \$\endgroup\$ Jan 14 at 1:52
  • \$\begingroup\$ Something close to that. \$\endgroup\$
    – DMGregory
    Jan 14 at 2:01
  • \$\begingroup\$ Violent shaking is pretty normal when dealing with rigidbodies. Not to say that they are infuriating, but most people run into the common trap of handling all their movement the same way they did before using rigidbodies (i.e. transform.position = nextPosition). What is basically happening is you are ignoring collisions by manually moving your object with then transform property, and the rigidbody component is correcting the position in FixedUpdate. This causes objects to clip in and out of each other which makes them shake (this is more obvious when your camera is parented to the object). \$\endgroup\$ Jan 14 at 2:28
0
\$\begingroup\$

Character controllers are difficult to write. You should use a kinetic rigidbody so you can control all the movement yourself. Your MoveCharacter() method should use raycasts or shapecasts to check to see if there's a wall, then only move up to the wall and not through it. The trick is to do this recursively when you hit a slope, sliding along the floor (project rest of movement vector onto slope) until you run out of movement or encounter an obstacle that would make you need to move backward to slide along.

If you just want a simple character controller without doing this yourself, you can use Unity's CharacterController class (though it's a bit dated). See CharacterController.Move.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.