2026-01-29 06:58:38 +00:00
|
|
|
|
using UnityEngine;
|
2026-01-30 07:45:11 +00:00
|
|
|
|
using System.Collections;
|
2026-02-06 04:20:12 +00:00
|
|
|
|
using System.Collections.Generic;
|
2026-01-29 06:58:38 +00:00
|
|
|
|
|
|
|
|
|
|
public class PlayerAttack : MonoBehaviour
|
|
|
|
|
|
{
|
2026-02-06 04:20:12 +00:00
|
|
|
|
[Header("--- 활 설정 ---")]
|
2026-02-06 05:32:48 +00:00
|
|
|
|
[SerializeField] private GameObject arrowPrefab;
|
|
|
|
|
|
[SerializeField] private Transform firePoint;
|
|
|
|
|
|
[SerializeField] private PlayerAnimator pAnim;
|
2026-02-06 04:20:12 +00:00
|
|
|
|
|
|
|
|
|
|
[Header("--- 일반 공격 (좌클릭) ---")]
|
|
|
|
|
|
[SerializeField] private float normalDamage = 10f;
|
|
|
|
|
|
[SerializeField] private float normalRange = 15f;
|
|
|
|
|
|
[SerializeField] private float normalSpeed = 20f;
|
|
|
|
|
|
[SerializeField] private float attackCooldown = 0.5f;
|
|
|
|
|
|
|
|
|
|
|
|
[Header("--- 차징 공격 (우클릭) ---")]
|
|
|
|
|
|
[SerializeField] private float maxChargeTime = 2.0f;
|
|
|
|
|
|
|
|
|
|
|
|
[System.Serializable]
|
|
|
|
|
|
public struct ChargeStage
|
|
|
|
|
|
{
|
|
|
|
|
|
public float chargeTime;
|
|
|
|
|
|
public float damageMult;
|
|
|
|
|
|
public float rangeMult;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[SerializeField] private List<ChargeStage> chargeStages;
|
2026-02-02 15:02:12 +00:00
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
[Header("--- 🎯 에임 보정 설정 ---")]
|
|
|
|
|
|
[SerializeField] private bool enableAutoAim = true; // 자동 조준 켜기/끄기
|
|
|
|
|
|
[SerializeField] private float autoAimRange = 15f; // 자동 조준 감지 범위
|
|
|
|
|
|
[SerializeField] private float autoAimAngle = 45f; // 마우스 커서 기준 각도 (넓을수록 감지 잘됨)
|
|
|
|
|
|
[Range(0f, 1f)]
|
|
|
|
|
|
[Tooltip("에임 보정 강도 (0: 보정 없음, 1: 완전 자동 조준)")]
|
|
|
|
|
|
[SerializeField] private float aimAssistStrength = 0.4f; // 40% 보정 (에임핵 느낌)
|
|
|
|
|
|
[SerializeField] private LayerMask enemyLayer; // 적 레이어
|
|
|
|
|
|
[Tooltip("차징 최대 단계에서만 자동 조준 활성화")]
|
|
|
|
|
|
[SerializeField] private bool onlyMaxCharge = true; // 최대 차징에서만 작동
|
|
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
private float _lastAttackTime;
|
|
|
|
|
|
private float _chargeTimer;
|
|
|
|
|
|
private bool _isCharging = false;
|
|
|
|
|
|
private bool _isAttacking = false;
|
2026-02-06 05:32:48 +00:00
|
|
|
|
private bool _waitForRelease = false;
|
|
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
private float _pendingDamage;
|
|
|
|
|
|
private float _pendingSpeed;
|
|
|
|
|
|
private float _pendingRange;
|
|
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// 🎯 발사 방향 저장
|
|
|
|
|
|
private Vector3 _pendingShootDirection;
|
|
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
public bool IsCharging => _isCharging;
|
2026-02-02 15:02:12 +00:00
|
|
|
|
public bool IsAttacking
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _isAttacking;
|
|
|
|
|
|
set => _isAttacking = value;
|
|
|
|
|
|
}
|
2026-02-06 04:20:12 +00:00
|
|
|
|
public float ChargeProgress => Mathf.Clamp01(_chargeTimer / maxChargeTime);
|
|
|
|
|
|
|
|
|
|
|
|
private void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (chargeStages == null || chargeStages.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
chargeStages = new List<ChargeStage>
|
|
|
|
|
|
{
|
|
|
|
|
|
new ChargeStage { chargeTime = 0f, damageMult = 1f, rangeMult = 1f },
|
|
|
|
|
|
new ChargeStage { chargeTime = 1f, damageMult = 1.5f, rangeMult = 1.2f },
|
|
|
|
|
|
new ChargeStage { chargeTime = 2f, damageMult = 2.5f, rangeMult = 1.5f }
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2026-02-06 09:27:08 +00:00
|
|
|
|
|
|
|
|
|
|
float calculatedMaxTime = 0f;
|
|
|
|
|
|
foreach (var stage in chargeStages)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (stage.chargeTime > calculatedMaxTime)
|
|
|
|
|
|
calculatedMaxTime = stage.chargeTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
maxChargeTime = Mathf.Max(calculatedMaxTime, 0.1f);
|
2026-02-06 04:20:12 +00:00
|
|
|
|
}
|
2026-01-30 07:45:11 +00:00
|
|
|
|
|
2026-01-29 06:58:38 +00:00
|
|
|
|
private void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_isCharging)
|
|
|
|
|
|
{
|
|
|
|
|
|
_chargeTimer += Time.deltaTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 05:32:48 +00:00
|
|
|
|
// --- [1] 일반 공격 ---
|
2026-01-29 06:58:38 +00:00
|
|
|
|
public void PerformNormalAttack()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Time.time < _lastAttackTime + attackCooldown) return;
|
2026-02-06 04:20:12 +00:00
|
|
|
|
if (_isAttacking) return;
|
2026-01-29 06:58:38 +00:00
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
_pendingDamage = normalDamage;
|
|
|
|
|
|
_pendingSpeed = normalSpeed;
|
|
|
|
|
|
_pendingRange = normalRange;
|
2026-01-30 07:45:11 +00:00
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// 🎯 마우스 방향 계산 (일반 공격은 자동 조준 없음)
|
|
|
|
|
|
_pendingShootDirection = GetMouseDirection();
|
|
|
|
|
|
|
2026-01-29 06:58:38 +00:00
|
|
|
|
_lastAttackTime = Time.time;
|
|
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
if (pAnim != null) pAnim.TriggerThrow();
|
2026-01-30 07:45:11 +00:00
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
StartCoroutine(AttackRoutine());
|
2026-01-30 07:45:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 05:32:48 +00:00
|
|
|
|
// --- [2] 차징 시작 ---
|
2026-02-06 04:20:12 +00:00
|
|
|
|
public void StartCharging()
|
2026-01-30 07:45:11 +00:00
|
|
|
|
{
|
2026-02-06 05:32:48 +00:00
|
|
|
|
if (_waitForRelease) return;
|
|
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
_isCharging = true;
|
|
|
|
|
|
_chargeTimer = 0f;
|
2026-01-30 06:30:27 +00:00
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
if (pAnim != null) pAnim.SetCharging(true);
|
|
|
|
|
|
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(true);
|
2026-01-29 06:58:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 05:32:48 +00:00
|
|
|
|
private void ResetChargingEffects()
|
2026-01-29 06:58:38 +00:00
|
|
|
|
{
|
2026-01-30 07:45:11 +00:00
|
|
|
|
_isCharging = false;
|
|
|
|
|
|
_chargeTimer = 0f;
|
2026-02-06 04:20:12 +00:00
|
|
|
|
|
2026-01-30 07:45:11 +00:00
|
|
|
|
if (pAnim != null) pAnim.SetCharging(false);
|
|
|
|
|
|
if (CinemachineShake.Instance != null) CinemachineShake.Instance.SetZoom(false);
|
2026-01-29 06:58:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// --- [3] 차징 취소 ---
|
2026-02-06 05:32:48 +00:00
|
|
|
|
public void CancelCharging()
|
|
|
|
|
|
{
|
|
|
|
|
|
ResetChargingEffects();
|
2026-02-06 09:27:08 +00:00
|
|
|
|
_waitForRelease = false;
|
2026-02-06 05:32:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// --- [4] 차징 발사 ---
|
2026-01-29 06:58:38 +00:00
|
|
|
|
public void ReleaseAttack()
|
|
|
|
|
|
{
|
2026-02-06 04:20:12 +00:00
|
|
|
|
if (!_isCharging) return;
|
2026-01-29 06:58:38 +00:00
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
ChargeStage currentStage = chargeStages[0];
|
|
|
|
|
|
foreach (var stage in chargeStages)
|
2026-01-31 13:07:35 +00:00
|
|
|
|
{
|
2026-02-06 04:20:12 +00:00
|
|
|
|
if (_chargeTimer >= stage.chargeTime) currentStage = stage;
|
2026-01-31 13:07:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
_pendingDamage = normalDamage * currentStage.damageMult;
|
|
|
|
|
|
_pendingSpeed = normalSpeed * currentStage.rangeMult;
|
|
|
|
|
|
_pendingRange = normalRange * currentStage.rangeMult;
|
2026-01-31 13:07:35 +00:00
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// 🎯 발사 방향 계산 (차징 최대 시 자동 조준)
|
|
|
|
|
|
bool isMaxCharge = _chargeTimer >= maxChargeTime * 0.95f; // 95% 이상이면 최대 차징
|
|
|
|
|
|
_pendingShootDirection = GetShootDirection(isMaxCharge);
|
|
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
if (pAnim != null) pAnim.TriggerThrow();
|
2026-01-31 13:07:35 +00:00
|
|
|
|
|
2026-02-06 05:32:48 +00:00
|
|
|
|
_waitForRelease = true;
|
2026-02-06 04:20:12 +00:00
|
|
|
|
_lastAttackTime = Time.time;
|
|
|
|
|
|
StartCoroutine(AttackRoutine());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// --- [5] 🎯 마우스 방향 계산 ---
|
|
|
|
|
|
private Vector3 GetMouseDirection()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 마우스 위치 → 월드 좌표
|
|
|
|
|
|
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
|
|
|
|
|
|
Plane groundPlane = new Plane(Vector3.up, transform.position);
|
|
|
|
|
|
|
|
|
|
|
|
if (groundPlane.Raycast(ray, out float distance))
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 worldMousePos = ray.GetPoint(distance);
|
|
|
|
|
|
Vector3 direction = (worldMousePos - firePoint.position).normalized;
|
|
|
|
|
|
direction.y = 0; // 수평 발사
|
|
|
|
|
|
return direction;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 실패 시 플레이어 정면
|
|
|
|
|
|
return transform.forward;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- [6] 🎯 발사 방향 계산 (에임 어시스트 포함) ---
|
|
|
|
|
|
private Vector3 GetShootDirection(bool isMaxCharge)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 mouseDir = GetMouseDirection();
|
|
|
|
|
|
|
|
|
|
|
|
// 자동 조준 비활성화 또는 최대 차징 아님
|
|
|
|
|
|
if (!enableAutoAim || (onlyMaxCharge && !isMaxCharge))
|
|
|
|
|
|
{
|
|
|
|
|
|
return mouseDir;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 🎯 적 탐색
|
|
|
|
|
|
Transform bestTarget = FindBestTarget(mouseDir);
|
|
|
|
|
|
|
|
|
|
|
|
if (bestTarget != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 적 방향 계산 (중심부 조준)
|
|
|
|
|
|
Vector3 targetPos = bestTarget.position + Vector3.up * 1.2f;
|
|
|
|
|
|
Vector3 targetDir = (targetPos - firePoint.position).normalized;
|
|
|
|
|
|
targetDir.y = 0; // 수평 발사
|
|
|
|
|
|
|
|
|
|
|
|
// ✨ 에임 어시스트: 마우스 방향과 적 방향을 섞음!
|
|
|
|
|
|
// aimAssistStrength = 0.4 → 마우스 60% + 적 40%
|
|
|
|
|
|
Vector3 assistedDir = Vector3.Lerp(mouseDir, targetDir, aimAssistStrength);
|
|
|
|
|
|
assistedDir.y = 0;
|
|
|
|
|
|
assistedDir.Normalize();
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Log($"🎯 에임 어시스트 활성화! 타겟: {bestTarget.name}, 보정 강도: {aimAssistStrength * 100}%");
|
|
|
|
|
|
return assistedDir;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 적 없으면 마우스 방향
|
|
|
|
|
|
return mouseDir;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- [7] 🎯 최적 타겟 찾기 ---
|
|
|
|
|
|
private Transform FindBestTarget(Vector3 mouseDirection)
|
|
|
|
|
|
{
|
|
|
|
|
|
Collider[] enemies = Physics.OverlapSphere(transform.position, autoAimRange, enemyLayer);
|
|
|
|
|
|
|
|
|
|
|
|
if (enemies.Length == 0) return null;
|
|
|
|
|
|
|
|
|
|
|
|
Transform bestTarget = null;
|
|
|
|
|
|
float bestScore = float.MaxValue;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var enemy in enemies)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 dirToEnemy = (enemy.transform.position - transform.position).normalized;
|
|
|
|
|
|
|
|
|
|
|
|
// 마우스 방향과의 각도 체크
|
|
|
|
|
|
float angle = Vector3.Angle(mouseDirection, dirToEnemy);
|
|
|
|
|
|
if (angle > autoAimAngle) continue; // 각도 범위 밖
|
|
|
|
|
|
|
|
|
|
|
|
// 거리 체크
|
|
|
|
|
|
float distance = Vector3.Distance(transform.position, enemy.transform.position);
|
|
|
|
|
|
|
|
|
|
|
|
// 점수 계산: 각도 + 거리 (낮을수록 좋음)
|
|
|
|
|
|
float score = angle * 0.5f + distance * 0.5f;
|
|
|
|
|
|
|
|
|
|
|
|
if (score < bestScore)
|
|
|
|
|
|
{
|
|
|
|
|
|
bestScore = score;
|
|
|
|
|
|
bestTarget = enemy.transform;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return bestTarget;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- [8] 이벤트: 화살 생성 ---
|
2026-02-06 04:20:12 +00:00
|
|
|
|
public void OnShootArrow()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (arrowPrefab == null || firePoint == null) return;
|
2026-01-31 13:07:35 +00:00
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// 🎯 저장된 방향으로 회전 계산
|
|
|
|
|
|
Quaternion shootRotation = Quaternion.LookRotation(_pendingShootDirection);
|
|
|
|
|
|
|
|
|
|
|
|
// 화살 생성 (계산된 방향으로)
|
|
|
|
|
|
GameObject arrow = Instantiate(arrowPrefab, firePoint.position, shootRotation);
|
|
|
|
|
|
|
|
|
|
|
|
// ArrowItem 초기화
|
|
|
|
|
|
ArrowItem arrowItem = arrow.GetComponent<ArrowItem>();
|
|
|
|
|
|
if (arrowItem != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
arrowItem.Initialize(_pendingDamage, _pendingSpeed, _pendingRange);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-01-29 06:58:38 +00:00
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// 하위 호환
|
|
|
|
|
|
PlayerArrow arrowScript = arrow.GetComponent<PlayerArrow>();
|
2026-02-06 04:20:12 +00:00
|
|
|
|
if (arrowScript != null)
|
2026-01-29 06:58:38 +00:00
|
|
|
|
{
|
2026-02-06 04:20:12 +00:00
|
|
|
|
arrowScript.Initialize(_pendingDamage, _pendingSpeed, _pendingRange);
|
2026-01-29 06:58:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// --- [9] 이벤트: 공격 끝 ---
|
2026-02-06 05:32:48 +00:00
|
|
|
|
public void OnAttackEnd()
|
|
|
|
|
|
{
|
|
|
|
|
|
_isAttacking = false;
|
|
|
|
|
|
ResetChargingEffects();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// --- [10] 안전장치 코루틴 ---
|
2026-02-06 04:20:12 +00:00
|
|
|
|
private IEnumerator AttackRoutine()
|
2026-01-29 06:58:38 +00:00
|
|
|
|
{
|
2026-02-06 04:20:12 +00:00
|
|
|
|
_isAttacking = true;
|
2026-02-06 05:32:48 +00:00
|
|
|
|
yield return new WaitForSeconds(0.6f);
|
|
|
|
|
|
|
|
|
|
|
|
if (_isAttacking)
|
|
|
|
|
|
{
|
|
|
|
|
|
_isAttacking = false;
|
|
|
|
|
|
ResetChargingEffects();
|
|
|
|
|
|
}
|
2026-01-29 06:58:38 +00:00
|
|
|
|
}
|
2026-02-01 15:49:12 +00:00
|
|
|
|
|
2026-02-06 09:27:08 +00:00
|
|
|
|
// --- [11] 화살 교체 ---
|
|
|
|
|
|
public void SwapArrow(GameObject newArrow)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (newArrow == null) return;
|
|
|
|
|
|
arrowPrefab = newArrow;
|
|
|
|
|
|
Debug.Log($"화살이 {newArrow.name}(으)로 교체되었습니다!");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-06 04:20:12 +00:00
|
|
|
|
public void StartWeaponCollision() { }
|
|
|
|
|
|
public void StopWeaponCollision() { }
|
2026-02-06 09:27:08 +00:00
|
|
|
|
|
|
|
|
|
|
// --- [12] 🎯 디버그: 감지 범위 시각화 ---
|
|
|
|
|
|
private void OnDrawGizmosSelected()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!enableAutoAim) return;
|
|
|
|
|
|
|
|
|
|
|
|
// 자동 조준 범위 (노란색 원)
|
|
|
|
|
|
Gizmos.color = Color.yellow;
|
|
|
|
|
|
Gizmos.DrawWireSphere(transform.position, autoAimRange);
|
|
|
|
|
|
|
|
|
|
|
|
// 마우스 방향 (파란색 선)
|
|
|
|
|
|
if (Application.isPlaying && firePoint != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 mouseDir = GetMouseDirection();
|
|
|
|
|
|
Gizmos.color = Color.blue;
|
|
|
|
|
|
Gizmos.DrawRay(firePoint.position, mouseDir * 5f);
|
|
|
|
|
|
|
|
|
|
|
|
// 🎯 에임 어시스트 방향 (빨간색 선)
|
|
|
|
|
|
Transform target = FindBestTarget(mouseDir);
|
|
|
|
|
|
if (target != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Vector3 targetPos = target.position + Vector3.up * 1.2f;
|
|
|
|
|
|
Vector3 targetDir = (targetPos - firePoint.position).normalized;
|
|
|
|
|
|
targetDir.y = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 보정된 최종 방향
|
|
|
|
|
|
Vector3 assistedDir = Vector3.Lerp(mouseDir, targetDir, aimAssistStrength);
|
|
|
|
|
|
assistedDir.Normalize();
|
|
|
|
|
|
|
|
|
|
|
|
Gizmos.color = Color.red;
|
|
|
|
|
|
Gizmos.DrawRay(firePoint.position, assistedDir * 7f);
|
|
|
|
|
|
|
|
|
|
|
|
// 타겟 위치 표시
|
|
|
|
|
|
Gizmos.color = Color.green;
|
|
|
|
|
|
Gizmos.DrawWireSphere(targetPos, 0.3f);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 감지 각도 (연한 초록색 선)
|
|
|
|
|
|
Gizmos.color = new Color(0, 1, 0, 0.3f);
|
|
|
|
|
|
Vector3 leftBound = Quaternion.Euler(0, -autoAimAngle, 0) * mouseDir;
|
|
|
|
|
|
Vector3 rightBound = Quaternion.Euler(0, autoAimAngle, 0) * mouseDir;
|
|
|
|
|
|
Gizmos.DrawRay(firePoint.position, leftBound * autoAimRange);
|
|
|
|
|
|
Gizmos.DrawRay(firePoint.position, rightBound * autoAimRange);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-29 06:58:38 +00:00
|
|
|
|
}
|