97 lines
2.8 KiB
C#
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);
|
|
}
|
|
}
|