|
| using System.Collections; | 
|  | using System.Collections.Generic; | 
|  | using UnityEngine; | 
|  |  | 
|  | public class PlayerController : MonoBehaviour | 
|  | { | 
|  |  | 
|  | [SerializeField] | 
|  | private float movementSpeed; | 
|  | [SerializeField] | 
|  | private float groundCheckRadius; | 
|  | [SerializeField] | 
|  | private float jumpForce; | 
|  | [SerializeField] | 
|  | private float slopeCheckDistance; | 
|  | [SerializeField] | 
|  | private float maxSlopeAngle; | 
|  | [SerializeField] | 
|  | private Transform groundCheck; | 
|  | [SerializeField] | 
|  | private LayerMask whatIsGround; | 
|  | [SerializeField] | 
|  | private PhysicsMaterial2D noFriction; | 
|  | [SerializeField] | 
|  | private PhysicsMaterial2D fullFriction; | 
|  |  | 
|  | private float xInput; | 
|  | private float slopeDownAngle; | 
|  | private float slopeSideAngle; | 
|  | private float lastSlopeAngle; | 
|  |  | 
|  | private int facingDirection = 1; | 
|  |  | 
|  | private bool isGrounded; | 
|  | private bool isOnSlope; | 
|  | private bool isJumping; | 
|  | private bool canWalkOnSlope; | 
|  | private bool canJump; | 
|  |  | 
|  | private Vector2 newVelocity; | 
|  | private Vector2 newForce; | 
|  | private Vector2 capsuleColliderSize; | 
|  |  | 
|  | private Vector2 slopeNormalPerp; | 
|  |  | 
|  | private Rigidbody2D rb; | 
|  | private CapsuleCollider2D cc; | 
|  |  | 
|  | private void Start() | 
|  | { | 
|  | rb = GetComponent<Rigidbody2D>(); | 
|  | cc = GetComponent<CapsuleCollider2D>(); | 
|  |  | 
|  | capsuleColliderSize = cc.size; | 
|  | } | 
|  |  | 
|  | private void Update() | 
|  | { | 
|  | CheckInput(); | 
|  | } | 
|  |  | 
|  | private void FixedUpdate() | 
|  | { | 
|  | CheckGround(); | 
|  | SlopeCheck(); | 
|  | ApplyMovement(); | 
|  | } | 
|  |  | 
|  | private void CheckInput() | 
|  | { | 
|  | xInput = Input.GetAxisRaw("Horizontal"); | 
|  |  | 
|  | if (xInput == 1 && facingDirection == -1) | 
|  | { | 
|  | Flip(); | 
|  | } | 
|  | else if (xInput == -1 && facingDirection == 1) | 
|  | { | 
|  | Flip(); | 
|  | } | 
|  |  | 
|  | if (Input.GetButtonDown("Jump")) | 
|  | { | 
|  | Jump(); | 
|  | } | 
|  |  | 
|  | } | 
|  | private void CheckGround() | 
|  | { | 
|  | isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround); | 
|  |  | 
|  | if(rb.velocity.y <= 0.0f) | 
|  | { | 
|  | isJumping = false; | 
|  | } | 
|  |  | 
|  | if(isGrounded && !isJumping && slopeDownAngle <= maxSlopeAngle) | 
|  | { | 
|  | canJump = true; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | private void SlopeCheck() | 
|  | { | 
|  | Vector2 checkPos = transform.position - (Vector3)(new Vector2(0.0f, capsuleColliderSize.y / 2)); | 
|  |  | 
|  | SlopeCheckHorizontal(checkPos); | 
|  | SlopeCheckVertical(checkPos); | 
|  | } | 
|  |  | 
|  | private void SlopeCheckHorizontal(Vector2 checkPos) | 
|  | { | 
|  | RaycastHit2D slopeHitFront = Physics2D.Raycast(checkPos, transform.right, slopeCheckDistance, whatIsGround); | 
|  | RaycastHit2D slopeHitBack = Physics2D.Raycast(checkPos, -transform.right, slopeCheckDistance, whatIsGround); | 
|  |  | 
|  | if (slopeHitFront) | 
|  | { | 
|  | isOnSlope = true; | 
|  |  | 
|  | slopeSideAngle = Vector2.Angle(slopeHitFront.normal, Vector2.up); | 
|  |  | 
|  | } | 
|  | else if (slopeHitBack) | 
|  | { | 
|  | isOnSlope = true; | 
|  |  | 
|  | slopeSideAngle = Vector2.Angle(slopeHitBack.normal, Vector2.up); | 
|  | } | 
|  | else | 
|  | { | 
|  | slopeSideAngle = 0.0f; | 
|  | isOnSlope = false; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | private void SlopeCheckVertical(Vector2 checkPos) | 
|  | { | 
|  | RaycastHit2D hit = Physics2D.Raycast(checkPos, Vector2.down, slopeCheckDistance, whatIsGround); | 
|  |  | 
|  | if (hit) | 
|  | { | 
|  |  | 
|  | slopeNormalPerp = Vector2.Perpendicular(hit.normal).normalized; | 
|  |  | 
|  | slopeDownAngle = Vector2.Angle(hit.normal, Vector2.up); | 
|  |  | 
|  | if(slopeDownAngle != lastSlopeAngle) | 
|  | { | 
|  | isOnSlope = true; | 
|  | } | 
|  |  | 
|  | lastSlopeAngle = slopeDownAngle; | 
|  |  | 
|  | Debug.DrawRay(hit.point, slopeNormalPerp, Color.blue); | 
|  | Debug.DrawRay(hit.point, hit.normal, Color.green); | 
|  |  | 
|  | } | 
|  |  | 
|  | if (slopeDownAngle > maxSlopeAngle || slopeSideAngle > maxSlopeAngle) | 
|  | { | 
|  | canWalkOnSlope = false; | 
|  | } | 
|  | else | 
|  | { | 
|  | canWalkOnSlope = true; | 
|  | } | 
|  |  | 
|  | if (isOnSlope && canWalkOnSlope && xInput == 0.0f) | 
|  | { | 
|  | rb.sharedMaterial = fullFriction; | 
|  | } | 
|  | else | 
|  | { | 
|  | rb.sharedMaterial = noFriction; | 
|  | } | 
|  | } | 
|  |  | 
|  | private void Jump() | 
|  | { | 
|  | if (canJump) | 
|  | { | 
|  | canJump = false; | 
|  | isJumping = true; | 
|  | newVelocity.Set(0.0f, 0.0f); | 
|  | rb.velocity = newVelocity; | 
|  | newForce.Set(0.0f, jumpForce); | 
|  | rb.AddForce(newForce, ForceMode2D.Impulse); | 
|  | } | 
|  | } | 
|  |  | 
|  | private void ApplyMovement() | 
|  | { | 
|  | if (isGrounded && !isOnSlope && !isJumping) //if not on slope | 
|  | { | 
|  | Debug.Log("This one"); | 
|  | newVelocity.Set(movementSpeed * xInput, 0.0f); | 
|  | rb.velocity = newVelocity; | 
|  | } | 
|  | else if (isGrounded && isOnSlope && canWalkOnSlope && !isJumping) //If on slope | 
|  | { | 
|  | newVelocity.Set(movementSpeed * slopeNormalPerp.x * -xInput, movementSpeed * slopeNormalPerp.y * -xInput); | 
|  | rb.velocity = newVelocity; | 
|  | } | 
|  | else if (!isGrounded) //If in air | 
|  | { | 
|  | newVelocity.Set(movementSpeed * xInput, rb.velocity.y); | 
|  | rb.velocity = newVelocity; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | private void Flip() | 
|  | { | 
|  | facingDirection *= -1; | 
|  | transform.Rotate(0.0f, 180.0f, 0.0f); | 
|  | } | 
|  |  | 
|  | private void OnDrawGizmos() | 
|  | { | 
|  | Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius); | 
|  | } | 
|  |  | 
|  | } | 
|  |