I’m pretty new to Unity, and I’ve been trying to make a basic 2D platformer using 2d Toolkit. I tried using the Character Controller, but I need the precision of a box collider, I can’t use the capsule collider that is built into it.
I found a blog post about how to make a 2D Platformer using raycasts to simulate collisions, and I’ve tweaked the code considerably to get it working (the code from the blog post simply doesn’t work at all, variables are missing and all sorts of stuff is wrong).
The edited code kind of works, but I’m having some problems with it. The character sometimes “sinks” into the ground more than others, and sometimes just flat out ignores the wall raycasts. In addition, whenever the wall raycast does block the character, it gives me the error “NullReferenceException: Object reference not set to an instance of an object” in the console, pointing at lines 95, 56, 79, and 36.
Does anyone have any idea what my problem might be? I’ve been trying to get this working for days.
var velocity = Vector2(0, 0);
var maxVelocity = Vector2(0.35, 2.35);
var gravity : float;
var onGround = false;
var onLeftWall = false;
var onRightWall = false;
function FixedUpdate () {
//Limits the speed to the maxVelocity
if (velocity.x > maxVelocity.x) velocity.x = maxVelocity.x;
else if (velocity.x < -maxVelocity.x) velocity.x = -maxVelocity.x;
if (velocity.y < -maxVelocity.y) velocity.y = -maxVelocity.y;
//Instatiate the raycast variables
var LFloorRay = new Ray(collider.bounds.center - collider.bounds.extents + Vector3(0,1,0), Vector3.down);
var LFloorHit : RaycastHit;
var LFloorWallRay = new Ray(collider.bounds.center - collider.bounds.extents + Vector3(0,1,0), Vector3.left);
var LFloorWallHit : RaycastHit;
var RFloorRay = new Ray(collider.bounds.center - Vector3(-collider.bounds.extents.x, collider.bounds.extents.y, collider.bounds.extents.z) + Vector3(0,1,0), Vector3.down);
var RFloorHit : RaycastHit;
var RFloorWallRay = new Ray(collider.bounds.center - Vector3(-collider.bounds.extents.x, collider.bounds.extents.y, collider.bounds.extents.z) + Vector3(0,1,0), Vector3.right);
var RFloorWallHit : RaycastHit;
var player : Transform;
//check to see if the Bottom Left Floor raycast hits a "Solid" platform
if (Physics.Raycast (LFloorRay.origin, Vector3.down, LFloorHit, 1))
{
if (LFloorHit.collider.gameObject.CompareTag("Solid"))
{
Debug.DrawLine (LFloorRay.origin, LFloorHit.point, Color.red);
if (onGround == false)
{
onGround = true;
velocity.y = 0; //If it hits a "Solid" platform, then make its vertical speed 0
//and place the object ontop of the platform, but only if it wasn't already on a solid platform
player.position = Vector3(player.position.x, LFloorHit.point.y - (collider.bounds.center.y + collider.bounds.extents.y), player.position.z);
}
}
else //if the object is not "Solid", then ignore it
{
onGround = false;
velocity.y -= gravity * Time.deltaTime;
}//If bottom left doesn't hit, check the bottom right
} else if (Physics.Raycast (RFloorRay.origin, Vector3.down, RFloorHit, 1))
{
if (RFloorHit.collider.gameObject.CompareTag("Solid"))
{
Debug.DrawLine (RFloorRay.origin, RFloorHit.point, Color.red);
if (onGround == false)
{
onGround = true;
velocity.y = 0; //same as above
player.position = Vector3(player.position.x, RFloorHit.point.y - (collider.bounds.center.y + collider.bounds.extents.y), player.position.z);
}
}
else
{
onGround = false;
velocity.y -= gravity * Time.deltaTime;
}
} else { //if nothing is hit by either raycast, apply gravity.
onGround = false;
velocity.y -= gravity * Time.deltaTime;
}
//Wall collision, checks to see if the player has touched a wall on their left side
if (Physics.Raycast (LFloorWallRay.origin, Vector3.left, LFloorWallHit, 0.3))
{
if (LFloorWallHit.collider.gameObject.CompareTag("Solid"))
{
Debug.DrawLine (LFloorWallRay.origin, LFloorWallHit.point, Color.red);
if (onLeftWall) {if (velocity.x < 0) velocity.x = 0;} else //if they are touching a wall, don't allow them to go
//any further in that direction
if (onLeftWall == false){
onLeftWall = true; //If they aren't touching a wall, place them beside the wall.
player.position = Vector3(LFloorWallHit.point.x + (collider.bounds.center.x + collider.bounds.extents.x),player.position.y, player.position.z);
}
} else {
onLeftWall = false;
}
} else onLeftWall = false;
//same as above except for the right side instead of the left
if (Physics.Raycast (RFloorWallRay.origin, Vector3.right, RFloorWallHit, 0.3))
{
if (RFloorWallHit.collider.gameObject.CompareTag("Solid"))
{
Debug.DrawLine (RFloorWallRay.origin, RFloorWallHit.point, Color.red);
if (onRightWall) {if (velocity.x > 0) velocity.x = 0;} else
if (onRightWall == false){
onRightWall = true;
player.position = Vector3(RFloorWallHit.point.x - (collider.bounds.center.x + collider.bounds.extents.x),player.position.y, player.position.z);
}
} else {
onRightWall = false;
}
} else onRightWall = false;
//change the player's position depending on the calculated velocities
transform.position.x += velocity.x;
transform.position.y += velocity.y;
}