Advertisement
msbranin

CharacterController2D.cs

Jul 7th, 2014
324
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class CharacterController2D : MonoBehaviour
  5. {
  6.     private const float SkinWidth = .02f;
  7.     private const int TotalHorizontalRays = 8;
  8.     private const int TotalVerticalRays = 4;
  9.  
  10.     private static readonly float SlopeLimitTangant = Mathf.Tan (75f* Mathf.Deg2Rad);
  11.  
  12.     public LayerMask PlatformMask;
  13.     public ControllerParameters2D DefaultParameters;
  14.  
  15.     public ControllerState2D State { get; private set; }
  16.     public Vector2 Velocity { get { return _velocity; } }
  17.     public bool HandleCollisions { get; set; }
  18.     public ControllerParameters2D Parameters { get { return _overrideParameters ?? DefaultParameters; } }
  19.     public GameObject StandingOn { get; private set; }
  20.     public bool CanJump
  21.     {
  22.         get
  23.         {
  24.             if (Parameters.JumpRestrictions == ControllerParameters2D.JumpBehavior.CanJumpAnywhere)
  25.                 return _jumpIn <= 0;
  26.  
  27.             if (Parameters.JumpRestrictions == ControllerParameters2D.JumpBehavior.CanJumpOnGround)
  28.                 return State.IsGrounded;
  29.  
  30.             return false;
  31.         }
  32.     }
  33.  
  34.     private Vector2 _velocity;
  35.     private Transform _transform;
  36.     private Vector3 _localScale;
  37.     private BoxCollider2D _boxCollider;
  38.     private ControllerParameters2D _overrideParameters;
  39.     private float _jumpIn;
  40.  
  41.     private Vector3
  42.         _raycastTopLeft,
  43.         _raycastBottomRight,
  44.         _raycastBottomLeft;
  45.  
  46.     private float
  47.         _verticalDistanceBetweenRays,
  48.         _horizontalDistanceBetweenRays;
  49.  
  50.     public void Awake()
  51.     {
  52.         HandleCollisions = true;
  53.         State = new ControllerState2D();
  54.         _transform = transform;
  55.         _localScale = transform.localScale;
  56.         _boxCollider = GetComponent<BoxCollider2D>();
  57.  
  58.         var colliderWidth = _boxCollider.size.x * Mathf.Abs (transform.localScale.x) - (2 * SkinWidth);
  59.         _horizontalDistanceBetweenRays  = colliderWidth / (TotalVerticalRays - 1);
  60.  
  61.         var ColliderHeight = _boxCollider.size.y * Mathf.Abs(transform.localScale.y) - (2 * SkinWidth);
  62.         _verticalDistanceBetweenRays = ColliderHeight / (TotalHorizontalRays - 1);
  63.     }
  64.  
  65.     public void AddForce(Vector2 force)
  66.     {
  67.         _velocity += force;
  68.     }
  69.  
  70.     public void SetForce(Vector2 force)
  71.     {
  72.         _velocity = force;
  73.     }
  74.  
  75.     public void SetHorizontalForce(float x)
  76.     {
  77.         _velocity.x = x;
  78.     }
  79.  
  80.     public void SetVerticalForce (float y)
  81.     {
  82.         _velocity.y = y;
  83.     }
  84.  
  85.     public void Jump()
  86.     {
  87.         // TODO: Moving platform Support
  88.         AddForce(new Vector2(0, Parameters.JumpMagnitude));
  89.         _jumpIn = Parameters.JumpFrequency;
  90.     }
  91.  
  92.     public void LateUpdate()
  93.     {
  94.         _jumpIn -= Time.deltaTime;
  95.         _velocity.y += Parameters.Gravity * Time.deltaTime;
  96.         Move(Velocity * Time.deltaTime);
  97.  
  98.     }
  99.  
  100.     private void Move(Vector2 deltaMovement)
  101.     {
  102.         var wasGrounded = State.IsCollidingBelow;
  103.         State.Reset();
  104.  
  105.         if (HandleCollisions)
  106.         {
  107.             HandlePlatforms();
  108.             CalculateRayOrigins();
  109.  
  110.             if (deltaMovement.y < 0 && wasGrounded)
  111.                 HandleVerticalSlope(ref deltaMovement);
  112.  
  113.             if (Mathf.Abs(deltaMovement.x) > .001f)
  114.                 MoveHorizontally(ref deltaMovement);
  115.  
  116.             MoveVertically(ref deltaMovement);
  117.         }
  118.  
  119.         _transform.Translate(deltaMovement, Space.World);
  120.  
  121.         // TODO: Additional moving platform code
  122.  
  123.         if (Time.deltaTime > 0)
  124.             _velocity = deltaMovement / Time.deltaTime;
  125.  
  126.         _velocity.x = Mathf.Min(_velocity.x, Parameters.MaxVelocity.x);
  127.         _velocity.y = Mathf.Min(_velocity.y, Parameters.MaxVelocity.y);
  128.  
  129.         if (State.IsMovingUpSlope)
  130.             _velocity.y = 0;
  131.     }
  132.  
  133.     private void HandlePlatforms()
  134.     {
  135.  
  136.     }
  137.  
  138.     private void CalculateRayOrigins()
  139.     {
  140.         var size = new Vector2(_boxCollider.size.x * Mathf.Abs(_localScale.x), _boxCollider.size.y * Mathf.Abs(_localScale.y)) / 2;
  141.         var center = new Vector2(_boxCollider.center.x * _localScale.x, _boxCollider.center.y * _localScale.y);
  142.  
  143.         _raycastTopLeft = _transform.position + new Vector3(center.x - size.x + SkinWidth, center.y + size.y - SkinWidth);
  144.         _raycastBottomRight = _transform.position + new Vector3(center.x + size.x - SkinWidth, center.y - size.y + SkinWidth);
  145.         _raycastBottomLeft = _transform.position + new Vector3(center.x - size.x + SkinWidth, center.y - size.y + SkinWidth);
  146.     }
  147.  
  148.     private void MoveHorizontally(ref Vector2 deltaMovement)
  149.     {
  150.         var isGoingRight = deltaMovement.x > 0;
  151.         var rayDistance = Mathf.Abs(deltaMovement.x) + SkinWidth;
  152.         var rayDirection = isGoingRight ? Vector2.right : -Vector2.right;
  153.         var rayOrigin = isGoingRight ? _raycastBottomRight : _raycastBottomLeft;
  154.        
  155.         for (var i = 0; i < TotalHorizontalRays; i++)
  156.         {
  157.             var rayVector = new Vector2(rayOrigin.x, rayOrigin.y + (i * _verticalDistanceBetweenRays));
  158.             Debug.DrawRay(rayVector, rayDirection * rayDistance, Color.red);
  159.  
  160.             var rayCastHit = Physics2D.Raycast(rayVector, rayDirection, rayDistance, PlatformMask);
  161.             if (!rayCastHit)
  162.                 continue;
  163.            
  164.  
  165.             if (i == 0 && HandleHorizontalSlope(ref deltaMovement, Vector2.Angle(rayCastHit.normal, Vector2.up), isGoingRight))
  166.                 break;
  167.  
  168.             deltaMovement.x = rayCastHit.point.x - rayVector.x;
  169.             rayDistance = Mathf.Abs(deltaMovement.x);
  170.  
  171.             if (isGoingRight)
  172.             {
  173.                 deltaMovement.x -= SkinWidth;
  174.                 State.IsCollidingRight = true;
  175.             }
  176.             else
  177.             {
  178.                 deltaMovement.x += SkinWidth;
  179.                 State.IsCollidingLeft = true;
  180.             }
  181.  
  182.             if (rayDistance < SkinWidth + .0001f)
  183.                 break;
  184.         }
  185.     }
  186.  
  187.     private void MoveVertically(ref Vector2 deltaMovement)
  188.     {
  189.         var isGoingUp = deltaMovement.y > 0;
  190.         var rayDistance = Mathf.Abs(deltaMovement.y) + SkinWidth;
  191.         var rayDirection = isGoingUp ? Vector2.up : -Vector2.up;
  192.         var rayOrigin = isGoingUp ? _raycastTopLeft : _raycastBottomLeft;
  193.  
  194.         rayOrigin.x += deltaMovement.x;
  195.  
  196.         var standingOnDistance = float.MaxValue;
  197.         for (var i = 0; i < TotalVerticalRays; i++)
  198.         {
  199.             var rayVector = new Vector2(rayOrigin.x + (i * _horizontalDistanceBetweenRays), rayOrigin.y);
  200.             Debug.DrawRay(rayVector, rayDirection * rayDistance, Color.red);
  201.  
  202.             var raycastHit = Physics2D.Raycast(rayVector, rayDirection, rayDistance, PlatformMask);
  203.             if (!raycastHit)
  204.                 continue;          
  205.  
  206.             if (!isGoingUp)
  207.             {
  208.                 var verticalDistanceToHit = _transform.position.y - raycastHit.point.y;
  209.                 if (verticalDistanceToHit < standingOnDistance)
  210.                 {
  211.                     standingOnDistance = verticalDistanceToHit;
  212.                     StandingOn = raycastHit.collider.gameObject;
  213.                 }
  214.             }
  215.  
  216.             deltaMovement.y = raycastHit.point.y - rayVector.y;
  217.             rayDistance = Mathf.Abs(deltaMovement.y);
  218.  
  219.             if (isGoingUp)
  220.             {
  221.                 deltaMovement.y -= SkinWidth;
  222.                 State.IsCollidingAbove = true;
  223.             }
  224.             else
  225.             {
  226.                 deltaMovement.y += SkinWidth;
  227.                 State.IsCollidingBelow = true;
  228.              }
  229.  
  230.             if (!isGoingUp && deltaMovement.y > .0001f)
  231.             {
  232.                 State.IsMovingUpSlope = true;
  233.             }
  234.  
  235.             if (rayDistance < SkinWidth + .0001f)
  236.                 break;
  237.  
  238.         }
  239.  
  240.     }
  241.  
  242.     private void HandleVerticalSlope(ref Vector2 deltaMovement)
  243.     {
  244.         var center = (_raycastBottomLeft.x + _raycastBottomRight.x) / 2;
  245.         var direction = -Vector2.up;
  246.  
  247.         var slopeDistance = SlopeLimitTangant * (_raycastBottomRight.x - center);
  248.         var slopeRayVector = new Vector2(center, _raycastBottomLeft.y);
  249.  
  250.         Debug.DrawRay(slopeRayVector, direction * slopeDistance, Color.yellow);
  251.  
  252.         var raycastHit = Physics2D.Raycast(slopeRayVector, direction, slopeDistance, PlatformMask);
  253.         if (!raycastHit)
  254.             return;
  255.  
  256.         // Resharper disable CompareOfFloatsByEqualityOperator
  257.  
  258.         var isMovingDownSlope = Mathf.Sign(raycastHit.normal.x) == Mathf.Sign(deltaMovement.x);
  259.         if (!isMovingDownSlope)
  260.             return;
  261.  
  262.         var angle = Vector2.Angle(raycastHit.normal, Vector2.up);
  263.         if (Mathf.Abs(angle) < .0001f)
  264.             return;
  265.  
  266.         State.IsMovingDownSlope = true;
  267.         State.SlopeAngle = angle;
  268.         deltaMovement.y = raycastHit.point.y - slopeRayVector.y;
  269.  
  270.     }
  271.  
  272.     private bool HandleHorizontalSlope(ref Vector2 deltaMovement, float angle, bool isGoingRight)
  273.     {
  274.         if (Mathf.RoundToInt(angle) == 90)
  275.             return false;
  276.  
  277.         if (angle > Parameters.SlopeLimit)
  278.         {
  279.             deltaMovement.x = 0;
  280.             return true;
  281.         }
  282.  
  283.         if (deltaMovement.y > .07f)
  284.             return true;
  285.  
  286.         deltaMovement.x += isGoingRight ? -SkinWidth : SkinWidth;
  287.         deltaMovement.y = Mathf.Abs(Mathf.Tan(angle * Mathf.Deg2Rad) * deltaMovement.x);
  288.         State.IsMovingUpSlope = true;
  289.         State.IsCollidingBelow = true;
  290.         return true;
  291.     }
  292.  
  293.     public void OnTriggerEnter2D(Collider2D other)
  294.     {
  295.    
  296.     }
  297.  
  298.     public void OnTriggerExit2D(Collider2D other)
  299.     {
  300.  
  301.     }
  302. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement