Files
Learning-UnityNGO/Assets/CONTENT/FEATURES/DEV-TEST/Scripts/PlayerHealth.cs
T
2026-07-02 17:04:29 +03:00

126 lines
3.4 KiB
C#

using UnityEngine;
using Unity.Netcode;
using Unity.Netcode.Components;
using System;
public class PlayerHealth : NetworkBehaviour
{
[SerializeField] private int maxHealth = 100;
public NetworkVariable<int> currentHealth = new NetworkVariable<int>(
100,
NetworkVariableReadPermission.Everyone,
NetworkVariableWritePermission.Server
);
public NetworkVariable<bool> isDead = new NetworkVariable<bool>(false);
public event Action<int, int> HealthChanged;
public event Action Died;
private bool isServer;
public void Init(bool _isServer)
{
isServer = _isServer;
currentHealth.OnValueChanged += OnHealthChanged;
if(isServer)
{
currentHealth.Value = maxHealth;
}
HealthChanged?.Invoke(currentHealth.Value, maxHealth);
}
private void OnHealthChanged(int _previousValue, int _newValue)
{
HealthChanged?.Invoke(_newValue, maxHealth);
if(_newValue <= 0)
{
Die();
}
}
public void TakeDamage(int _damageAmount)
{
if (!isServer) return;
if(isDead.Value) return;
currentHealth.Value = Mathf.Max(0, currentHealth.Value - _damageAmount);
}
public override void OnNetworkDespawn()
{
currentHealth.OnValueChanged -= OnHealthChanged;
}
private void Die()
{
if(!isServer) return;
isDead.Value = true;
OnDiedClientRpc();
}
public void Respawn(Vector3 _spawnPosition)
{
if(!isServer) return;
isDead.Value = false;
currentHealth.Value = maxHealth;
RespawnClientRpc(_spawnPosition);
}
public void PushCurrentHealthValue()
{
HealthChanged?.Invoke(currentHealth.Value, maxHealth);
}
[ClientRpc]
private void OnDiedClientRpc()
{
Debug.Log($"Player {OwnerClientId} died");
SetPhysicsAndVisualsActive(false);
Died?.Invoke();
}
[ClientRpc]
private void RespawnClientRpc(Vector3 _spawnPosition)
{
SetPhysicsAndVisualsActive(true);
// Позицию задаёт только владелец — он авторитет над NetworkTransform (Owner authority)
if (!IsOwner) return;
TeleportOwner(_spawnPosition);
}
// Телепорт без интерполяции. CharacterController кэширует свою позицию,
// поэтому его надо выключить на время установки трансформа.
private void TeleportOwner(Vector3 _spawnPosition)
{
CharacterController _controller = GetComponent<CharacterController>();
if (_controller != null) _controller.enabled = false;
NetworkTransform _netTransform = GetComponent<NetworkTransform>();
if (_netTransform != null)
_netTransform.Teleport(_spawnPosition, transform.rotation, transform.localScale);
else
transform.position = _spawnPosition;
if (_controller != null) _controller.enabled = true;
}
private void SetPhysicsAndVisualsActive(bool _isActive)
{
foreach (Collider collider in GetComponentsInChildren<Collider>())
collider.enabled = _isActive;
foreach (MeshRenderer meshRenderer in GetComponentsInChildren<MeshRenderer>())
meshRenderer.enabled = _isActive;
}
}