This game I have been working on for fun is turning out quite good, but the player controller is giving me some headaches, especially on platform detection. I’ve come through a lot of obstacles and I think I found a solution to use from now on. I’ll not go on details here, since it’s long, but I’ll attach the whole script just in case. But the thing is, to check if the player in on the ground (making contact with the platform from above), I check the colliders bounds, as seen here:
if (other.collider.bounds.max.y == minBounds.y)
{
Debug.Log("On Ground");
jumpCount = 0;
grounded = true;
}
But it doesn’t return true, even though the values for the y axis are exactly the same.
Here’s the full script:
using UnityEngine;
using System.Collections;
public class playerController : MonoBehaviour
{
Rigidbody rb; // Player's rigidbody
public BoxCollider playerCollider; // Player's box collider
bool canMove = true; // Can the player move?
string moveDirection; // What direction the player can move if it's colliding with the left/right side of a platform. Read the code to understand better.
bool grounded = false; // Is the player grounded?
bool canJump; // Can the player jump? I.E. Double jump. Independent from grounded.
bool canWallJump; // Can the player walljump? Not yet implemented.
int jumpCount = 0; // Jump count. Used by double jump.
float playerInputX; // Player input in the x value.
float speed = 4; // The player's speed
float defaultSpeed; // Player's default speed
Vector3 colliderMax; //
Vector3 colliderMin; // Colliders collider(...) => used in collisionEnter a.k.a. the (Collision other) object.
Vector3 maxBounds; // Boundaries max||min(...) => player's boundaries
Vector3 minBounds; //
void Start()
{
rb = GetComponent<Rigidbody>(); // Get rigidbody component
defaultSpeed = speed; // Set default speed to initial speed
}
//General
void Update()
{
// Set up player input
playerInputX = Input.GetAxis("Horizontal");
// Run Faster: Start
if (Input.GetKeyDown(KeyCode.LeftShift) || Input.GetKeyDown("joystick button 2"))
{
speed += 3;
}
if (Input.GetKeyUp(KeyCode.LeftShift) || Input.GetKeyUp("joystick button 2"))
{
speed = defaultSpeed;
}
// Run Faster: End
if (jumpCount == 2) // Double jump properties:
canJump = false; //
if (jumpCount == 1) // Player can only double jump if it has jumped less than one time.
canJump = true; //
if (Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown("joystick button 0"))
{
if (grounded || canJump) // If the player is either grounded or can double jump, jump.
{
jumpCount++; // Add one to jump count
Jump(jumpCount); // Jump accordingly to the jump count.
}
}
}
// Physics
void FixedUpdate()
{
if (canMove)
{
rb.velocity = new Vector3(playerInputX * speed, rb.velocity.y, 0); // Move the player in the x axis.
}
if (!canMove) // If the player is in a wall
{
if (moveDirection == "left") // If the wall is on the right side
{
if (playerInputX < 0) // If the player wants to go to the left
{
rb.velocity = new Vector3(playerInputX * speed, -0.5f, 0); // Do it and make the player slide down a little slower to wall jump
}
if (playerInputX > 0) // If the player wants to go right (side of the wall)
{
rb.velocity = new Vector3(0, -0.5f, 0); // Don't do it to avoid the player getting stuck. Still slow down the player in the Y axis.
}
}
if (moveDirection == "right") // Does everything like above except that it is for the opposite side (left)
{
if (playerInputX > 0)
{
rb.velocity = new Vector3(playerInputX * speed, -0.5f, 0);
}
if (playerInputX < 0)
{
rb.velocity = new Vector3(0, -0.5f, 0);
}
}
}
}
void Jump(int jumpType) // Jump function
{
if (jumpType == 1)
rb.AddForce(Vector3.up * 25f, ForceMode.Impulse); // Regular jump //
if (jumpType == 2) // Originally they were intended to be different, but it just didn't feel right.
rb.AddForce(Vector3.up * 25f, ForceMode.Impulse); // Double jump //
}
// Grounded and wall detection. Really long.
void OnCollisionEnter(Collision other)
{
if(other.collider.tag == "Platform") // Is the player colliding with a platform?
{
colliderMax = other.collider.bounds.max; //
colliderMin = other.collider.bounds.min; //
// Define the boundaries based on the box colliders.
maxBounds = playerCollider.bounds.max; //
minBounds = playerCollider.bounds.min; //
if (colliderMax.y > transform.position.y && transform.position.y > colliderMin.y) // Is the player is on the side of a platform?
{
//canJump = false;
canMove = false;
grounded = false;
if (colliderMax.x > transform.position.x) // Collider to the right
{
Debug.Log("Collider to the right");
moveDirection = "left";
}
if (colliderMax.x < transform.position.x) // Collider to the left
{
Debug.Log("Collider to the left");
moveDirection = "right";
}
}
if (colliderMax.y > minBounds.y + 0.1f && minBounds.y > colliderMin.y) // Is the player is on the side of a platform?
{
//canJump = false;
canMove = false;
grounded = false;
if (colliderMax.x > transform.position.x) // Collider to the right
{
Debug.Log("Collider to the right");
moveDirection = "left";
}
if (colliderMax.x < transform.position.x) // Collider to the left
{
Debug.Log("Collider to the left");
moveDirection = "right";
}
}
if (colliderMax.y > maxBounds.y - 0.1f && maxBounds.y > colliderMin.y) // Is the player is on the side of a platform?
{
//canJump = false;
canMove = false;
grounded = false;
if (colliderMax.x > transform.position.x) // Collider to the right
{
Debug.Log("Collider to the right");
moveDirection = "left";
}
if (colliderMax.x < transform.position.x) // Collider to the left
{
Debug.Log("Collider to the left");
moveDirection = "right";
}
}
if (colliderMax.y > transform.position.y) // Is the player below a platform?
{
grounded = false;
}
if (other.collider.bounds.max.y == minBounds.y) // Is the player on a platform? For some reason this doesn't work.
{
Debug.Log("On Ground");
jumpCount = 0;
grounded = true;
}
}
if(other.collider.tag == "Spike") // Game over.
{
MeshRenderer renderer = GetComponent<MeshRenderer>();
renderer.enabled = false;
Invoke("Restart", 2f);
}
}
void OnCollisionExit(Collision other)
{
if (other.collider.tag == "Platform") // Has the player exited a platform?
{
grounded = false;
canMove = true;
}
}
void Restart()
{
Application.LoadLevel(0);
}
}