- Home /
Yet another 2D pixel perfect movement question
I want to make a precise 2D platormer, something like Thomas Was Alone. The difficulty comes when trying to make a precise pixel perfect collision. I tried several different approaches, but none of them worked out the way I wanted.
These were my attempts:
CharacterController: I just couldn't adapt it to work in this 2D platformer. Its 3D's properties just caused me problems.
Moving the transform: some conflicts with the rest of Unity's physics because I'm moving the transform directly and not the rigidbody.
Changing the rigidbody's velocity: this was what came the closer to what I want, but it seems too unstable. The player keeps shaking and sometimes it bounces when falling.
In all these three options, I tried a lot of combinations with Unity's physics (like gravity, physics materials, rigidbody options).
The following code is my latest attempt (in this case, the game is a runner, so I need to move him to right every frame):
using UnityEngine;
using System.Collections;
public class Character : MonoBehaviour
{
private float speed = 5.0f;
private float jumpSpeed = 8.0f;
private bool isGrounded = false;
private bool isBlocked = false;
private Transform myTransform;
private Rigidbody myRigidbody;
private Vector3 mySize;
protected void Start()
{
myTransform = transform;
myRigidbody = rigidbody;
mySize = myTransform.localScale;
}
protected void FixedUpdate()
{
CheckCollisions();
if (!isBlocked) {
if (myRigidbody.velocity.x < speed) {
myRigidbody.velocity = new Vector3(speed, myRigidbody.velocity.y, 0);
}
}
else if (myRigidbody.velocity.x != 0) {
myRigidbody.velocity = new Vector3(0, myRigidbody.velocity.y, 0);
}
if (isGrounded && Input.GetButtonDown("Jump")) {
myRigidbody.AddForce(Vector3.up * jumpSpeed, ForceMode.VelocityChange);
isGrounded = false;
}
}
private void CheckCollisions()
{
// Correction factor.
float margin = 0.01f;
Vector3 myPos = myTransform.position;
isGrounded = Physics.Raycast(myPos, -Vector3.up, mySize.y / 2 + margin);
isGrounded |= Physics.Raycast(myPos - Vector3.right * (mySize.x / 2 - margin), -Vector3.up, mySize.y / 2 + margin);
isGrounded |= Physics.Raycast(myPos + Vector3.right * (mySize.x / 2 - margin), -Vector3.up, mySize.y / 2 + margin);
isBlocked = Physics.Raycast(myPos, Vector3.right, mySize.x / 2 + margin);
isBlocked |= Physics.Raycast(myPos - Vector3.up * (mySize.y / 2 - margin), Vector3.right, mySize.x / 2 + margin);
isBlocked |= Physics.Raycast(myPos + Vector3.up * (mySize.y / 2 - margin), Vector3.right, mySize.x / 2 + margin);
}
}
Do you have any suggestions? I'll take anything!
You could try creating your own character controller (I had to do it too). Try looking at Physics.CapsuleCast
I guess creating my own controller is what I have left. Using Physics.CapsuleCast seems like a good idea. Thanks!
Just note that when doing this, you must include the "skinWidth" feature from the built-in character controller, or else you will have instances where you will fall through the ground... (I speak from experience ;) )