AmbushedRaccoon

Паркур и Unity - часть 1: class ParkourController

May 31st, 2020
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.42 KB | None | 0 0
  1. public class ParkourController : MonoBehaviour
  2. {
  3.     [SerializeField]
  4.     private LayerMask _obstacleMask;
  5.  
  6.     [SerializeField]
  7.     [Range(0f, 5f)]
  8.     private float _parkourHeight = 1f;
  9.     [SerializeField]
  10.     [Range(0, 60f)]
  11.     float _translationVelocity = 2f;
  12.     [SerializeField]
  13.     [Range(0, 60f)]
  14.     float _climbVelocity = 2f;
  15.     [SerializeField]
  16.     [Range(0, 60f)]
  17.     float _forwardVelocity = 2f;
  18.  
  19.  
  20.     private List<ParkourObstacle> _parkourObstacles = new List<ParkourObstacle>();
  21.     private DoomController _playerController;
  22.     private CapsuleCollider _parkourCollider;
  23.     private Rigidbody _rigidbody;
  24.     private bool _isClimbing = false;
  25.     private float _velocityBeforeClimb;
  26.  
  27.     private void Start()
  28.     {
  29.         _playerController = GetComponent<DoomController>();
  30.         _rigidbody = GetComponent<Rigidbody>();
  31.         foreach (CapsuleCollider collider in GetComponents<CapsuleCollider>())
  32.         {
  33.             if (collider.isTrigger)
  34.             {
  35.                 _parkourCollider = collider;
  36.                 break;
  37.             }
  38.         }
  39.     }
  40.  
  41.     private void Update()
  42.     {
  43.         bool isForwardPressed = Input.GetAxis("Vertical") > 0f;
  44.         bool isJumpPressed = Input.GetAxis("Jump") > 0f;
  45.         if (isCrouchPressed && _parkourCoroutine != null)
  46.         {
  47.             StopCoroutine(_parkourCoroutine);
  48.             _parkourCoroutine = null;
  49.             StopClimbing(false);
  50.         }
  51.         if (!_playerController.IsGrounded && isForwardPressed && !_isClimbing && _parkourObstacles.Count > 0 && isJumpPressed)
  52.         {
  53.             RaycastHit hit;
  54.             if (Physics.Raycast(transform.position, transform.forward, out hit, _parkourCollider.radius, _obstacleMask))
  55.             {
  56.                 var parkourObstacle = _parkourObstacles.Find(obstacle => obstacle.Collider == hit.collider);
  57.                 ParkourObstacle.Wall wall = default(ParkourObstacle.Wall);
  58.                 if (parkourObstacle != null && parkourObstacle.TryGetWall(hit.point, ref wall))
  59.                 {
  60.                     Vector3 highestPoint = wall.GetHighestPoint();
  61.                     if (highestPoint.y > transform.position.y && highestPoint.y - transform.position.y <= _parkourHeight)
  62.                     {
  63.                         StartClimbing(parkourObstacle, wall, hit.point);
  64.                     }
  65.                 }
  66.             }
  67.         }
  68.     }
  69.  
  70.     private void StartClimbing(ParkourObstacle obstacle, ParkourObstacle.Wall wall, Vector3 startPoint)
  71.     {
  72.         _isClimbing = true;
  73.         Plane wallPlane = new Plane(wall.GetPoint(0), wall.GetPoint(1), wall.GetPoint(2));
  74.         Vector3 startPostion1 = startPoint + (wallPlane.normal * _playerController.CharacterRadius * -1);
  75.         Vector3 startPostion2 = startPoint + (wallPlane.normal * _playerController.CharacterRadius);
  76.         Vector3 climbStartPosition = Vector3.Distance(transform.position, startPostion1) < Vector3.Distance(transform.position, startPostion2) ? startPostion1 : startPostion2;
  77.         Quaternion climbStartRtotation = Quaternion.LookRotation(startPoint - climbStartPosition, Vector3.up);
  78.  
  79.         _velocityBeforeClimb = new Vector2(_rigidbody.velocity.x, _rigidbody.velocity.z).magnitude;
  80.         _rigidbody.velocity = Vector3.zero;
  81.         _playerController.enabled = false;
  82.         _rigidbody.isKinematic = true;
  83.  
  84.         _parkourCoroutine = StartCoroutine(Climbing(obstacle, wall, climbStartPosition, climbStartRtotation));
  85.     }
  86.  
  87.     private void StopClimbing(bool isComplite = true)
  88.     {
  89.         _isClimbing = false;
  90.         _playerController.enabled = true;
  91.         _rigidbody.isKinematic = false;
  92.         LastParkourTime = Time.realtimeSinceStartup;
  93.         _rigidbody.velocity = transform.forward * _velocityBeforeClimb;
  94.     }
  95.  
  96.     private IEnumerator Climbing(ParkourObstacle obstacle, ParkourObstacle.Wall wall, Vector3 startPoint, Quaternion startRotation)
  97.     {
  98.         Vector3 startPlayerPosition = transform.position;
  99.         Quaternion startPlayerRotation = transform.rotation;
  100.         float elapsed = 0f;
  101.         float translationTime = Vector3.Distance(startPlayerPosition, startPoint) / _translationVelocity;
  102.         while (elapsed < translationTime)
  103.         {
  104.             transform.position = Vector3.Lerp(startPlayerPosition, startPoint, elapsed / translationTime);
  105.             transform.rotation = Quaternion.Lerp(startPlayerRotation, startRotation, elapsed / translationTime);
  106.             elapsed += Time.deltaTime;
  107.             yield return null;
  108.         }
  109.         transform.rotation = startRotation;
  110.  
  111.         startPlayerPosition = transform.position;
  112.         Vector3 targetUpPosition = new Vector3(transform.position.x,
  113.             wall.GetHighestPoint().y + _playerController.CharacterHeight / 2,
  114.             transform.position.z);
  115.         Vector3 targetForwardPosition = targetUpPosition + transform.forward * _playerController.CharacterRadius * 2;
  116.         elapsed = 0f;
  117.         float climbTime = Vector3.Distance(startPlayerPosition, targetUpPosition) / _climbVelocity;
  118.         while (elapsed < climbTime)
  119.         {
  120.             transform.position = Vector3.Lerp(startPlayerPosition, targetUpPosition, elapsed / climbTime);
  121.             elapsed += Time.deltaTime;
  122.             yield return null;
  123.         }
  124.         float forwardTime = Vector3.Distance(startPlayerPosition, targetForwardPosition) / _forwardVelocity;
  125.         elapsed = 0f;
  126.         startPlayerPosition = transform.position;
  127.         while (elapsed < forwardTime)
  128.         {
  129.             transform.position = Vector3.Lerp(startPlayerPosition, targetForwardPosition, elapsed / forwardTime);
  130.             elapsed += Time.deltaTime;
  131.             yield return null;
  132.         }
  133.         StopClimbing();
  134.     }
  135.  
  136.     private void OnTriggerEnter(Collider other)
  137.     {
  138.         if (((1 << other.gameObject.layer) & _obstacleMask) != 0)
  139.         {
  140.             _parkourObstacles.Add(GetParkourObstacle(other.gameObject));
  141.         }
  142.     }
  143.  
  144.     private void OnTriggerExit(Collider other)
  145.     {
  146.         if (((1 << other.gameObject.layer) & _obstacleMask) != 0)
  147.         {
  148.             BoxCollider collider = other.GetComponent<BoxCollider>();
  149.             _parkourObstacles.Remove(_parkourObstacles.Find(obstacle => obstacle.Collider == collider));
  150.  
  151.             Debug.Log(_parkourObstacles.Count());
  152.         }
  153.     }
  154.  
  155.     private ParkourObstacle GetParkourObstacle(GameObject gameObject)
  156.     {
  157.         BoxCollider collider = gameObject.GetComponent<BoxCollider>();
  158.         var points = new Vector3[8];
  159.         float xSize = collider.size.x;
  160.         float ySize = collider.size.y;
  161.         float zSize = collider.size.z;
  162.         Vector3 center = collider.center;
  163.         //Wall0 - 0, 1, 2, 3
  164.         //Wall1 - 0, 2, 4, 6
  165.         //Wall2 - 4, 5, 6, 7
  166.         //Wall3 - 1, 3, 5, 7
  167.         //Floor - 0, 1, 4, 5
  168.  
  169.         points[0] = gameObject.transform.TransformPoint(new Vector3(center.x + xSize / 2, center.y + ySize / 2, center.z + zSize / 2));
  170.         points[1] = gameObject.transform.TransformPoint(new Vector3(center.x - xSize / 2, center.y + ySize / 2, center.z + zSize / 2));
  171.         points[2] = gameObject.transform.TransformPoint(new Vector3(center.x + xSize / 2, center.y - ySize / 2, center.z + zSize / 2));
  172.         points[3] = gameObject.transform.TransformPoint(new Vector3(center.x - xSize / 2, center.y - ySize / 2, center.z + zSize / 2));
  173.         points[4] = gameObject.transform.TransformPoint(new Vector3(center.x + xSize / 2, center.y + ySize / 2, center.z - zSize / 2));
  174.         points[5] = gameObject.transform.TransformPoint(new Vector3(center.x - xSize / 2, center.y + ySize / 2, center.z - zSize / 2));
  175.         points[6] = gameObject.transform.TransformPoint(new Vector3(center.x + xSize / 2, center.y - ySize / 2, center.z - zSize / 2));
  176.         points[7] = gameObject.transform.TransformPoint(new Vector3(center.x - xSize / 2, center.y - ySize / 2, center.z - zSize / 2));
  177.  
  178.         return new ParkourObstacle(new ParkourObstacle.Wall(points[0], points[1], points[4], points[5]),
  179.             new ParkourObstacle.Wall[]
  180.             {
  181.                 new ParkourObstacle.Wall(points[0], points[1], points[2], points[3]),
  182.                 new ParkourObstacle.Wall(points[0], points[2], points[4], points[5]),
  183.                 new ParkourObstacle.Wall(points[4], points[5], points[6], points[7]),
  184.                 new ParkourObstacle.Wall(points[1], points[3], points[5], points[7]),
  185.             },
  186.             collider);
  187.     }
  188. }
  189.  
  190. public class ParkourObstacle
  191. {
  192.     private Wall _floor;
  193.  
  194.     private Wall[] _walls;
  195.     private BoxCollider _collider;
  196.  
  197.     public BoxCollider Collider
  198.     {
  199.         get => _collider;
  200.     }
  201.  
  202.     public ParkourObstacle(Wall floor, Wall[] walls, BoxCollider collider)
  203.     {
  204.         _floor = floor;
  205.         _walls = walls;
  206.         _collider = collider;
  207.     }
  208.  
  209.     public bool TryGetWall(Vector3 point, ref Wall wall)
  210.     {
  211.         for (int i = 0; i < _walls.Length; i++)
  212.         {
  213.             Plane wallPlane = new Plane(_walls[i].GetPoint(0), _walls[i].GetPoint(1), _walls[i].GetPoint(2));
  214.             if (wallPlane.ClosestPointOnPlane(point) == point)
  215.             {
  216.                 wall = _walls[i];
  217.                 return true;
  218.             }
  219.         }
  220.         return false;
  221.     }
  222.  
  223.     public struct Wall
  224.     {
  225.         private Vector3 _point0;
  226.         private Vector3 _point1;
  227.         private Vector3 _point2;
  228.         private Vector3 _point3;
  229.         private const int _pointsCount = 4;
  230.  
  231.         public Wall(Vector3 point0, Vector3 point1, Vector3 point2, Vector3 point3)
  232.         {
  233.             _point0 = point0;
  234.             _point1 = point1;
  235.             _point2 = point2;
  236.             _point3 = point3;
  237.         }
  238.  
  239.         public Vector3 GetHighestPoint()
  240.         {
  241.             Vector3 maxPoint = Vector3.negativeInfinity;
  242.             for (int i = 0; i < _pointsCount; i++)
  243.             {
  244.                 var currentPoint = GetPoint(i);
  245.                 if (currentPoint.y > maxPoint.y)
  246.                 {
  247.                     maxPoint = currentPoint;
  248.                 }
  249.             }
  250.             return maxPoint;
  251.         }
  252.  
  253.         public Vector3 GetPoint(int index)
  254.         {
  255.             switch (index)
  256.             {
  257.                 case 0: return _point0;
  258.                 case 1: return _point1;
  259.                 case 2: return _point2;
  260.                 case 3: return _point3;
  261.                 default: throw new System.Exception("Wall::GetPoint index out of range");
  262.             }
  263.         }
  264.     }
  265. }
Add Comment
Please, Sign In to add comment