0
votes

I have a player and a few NPCs. The NPCs have random movement, and I control my players movement. They both have RigidBody2D to deal with physics and BoxCollider2D to deal with Collisions.

However, when I walk into a NPC my player pushes it. Same thing if a NPC moves into my player while the player stands still.

I can't set the mass of either object to some extreme number since that will interfere with how they behave with other objects in my game.

What I want: When an NPC collides with the player, the NPC stops (I get this effect if I set player mass to ex. 1000, but then the player can push the NPC, which I dont want), and the NPC acts as a "wall", i.e it doesnt move, but nor can the player push it around. How can I do this?

EDIT: So I created my own method for it:

void OnCollisionEnter2D(Collision2D other){
    if (other.gameObject.name == "Player") {
        collidedWithPlayer = true; //we only move if !collidedWithPlayer
        isMoving = false; //stop moving
        myRigidBody.mass = 1000; //turn NPC into "wall"
    }
}

void OnCollisionExit2D(Collision2D other){
    if (other.gameObject.name == "Player") {
        collidedWithPlayer = false;
        waitCounter = waitTime; //stop NPC from starting to move right after we exit
        myRigidBody.mass = 1;
    }
}

I mean this works, but is there no native method to do this?

1

1 Answers

1
votes

What you are trying to do is essentially use a "realistic" physics engine to create rather unrealistic physics. That's why it's not supported by Unity's built-in functions. Furthermore, you are correct in assuming that messing with the object masses is not a good idea.

Here's one suggestion that avoids playing with mass. It's a bit kludgey, but give it a try and see if it works for you. (I assume your player rigidbody is not Kinematic?)

Step 1: Create 2 new layers; call them NPCWall and PlayerWall. Setup 2D physics so that player collides with NPCWall and NPC collides with PlayerWall, but player does not collide with NPCs. (If your NPCs and player are on the same layer, then of course put them on 2 separate layers.)

Step 2: Create an NPCWall prefab that uses the same kind of collider as the NPCs. I assume you only have one size of NPC. Likewise, create a PlayerWall prefab that uses the same kind of collider as the player. Set the NPCWall prefab to NPCWall layer, and PlayerWall prefab to PlayerWall layer.

Step 3: We can't parent the NPCWall to the NPC, because it would end up as part of the rigidbody. Therefore add a simple script to the NPCWall and PlayerWall:

public class TrackingWall
{
    //This invisible wall follows an NPC around to block the player.
    //It also follows the player around to block NPCs.

    Transform followTransform;

    public void Init(Transform targetTrans)
    {
        followTransform = targetTrans;
        transform.position = followTransform.position;
        transform.rotation = followTransform.rotation;
    }

    void Update()
    {
        if (followTransform == null)
            Destroy(gameObject);
        transform.position = followTransform.position;
        transform.rotation = followTransform.rotation;
    }
}

Step 4: In the NPC and player scripts:

TrackingWall myWallPrefab;

void Start()
{
  [whatever else you are doing in Start()]
  TrackingWall myWall = Instantiate<TrackingWall>(myWallPrefab);
  myWall.Init(transform);
}

Obviously, for NPCs, myWallPrefab should be set to the NPCWall prefab, and for players, myWallPrefab should be set to the PlayerWall prefab.

In theory this should give each character an impenetrable, immovable wall that only moves when they do, prevents other characters from pushing them, and cleans itself up when they are destroyed. I can't guarantee it will work though!