forked from cgvr/DeltaVR
		
	
		
			
				
	
	
		
			235 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
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 0f; // default score
 | 
						||
    }
 | 
						||
 | 
						||
}
 | 
						||
 |