Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class ParkourController : MonoBehaviour
- {
- [SerializeField]
- private LayerMask _obstacleMask;
- [SerializeField]
- [Range(0f, 5f)]
- private float _parkourHeight = 1f;
- [SerializeField]
- [Range(0, 60f)]
- float _translationVelocity = 2f;
- [SerializeField]
- [Range(0, 60f)]
- float _climbVelocity = 2f;
- [SerializeField]
- [Range(0, 60f)]
- float _forwardVelocity = 2f;
- private List<ParkourObstacle> _parkourObstacles = new List<ParkourObstacle>();
- private DoomController _playerController;
- private CapsuleCollider _parkourCollider;
- private Rigidbody _rigidbody;
- private bool _isClimbing = false;
- private float _velocityBeforeClimb;
- private void Start()
- {
- _playerController = GetComponent<DoomController>();
- _rigidbody = GetComponent<Rigidbody>();
- foreach (CapsuleCollider collider in GetComponents<CapsuleCollider>())
- {
- if (collider.isTrigger)
- {
- _parkourCollider = collider;
- break;
- }
- }
- }
- private void Update()
- {
- bool isForwardPressed = Input.GetAxis("Vertical") > 0f;
- bool isJumpPressed = Input.GetAxis("Jump") > 0f;
- if (isCrouchPressed && _parkourCoroutine != null)
- {
- StopCoroutine(_parkourCoroutine);
- _parkourCoroutine = null;
- StopClimbing(false);
- }
- if (!_playerController.IsGrounded && isForwardPressed && !_isClimbing && _parkourObstacles.Count > 0 && isJumpPressed)
- {
- RaycastHit hit;
- if (Physics.Raycast(transform.position, transform.forward, out hit, _parkourCollider.radius, _obstacleMask))
- {
- var parkourObstacle = _parkourObstacles.Find(obstacle => obstacle.Collider == hit.collider);
- ParkourObstacle.Wall wall = default(ParkourObstacle.Wall);
- if (parkourObstacle != null && parkourObstacle.TryGetWall(hit.point, ref wall))
- {
- Vector3 highestPoint = wall.GetHighestPoint();
- if (highestPoint.y > transform.position.y && highestPoint.y - transform.position.y <= _parkourHeight)
- {
- StartClimbing(parkourObstacle, wall, hit.point);
- }
- }
- }
- }
- }
- private void StartClimbing(ParkourObstacle obstacle, ParkourObstacle.Wall wall, Vector3 startPoint)
- {
- _isClimbing = true;
- Plane wallPlane = new Plane(wall.GetPoint(0), wall.GetPoint(1), wall.GetPoint(2));
- Vector3 startPostion1 = startPoint + (wallPlane.normal * _playerController.CharacterRadius * -1);
- Vector3 startPostion2 = startPoint + (wallPlane.normal * _playerController.CharacterRadius);
- Vector3 climbStartPosition = Vector3.Distance(transform.position, startPostion1) < Vector3.Distance(transform.position, startPostion2) ? startPostion1 : startPostion2;
- Quaternion climbStartRtotation = Quaternion.LookRotation(startPoint - climbStartPosition, Vector3.up);
- _velocityBeforeClimb = new Vector2(_rigidbody.velocity.x, _rigidbody.velocity.z).magnitude;
- _rigidbody.velocity = Vector3.zero;
- _playerController.enabled = false;
- _rigidbody.isKinematic = true;
- _parkourCoroutine = StartCoroutine(Climbing(obstacle, wall, climbStartPosition, climbStartRtotation));
- }
- private void StopClimbing(bool isComplite = true)
- {
- _isClimbing = false;
- _playerController.enabled = true;
- _rigidbody.isKinematic = false;
- LastParkourTime = Time.realtimeSinceStartup;
- _rigidbody.velocity = transform.forward * _velocityBeforeClimb;
- }
- private IEnumerator Climbing(ParkourObstacle obstacle, ParkourObstacle.Wall wall, Vector3 startPoint, Quaternion startRotation)
- {
- Vector3 startPlayerPosition = transform.position;
- Quaternion startPlayerRotation = transform.rotation;
- float elapsed = 0f;
- float translationTime = Vector3.Distance(startPlayerPosition, startPoint) / _translationVelocity;
- while (elapsed < translationTime)
- {
- transform.position = Vector3.Lerp(startPlayerPosition, startPoint, elapsed / translationTime);
- transform.rotation = Quaternion.Lerp(startPlayerRotation, startRotation, elapsed / translationTime);
- elapsed += Time.deltaTime;
- yield return null;
- }
- transform.rotation = startRotation;
- startPlayerPosition = transform.position;
- Vector3 targetUpPosition = new Vector3(transform.position.x,
- wall.GetHighestPoint().y + _playerController.CharacterHeight / 2,
- transform.position.z);
- Vector3 targetForwardPosition = targetUpPosition + transform.forward * _playerController.CharacterRadius * 2;
- elapsed = 0f;
- float climbTime = Vector3.Distance(startPlayerPosition, targetUpPosition) / _climbVelocity;
- while (elapsed < climbTime)
- {
- transform.position = Vector3.Lerp(startPlayerPosition, targetUpPosition, elapsed / climbTime);
- elapsed += Time.deltaTime;
- yield return null;
- }
- float forwardTime = Vector3.Distance(startPlayerPosition, targetForwardPosition) / _forwardVelocity;
- elapsed = 0f;
- startPlayerPosition = transform.position;
- while (elapsed < forwardTime)
- {
- transform.position = Vector3.Lerp(startPlayerPosition, targetForwardPosition, elapsed / forwardTime);
- elapsed += Time.deltaTime;
- yield return null;
- }
- StopClimbing();
- }
- private void OnTriggerEnter(Collider other)
- {
- if (((1 << other.gameObject.layer) & _obstacleMask) != 0)
- {
- _parkourObstacles.Add(GetParkourObstacle(other.gameObject));
- }
- }
- private void OnTriggerExit(Collider other)
- {
- if (((1 << other.gameObject.layer) & _obstacleMask) != 0)
- {
- BoxCollider collider = other.GetComponent<BoxCollider>();
- _parkourObstacles.Remove(_parkourObstacles.Find(obstacle => obstacle.Collider == collider));
- Debug.Log(_parkourObstacles.Count());
- }
- }
- private ParkourObstacle GetParkourObstacle(GameObject gameObject)
- {
- BoxCollider collider = gameObject.GetComponent<BoxCollider>();
- var points = new Vector3[8];
- float xSize = collider.size.x;
- float ySize = collider.size.y;
- float zSize = collider.size.z;
- Vector3 center = collider.center;
- //Wall0 - 0, 1, 2, 3
- //Wall1 - 0, 2, 4, 6
- //Wall2 - 4, 5, 6, 7
- //Wall3 - 1, 3, 5, 7
- //Floor - 0, 1, 4, 5
- points[0] = gameObject.transform.TransformPoint(new Vector3(center.x + xSize / 2, center.y + ySize / 2, center.z + zSize / 2));
- points[1] = gameObject.transform.TransformPoint(new Vector3(center.x - xSize / 2, center.y + ySize / 2, center.z + zSize / 2));
- points[2] = gameObject.transform.TransformPoint(new Vector3(center.x + xSize / 2, center.y - ySize / 2, center.z + zSize / 2));
- points[3] = gameObject.transform.TransformPoint(new Vector3(center.x - xSize / 2, center.y - ySize / 2, center.z + zSize / 2));
- points[4] = gameObject.transform.TransformPoint(new Vector3(center.x + xSize / 2, center.y + ySize / 2, center.z - zSize / 2));
- points[5] = gameObject.transform.TransformPoint(new Vector3(center.x - xSize / 2, center.y + ySize / 2, center.z - zSize / 2));
- points[6] = gameObject.transform.TransformPoint(new Vector3(center.x + xSize / 2, center.y - ySize / 2, center.z - zSize / 2));
- points[7] = gameObject.transform.TransformPoint(new Vector3(center.x - xSize / 2, center.y - ySize / 2, center.z - zSize / 2));
- return new ParkourObstacle(new ParkourObstacle.Wall(points[0], points[1], points[4], points[5]),
- new ParkourObstacle.Wall[]
- {
- new ParkourObstacle.Wall(points[0], points[1], points[2], points[3]),
- new ParkourObstacle.Wall(points[0], points[2], points[4], points[5]),
- new ParkourObstacle.Wall(points[4], points[5], points[6], points[7]),
- new ParkourObstacle.Wall(points[1], points[3], points[5], points[7]),
- },
- collider);
- }
- }
- public class ParkourObstacle
- {
- private Wall _floor;
- private Wall[] _walls;
- private BoxCollider _collider;
- public BoxCollider Collider
- {
- get => _collider;
- }
- public ParkourObstacle(Wall floor, Wall[] walls, BoxCollider collider)
- {
- _floor = floor;
- _walls = walls;
- _collider = collider;
- }
- public bool TryGetWall(Vector3 point, ref Wall wall)
- {
- for (int i = 0; i < _walls.Length; i++)
- {
- Plane wallPlane = new Plane(_walls[i].GetPoint(0), _walls[i].GetPoint(1), _walls[i].GetPoint(2));
- if (wallPlane.ClosestPointOnPlane(point) == point)
- {
- wall = _walls[i];
- return true;
- }
- }
- return false;
- }
- public struct Wall
- {
- private Vector3 _point0;
- private Vector3 _point1;
- private Vector3 _point2;
- private Vector3 _point3;
- private const int _pointsCount = 4;
- public Wall(Vector3 point0, Vector3 point1, Vector3 point2, Vector3 point3)
- {
- _point0 = point0;
- _point1 = point1;
- _point2 = point2;
- _point3 = point3;
- }
- public Vector3 GetHighestPoint()
- {
- Vector3 maxPoint = Vector3.negativeInfinity;
- for (int i = 0; i < _pointsCount; i++)
- {
- var currentPoint = GetPoint(i);
- if (currentPoint.y > maxPoint.y)
- {
- maxPoint = currentPoint;
- }
- }
- return maxPoint;
- }
- public Vector3 GetPoint(int index)
- {
- switch (index)
- {
- case 0: return _point0;
- case 1: return _point1;
- case 2: return _point2;
- case 3: return _point3;
- default: throw new System.Exception("Wall::GetPoint index out of range");
- }
- }
- }
- }
Add Comment
Please, Sign In to add comment