Files
2025-05-26 00:46:28 +02:00

140 lines
4.8 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.Interactables;
namespace XRMultiplayer.MiniGames
{
/// <summary>
/// Represents a mini-game called "Whack-A-Pig" where the player needs to hit pigs with a hammer.
/// </summary>
public class MiniGame_Whack : MiniGameBase
{
/// <summary>
/// The time to wait before resetting the hammer's position.
/// </summary>
[SerializeField] float m_HammerResetTime = .25f;
/// <summary>
/// The interactable objects to use for the mini-game.
/// </summary>
readonly Dictionary<XRBaseInteractable, Pose> m_InteractablePoses = new();
/// <summary>
/// The networked gameplay to use for handling the networked gameplay logic.
/// </summary>
NetworkedWhackAPig m_NetworkedGameplay;
/// <summary>
/// The current score of the mini-game.
/// </summary>
int m_CurrentScore = 0;
/// <inheritdoc/>
public override void Start()
{
base.Start();
TryGetComponent(out m_NetworkedGameplay);
foreach (var interactable in m_GameInteractables)
{
if (!m_InteractablePoses.ContainsKey(interactable))
{
m_InteractablePoses.Add(interactable, new Pose(interactable.transform.position, interactable.transform.rotation));
interactable.selectExited.AddListener(HammerDropped);
}
}
}
/// <inheritdoc/>
void OnDestroy()
{
foreach (var kvp in m_InteractablePoses)
{
kvp.Key.selectExited.RemoveListener(HammerDropped);
}
}
/// <summary>
/// Sets up the game by resetting the current score.
/// </summary>
public override void SetupGame()
{
base.SetupGame();
m_CurrentScore = 0;
m_NetworkedGameplay.ResetGame();
}
/// <summary>
/// Starts the game by spawning pigs if the player is the server.
/// </summary>
public override void StartGame()
{
base.StartGame();
if (m_NetworkedGameplay.IsServer)
{
m_NetworkedGameplay.SpawnProcessServer();
}
}
/// <summary>
/// Finishes the game and ends the networked gameplay.
/// </summary>
/// <param name="submitScore">Whether to submit the score or not.</param>
public override void FinishGame(bool submitScore = true)
{
base.FinishGame(submitScore);
m_NetworkedGameplay.EndGame();
}
/// <summary>
/// Called when the hammer is dropped on an interactable object.
/// </summary>
/// <param name="args">The interaction event arguments.</param>
void HammerDropped(BaseInteractionEventArgs args)
{
XRBaseInteractable interactable = (XRBaseInteractable)args.interactableObject;
if (m_InteractablePoses.ContainsKey(interactable))
{
StartCoroutine(DropHammerAfterTimeRoutine(interactable));
}
}
/// <summary>
/// Coroutine that drops the hammer after a specified time and resets the interactable's position.
/// </summary>
/// <param name="interactable">The interactable object.</param>
IEnumerator DropHammerAfterTimeRoutine(XRBaseInteractable interactable)
{
yield return new WaitForSeconds(m_HammerResetTime);
if (!interactable.isSelected)
{
Rigidbody body = interactable.GetComponent<Rigidbody>();
bool wasKinematic = body.isKinematic;
body.isKinematic = true;
interactable.transform.SetPositionAndRotation(m_InteractablePoses[interactable].position, m_InteractablePoses[interactable].rotation);
yield return new WaitForFixedUpdate();
body.isKinematic = wasKinematic;
foreach (var collider in interactable.colliders)
{
collider.enabled = true;
}
}
}
/// <summary>
/// Updates the local player's score and submits it to the server.
/// </summary>
/// <param name="pointValue">The point value to add to the score.</param>
public void LocalPlayerScored(int pointValue)
{
m_CurrentScore += pointValue;
if (m_CurrentScore < 0) m_CurrentScore = 0;
m_MiniGameManager.SubmitScoreServerRpc(m_CurrentScore, XRINetworkPlayer.LocalPlayer.OwnerClientId);
}
}
}