2D linecast is allowing NPCs to move onto same position
After finishing the 2d roguelike tutorial, I started to play around with the code. Specifically, changing it to be realtime instead of turn based. I've run into an issue where NPCs occasionally move onto the same position. I've tried a few fixes, but the problem has remained. Any help in understanding what I'm doing wrong or what the underlying issue is would be a great help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Character : MonoBehaviour {
private BoxCollider2D boxCollider;
private float inverseMoveTime;
private float moveTime = .04f;
bool movingEnabled = true;
private Rigidbody2D rigidBody;
protected void attemptMove(int x, int y) {
if (!movingEnabled || (x == 0 && y == 0)) return;
Vector3 movement = new Vector3(x, y, 0);
Vector3 endPos = transform.position + movement;
RaycastHit2D hit = checkForHit(endPos);
if (hit.transform == null) {
move(endPos);
}
}
RaycastHit2D checkForHit(Vector3 endPos) {
boxCollider.enabled = false;
RaycastHit2D hit = Physics2D.Linecast(transform.position, endPos);
boxCollider.enabled = true;
return hit;
}
void move(Vector3 endPos) {
StartCoroutine(moveSmoothly(endPos));
// StartCoroutine(moveChoppy(endPos));
}
IEnumerator moveChoppy(Vector3 endPos) {
movingEnabled = false;
rigidBody.MovePosition(endPos);
yield return new WaitForSeconds(moveTime);
movingEnabled = true;
}
protected IEnumerator moveSmoothly(Vector3 endPos) {
movingEnabled = false;
float sqrRemainingDistance = (transform.position - endPos).sqrMagnitude;
while(sqrRemainingDistance > float.Epsilon) {
Vector3 newPostion = Vector3.MoveTowards(rigidBody.position, endPos, inverseMoveTime * Time.deltaTime);
rigidBody.MovePosition(newPostion);
sqrRemainingDistance = (transform.position - endPos).sqrMagnitude;
yield return null;
}
movingEnabled = true;
}
protected virtual void Start () {
boxCollider = GetComponent<BoxCollider2D>();
inverseMoveTime = 1f / moveTime;
rigidBody = GetComponent<Rigidbody2D>();
}
void Update () {
attemptMove(Random.Range(-1, 2), Random.Range(-1, 2));
}
}
The things I've tried to fix it:
Use a game manager to iterate over the NPCs calling a custom update method. This was to force an order, thinking it might be a concurrency issue.
Move directly to the position instead of using a coroutine to smoothly move. Thinking that the second NPC could still think the position is unoccupied since the first one has only begun to move into it.
Use Collider2D.Raycast instead of temporarily disabling the collider to use Physics2D.Linecast. Thinking the second NPC is doing its calculation while the first one has its collider disabled.
I'm at a loss about what else to try. Any links to guides that explain how these things are interacting would be great, too. Thanks!