Added UI and more
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
@@ -37,22 +38,28 @@ public class RoundManager : NetworkBehaviour
|
||||
|
||||
private List<PlayerHealth> alivePlayers = new List<PlayerHealth>();
|
||||
|
||||
private NetworkList<PlayerScore> playerScores;
|
||||
private NetworkList<PlayerScore> playerScores = new NetworkList<PlayerScore>();
|
||||
|
||||
// pitDefenders[i] = ClientId игрока, которому принадлежит яма с pitIndex == i
|
||||
private ulong[] pitDefenders;
|
||||
|
||||
private const ulong NoWinner = ulong.MaxValue;
|
||||
|
||||
private bool isTimerRunning = false;
|
||||
public event Action<float> TimerChanged;
|
||||
public event Action<int> RoundChanged;
|
||||
public event Action ScoresChanged;
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
currentRound.OnValueChanged += OnRoundChanged;
|
||||
isRoundActive.OnValueChanged += OnRoundStateChanged;
|
||||
roundTimeRemaining.OnValueChanged += OnRoundTimeChanged;
|
||||
playerScores.OnListChanged += OnScoresChanged;
|
||||
|
||||
// roundTimeRemaining.OnValueChanged += OnTimerChanged;
|
||||
|
||||
if (IsServer)
|
||||
if (IsServer)
|
||||
{
|
||||
// StartTimerServerRPC();
|
||||
currentRound.Value = 0;
|
||||
StartCoroutine(StartRoundWithDelay());
|
||||
}
|
||||
}
|
||||
@@ -60,47 +67,51 @@ public class RoundManager : NetworkBehaviour
|
||||
private void Update()
|
||||
{
|
||||
if (!IsServer) return;
|
||||
if(!IsRoundActive) return;
|
||||
if (!IsRoundActive) return;
|
||||
|
||||
roundTimeRemaining.Value = Mathf.Max(0f, roundTimeRemaining.Value - Time.deltaTime);
|
||||
|
||||
if(roundTimeRemaining.Value <= 0f)
|
||||
if (roundTimeRemaining.Value <= 0f)
|
||||
{
|
||||
StartCoroutine(EndRound(0ul));
|
||||
StartCoroutine(EndRound(NoWinner));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// public void OnTimerChanged(float _previousValue, float _newValue)
|
||||
|
||||
|
||||
void Awake()
|
||||
{
|
||||
{
|
||||
Current = this;
|
||||
|
||||
playerScores = new NetworkList<PlayerScore>();
|
||||
roundTimeRemaining.Value = roundDuration.Value;
|
||||
}
|
||||
|
||||
|
||||
public void OnPlayerFellIntoPit(ulong _winnerClientId)
|
||||
public void OnPlayerEnteredPit(int _pitIndex, ulong _enteringClientId)
|
||||
{
|
||||
if (!IsServer) return;
|
||||
if (!isRoundActive.Value) return;
|
||||
|
||||
if(!isRoundActive.Value) return;
|
||||
if (pitDefenders == null) return;
|
||||
if (_pitIndex < 0 || _pitIndex >= pitDefenders.Length) return;
|
||||
|
||||
// Своя яма — не считается, побеждают только за попадание в ЧУЖУЮ яму.
|
||||
// Для клона сюда приходит ClientId его ОРИГИНАЛА (см. PitZone) — правило работает так же.
|
||||
if (_enteringClientId == pitDefenders[_pitIndex]) return;
|
||||
|
||||
AddScore(_enteringClientId);
|
||||
StartCoroutine(EndRound(_enteringClientId));
|
||||
}
|
||||
|
||||
private void AddScore(ulong _clientId)
|
||||
{
|
||||
for (int _i = 0; _i < playerScores.Count; _i++)
|
||||
{
|
||||
if (playerScores[_i].ClientId != _clientId) continue;
|
||||
|
||||
playerScores[_i] = new PlayerScore
|
||||
{
|
||||
ClientId = _winnerClientId,
|
||||
ClientId = _clientId,
|
||||
Score = playerScores[_i].Score + 1
|
||||
};
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
StartCoroutine(EndRound(_winnerClientId));
|
||||
}
|
||||
|
||||
public void OnPlayerDied(PlayerHealth _playerHealth)
|
||||
@@ -118,10 +129,10 @@ public class RoundManager : NetworkBehaviour
|
||||
public void RegisterPlayer(ulong _clientId)
|
||||
{
|
||||
if (!IsServer) return;
|
||||
|
||||
|
||||
foreach (var _s in playerScores)
|
||||
if (_s.ClientId == _clientId) return;
|
||||
|
||||
|
||||
playerScores.Add(new PlayerScore { ClientId = _clientId, Score = 0 });
|
||||
}
|
||||
|
||||
@@ -129,7 +140,14 @@ public class RoundManager : NetworkBehaviour
|
||||
{
|
||||
isRoundActive.Value = false;
|
||||
|
||||
string _winner = _winnerClientId != 0 ? $"Player {_winnerClientId} wins!" : "No winner";
|
||||
// Сразу: стоп клонов + запись раунда в архив.
|
||||
// Обязательно ДО WaitForSeconds — иначе клоны бегают и стреляют на экране победы.
|
||||
if (GhostRoundManager.Current != null)
|
||||
GhostRoundManager.Current.ServerEndRound();
|
||||
|
||||
string _winner = _winnerClientId == NoWinner
|
||||
? "No winner (time up)"
|
||||
: $"Player {_winnerClientId} wins!";
|
||||
|
||||
RoundEndedClientRPC(_winner);
|
||||
|
||||
@@ -143,17 +161,40 @@ public class RoundManager : NetworkBehaviour
|
||||
private void RespawnAllPlayers()
|
||||
{
|
||||
if (!IsServer) return;
|
||||
if (spawnPoints == null || spawnPoints.Length == 0) return;
|
||||
|
||||
var _allPlayers = FindObjectsByType<PlayerHealth>(FindObjectsSortMode.None);
|
||||
PlayerHealth[] _found = FindObjectsByType<PlayerHealth>(FindObjectsSortMode.None);
|
||||
|
||||
// Только живые игроки: у клона тоже есть PlayerHealth,
|
||||
// но ему нельзя давать яму и спавн-поинт
|
||||
List<PlayerHealth> _players = new List<PlayerHealth>();
|
||||
foreach (PlayerHealth _p in _found)
|
||||
{
|
||||
if (_p.GetComponent<GhostPlayer>() != null) continue;
|
||||
_players.Add(_p);
|
||||
}
|
||||
|
||||
// Детерминированный порядок раздачи ям: клон слепо повторяет прошлый раунд,
|
||||
// значит "чья яма где" должно совпадать из раунда в раунд.
|
||||
// FindObjectsByType порядок не гарантирует — сортируем по ClientId.
|
||||
_players.Sort((_a, _b) => _a.OwnerClientId.CompareTo(_b.OwnerClientId));
|
||||
|
||||
alivePlayers.Clear();
|
||||
|
||||
for (int _q = 0; _q < _allPlayers.Length; _q++)
|
||||
{
|
||||
Vector3 _spawnPosition = spawnPoints[_q % spawnPoints.Length].position;
|
||||
// Одна яма на игрока: игрок с индексом _q защищает яму pitIndex == _q
|
||||
pitDefenders = new ulong[_players.Count];
|
||||
|
||||
_allPlayers[_q].Respawn(_spawnPosition);
|
||||
alivePlayers.Add(_allPlayers[_q]);
|
||||
for (int _q = 0; _q < _players.Count; _q++)
|
||||
{
|
||||
ulong _clientId = _players[_q].OwnerClientId;
|
||||
|
||||
RegisterPlayer(_clientId);
|
||||
pitDefenders[_q] = _clientId;
|
||||
|
||||
Vector3 _spawnPosition = spawnPoints[_q % spawnPoints.Length].position;
|
||||
_players[_q].Respawn(_spawnPosition);
|
||||
|
||||
alivePlayers.Add(_players[_q]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,14 +202,30 @@ public class RoundManager : NetworkBehaviour
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
|
||||
yield return new WaitUntil(() =>
|
||||
FindObjectsByType<PlayerHealth>(FindObjectsSortMode.None).Length >= 2);
|
||||
yield return new WaitUntil(() => CountRealPlayers() >= 2);
|
||||
|
||||
RespawnAllPlayers();
|
||||
|
||||
// Спавним клонов прошлых раундов и включаем запись у живых игроков
|
||||
if (GhostRoundManager.Current != null)
|
||||
GhostRoundManager.Current.ServerStartRound();
|
||||
|
||||
roundTimeRemaining.Value = roundDuration.Value;
|
||||
isRoundActive.Value = true;
|
||||
|
||||
RoundStartedClientRPC(currentRound.Value);
|
||||
}
|
||||
|
||||
// Считаем только настоящих игроков — у клонов тоже есть PlayerHealth
|
||||
private int CountRealPlayers()
|
||||
{
|
||||
PlayerHealth[] _found = FindObjectsByType<PlayerHealth>(FindObjectsSortMode.None);
|
||||
int _count = 0;
|
||||
foreach (PlayerHealth _p in _found)
|
||||
if (_p.GetComponent<GhostPlayer>() == null) _count++;
|
||||
return _count;
|
||||
}
|
||||
|
||||
[ClientRpc]
|
||||
private void RoundStartedClientRPC(int _round)
|
||||
{
|
||||
@@ -182,6 +239,23 @@ public class RoundManager : NetworkBehaviour
|
||||
}
|
||||
|
||||
public bool IsRoundActive => isRoundActive.Value;
|
||||
public int CurrentRound => currentRound.Value;
|
||||
public float RoundTimeRemaining => roundTimeRemaining.Value;
|
||||
|
||||
public int GetScore(ulong _clientId)
|
||||
{
|
||||
foreach (PlayerScore _s in playerScores)
|
||||
if (_s.ClientId == _clientId) return _s.Score;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Для 2 игроков: счёт первого игрока, чей ClientId не равен локальному
|
||||
public int GetEnemyScore(ulong _localClientId)
|
||||
{
|
||||
foreach (PlayerScore _s in playerScores)
|
||||
if (_s.ClientId != _localClientId) return _s.Score;
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
@@ -190,15 +264,27 @@ public class RoundManager : NetworkBehaviour
|
||||
|
||||
currentRound.OnValueChanged -= OnRoundChanged;
|
||||
isRoundActive.OnValueChanged -= OnRoundStateChanged;
|
||||
roundTimeRemaining.OnValueChanged -= OnRoundTimeChanged;
|
||||
playerScores.OnListChanged -= OnScoresChanged;
|
||||
}
|
||||
|
||||
private void OnScoresChanged(NetworkListEvent<PlayerScore> _event)
|
||||
{
|
||||
ScoresChanged?.Invoke();
|
||||
}
|
||||
|
||||
private void OnRoundTimeChanged(float _previousValue, float _newValue)
|
||||
{
|
||||
TimerChanged?.Invoke(_newValue);
|
||||
}
|
||||
|
||||
private void OnRoundChanged(int _previousValue, int _newValue)
|
||||
{
|
||||
|
||||
RoundChanged?.Invoke(_newValue);
|
||||
}
|
||||
|
||||
private void OnRoundStateChanged(bool _previousValue, bool _newValue)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user