Nes Quake
Nes Quake

Reputation: 11

How to make a pushable rigidbody not get stuck in a non-pushable rigidbody

Brand new to Unity/C# so this might be a stupid error. I have a player and a push-able box that when pushed towards another object (that usually the player cannot walk through) causes the box to stop moving and the player to get stuck and be unable to move but stuck mid-animation.

They basically just all get stuck in eachother https://i.sstatic.net/rkNtu.png

I followed tutorials for a lot of these things but couldn't manage to find one for pushing the box so I did it by myself, which is what I'm thinking caused these issues.

The player has a 2D circle collider and a 2D rigidbody (with a dynamic body type and discrete collision detection). It also has all of its code to do with walking that looks like this:

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

public class PlayerController : MonoBehaviour
{
    //Movement speed variable
    public float moveSpeed;

    //Giving information of where the collisions layer is (edited in actual unity)
    public LayerMask collisionsLayer;

    //Variable to check if the character is moving
    private bool isMoving;
    private Vector2 input;

    //Animation SetUp
    private Animator animator;

    private void Awake()
    {
        animator = GetComponent<Animator>();
    }

    //End of Animation SetUp

    private void Update()
    {
        //If the player is NOT moving
        if (!isMoving)
        {
            //'GetAxisRaw' gives 1 or -1 --> right = 1, left = -1
            input.x = Input.GetAxisRaw("Horizontal");
            input.y = Input.GetAxisRaw("Vertical");

            //Making it so that the player cannot move diagonally
            if (input.x != 0) input.y = 0;

            if (input != Vector2.zero)
            {
                //Animation section
                animator.SetFloat("moveX",input.x);
                animator.SetFloat("moveY",input.y);
                //End of animation section
                var targetPos = transform.position;
                //Adds 1 or -1 depending on the key input (GetAxisRaw)
                targetPos.x += input.x;
                targetPos.y += input.y;

                if (IsWalkable(targetPos)) 
                    //Calls coroutine 'IEnumerator Move'
                    StartCoroutine(Move(targetPos));
                
                    
            }
        }

        //for animation
        animator.SetBool("isMoving",isMoving);

        //Special type of function w/ 'IEnumerator' as return type. Used to do something over a period of time. 
        IEnumerator Move(Vector3 targetPos)
        {
            isMoving = true; 

            //Checks if the diff between the target position & the players current position is greater than a vry small value 
            while ((targetPos - transform.position).sqrMagnitude > Mathf.Epsilon)
            {
                //If there is a diff btwn targetpos & the current position --> we will move the player towards the target position by a very small amount
                transform.position = Vector3.MoveTowards(transform.position, targetPos, moveSpeed * Time.deltaTime);
                //Stops execution of the coroutine, resumes it in the next update function
                yield return null;
            }

            //Sets the players current position to the target position 
            transform.position = targetPos;

            isMoving = false;
    }

    


    }

    //Checking if the next available tile is actually able to be walked on / if the next tile is blocked
    private bool IsWalkable(Vector3 targetPos)
    {
        if(Physics2D.OverlapCircle(targetPos, 0.1f, collisionsLayer) != null)
        {
            return false;
        }

        return true;
    }


}

The box has a box collider 2D and a 2D rigidbody (dynamic bodytype; discrete collision detection) And the collisions tilemap (which is set to be used by the composite) has a tilemap collider 2D, rigidbody 2D (static) and a composite collider 2D

If anyone actually knows how to make it so that the entire game doesn't break when I try to move the box past objects, that'd be really helpful because I've been working on this for ages and haven't figured anything out at all

Upvotes: 0

Views: 42

Answers (1)

Chuck
Chuck

Reputation: 2102

You should try running the debugger. I think you're finding yourself in an interlocked condition, where your character can't get to the target position (because it's blocked), but it hasn't reached the target position (because it's blocked), so it keeps trying to move, which prevents you from giving it a new command.

I think the easiest way to work around this is to cache your target directions - should be in positive x, positive y, or negative x, or negative y. Then, if you detect the user trying to move in the opposite direction you cancel the move and start a new one.

There are lots of ways to work around this, though, and I do see you are trying to check the target before moving to it, but you're checking the raw input, which may overshoot an obstacle. For example, if the tree is at 0.5 meters, but you're looking at a target of 1 meter, then the target is clear. You get blocked by the tree at 0.5 meters, and because you never reach 1 meter you never exit the coroutine.

You've got to run a debugger and step through the code and see what specifically isn't responding.

Upvotes: 0

Related Questions