My original plan of adding the colliders and letting Unity deal with all the collisions failed pretty miserably the first time. My new plan is to call a function to check if there are any collisions at the destination, and only move if it is clear. In Unity, typically functions called raycasts or linecasts are used. They invisibly extend in the given direction and return any collisions. After a bit of checking the documentation on linecasts, I wrote a function to validate movement.
protected bool ValidateMove(Vector3 movement) { // linecast one unit over in the proper direction. If null return false. Otherwise return true. float xPos = transform.position.x; float yPos = transform.position.y; Vector2 startPoint = new Vector2(xPos, yPos); Vector2 endPoint = new Vector2(movement.x + xPos, movement.y + yPos); if (Physics2D.Linecast(startPoint, endPoint)) { Debug.Log("Blocked - Something is in the way"); return false; } return true; }
There is a problem thought. Turns out that linecasts will return any collisions from the start point and end point and this includes the box collider surrounding the very object I am moving, so I need to disable it while running the linecast. Here is the second try, accounting for that.
protected bool ValidateMove(Vector3 movement) { // linecast one unit over in the proper direction. If null return false. Otherwise return true. float xPos = transform.position.x; float yPos = transform.position.y; Vector2 startPoint = new Vector2(xPos, yPos); Vector2 endPoint = new Vector2(movement.x + xPos, movement.y + yPos); // get the objects box collider and disable for the linecast. Reenable after the linecast is complete. BoxCollider2D box = this.GetComponent(); box.enabled = false; RaycastHit2D linecast = Physics2D.Linecast(startPoint, endPoint); box.enabled = true; if (linecast) { Debug.Log("Blocked - Something is in the way"); return false; } return true; } }
So, I save everything and run it. Voila, my sprite moves around and properly collides with the water, rock and npc. No walking on water or clipping through things. There are a couple things, I can still do to improve the code. For instance, I can direct my linecast to check particular layers in case I wanted to treat collisions differently. An example of that would be if I wanted to let my player push the rock instead of having it block movement (something, I will do eventually). But for now, I’m satisfied with it.