/
Lexan97
/
Cowbeat
Обзор
Документация
Войти
/
Lexan97
/
Cowbeat
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
Assets/Scripts/Player/PlayerCombat.cs
332 строки
11 KB
Lexa97
Final Commit gor present
26 май 2026, 23:40
26 май 2026, 23:40
70e9bdb
Код
Авторство
О чём код?
using UnityEngine; using System.Collections.Generic; using Unity.Cinemachine; // Используем новую Cinemachine public class PlayerCombat : MonoBehaviour { public static float globalDamageBonus = 0f; [Header("Combat Settings")] [SerializeField] private float combatEnterRadius = 10f; [SerializeField] private float combatExitDelay = 3f; [SerializeField] private float attackInputWindow = 1f; [Header("Урон")] [Range(0f, 0.5f)] [SerializeField] private float damageVariance = 0.15f; [Header("References")] [SerializeField] private PlayerMovement playerMovement; [SerializeField] private Animator animator; [SerializeField] private GameObject cinemachineObject; [SerializeField] private Transform attackPoint; [SerializeField] private LayerMask enemyLayer; [SerializeField] private AttackData[] comboChain; [Header("Targeting")] [SerializeField] private float maxTargetDistance = 5f; [Header("Cancel Windows")] [SerializeField] private float jumpCancelDelay = 0.3f; [SerializeField] private float moveCancelDelay = 0.6f; public float JumpCancelDelay => jumpCancelDelay; public float MoveCancelDelay => moveCancelDelay; private int currentComboStep = 0; private float comboWindowEnd = 0f; private bool isAttacking = false; private bool isInCombatMode = false; private float lastCombatActionTime = 0f; private bool isHitStopping = false; // ИСПРАВЛЕНИЕ: Меняем устаревший CinemachineFreeLook на актуальный CinemachineCamera private CinemachineCamera cinemachine; public bool IsAttacking => isAttacking; public bool IsInCombatMode => isInCombatMode; private int executingAttackIndex = 0; public float attackStartTime; private List<EnemyHealth> hitEnemiesInCurrentAttack = new List<EnemyHealth>(); private PlayerStats playerStats; void Start() { if (playerMovement == null) playerMovement = GetComponent<PlayerMovement>(); if (animator == null) animator = GetComponent<Animator>(); playerStats = GetComponent<PlayerStats>(); if (attackPoint == null) { GameObject attackObj = new GameObject("AttackPoint"); attackPoint = attackObj.transform; attackPoint.SetParent(transform); attackPoint.localPosition = new Vector3(0, 1f, 0.7f); } if (cinemachineObject != null) { // ИСПРАВЛЕНИЕ: Получаем новый актуальный компонент камеры cinemachine = cinemachineObject.GetComponent<CinemachineCamera>(); } } void Update() { if (playerStats != null && playerStats.isDead) return; HandleCombatMode(); HandleAttackInput(); if (isAttacking && !animator.GetBool("IsAttacking")) isAttacking = false; } private void HandleCombatMode() { Collider[] enemies = Physics.OverlapSphere(transform.position, combatEnterRadius, enemyLayer); bool enemyNearby = enemies.Length > 0; if (enemyNearby || isAttacking) { lastCombatActionTime = Time.time; if (!isInCombatMode) { isInCombatMode = true; animator.SetBool("isCombatMode", true); } } else if (Time.time - lastCombatActionTime > combatExitDelay) { if (isInCombatMode) { isInCombatMode = false; animator.SetBool("isCombatMode", false); } } } private void SetCombatMode(bool state) { isInCombatMode = state; animator.SetBool("isCombatMode", state); } private void HandleAttackInput() { if (ShopManager.IsShopOpen) return; AimController aim = GetComponent<AimController>(); if (aim != null && aim.isAiming) return; if (playerMovement != null && playerMovement.isRolling) return; bool isJumping = animator.GetBool("isJumping"); if (Input.GetMouseButtonDown(0) && !isJumping) { TryStartAttack(); } if (Time.time > comboWindowEnd) { currentComboStep = 0; } } private void TryStartAttack() { if (isAttacking) return; hitEnemiesInCurrentAttack.Clear(); StartCoroutine(PunchFOV()); SnapToTarget(); animator.SetBool("IsAttacking", true); isAttacking = true; animator.SetInteger("ComboStep", currentComboStep); animator.SetTrigger("Attack"); attackStartTime = Time.time; comboWindowEnd = Time.time + attackInputWindow; executingAttackIndex = currentComboStep; currentComboStep = (currentComboStep + 1) % 4; } public void AttackEnd() { animator.SetBool("IsAttacking", false); isAttacking = false; } public void AttackHit() { if (comboChain == null || comboChain.Length == 0) return; AttackData currentAttack = comboChain[executingAttackIndex]; bool shouldFlyLeft = (executingAttackIndex == 0 || executingAttackIndex == 2); Collider[] hitColliders = Physics.OverlapSphere(attackPoint.position, currentAttack.searchRadius, enemyLayer); foreach (Collider enemyCollider in hitColliders) { EnemyHealth enemyHealth = enemyCollider.GetComponentInParent<EnemyHealth>(); if (enemyHealth != null && !hitEnemiesInCurrentAttack.Contains(enemyHealth)) { bool isFinal = (executingAttackIndex == 3); float baseDamage = currentAttack.damage + globalDamageBonus; float minDmg = baseDamage * (1f - damageVariance); float maxDmg = baseDamage * (1f + damageVariance); float randomizedDamage = Mathf.Round(Random.Range(minDmg, maxDmg)); enemyHealth.TakeDamage(randomizedDamage, shouldFlyLeft, isFinal); Vector3 knockbackDir = (enemyCollider.transform.position - transform.position).normalized; float currentKnockback = isFinal ? 10f : 5f; enemyHealth.ApplyKnockback(knockbackDir, currentKnockback); hitEnemiesInCurrentAttack.Add(enemyHealth); StartCoroutine(HitStop(isFinal ? 0.08f : 0.04f)); } } } private void OnDrawGizmosSelected() { if (attackPoint == null) return; Gizmos.color = Color.red; float radius = (comboChain != null && comboChain.Length > 0) ? comboChain[0].searchRadius : 1.5f; Gizmos.DrawWireSphere(attackPoint.position, radius); } private void SnapToTarget() { Collider[] potentialTargets = Physics.OverlapSphere(transform.position, maxTargetDistance, enemyLayer); Transform closestEnemy = null; float closestDistance = Mathf.Infinity; foreach (var collider in potentialTargets) { Vector3 directionToEnemy = (collider.transform.position - transform.position).normalized; directionToEnemy.y = 0; float angle = Vector3.Angle(transform.forward, directionToEnemy); if (angle <= 60f) { float distance = Vector3.Distance(transform.position, collider.transform.position); if (distance < closestDistance) { closestDistance = distance; closestEnemy = collider.transform; } } } if (closestEnemy != null) { MakeSnap(closestEnemy); } } private void MakeSnap(Transform closestEnemy) { Vector3 direction = (closestEnemy.position - transform.position).normalized; direction.y = 0; transform.rotation = Quaternion.LookRotation(direction); Vector3 targetPos = closestEnemy.position - direction * 1.2f; targetPos.y = transform.position.y; StartCoroutine(LungeTowardsTarget(targetPos)); if (cinemachine != null) StartCoroutine(RotateCameraToTarget(direction)); } public void CancelAttack() { if (isAttacking) { isAttacking = false; animator.SetBool("IsAttacking", false); } } private System.Collections.IEnumerator PunchFOV() { if (cinemachine == null) yield break; float defaultFOV = cinemachine.Lens.FieldOfView; float targetFOV = defaultFOV - 5f; float elapsed = 0; while (elapsed < 0.05f) { cinemachine.Lens.FieldOfView = Mathf.Lerp(defaultFOV, targetFOV, elapsed / 0.05f); elapsed += Time.unscaledDeltaTime; yield return null; } elapsed = 0; while (elapsed < 0.2f) { cinemachine.Lens.FieldOfView = Mathf.Lerp(targetFOV, defaultFOV, elapsed / 0.2f); elapsed += Time.unscaledDeltaTime; yield return null; } cinemachine.Lens.FieldOfView = defaultFOV; } private System.Collections.IEnumerator HitStop(float duration) { if (isHitStopping) yield break; isHitStopping = true; Time.timeScale = 0f; yield return new WaitForSecondsRealtime(duration); Time.timeScale = 1f; isHitStopping = false; } private System.Collections.IEnumerator LungeTowardsTarget(Vector3 targetPos) { float time = 0; float duration = 0.2f; Vector3 startPos = transform.position; CharacterController controller = GetComponent<CharacterController>(); if (controller == null) yield break; while (time < duration) { if (!controller.enabled) yield break; Vector3 currentTargetPos = Vector3.Lerp(startPos, targetPos, time / duration); Vector3 moveDiff = currentTargetPos - transform.position; moveDiff.y = 0; controller.Move(moveDiff); time += Time.deltaTime; yield return null; } } private System.Collections.IEnumerator RotateCameraToTarget(Vector3 direction) { if (cinemachine == null) yield break; float targetRotation = Quaternion.LookRotation(direction).eulerAngles.y; yield return null; } public static void AddDamage(float amount) { globalDamageBonus += amount; Debug.Log($"Бонус урона ближнего боя: +{globalDamageBonus}"); } }