Files
2026-07-06 18:01:21 +03:00

97 lines
2.8 KiB
C#

using Unity.Netcode;
using UnityEngine;
[DefaultExecutionOrder(100)] // после PlayerMovement.LateUpdate (pitch камеры)
public class PlayerShoot : NetworkBehaviour
{
[SerializeField] float damageAmount = 10f;
[SerializeField] float range = 100f;
[SerializeField] Transform cameraRoot;
[SerializeField] GameObject hitEffectPrefab;
private PlayerHealth playerHealth;
private WeaponView weaponView;
private PlayerShield playerShield;
private bool isActive = false;
public void Init()
{
isActive = true;
playerHealth = GetComponent<PlayerHealth>();
playerShield = GetComponent<PlayerShield>();
weaponView = GetComponentInChildren<WeaponView>(true);
}
private void LateUpdate()
{
if (!isActive) return;
if (playerHealth == null || playerHealth.isDead.Value) return;
if (playerShield != null && playerShield.IsShieldUp) return;
if (Input.GetMouseButtonDown(0))
{
Vector3 _origin = cameraRoot.position;
Vector3 _direction = cameraRoot.forward;
weaponView?.PlayShoot();
// Мгновенный фидбек на стреляющем клиенте — не ждём серверный ClientRpc
if (TryRaycastShot(_origin, _direction, out RaycastHit _predictedHit))
SpawnHitEffectLocal(_predictedHit.point);
ShootServerRpc(_origin, _direction);
}
}
[ServerRpc]
private void ShootServerRpc(Vector3 _origin, Vector3 _direction)
{
GetComponent<GhostRecorder>()?.RecordShot(_origin, _direction);
if (!TryRaycastShot(_origin, _direction, out RaycastHit _hit))
return;
PlayerHealth _targetHealth = _hit.collider.GetComponentInParent<PlayerHealth>();
if (_targetHealth != null)
_targetHealth.TakeDamage((int)damageAmount);
SpawnHitEffectClientRpc(_hit.point);
}
[ClientRpc]
private void SpawnHitEffectClientRpc(Vector3 _hitPosition)
{
// Владелец уже показал эффект локально при клике
if (IsOwner) return;
SpawnHitEffectLocal(_hitPosition);
}
private bool TryRaycastShot(Vector3 _origin, Vector3 _direction, out RaycastHit _hit)
{
_hit = default;
if (!Physics.Raycast(_origin, _direction, out _hit, range))
return false;
Collider[] _ownerColliders = GetComponentsInChildren<Collider>();
for (int i = 0; i < _ownerColliders.Length; i++)
{
if (_ownerColliders[i] == _hit.collider)
return false;
}
return true;
}
private void SpawnHitEffectLocal(Vector3 _hitPosition)
{
if (hitEffectPrefab == null) return;
Instantiate(hitEffectPrefab, _hitPosition, Quaternion.identity);
}
}