235 lines
6.4 KiB
C#
Raw Blame History

using System;
using System.Collections.Generic;
using System.Linq;
using _PROJECT.Scripts.Bow;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using TMPro;
using Unity.XR.CoreUtils;
using UnityEngine;
using Random = UnityEngine.Random;
public class ArcheryRange : NetworkBehaviour
{
public TMP_Text highScoreText;
public TMP_Text timeLeftText;
public TMP_Text scoreText;
public Transform targetStartPosition;
public Transform targetEndPosition;
public GameObject targetPrefab;
public StartTarget startTarget;
public Vector3 minRandomOffset = new Vector3(0f, -2f, -5f);
public Vector3 maxRandomOffset = new Vector3(0f, 2f, 5f);
public float roundLength = 60f;
public float targetSpawnTime = 3f;
public KeyboardManager keyboardManager;
private List<ArcheryTarget> _targets;
[SyncVar]
private float _score;
private float _maxScore;
private float _roundEndTime;
private float _nextTargetTime;
private bool _roundActive;
private readonly List<XROrigin> _presentPlayers = new();
private XROrigin _scoredPlayer;
public override void OnStartServer()
{
base.OnStartServer();
_roundActive = false;
_targets = new List<ArcheryTarget>();
_score = 0;
_maxScore = 0;
_roundEndTime = 0f;
_maxScore = LoadScoreFromDisk();
//+Debug.Log($"highScore is {_maxScore}");
StartCoroutine(DelayedSetHighScoreText(10f)); // Cannot immediately assign these values because fishnet needs time.
}
private System.Collections.IEnumerator DelayedSetHighScoreText(float delaySeconds)
{
yield return new WaitForSeconds(delaySeconds);
SetHighScoreText($"High Score: {_maxScore}");
}
private void OnTriggerEnter(Collider other)
{
SetHighScoreText($"High Score: {_maxScore}"); // Refresh high score UI
XROrigin enteredPlayer = other.GetComponent<XROrigin>();
if (enteredPlayer == null || _presentPlayers.Contains(enteredPlayer))
return;
_presentPlayers.Add(enteredPlayer); // Adds to the end
}
private void OnTriggerExit(Collider other)
{
XROrigin exitedPlayer = other.GetComponent<XROrigin>();
if (exitedPlayer == null) return;
_presentPlayers.Remove(exitedPlayer); // Shifts others left automatically
if (exitedPlayer == _scoredPlayer) keyboardManager.DeActivate(); // If the player <20>refuses to enter their name.
}
public override void OnStopServer()
{
base.OnStopServer();
SaveScoreToDisk(_maxScore);
}
// Update is called once per frame
void Update()
{
if (!IsServer) return;
if (!_roundActive) return;
if (Time.time >= _roundEndTime)
{
ResetRange();
}
else
{
SetTimeLeftText($"Time Left: {Math.Ceiling((_roundEndTime - Time.time) % 60)}");
if (Time.time >= _nextTargetTime)
{
_nextTargetTime = Time.time + targetSpawnTime;
SpawnTarget();
}
}
}
private void SpawnTarget()
{
if (!IsServer) return;
var randomPos = targetStartPosition.position + new Vector3(
Random.Range(minRandomOffset.x, maxRandomOffset.x),
(float)Math.Round(Random.Range(minRandomOffset.y, maxRandomOffset.y)),
Random.Range(minRandomOffset.z, maxRandomOffset.z));
var target = SpawnTarget(randomPos);
_targets.Add(target);
}
private ArcheryTarget SpawnTarget(Vector3 randomPos)
{
var prefab = Instantiate(targetPrefab, randomPos, Quaternion.identity, null);
ArcheryTarget target = prefab.GetComponent<ArcheryTarget>();
target.endPosition = targetEndPosition.position;
target.addScore = AddScore;
Spawn(prefab);
return target;
}
public void ResetRange()
{
if (!IsServer) return;
foreach (var target in _targets.Where(target => target != null))
{
Despawn(target.gameObject, DespawnType.Pool);
}
_targets = new List<ArcheryTarget>();
if (_maxScore < _score) _maxScore = _score;
if(_presentPlayers.Count != 0) // If there are players in the area.
{
// Gives the score to the player longest-lasting in the area. It would be better to give it to the player that fired the starting arrow, but I'm not spending 10 hours on this.
XROrigin scoringPlayer = _presentPlayers.First();
Menu playermenu = scoringPlayer.GetComponentInChildren<Menu>();
_scoredPlayer = scoringPlayer;
playermenu.setCanvasVisibility(false); // Deactivates the menu to avoid overlap issues.
Transform keyboardPlacement = playermenu.updateMenuTransform();
keyboardManager.Activate(_score, keyboardPlacement);
SaveScoreToDisk(_maxScore);
SetHighScoreText($"High Score: {_maxScore}");
}
_score = 0;
startTarget.ShowTarget();
_roundActive = false;
SetTimeLeftText("");
}
public void StartRound()
{
if (!IsServer) return;
_roundEndTime = Time.time + roundLength;
_nextTargetTime = Time.time;
_roundActive = true;
}
public void AddScore(float distance)
{
if (!IsServer) return;
_score += distance;
SetScoreText($"Score: {_score}");
}
[ObserversRpc]
public void SetHighScoreText(string text)
{
highScoreText.text = text;
}
[ObserversRpc]
public void SetScoreText(string text)
{
scoreText.text = text;
}
[ObserversRpc]
public void SetTimeLeftText(string text)
{
timeLeftText.text = text;
}
public class SaveData
{
public float HighScore;
}
public void SaveScoreToDisk(float highScore)
{
SaveData data = new SaveData { HighScore = highScore };
string json = JsonUtility.ToJson(data);
System.IO.File.WriteAllText("highscore.json", json);
}
public float LoadScoreFromDisk()
{
if (System.IO.File.Exists("highscore.json"))
{
string json = System.IO.File.ReadAllText("highscore.json");
SaveData data = JsonUtility.FromJson<SaveData>(json);
return data.HighScore;
}
return -1f; // default score
}
}