2D Top Down Circular Collisions (Without a Rigidbody)

Hi there,

I’m looking to replicate the CharacterController.Move function, using a top down 2D object. Unfortunately I can’t use a Rigidbody2D, as my movement is being synced over an authoritative network and it has been causing jittery movement for the player. I can’t just use 3D physics because a lot of our gameplay is reliant on functionality using Sprites.

Right now I’m doing eight OverlapCircles (one in each direction) and removing the movement direction from the input for those that return positive, but this is only preventing head on and diagonal collisions. Using a controller allows quite a bit of cheeky maneuverability, and even with a keyboard you can squeeze through gaps smaller than your collider.

The other restriction I have is that my level is made up of many, compound edge colliders (spread across numerous GameObjects), so waiting for the player to be in an illegal position and then spitting them out isn’t feasible.

Here is my current Move() function. CharacterCollisionPoint2D is just an object with a position (relative to the player), and two booleans to keep track of it.

public void Move(Vector2 movement){
    if(movement == Vector2.zero){ return;}
	Vector2 currentPosition = _transform.position;
	Vector2 targetPosition = currentPosition + movement;
	Vector2 targetDirection = targetPosition - currentPosition;
	float moveDistance = targetDirection.magnitude;

	Vector2 desiredMotion = targetDirection * moveDistance;

	foreach(CharacterCollisionPoint2D collider in colliders){
	    bool movingAwayX = (movement.x < 0 && collider.position.x > 0) || (movement.x > 0 && collider.position.x < 0);
	    bool movingAwayY = (movement.y < 0 && collider.position.y > 0) || (movement.y > 0 && collider.position.y < 0);

	    if(movingAwayX || movingAwayY){
	        collider.isActive = false;
	        continue;
	    }

	    collider.isActive = true;

	    if(Physics2D.OverlapCircle(currentPosition + collider.position, 0.15f, nonPlayer)){
	        collider.isColliding = true;
	        Vector2 directionIntoCollision = (currentPosition + collider.position - currentPosition).normalized;
	        desiredMotion -= directionIntoCollision * (Vector2.Dot (desiredMotion, directionIntoCollision));
	    } else {
	        collider.isColliding = false;
        }
	}

    desiredMotion = desiredMotion.normalized * moveDistance;

	_transform.Translate(desiredMotion);
}

And here is a package with a very, very basic scene and Player setup (Click the player to see the debug lines):

https://dl.dropboxusercontent.com/u/6612485/2d-topdown-charactercontroller.unitypackage

I’m open to any alternative methods. I was previously using a Rigidbody2D with Rigidbody2D.MovePosition while setting up the movement, and it was working perfectly, unfortunately it just isn’t possible to smoothly control over the network.

Any and all help appreciated!

We ended up getting an excellent freelancer to solve this, and it works perfectly. I’ve put the final result up on GitHub for anyone in the same situation: