I want to make the player slip when they step on the slippery surface (light blue colored). I first attempted it with a Physics Material 2D (w/ 0 friction and bounciness) but since I’m directly changing the player’s RigidBody velocity in the player controller script when they move, the surface has no effect on them, so the player simply walks like usual. I tried several other things but to no avail. Any way to make it work?
PlayerController.cs
// Class which handles player movement
[RequireComponent(typeof(Rigidbody2D))]
public class PlayerController : MonoBehaviour
{
[Header("Game Object and Component References")]
[Tooltip("The Input Manager component used to gather player input.")]
public InputManager inputManager = null;
[Tooltip("The Ground Check component used to check whether this player is grounded currently.")]
public GroundCheck groundCheck = null;
[Tooltip("The sprite renderer that represents the player.")]
public SpriteRenderer spriteRenderer = null;
[Tooltip("The health component attached to the player.")]
public Health playerHealth;
// The rigidbody used to move the player (necessary for this component, so not made public)
private Rigidbody2D playerRigidbody = null;
// Enum to help determine which direction the player is facing.
public enum PlayerDirection
{
Right,
Left
}
// Which way the player is facing right now
public PlayerDirection facing
{
get
{
if (horizontalMovementInput > 0)
{
return PlayerDirection.Right;
}
else if (horizontalMovementInput < 0)
{
return PlayerDirection.Left;
}
else
{
if (spriteRenderer != null && spriteRenderer.flipX == true)
return PlayerDirection.Left;
return PlayerDirection.Right;
}
}
}
// Whether this player is grounded false if no ground check component assigned
public bool grounded
{
get
{
if (groundCheck != null)
{
return groundCheck.CheckGrounded();
}
else
{
return false;
}
}
}
// The horizontal movement input collected from the input manager
public float horizontalMovementInput
{
get
{
if (inputManager != null)
return inputManager.horizontalMovement;
else
return 0;
}
}
// the jump input collected from the input manager
public bool jumpInput
{
get
{
if (inputManager != null)
return inputManager.jumpStarted;
else
return false;
}
}
[Header("Movement Settings")]
[Tooltip("The speed at which to move the player horizontally")]
public float movementSpeed = 4.0f;
[Header("Jump Settings")]
[Tooltip("The force with which the player jumps.")]
public float jumpPower = 10.0f;
[Tooltip("The number of jumps that the player is alowed to make.")]
public int allowedJumps = 1;
[Tooltip("The duration that the player spends in the \"jump\" state")]
public float jumpDuration = 0.1f;
[Tooltip("The effect to spawn when the player jumps")]
public GameObject jumpEffect = null;
[Tooltip("Layers to pass through when moving upwards")]
public List<string> passThroughLayers = new List<string>();
// The number of times this player has jumped since being grounded
private int timesJumped = 0;
// Whether the player is in the middle of a jump right now
private bool jumping = false;
// Enum used for categorizing the player's state
public enum PlayerState
{
Idle,
Walk,
Jump,
Fall,
Dead
}
[HideInInspector]
// The player's current state (walking, idle, jumping, falling, or dead)
public PlayerState state = PlayerState.Idle;
private void Start()
{
SetupRigidbody();
SetUpInputManager();
}
private void LateUpdate()
{
ProcessInput();
HandleSpriteDirection();
DetermineState();
}
private void ProcessInput()
{
HandleMovementInput();
HandleJumpInput();
}
// Handles movement input
private void HandleMovementInput()
{
Vector2 movementForce = Vector2.zero;
if (Mathf.Abs(horizontalMovementInput) > 0 && state != PlayerState.Dead)
{
movementForce = horizontalMovementInput * movementSpeed * transform.right;
}
MovePlayer(movementForce);
}
// Moves the player with a specified force
private void MovePlayer(Vector2 movementForce)
{
float horizontalVelocity = movementForce.x;
float verticalVelocity = (grounded && !jumping) ? 0 : playerRigidbody.velocity.y;
playerRigidbody.velocity = new Vector2(horizontalVelocity, verticalVelocity);
if (playerRigidbody.velocity.y > 0)
{
foreach (string layerName in passThroughLayers)
{
Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("Player"), LayerMask.NameToLayer(layerName), true);
}
}
else
{
foreach (string layerName in passThroughLayers)
{
Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("Player"), LayerMask.NameToLayer(layerName), false);
}
}
}
// Handles jump input
private void HandleJumpInput()
{
if (jumpInput)
{
StartCoroutine(Jump(1.0f));
}
}
// Coroutine which causes the player to jump.
private IEnumerator Jump(float powerMultiplier = 1.0f)
{
if (timesJumped < allowedJumps && state != PlayerState.Dead)
{
jumping = true;
float time = 0;
SpawnJumpEffect();
playerRigidbody.velocity = new Vector2(playerRigidbody.velocity.x, 0);
playerRigidbody.AddForce(jumpPower * powerMultiplier * transform.up, ForceMode2D.Impulse);
timesJumped++;
while (time < jumpDuration)
{
yield return null;
time += Time.deltaTime;
}
jumping = false;
}
}
// Spawns the effect that occurs when the player jumps
private void SpawnJumpEffect()
{
if (jumpEffect != null)
{
Instantiate(jumpEffect, transform.position, transform.rotation, null);
}
}
// Bounces the player upwards, refunding jumps.
public void Bounce()
{
timesJumped = 0;
if (inputManager.jumpHeld)
{
StartCoroutine(Jump(1.5f));
}
else
{
StartCoroutine(Jump(1.0f));
}
}
// Determines which way the player should be facing, then makes them face in that direction
private void HandleSpriteDirection()
{
if (spriteRenderer != null)
{
if (facing == PlayerDirection.Left)
{
spriteRenderer.flipX = true;
}
else
{
spriteRenderer.flipX = false;
}
}
}
// Gets and returns the player's current state
private PlayerState GetState()
{
return state;
}
// Sets the player's current state
private void SetState(PlayerState newState)
{
state = newState;
}
// Determines which state is appropriate for the player currently
private void DetermineState()
{
if (playerHealth.currentHealth <= 0)
{
SetState(PlayerState.Dead);
}
else if (grounded)
{
if (Mathf.Abs(horizontalMovementInput) > 0)
{
SetState(PlayerState.Walk);
}
else
{
SetState(PlayerState.Idle);
}
if (!jumping)
{
timesJumped = 0;
}
}
else
{
if (jumping)
{
SetState(PlayerState.Jump);
}
else
{
SetState(PlayerState.Fall);
}
}
}
// Sets up the player's rigidbody
private void SetupRigidbody()
{
if (playerRigidbody == null)
{
playerRigidbody = GetComponent<Rigidbody2D>();
}
}
// Gets the reference to the input manager
private void SetUpInputManager()
{
inputManager = InputManager.instance;
if (inputManager == null)
{
Debug.LogError("There is no InputManager set up in the scene for the PlayerController to read from");
}
}
}
