чё то чё то есть
This commit is contained in:
parent
f632508497
commit
f12b4aef0d
@ -1,24 +1,35 @@
|
||||
using _Project.Scripts.PlayerUtils;
|
||||
using UnityEngine;
|
||||
using _Project.Scripts.Utilities;
|
||||
|
||||
namespace _Project.Scripts
|
||||
namespace _Project.Scripts.PlayerUtils
|
||||
{
|
||||
public class Player : MonoSingleton<Player>
|
||||
{
|
||||
private PlayerMovement movement;
|
||||
public PlayerControls controls { get; set; }
|
||||
public PlayerControls Controls { get; private set; }
|
||||
|
||||
void Awake()
|
||||
public PlayerMovement Movement { get; private set; }
|
||||
public PlayerCamera CameraController { get; private set; }
|
||||
public PlayerCombat Combat { get; private set; }
|
||||
public PlayerSound Sound { get; private set; }
|
||||
public PlayerUI UI { get; private set; } // Новый модуль
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
movement = GetComponent<PlayerMovement>();
|
||||
controls = GetComponent<PlayerControls>();
|
||||
Controls = new PlayerControls();
|
||||
|
||||
Movement = GetComponent<PlayerMovement>();
|
||||
CameraController = GetComponent<PlayerCamera>();
|
||||
Combat = GetComponent<PlayerCombat>();
|
||||
Sound = GetComponent<PlayerSound>();
|
||||
UI = GetComponent<PlayerUI>(); // Инициализация
|
||||
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
Cursor.visible = false;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
private void OnEnable() => Controls.Player.Enable();
|
||||
private void OnDisable() => Controls.Player.Disable();
|
||||
}
|
||||
}
|
||||
118
Assets/_Project/Scripts/PlayerUtils/PlayerCamera.cs
Normal file
118
Assets/_Project/Scripts/PlayerUtils/PlayerCamera.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace _Project.Scripts.PlayerUtils
|
||||
{
|
||||
public class PlayerCamera : MonoBehaviour
|
||||
{
|
||||
[Header("Камера и Настройки")]
|
||||
[SerializeField] private Transform cameraPosition;
|
||||
[SerializeField] private float mouseSensitivity = 0.1f;
|
||||
[SerializeField] private float maxLookAngle = 80f;
|
||||
|
||||
[Header("Высота камеры")]
|
||||
[SerializeField] private float standingCameraY = 1.6f;
|
||||
[SerializeField] private float crouchingCameraY = 0.8f;
|
||||
[SerializeField] private float crouchTransitionSpeed = 15f;
|
||||
[SerializeField] private float slideCameraTiltAngle = 4f;
|
||||
|
||||
[Header("Тряска Камеры (Headbob)")]
|
||||
public bool enableHeadBob = true;
|
||||
[SerializeField] private float walkBobSpeed = 12f;
|
||||
[SerializeField] private float walkBobAmount = 0.04f;
|
||||
[SerializeField] private float sprintBobSpeed = 15f;
|
||||
[SerializeField] private float sprintBobAmount = 0.07f;
|
||||
[SerializeField] private float impactRecoverySpeed = 6f;
|
||||
|
||||
private PlayerControls controls;
|
||||
private PlayerMovement movement;
|
||||
|
||||
private float cameraPitch = 0f;
|
||||
private float yRotation = 0f;
|
||||
private float currentCameraTilt = 0f;
|
||||
private float baseCameraY;
|
||||
|
||||
private float bobTimer = 0f;
|
||||
private Vector3 bobOffset = Vector3.zero;
|
||||
private float currentImpactOffset = 0f;
|
||||
private bool stepTaken = false;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
controls = Player.Instance.Controls;
|
||||
movement = Player.Instance.Movement;
|
||||
|
||||
mouseSensitivity = PlayerPrefs.GetFloat("MouseSensitivity", mouseSensitivity);
|
||||
baseCameraY = standingCameraY;
|
||||
yRotation = transform.eulerAngles.y;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
HandleMouseLook();
|
||||
HandleCameraAndBobbing();
|
||||
}
|
||||
|
||||
private void HandleMouseLook()
|
||||
{
|
||||
Vector2 lookInput = controls.Player.Look.ReadValue<Vector2>();
|
||||
|
||||
cameraPitch -= lookInput.y * mouseSensitivity;
|
||||
cameraPitch = Mathf.Clamp(cameraPitch, -maxLookAngle, maxLookAngle);
|
||||
|
||||
float targetTilt = movement.IsSliding ? -slideCameraTiltAngle : 0f;
|
||||
currentCameraTilt = Mathf.Lerp(currentCameraTilt, targetTilt, Time.deltaTime * 10f);
|
||||
|
||||
cameraPosition.localRotation = Quaternion.Euler(cameraPitch, 0f, currentCameraTilt);
|
||||
|
||||
yRotation += lookInput.x * mouseSensitivity;
|
||||
transform.rotation = Quaternion.Euler(0f, yRotation, 0f);
|
||||
}
|
||||
|
||||
private void HandleCameraAndBobbing()
|
||||
{
|
||||
bool isLowered = movement.IsCrouching || movement.IsSliding;
|
||||
float targetCamY = isLowered ? crouchingCameraY : standingCameraY;
|
||||
baseCameraY = Mathf.Lerp(baseCameraY, targetCamY, Time.deltaTime * crouchTransitionSpeed);
|
||||
|
||||
bool isMoving = movement.MoveInput.sqrMagnitude > 0.01f && movement.IsGrounded && !movement.IsSliding;
|
||||
|
||||
if (isMoving && enableHeadBob)
|
||||
{
|
||||
float speed = movement.IsSprinting ? sprintBobSpeed : walkBobSpeed;
|
||||
float amount = movement.IsSprinting ? sprintBobAmount : walkBobAmount;
|
||||
|
||||
bobTimer += Time.deltaTime * speed;
|
||||
bobOffset.x = Mathf.Cos(bobTimer * 0.5f) * amount;
|
||||
bobOffset.y = Mathf.Sin(bobTimer) * amount;
|
||||
|
||||
if (Mathf.Sin(bobTimer) <= -0.9f && !stepTaken)
|
||||
{
|
||||
// ВЫЗОВ ЗВУКА ИЗ НОВОГО МОДУЛЯ
|
||||
Player.Instance.Sound.PlayFootstep(movement.IsSprinting);
|
||||
stepTaken = true;
|
||||
}
|
||||
else if (Mathf.Sin(bobTimer) > -0.2f) stepTaken = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bobTimer = 0f;
|
||||
stepTaken = false;
|
||||
bobOffset = Vector3.Lerp(bobOffset, Vector3.zero, Time.deltaTime * 10f);
|
||||
}
|
||||
|
||||
currentImpactOffset = Mathf.Lerp(currentImpactOffset, 0f, Time.deltaTime * impactRecoverySpeed);
|
||||
cameraPosition.localPosition = new Vector3(bobOffset.x, baseCameraY + bobOffset.y - currentImpactOffset, 0f);
|
||||
}
|
||||
|
||||
public void ApplyRecoil(float amount)
|
||||
{
|
||||
cameraPitch -= amount;
|
||||
}
|
||||
|
||||
public void TriggerJumpImpact()
|
||||
{
|
||||
if (enableHeadBob) currentImpactOffset = 0.1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/_Project/Scripts/PlayerUtils/PlayerCamera.cs.meta
Normal file
3
Assets/_Project/Scripts/PlayerUtils/PlayerCamera.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbe0b1999f6642cdb1f20dadcd7c0934
|
||||
timeCreated: 1790100214
|
||||
77
Assets/_Project/Scripts/PlayerUtils/PlayerCombat.cs
Normal file
77
Assets/_Project/Scripts/PlayerUtils/PlayerCombat.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace _Project.Scripts.PlayerUtils
|
||||
{
|
||||
public class PlayerCombat : MonoBehaviour
|
||||
{
|
||||
[Header("Оружие и Стрельба (Hitscan)")]
|
||||
[SerializeField] private float damage = 25f;
|
||||
[SerializeField] private float fireRate = 0.12f;
|
||||
[SerializeField] private float weaponRange = 100f;
|
||||
[SerializeField] private LayerMask hitLayers = ~0;
|
||||
[SerializeField] private bool isAutomatic = true;
|
||||
[SerializeField] private float recoilKick = 1.2f;
|
||||
|
||||
[Header("Эффекты (без звука)")]
|
||||
[SerializeField] private ParticleSystem muzzleFlash;
|
||||
[SerializeField] private GameObject impactPrefab;
|
||||
|
||||
[Header("Ссылки")]
|
||||
[SerializeField] private Transform cameraPosition;
|
||||
|
||||
private PlayerControls controls;
|
||||
private float shootTimer = 0f;
|
||||
private bool isShootingInput = false;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
controls = Player.Instance.Controls;
|
||||
|
||||
controls.Player.Attack.started += _ => isShootingInput = true;
|
||||
controls.Player.Attack.canceled += _ => isShootingInput = false;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (shootTimer > 0f) shootTimer -= Time.deltaTime;
|
||||
|
||||
bool shootPressed = isShootingInput || (Mouse.current != null && (isAutomatic ? Mouse.current.leftButton.isPressed : Mouse.current.leftButton.wasPressedThisFrame));
|
||||
|
||||
if (shootPressed && shootTimer <= 0f)
|
||||
{
|
||||
Shoot();
|
||||
}
|
||||
}
|
||||
|
||||
private void Shoot()
|
||||
{
|
||||
shootTimer = fireRate;
|
||||
|
||||
// ВЫЗОВ ЗВУКА ИЗ НОВОГО МОДУЛЯ
|
||||
Player.Instance.Sound.PlayShoot();
|
||||
|
||||
if (muzzleFlash != null) muzzleFlash.Play();
|
||||
Player.Instance.CameraController.ApplyRecoil(recoilKick);
|
||||
|
||||
Ray ray = new Ray(cameraPosition.position, cameraPosition.forward);
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, weaponRange, hitLayers, QueryTriggerInteraction.Ignore))
|
||||
{
|
||||
if (hit.collider.TryGetComponent<IDamageable>(out var damageable))
|
||||
{
|
||||
damageable.TakeDamage(damage);
|
||||
}
|
||||
else if (hit.rigidbody != null)
|
||||
{
|
||||
hit.rigidbody.AddForceAtPosition(-hit.normal * (damage * 10f), hit.point, ForceMode.Impulse);
|
||||
}
|
||||
|
||||
if (impactPrefab != null)
|
||||
{
|
||||
GameObject impact = Instantiate(impactPrefab, hit.point + (hit.normal * 0.001f), Quaternion.LookRotation(hit.normal));
|
||||
Destroy(impact, 3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/_Project/Scripts/PlayerUtils/PlayerCombat.cs.meta
Normal file
3
Assets/_Project/Scripts/PlayerUtils/PlayerCombat.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9d6178191654e72a147db739b22275f
|
||||
timeCreated: 1790100245
|
||||
@ -1,41 +1,27 @@
|
||||
using _Project.Scripts.Utilities;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace _Project.Scripts.PlayerUtils
|
||||
{
|
||||
public class PlayerMovement : MonoSingleton<PlayerMovement>
|
||||
[RequireComponent(typeof(Rigidbody), typeof(CapsuleCollider))]
|
||||
public class PlayerMovement : MonoBehaviour
|
||||
{
|
||||
[Header("Камера и Мышь")]
|
||||
[SerializeField] private Transform cameraPosition;
|
||||
[SerializeField] private float mouseSensitivity = 0.1f;
|
||||
[SerializeField] private float maxLookAngle = 80f;
|
||||
|
||||
[Header("Скорости передвижения (м/с)")]
|
||||
[SerializeField] private float moveSpeed = 6.5f; // Обычный бег (~250 u/s)
|
||||
[SerializeField] private float sprintSpeed = 9.5f; // Спринт (~360 u/s)
|
||||
[SerializeField] private float moveSpeed = 6.5f;
|
||||
[SerializeField] private float sprintSpeed = 9.5f;
|
||||
[SerializeField] private float crouchSpeed = 3f;
|
||||
|
||||
[Header("Параметры Подката (Slide)")]
|
||||
[Tooltip("Начальная взрывная скорость подката")]
|
||||
[SerializeField] private float slideInitialSpeed = 15f; // (~580 u/s)
|
||||
[Tooltip("Длительность скольжения в секундах")]
|
||||
[SerializeField] private float slideInitialSpeed = 15f;
|
||||
[SerializeField] private float slideDuration = 0.85f;
|
||||
[Tooltip("Трение коленей при подкате")]
|
||||
[SerializeField] private float slideFriction = 2.8f;
|
||||
[Tooltip("Наклон камеры набок при подкате (градусы)")]
|
||||
[SerializeField] private float slideCameraTiltAngle = 4f;
|
||||
[SerializeField] private float slideCooldown = 0.35f;
|
||||
|
||||
[Header("Физика CS / Source (Bunnyhop & Strafe)")]
|
||||
[Tooltip("Трение на земле (гасит скорость, если не успели прыгнуть вовремя)")]
|
||||
[SerializeField] private float groundFriction = 5f;
|
||||
[Tooltip("Ускорение на земле")]
|
||||
[SerializeField] private float groundAcceleration = 10f;
|
||||
[Tooltip("Сила набора скорости в воздухе при стрейфах (sv_airaccelerate)")]
|
||||
[SerializeField] private float airAcceleration = 80f;
|
||||
[Tooltip("Лимит добавления скорости в воздухе")]
|
||||
[SerializeField] private float airCap = 2.0f;
|
||||
[Tooltip("Показывать спидометр на экране")]
|
||||
[SerializeField] private bool showSpeedometer = true;
|
||||
|
||||
[Header("Гравитация и Прыжок")]
|
||||
@ -44,64 +30,220 @@ namespace _Project.Scripts.PlayerUtils
|
||||
[SerializeField] private float fallMultiplier = 1.8f;
|
||||
[SerializeField] private LayerMask groundLayer;
|
||||
[SerializeField] private float groundCheckDistance = 0.12f;
|
||||
[Tooltip("Буфер прыжка (время поблажки для колесика мыши)")]
|
||||
[SerializeField] private float jumpBufferTime = 0.12f;
|
||||
|
||||
[Header("Параметры приседания")]
|
||||
[Header("Коллайдер (Приседание)")]
|
||||
[SerializeField] private float standingHeight = 2f;
|
||||
[SerializeField] private float crouchingHeight = 1.05f;
|
||||
[SerializeField] private float standingCameraY = 1.6f;
|
||||
[SerializeField] private float crouchingCameraY = 0.8f;
|
||||
[SerializeField] private float crouchTransitionSpeed = 15f;
|
||||
|
||||
private Rigidbody rb;
|
||||
private CapsuleCollider col;
|
||||
private PlayerControls controls;
|
||||
|
||||
private Vector2 moveInput;
|
||||
private Vector2 lookInput;
|
||||
public bool IsGrounded { get; private set; }
|
||||
public bool IsSprinting { get; private set; }
|
||||
public bool IsCrouching { get; private set; }
|
||||
public bool IsSliding { get; private set; }
|
||||
public Vector2 MoveInput { get; private set; }
|
||||
public float CurrentSpeed => horizontalVelocity.magnitude;
|
||||
private bool wasGrounded;
|
||||
private float jumpBufferTimer = 0f;
|
||||
private Vector3 horizontalVelocity = Vector3.zero;
|
||||
private float verticalVelocity = 0f;
|
||||
|
||||
private bool isGrounded;
|
||||
private bool wasGrounded;
|
||||
private bool isSprinting = false;
|
||||
private bool isCrouching = false;
|
||||
private float jumpBufferTimer = 0f;
|
||||
|
||||
// Подкат
|
||||
private bool isSliding = false;
|
||||
private float slideTimer = 0f;
|
||||
private float slideCurrentSpeed = 0f;
|
||||
private Vector3 slideDirection = Vector3.zero;
|
||||
private float slideCooldownTimer = 0f;
|
||||
|
||||
private PlayerControls controls;
|
||||
|
||||
void Awake()
|
||||
private void Start()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
rb = GetComponent<Rigidbody>();
|
||||
col = GetComponent<CapsuleCollider>();
|
||||
mouseSensitivity = PlayerPrefs.GetFloat("MouseSensitivity", mouseSensitivity);
|
||||
|
||||
rb.useGravity = false;
|
||||
rb.freezeRotation = true;
|
||||
rb.interpolation = RigidbodyInterpolation.None;
|
||||
|
||||
controls = new PlayerControls();
|
||||
controls = Player.Instance.Controls;
|
||||
|
||||
controls = Player.Instance.controls;
|
||||
// Спринт
|
||||
controls.Player.Sprint.started += ctx => isSprinting = true;
|
||||
controls.Player.Sprint.canceled += ctx => isSprinting = false;
|
||||
controls.Player.Sprint.started += _ => IsSprinting = true;
|
||||
controls.Player.Sprint.canceled += _ => IsSprinting = false;
|
||||
|
||||
/* // Присед и Подкат
|
||||
controls.Player.Crouch.started += ctx => OnCrouchPressed();
|
||||
controls.Player.Crouch.canceled += ctx => OnCrouchReleased();
|
||||
controls.Player.Crouch.started += _ => OnCrouchPressed();
|
||||
controls.Player.Crouch.canceled += _ => OnCrouchReleased();
|
||||
|
||||
// Прыжок на Пробел (через буфер)
|
||||
controls.Player.Jump.performed += ctx => QueueJump();
|
||||
*/
|
||||
controls.Player.Jump.performed += _ => QueueJump();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
MoveInput = controls.Player.Move.ReadValue<Vector2>();
|
||||
|
||||
if (jumpBufferTimer > 0f) jumpBufferTimer -= Time.deltaTime;
|
||||
if (slideCooldownTimer > 0f) slideCooldownTimer -= Time.deltaTime;
|
||||
|
||||
if (Mouse.current != null && Mathf.Abs(Mouse.current.scroll.y.ReadValue()) > 0.1f)
|
||||
QueueJump();
|
||||
|
||||
HandleColliderHeight();
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
CheckGrounded();
|
||||
CalculateCustomGravity();
|
||||
|
||||
if (jumpBufferTimer > 0f && IsGrounded)
|
||||
ExecuteJump();
|
||||
|
||||
ApplyMovement();
|
||||
|
||||
rb.linearVelocity = new Vector3(horizontalVelocity.x, verticalVelocity, horizontalVelocity.z);
|
||||
wasGrounded = IsGrounded;
|
||||
}
|
||||
|
||||
private void HandleColliderHeight()
|
||||
{
|
||||
bool isLowered = IsCrouching || IsSliding;
|
||||
float targetHeight = isLowered ? crouchingHeight : standingHeight;
|
||||
col.height = Mathf.Lerp(col.height, targetHeight, Time.deltaTime * crouchTransitionSpeed);
|
||||
col.center = new Vector3(col.center.x, col.height * 0.5f, col.center.z);
|
||||
}
|
||||
|
||||
private void QueueJump() => jumpBufferTimer = jumpBufferTime;
|
||||
|
||||
private void ExecuteJump()
|
||||
{
|
||||
if (IsSliding)
|
||||
{
|
||||
horizontalVelocity = slideDirection * slideCurrentSpeed;
|
||||
StopSlide();
|
||||
}
|
||||
|
||||
verticalVelocity = Mathf.Sqrt(jumpHeight * -2f * gravity);
|
||||
jumpBufferTimer = 0f;
|
||||
|
||||
Player.Instance.CameraController.TriggerJumpImpact();
|
||||
|
||||
// ВЫЗОВ ЗВУКА ИЗ НОВОГО МОДУЛЯ
|
||||
Player.Instance.Sound.PlayJump();
|
||||
}
|
||||
|
||||
private void ApplyMovement()
|
||||
{
|
||||
if (IsSliding)
|
||||
{
|
||||
slideCurrentSpeed = Mathf.Lerp(slideCurrentSpeed, crouchSpeed, Time.fixedDeltaTime * slideFriction);
|
||||
slideTimer -= Time.fixedDeltaTime;
|
||||
|
||||
Vector3 steerDir = (transform.forward * MoveInput.y + transform.right * MoveInput.x).normalized;
|
||||
if (steerDir.sqrMagnitude > 0.01f)
|
||||
slideDirection = Vector3.Slerp(slideDirection, steerDir, Time.fixedDeltaTime * 2.5f);
|
||||
|
||||
horizontalVelocity = slideDirection * slideCurrentSpeed;
|
||||
|
||||
if (slideTimer <= 0f || slideCurrentSpeed <= crouchSpeed + 0.5f)
|
||||
{
|
||||
StopSlide();
|
||||
IsCrouching = controls.Player.Crouch.IsPressed();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 wishDir = (transform.forward * MoveInput.y + transform.right * MoveInput.x);
|
||||
wishDir.y = 0f;
|
||||
wishDir.Normalize();
|
||||
|
||||
float targetSpeed = IsCrouching ? crouchSpeed : (IsSprinting ? sprintSpeed : moveSpeed);
|
||||
|
||||
if (IsGrounded)
|
||||
{
|
||||
if (jumpBufferTimer <= 0f) ApplyGroundFriction();
|
||||
Accelerate(wishDir, targetSpeed, groundAcceleration);
|
||||
}
|
||||
else
|
||||
{
|
||||
AirAccelerate(wishDir, targetSpeed, airAcceleration, airCap);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyGroundFriction()
|
||||
{
|
||||
float speed = horizontalVelocity.magnitude;
|
||||
if (speed < 0.0001f) { horizontalVelocity = Vector3.zero; return; }
|
||||
float drop = speed * groundFriction * Time.fixedDeltaTime;
|
||||
horizontalVelocity *= (Mathf.Max(speed - drop, 0f) / speed);
|
||||
}
|
||||
|
||||
private void Accelerate(Vector3 wishDir, float wishSpeed, float accel)
|
||||
{
|
||||
float currentSpeed = Vector3.Dot(horizontalVelocity, wishDir);
|
||||
float addSpeed = Mathf.Max(wishSpeed - currentSpeed, 0f);
|
||||
horizontalVelocity += wishDir * Mathf.Min(accel * wishSpeed * Time.fixedDeltaTime, addSpeed);
|
||||
}
|
||||
|
||||
private void AirAccelerate(Vector3 wishDir, float wishSpeed, float accel, float cap)
|
||||
{
|
||||
float currentSpeed = Vector3.Dot(horizontalVelocity, wishDir);
|
||||
float addSpeed = Mathf.Max(Mathf.Min(wishSpeed, cap) - currentSpeed, 0f);
|
||||
horizontalVelocity += wishDir * Mathf.Min(accel * wishSpeed * Time.fixedDeltaTime, addSpeed);
|
||||
}
|
||||
|
||||
private void CheckGrounded()
|
||||
{
|
||||
float checkRadius = col.radius * 0.85f;
|
||||
float bottomOffset = (col.height * 0.5f) - checkRadius;
|
||||
Vector3 rayOrigin = transform.position + col.center - (Vector3.up * bottomOffset) + (Vector3.up * 0.05f);
|
||||
|
||||
IsGrounded = Physics.SphereCast(rayOrigin, checkRadius, Vector3.down, out _, groundCheckDistance + 0.05f, groundLayer, QueryTriggerInteraction.Ignore);
|
||||
|
||||
if (!wasGrounded && IsGrounded)
|
||||
{
|
||||
// ВЫЗОВ ЗВУКА ИЗ НОВОГО МОДУЛЯ
|
||||
Player.Instance.Sound.PlayLand();
|
||||
}
|
||||
|
||||
if (IsGrounded && jumpBufferTimer <= 0f && rb.linearVelocity.magnitude > 0.01f && horizontalVelocity == Vector3.zero)
|
||||
horizontalVelocity = new Vector3(rb.linearVelocity.x, 0f, rb.linearVelocity.z);
|
||||
}
|
||||
|
||||
private void CalculateCustomGravity()
|
||||
{
|
||||
if (IsGrounded && verticalVelocity < 0f) verticalVelocity = -2f;
|
||||
else verticalVelocity += ((verticalVelocity < 0f) ? (gravity * fallMultiplier) : gravity) * Time.fixedDeltaTime;
|
||||
}
|
||||
|
||||
private void OnCrouchPressed()
|
||||
{
|
||||
if (IsSprinting && IsGrounded && MoveInput.y > 0.2f && slideCooldownTimer <= 0f) StartSlide();
|
||||
else IsCrouching = true;
|
||||
}
|
||||
|
||||
private void OnCrouchReleased()
|
||||
{
|
||||
IsCrouching = false;
|
||||
if (IsSliding) StopSlide();
|
||||
}
|
||||
|
||||
private void StartSlide()
|
||||
{
|
||||
IsSliding = true;
|
||||
slideTimer = slideDuration;
|
||||
slideCurrentSpeed = slideInitialSpeed;
|
||||
slideDirection = (transform.forward * MoveInput.y + transform.right * MoveInput.x).normalized;
|
||||
if (slideDirection.sqrMagnitude < 0.01f) slideDirection = transform.forward;
|
||||
|
||||
// ВЫЗОВ ЗВУКА ИЗ НОВОГО МОДУЛЯ
|
||||
Player.Instance.Sound.PlaySlide();
|
||||
}
|
||||
|
||||
private void StopSlide()
|
||||
{
|
||||
IsSliding = false;
|
||||
slideCooldownTimer = slideCooldown;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
61
Assets/_Project/Scripts/PlayerUtils/PlayerSound.cs
Normal file
61
Assets/_Project/Scripts/PlayerUtils/PlayerSound.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace _Project.Scripts.PlayerUtils
|
||||
{
|
||||
[RequireComponent(typeof(AudioSource))]
|
||||
public class PlayerSound : MonoBehaviour
|
||||
{
|
||||
[Header("Настройки AudioSource")]
|
||||
[SerializeField] private AudioSource audioSource;
|
||||
|
||||
[Header("Звуки Передвижения")]
|
||||
[SerializeField] private AudioClip[] footstepSounds;
|
||||
[SerializeField] private AudioClip jumpSound;
|
||||
[SerializeField] private AudioClip landSound;
|
||||
[SerializeField] private AudioClip slideSound;
|
||||
|
||||
[Header("Звуки Оружия")]
|
||||
[SerializeField] private AudioClip shootSound;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
// Автоматически подцепит AudioSource при добавлении скрипта на объект
|
||||
audioSource = GetComponent<AudioSource>();
|
||||
}
|
||||
|
||||
public void PlayFootstep(bool isSprinting)
|
||||
{
|
||||
if (footstepSounds == null || footstepSounds.Length == 0) return;
|
||||
|
||||
int randomIndex = Random.Range(0, footstepSounds.Length);
|
||||
|
||||
// Немного меняем высоту звука для разнообразия
|
||||
audioSource.pitch = Random.Range(0.9f, 1.1f);
|
||||
|
||||
float volume = isSprinting ? 0.6f : 0.4f;
|
||||
audioSource.PlayOneShot(footstepSounds[randomIndex], volume);
|
||||
|
||||
audioSource.pitch = 1f; // Сбрасываем питч обратно
|
||||
}
|
||||
|
||||
public void PlayJump()
|
||||
{
|
||||
if (jumpSound != null) audioSource.PlayOneShot(jumpSound, 0.7f);
|
||||
}
|
||||
|
||||
public void PlayLand()
|
||||
{
|
||||
if (landSound != null) audioSource.PlayOneShot(landSound, 0.5f);
|
||||
}
|
||||
|
||||
public void PlaySlide()
|
||||
{
|
||||
if (slideSound != null) audioSource.PlayOneShot(slideSound, 0.7f);
|
||||
}
|
||||
|
||||
public void PlayShoot()
|
||||
{
|
||||
if (shootSound != null) audioSource.PlayOneShot(shootSound, 0.8f);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/_Project/Scripts/PlayerUtils/PlayerSound.cs.meta
Normal file
3
Assets/_Project/Scripts/PlayerUtils/PlayerSound.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 995d210808ca417ca08ca58fab7f8624
|
||||
timeCreated: 1790100334
|
||||
53
Assets/_Project/Scripts/PlayerUtils/PlayerUI.cs
Normal file
53
Assets/_Project/Scripts/PlayerUtils/PlayerUI.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace _Project.Scripts.PlayerUtils
|
||||
{
|
||||
public class PlayerUI : MonoBehaviour
|
||||
{
|
||||
[Header("Настройки Интерфейса")]
|
||||
[SerializeField] private bool showSpeedometer = true;
|
||||
|
||||
private PlayerMovement movement;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Берем ссылку на компонент передвижения через фасад Player
|
||||
movement = Player.Instance.Movement;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (!showSpeedometer || movement == null) return;
|
||||
|
||||
// Читаем публичное свойство скорости (мы добавим его ниже)
|
||||
float speed = movement.CurrentSpeed;
|
||||
float csUnits = speed * 38.5f;
|
||||
|
||||
GUIStyle style = new GUIStyle
|
||||
{
|
||||
fontSize = 24,
|
||||
fontStyle = FontStyle.Bold
|
||||
};
|
||||
|
||||
string state = "";
|
||||
|
||||
// Настраиваем цвет и текст состояния
|
||||
if (movement.IsSliding)
|
||||
{
|
||||
style.normal.textColor = Color.yellow;
|
||||
state = " [SLIDE]";
|
||||
}
|
||||
else if (!movement.IsGrounded)
|
||||
{
|
||||
style.normal.textColor = Color.green;
|
||||
state = " [AIR]";
|
||||
}
|
||||
else
|
||||
{
|
||||
style.normal.textColor = Color.white;
|
||||
}
|
||||
|
||||
GUI.Label(new Rect(30, 30, 500, 50), $"Speed: {speed:F1} m/s ({csUnits:F0} u/s){state}", style);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/_Project/Scripts/PlayerUtils/PlayerUI.cs.meta
Normal file
3
Assets/_Project/Scripts/PlayerUtils/PlayerUI.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8184cc49f30946f4802bbf1bbe841e2f
|
||||
timeCreated: 1790100443
|
||||
Loading…
Reference in New Issue
Block a user