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(); playerShield = GetComponent(); weaponView = GetComponentInChildren(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()?.RecordShot(_origin, _direction); if (!TryRaycastShot(_origin, _direction, out RaycastHit _hit)) return; PlayerHealth _targetHealth = _hit.collider.GetComponentInParent(); 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(); 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); } }