added scoring system for the bow game

This commit is contained in:
2025-05-20 14:53:35 +03:00
parent 03a3ca570e
commit ffd98b6322
36 changed files with 2275 additions and 84 deletions

View File

@@ -5,6 +5,7 @@ using _PROJECT.Scripts.Bow;
using FishNet.Object;
using FishNet.Object.Synchronizing;
using TMPro;
using Unity.XR.CoreUtils;
using UnityEngine;
using Random = UnityEngine.Random;
@@ -24,6 +25,8 @@ public class ArcheryRange : NetworkBehaviour
public float roundLength = 60f;
public float targetSpawnTime = 3f;
public KeyboardManager keyboardManager;
private List<ArcheryTarget> _targets;
[SyncVar]
@@ -33,6 +36,10 @@ public class ArcheryRange : NetworkBehaviour
private float _nextTargetTime;
private bool _roundActive;
private readonly List<XROrigin> _presentPlayers = new();
private XROrigin _scoredPlayer;
public override void OnStartServer()
{
base.OnStartServer();
@@ -41,7 +48,46 @@ public class ArcheryRange : NetworkBehaviour
_score = 0;
_maxScore = 0;
_roundEndTime = 0f;
SetHighScoreText("High Score: 0");
_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
@@ -101,9 +147,30 @@ public class ArcheryRange : NetworkBehaviour
_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;
SetHighScoreText($"High Score: {_maxScore}");
startTarget.ShowTarget();
_roundActive = false;
SetTimeLeftText("");
}
@@ -139,5 +206,29 @@ public class ArcheryRange : NetworkBehaviour
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
}
}

View File

@@ -0,0 +1,147 @@
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class KeyboardManager : MonoBehaviour
{
public enum ShiftMode { Lowercase, NextUppercase, Uppercase }
[Header("UI References")]
public TMP_Text nameTextField;
public TMP_Text scoreTextField;
public Button shiftButton;
public Button backspaceButton;
public Button enterButton;
public Button spaceButton;
[Header("Letter Buttons")]
public List<Button> letterButtons;
public int inputTextLimit = 12;
public ScoreBoard scoreBoard; // Reference to ScoreBoard
public string placeHolderText;
private string _input = "";
private float _currentScore;
private ShiftMode _shiftMode = ShiftMode.Lowercase;
void Start()
{
foreach (var button in letterButtons)
{
button.onClick.AddListener(() => OnLetterPressed(button));
}
shiftButton.onClick.AddListener(OnShiftPressed);
backspaceButton.onClick.AddListener(OnBackspacePressed);
enterButton.onClick.AddListener(OnEnterPressed);
spaceButton.onClick.AddListener(OnSpacePressed);
gameObject.SetActive(false); // Start disabled
}
public void Activate(float score, Transform assignedTransform)
{
_currentScore = score;
_input = "";
nameTextField.text = placeHolderText;
Debug.Log(_currentScore);
Debug.Log(_currentScore.ToString());
scoreTextField.text = _currentScore.ToString();
gameObject.SetActive(true);
gameObject.transform.position = assignedTransform.position;
gameObject.transform.rotation = assignedTransform.rotation;
}
public void DeActivate()
{
gameObject.SetActive(false);
}
private void addToInput(string newInput)
{
if (_input.Length < inputTextLimit)
_input += newInput;
}
void OnLetterPressed(Button button)
{
var label = button.GetComponentInChildren<TMP_Text>();
if (label == null) return;
string letter = label.text;
switch (_shiftMode)
{
case ShiftMode.Lowercase:
addToInput(letter.ToLower());
break;
case ShiftMode.Uppercase:
addToInput(letter.ToUpper());
break;
case ShiftMode.NextUppercase:
addToInput(letter.ToUpper());
_shiftMode = ShiftMode.Lowercase;
UpdateKeyLabels();
break;
}
UpdateOutput();
}
void OnShiftPressed()
{
_shiftMode = _shiftMode switch
{
ShiftMode.Lowercase => ShiftMode.NextUppercase,
ShiftMode.NextUppercase => ShiftMode.Uppercase,
ShiftMode.Uppercase => ShiftMode.Lowercase,
_ => ShiftMode.Lowercase
};
UpdateKeyLabels();
}
void OnBackspacePressed()
{
if (_input.Length > 0)
_input = _input.Substring(0, _input.Length - 1);
UpdateOutput();
}
void OnEnterPressed()
{
if (_input.Length > 0)
{
scoreBoard.SaveScore(_input, _currentScore);
gameObject.SetActive(false);
}
}
void OnSpacePressed()
{
addToInput(" ");
UpdateOutput();
}
void UpdateOutput()
{
nameTextField.text = _input;
}
void UpdateKeyLabels()
{
foreach (var button in letterButtons)
{
var label = button.GetComponentInChildren<TMP_Text>();
if (label == null) continue;
label.text = _shiftMode == ShiftMode.Lowercase ? label.text.ToLower() : label.text.ToUpper();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 148cae225a875104fa024390b4e9f9d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using TMPro;
using UnityEngine;
public class ScoreBoard : MonoBehaviour
{
[System.Serializable]
public class ScoreEntry
{
public string name;
public float score;
}
[System.Serializable]
public class ScoreData
{
public List<ScoreEntry> entries = new List<ScoreEntry>();
}
public TMP_Text scoreDisplayText;
private string filePath => Path.Combine(Application.persistentDataPath, "highscores.json");
private ScoreData _scoreData = new ScoreData();
void Start()
{
LoadScores();
DisplayTopScores();
}
public void SaveScore(string playerName, float score)
{
LoadScores();
_scoreData.entries.Add(new ScoreEntry { name = playerName, score = score });
_scoreData.entries = _scoreData.entries.OrderByDescending(e => e.score).Take(15).ToList(); // Keep top 15
string json = JsonUtility.ToJson(_scoreData, true);
File.WriteAllText(filePath, json);
DisplayTopScores();
}
public void LoadScores()
{
if (File.Exists(filePath))
{
string json = File.ReadAllText(filePath);
_scoreData = JsonUtility.FromJson<ScoreData>(json);
}
}
private void DisplayTopScores()
{
if (_scoreData.entries.Count == 0)
{
scoreDisplayText.text = "No scores yet.";
return;
}
scoreDisplayText.text = "Top Scores:\n";
for (int i = 0; i < _scoreData.entries.Count; i++)
{
var entry = _scoreData.entries[i];
scoreDisplayText.text += $"{i + 1}. {entry.name} - {entry.score}\n";
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 89213b914f7728045bdfc55d900827c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: