Advertisement
Guest User

code

a guest
Jun 2nd, 2025
13
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.41 KB | None | 0 0
  1.  
  2. using UnityEngine;
  3.  
  4. using System.Collections;
  5.  
  6. using System.Diagnostics;
  7.  
  8. [RequireComponent(typeof(CharacterController))]
  9.  
  10. public class FPSController : MonoBehaviour
  11.  
  12. {
  13.  
  14. [Header("Look Settings")]
  15.  
  16. public Transform playerCamera;
  17.  
  18. public float mouseSensitivity = 100f;
  19.  
  20. public float maxLookAngle = 90f;
  21.  
  22. public Transform cameraPivot; // Drag in CameraHolder
  23.  
  24. [Header("Movement Settings")]
  25.  
  26. public float walkSpeed = 5f;
  27.  
  28. public float runSpeed = 8f;
  29.  
  30. public float crouchSpeed = 3f;
  31.  
  32. public float jumpHeight = 1.5f;
  33.  
  34. public float gravity = -9.81f;
  35.  
  36. [Header("Keybinds")]
  37.  
  38. public KeyCode runKey = KeyCode.LeftShift;
  39.  
  40. public KeyCode crouchKey = KeyCode.LeftControl;
  41.  
  42. [Header("Kick Settings")]
  43.  
  44. public float kickRange = 2f;
  45.  
  46. public float kickForce = 500f;
  47.  
  48. public float kickCooldown = 1f;
  49.  
  50. public LayerMask kickableLayers;
  51.  
  52. private bool isKicking = false;
  53.  
  54. private float kickTimer = 0f;
  55.  
  56. [Header("Slide Settings")]
  57.  
  58. public float slideSpeed = 10f;
  59.  
  60. public float slideDuration = 1f;
  61.  
  62. public float slideCooldown = 1.5f;
  63.  
  64. public float slideHeight = 1f;
  65.  
  66. [Header("Crouch/Slide Shared Settings")]
  67.  
  68. public float crouchHeight = 1.2f;
  69.  
  70. public float crouchCameraHeight = 0.8f;
  71.  
  72. public float cameraSmoothSpeed = 8f;
  73.  
  74. [Header("Model Settings")]
  75.  
  76. public Transform playerModel;
  77.  
  78. public float modelYWhenStanding = 0f;
  79.  
  80. public float modelYWhenCrouching = -0.5f;
  81.  
  82. public float modelYWhenSliding = -0.7f;
  83.  
  84. [Header("Ground Check Settings")]
  85.  
  86. public float groundCheckDistance = 0.4f;
  87.  
  88. public float groundCheckRadius = 0.3f;
  89.  
  90. public LayerMask groundMask;
  91.  
  92. [Header("Upper Body Tracking")]
  93.  
  94. public Transform upperBodyBone;
  95.  
  96. public float upperBodyPitchLimit = 45f;
  97.  
  98. public float upperBodyFollowSpeed = 10f;
  99.  
  100. private CharacterController controller;
  101.  
  102. private Animator animator;
  103.  
  104. private float cameraPitch; // Tracks vertical camera angle
  105.  
  106. private float originalHeight;
  107.  
  108. private Vector3 originalCenter;
  109.  
  110. private float originalCameraY;
  111.  
  112. private float targetCameraY;
  113.  
  114. private Quaternion upperBodyStartRotation;
  115.  
  116. private Vector3 airMoveDirection;
  117.  
  118. private Vector3 lastGroundedVelocity;
  119.  
  120. private bool isPointing = false;
  121.  
  122. private Vector3 velocity;
  123.  
  124. private bool isSliding = false;
  125.  
  126. private bool isCrouching = false;
  127.  
  128. private float slideCooldownTimer = 0f;
  129.  
  130. private bool isGrounded = false;
  131.  
  132. void Start()
  133.  
  134. {
  135.  
  136. controller = GetComponent<CharacterController>();
  137.  
  138. animator = GetComponentInChildren<Animator>();
  139.  
  140. animator.cullingMode = AnimatorCullingMode.CullUpdateTransforms;
  141.  
  142. Cursor.lockState = CursorLockMode.Locked;
  143.  
  144. Cursor.visible = false;
  145.  
  146. // Reset camera to look forward on game start
  147.  
  148. cameraPitch = 0f;
  149.  
  150. playerCamera.localRotation = Quaternion.Euler(cameraPitch, 0f, 0f);
  151.  
  152. originalHeight = controller.height;
  153.  
  154. originalCenter = controller.center;
  155.  
  156. originalCameraY = playerCamera.localPosition.y;
  157.  
  158. targetCameraY = originalCameraY;
  159.  
  160. if (playerCamera == null)
  161.  
  162. UnityEngine.Debug.LogError("PlayerCamera not assigned!");
  163.  
  164. if (playerModel == null)
  165.  
  166. UnityEngine.Debug.LogError("Player model not assigned!");
  167.  
  168. if (upperBodyBone != null)
  169.  
  170. upperBodyStartRotation = upperBodyBone.localRotation;
  171.  
  172. }
  173.  
  174. void Update()
  175.  
  176. {
  177.  
  178. GroundCheck();
  179.  
  180. Look();
  181.  
  182. Move();
  183.  
  184. kickTimer -= Time.deltaTime;
  185.  
  186. // Toggle pointing pose
  187.  
  188. if (Input.GetKeyDown(KeyCode.Alpha1))
  189.  
  190. {
  191.  
  192. isPointing = true;
  193.  
  194. animator.SetBool("IsPointing", true);
  195.  
  196. }
  197.  
  198. // Cancel pointing on left-click
  199.  
  200. if (isPointing && Input.GetMouseButtonDown(0))
  201.  
  202. {
  203.  
  204. isPointing = false;
  205.  
  206. animator.SetBool("IsPointing", false);
  207.  
  208. }
  209.  
  210. if (Input.GetKeyDown(KeyCode.F) && kickTimer <= 0f && !isKicking && isGrounded)
  211.  
  212. {
  213.  
  214. StartCoroutine(PerformKick());
  215.  
  216. }
  217.  
  218. slideCooldownTimer -= Time.deltaTime;
  219.  
  220. Vector3 camPos = playerCamera.localPosition;
  221.  
  222. camPos.y = Mathf.Lerp(camPos.y, targetCameraY, Time.deltaTime * cameraSmoothSpeed);
  223.  
  224. playerCamera.localPosition = camPos;
  225.  
  226. UpdateModelPosition();
  227.  
  228. }
  229.  
  230. void LateUpdate()
  231.  
  232. {
  233.  
  234. if (upperBodyBone == null || animator == null) return;
  235.  
  236. // Skip rotation override if pointing or other emote is active
  237.  
  238. if (animator.GetCurrentAnimatorStateInfo(1).normalizedTime < 1f &&
  239.  
  240. animator.GetCurrentAnimatorStateInfo(1).IsTag("UpperBody")) return;
  241.  
  242. float pitch = Mathf.Clamp(cameraPitch, -upperBodyPitchLimit, upperBodyPitchLimit);
  243.  
  244. Quaternion pitchRotation = Quaternion.AngleAxis(pitch, Vector3.right);
  245.  
  246. upperBodyBone.localRotation = Quaternion.Slerp(
  247.  
  248. upperBodyBone.localRotation,
  249.  
  250. upperBodyStartRotation * pitchRotation,
  251.  
  252. Time.deltaTime * upperBodyFollowSpeed
  253.  
  254. );
  255.  
  256. }
  257.  
  258. void Look()
  259.  
  260. {
  261.  
  262. float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
  263.  
  264. float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
  265.  
  266. cameraPitch -= mouseY;
  267.  
  268. cameraPitch = Mathf.Clamp(cameraPitch, -maxLookAngle, maxLookAngle);
  269.  
  270. cameraPivot.localRotation = Quaternion.Euler(cameraPitch, 0f, 0f);
  271.  
  272. transform.Rotate(Vector3.up * mouseX);
  273.  
  274. }
  275.  
  276. void Move()
  277.  
  278. {
  279.  
  280. if (isGrounded && velocity.y < 0)
  281.  
  282. velocity.y = -2f;
  283.  
  284. float moveX = Input.GetAxis("Horizontal");
  285.  
  286. float moveZ = Input.GetAxis("Vertical");
  287.  
  288. Vector3 move = transform.right * moveX + transform.forward * moveZ;
  289.  
  290. float speed = walkSpeed;
  291.  
  292. bool isRunning = Input.GetKey(runKey) && !isSliding && !isCrouching;
  293.  
  294. if (isRunning) speed = runSpeed;
  295.  
  296. else if (isCrouching) speed = crouchSpeed;
  297.  
  298. if (Input.GetKeyDown(crouchKey) && Input.GetKey(runKey) && isGrounded && slideCooldownTimer <= 0 && !isSliding)
  299.  
  300. StartCoroutine(Slide());
  301.  
  302. if (!isSliding && Input.GetKey(crouchKey) && !Input.GetKey(runKey))
  303.  
  304. {
  305.  
  306. StartCrouch();
  307.  
  308. }
  309.  
  310. else if (!isSliding && !Input.GetKey(crouchKey) && isCrouching && CanStandUp())
  311.  
  312. {
  313.  
  314. StopCrouch();
  315.  
  316. }
  317.  
  318. controller.Move(move * speed * Time.deltaTime);
  319.  
  320. if (Input.GetButtonDown("Jump") && isGrounded && !isSliding && !isCrouching)
  321.  
  322. {
  323.  
  324. velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
  325.  
  326. animator.SetTrigger("Jump");
  327.  
  328. }
  329.  
  330. velocity.y += gravity * Time.deltaTime;
  331.  
  332. controller.Move(velocity * Time.deltaTime);
  333.  
  334. // Animations
  335.  
  336. animator.SetFloat("Speed", move.magnitude * speed);
  337.  
  338. animator.SetBool("IsSliding", isSliding);
  339.  
  340. animator.SetBool("IsCrouch", isCrouching);
  341.  
  342. animator.SetBool("IsGrounded", isGrounded);
  343.  
  344. animator.SetBool("IsFalling", !isGrounded && velocity.y < 0);
  345.  
  346. }
  347.  
  348. void GroundCheck()
  349.  
  350. {
  351.  
  352. Vector3 origin = transform.position + Vector3.up * (controller.radius + 0.1f);
  353.  
  354. isGrounded = Physics.SphereCast(origin, groundCheckRadius, Vector3.down, out RaycastHit hit, groundCheckDistance, groundMask);
  355.  
  356. }
  357.  
  358. bool IsHeadBlocked()
  359.  
  360. {
  361.  
  362. float radius = controller.radius * 0.95f;
  363.  
  364. Vector3 bottom = transform.position + Vector3.up * crouchHeight;
  365.  
  366. Vector3 top = transform.position + Vector3.up * (originalHeight - 0.05f);
  367.  
  368. return Physics.CheckCapsule(bottom, top, radius, groundMask);
  369.  
  370. }
  371.  
  372. bool CanStandUp()
  373.  
  374. {
  375.  
  376. return !IsHeadBlocked();
  377.  
  378. }
  379.  
  380. IEnumerator Slide()
  381.  
  382. {
  383.  
  384. isSliding = true;
  385.  
  386. slideCooldownTimer = slideCooldown;
  387.  
  388. controller.height = slideHeight;
  389.  
  390. controller.center = new Vector3(0, originalCenter.y - (originalHeight - slideHeight) / 2f, 0);
  391.  
  392. targetCameraY = crouchCameraHeight;
  393.  
  394. float elapsed = 0f;
  395.  
  396. while (elapsed < slideDuration)
  397.  
  398. {
  399.  
  400. Vector3 slideDir = transform.forward;
  401.  
  402. controller.Move(slideDir * slideSpeed * Time.deltaTime);
  403.  
  404. elapsed += Time.deltaTime;
  405.  
  406. yield return null;
  407.  
  408. }
  409.  
  410. controller.height = crouchHeight;
  411.  
  412. controller.center = new Vector3(0, originalCenter.y - (originalHeight - crouchHeight) / 2f, 0);
  413.  
  414. targetCameraY = crouchCameraHeight;
  415.  
  416. isSliding = false;
  417.  
  418. isCrouching = true;
  419.  
  420. }
  421.  
  422. IEnumerator PerformKick()
  423.  
  424. {
  425.  
  426. isKicking = true;
  427.  
  428. kickTimer = kickCooldown;
  429.  
  430. // ✅ Play kick animation
  431.  
  432. animator.SetTrigger("Kick");
  433.  
  434. // Wait for hit to land — adjust to match animation timing
  435.  
  436. yield return new WaitForSeconds(0.2f);
  437.  
  438. // ✅ Raycast to find hit object
  439.  
  440. if (Physics.Raycast(playerCamera.position, playerCamera.forward, out RaycastHit hit, kickRange, kickableLayers))
  441.  
  442. {
  443.  
  444. Rigidbody rb = hit.collider.attachedRigidbody;
  445.  
  446. if (rb != null)
  447.  
  448. {
  449.  
  450. Vector3 forceDir = hit.point - playerCamera.position;
  451.  
  452. forceDir.Normalize();
  453.  
  454. rb.AddForce(forceDir * kickForce, ForceMode.Impulse);
  455.  
  456. }
  457.  
  458. }
  459.  
  460. // Optional: wait until animation finishes
  461.  
  462. yield return new WaitForSeconds(0.3f);
  463.  
  464. isKicking = false;
  465.  
  466. }
  467.  
  468. void StartCrouch()
  469.  
  470. {
  471.  
  472. if (isCrouching) return;
  473.  
  474. isCrouching = true;
  475.  
  476. controller.height = crouchHeight;
  477.  
  478. controller.center = new Vector3(0, originalCenter.y - (originalHeight - crouchHeight) / 2f, 0);
  479.  
  480. targetCameraY = crouchCameraHeight;
  481.  
  482. }
  483.  
  484. void StopCrouch()
  485.  
  486. {
  487.  
  488. isCrouching = false;
  489.  
  490. controller.height = originalHeight;
  491.  
  492. controller.center = originalCenter;
  493.  
  494. targetCameraY = originalCameraY;
  495.  
  496. }
  497.  
  498. void UpdateModelPosition()
  499.  
  500. {
  501.  
  502. float modelY = modelYWhenStanding;
  503.  
  504. if (isSliding)
  505.  
  506. modelY = modelYWhenSliding;
  507.  
  508. else if (isCrouching)
  509.  
  510. modelY = modelYWhenCrouching;
  511.  
  512. // Set directly instead of Lerp when sliding
  513.  
  514. float targetY = isSliding ? modelY : Mathf.Lerp(playerModel.localPosition.y, modelY, Time.deltaTime * cameraSmoothSpeed);
  515.  
  516. Vector3 modelLocalPos = playerModel.localPosition;
  517.  
  518. modelLocalPos.y = targetY;
  519.  
  520. playerModel.localPosition = modelLocalPos;
  521.  
  522. }
  523.  
  524. void RotateUpperBodyToCamera()
  525.  
  526. {
  527.  
  528. if (upperBodyBone == null || playerCamera == null) return;
  529.  
  530. float pitch = playerCamera.localEulerAngles.x;
  531.  
  532. if (pitch > 180f) pitch -= 360f;
  533.  
  534. pitch = Mathf.Clamp(pitch, -upperBodyPitchLimit, upperBodyPitchLimit);
  535.  
  536. Quaternion targetRotation = Quaternion.Euler(pitch, 0f, 0f);
  537.  
  538. upperBodyBone.localRotation = Quaternion.Slerp(
  539.  
  540. upperBodyBone.localRotation,
  541.  
  542. targetRotation,
  543.  
  544. Time.deltaTime * upperBodyFollowSpeed
  545.  
  546. );
  547.  
  548. }
  549.  
  550. void OnDrawGizmosSelected()
  551.  
  552. {
  553.  
  554. if (controller == null) return;
  555.  
  556. Gizmos.color = Color.yellow;
  557.  
  558. float radius = controller.radius * 0.95f;
  559.  
  560. Vector3 bottom = transform.position + Vector3.up * crouchHeight;
  561.  
  562. Vector3 top = transform.position + Vector3.up * (originalHeight - 0.05f);
  563.  
  564. Gizmos.color = Color.red;
  565.  
  566. Gizmos.DrawRay(playerCamera.position, playerCamera.forward * kickRange);
  567.  
  568. Gizmos.DrawWireSphere(bottom, radius);
  569.  
  570. Gizmos.DrawWireSphere(top, radius);
  571.  
  572. Gizmos.DrawLine(bottom + Vector3.forward * radius, top + Vector3.forward * radius);
  573.  
  574. Gizmos.DrawLine(bottom - Vector3.forward * radius, top - Vector3.forward * radius);
  575.  
  576. Gizmos.DrawLine(bottom + Vector3.right * radius, top + Vector3.right * radius);
  577.  
  578. Gizmos.DrawLine(bottom - Vector3.right * radius, top - Vector3.right * radius);
  579.  
  580. }
  581.  
  582. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement