未発表パーティゲーム PlayerController.cs
- msandfrey3
- Aug 12, 2024
- 4 min read
using PartyGame.GameManagement;using LeftTurnStudios.Observables;using UnityEngine;using UnityEngine.InputSystem;using PartyGame.Config;using System.Collections;using PartyGame.Character.Abilities;using PartyGame.PhysicsManagement;using PartyGame.Multiplayer;using PartyGame.Scoring;using Fusion;using PartyGame.Multiplayer.Inputs;using System;using System.Linq;using System.Collections.Generic;using PartyGame.Character.Abilities.Grapple;using PartyGame.Cosmetics;using PartyGame.Props;using DG.Tweening;using PartyGame.CameraManagement;using PartyGame.PhysicsManagement.Collisions;namespace PartyGame.Character.Player{ [RequireComponent(typeof(PlayerInput))] public class PlayerController : NetworkBehaviour, IGameLoop, IPlayerController { public delegate void PlayerDied(PlayerController playerController); public PlayerDied OnPlayerDied { get; set; } [SerializeField] private Rigidbody _rigidbody; [SerializeField] private NetworkRigidbody _networkRigidbody; [SerializeField] private PlayerNumber _playerNumber = PlayerNumber.Unset; [SerializeField] private GrappleTurret _grappleTurret; [SerializeField] private BumperCar _bumperCar; [SerializeField] private SpeedTracker _speedTracker; [SerializeField] private WinnerEffect _winnerEffect; [SerializeField] private GameObject _stunVisual; [SerializeField] private float _stunDuration = 3.0f; [SerializeField] private float _stunCooldown = 3.0f; [Header("Abilities")] [SerializeField] private GrappleAbility _grappleAbility; [Header("Status Effects")] [SerializeField, Tooltip("Set to false to disable stun mechanic")] private bool _enableStunMechanic = true; [Networked(OnChanged = nameof(OnReadyUpdated))] private NetworkBool _isReady { get; set; }//only used in lobby now private int _localID; private bool _isStunned; private bool _canStun; private bool _enableCarRotation = false; private bool _areControlsEnabled = true; private IPhysicsManager _physicsManager; private ScoreManager _scoreManager; private TournamentLobbyManager _lobbyManager; private CollisionManager _collisionManager; private PlayerInput _playerInput; private PlayerInputHandler _playerInputHandler; private Observable<bool> _isRespawning = new Observable<bool>(false); private Observable<bool> _isActiveInGame = new Observable<bool>(false); private Observable<Color> _playerColor = new Observable<Color>(Color.white); public event Action<PlayerNumber, bool> OnReady; public PlayerInput PlayerInput => _playerInput; public Observable<bool> IsRespawning => _isRespawning; public Observable<bool> IsActiveInGame { get => _isActiveInGame; set => _isActiveInGame = value; } public GrappleTurret GrappleTurret => _grappleTurret; public IPhysicsManager PhysicsManager => _physicsManager; public Rigidbody Rigidbody => _rigidbody; public NetworkRigidbody NetworkRigidbody => _networkRigidbody; public GameObject GameObject => gameObject; public Transform Transform => _rigidbody.transform; public bool IsGrappling => _grappleAbility.IsGrappling; public PlayerNumber PlayerNumber => _playerNumber; public ScoreManager ScoreManager => _scoreManager; public Observable<Color> PlayerColor => _playerColor; public Ray AimRay => _grappleAbility.AimRay; public int LocalID { get => _localID; set => _localID = value; } public NetworkBool IsReady => _isReady; public IGrappleTarget GrappleTarget => _grappleAbility.GrappleTarget; public SpeedTracker SpeedTracker => _speedTracker; private void Awake() { PlayerConfig playerConfig = FindAnyObjectByType<PlayerConfig>(); _physicsManager = GetComponent<PhysicsManager>(); _physicsManager.MaxSpeed = playerConfig.GameSettingsConfig.MaxSpeed; _playerInput = GetComponent<PlayerInput>(); _scoreManager = GetComponent<ScoreManager>(); _playerInputHandler = GetComponent<PlayerInputHandler>(); _collisionManager = GetComponent<CollisionManager>(); _collisionManager.OnCollisionEnter += HandleCollisionEnter; _collisionManager.OnCollisionStay += HandleCollisionStay; _collisionManager.OnCollisionExit += HandleCollisionExit; } public override void Spawned() { _isReady = false; _lobbyManager = FindObjectOfType<TournamentLobbyManager>(); // We start with grappling enabled. For the lobby Unstun(); _canStun = _enableStunMechanic; _enableCarRotation = false; // Set the cosmetics data for the grapple ability PlayerCosmeticsManager playerCosmeticsManager = PlayerCosmeticsManager.Instance; PlayerCosmeticsData playerCosmeticsData = playerCosmeticsManager.GetPlayerCosmeticsData(_playerNumber); _grappleAbility.SetPlayerCosmeticsData(playerCosmeticsData); } public override void FixedUpdateNetwork() { HandlePlayerInput(); RotateTowardsMovement(); if (Runner.IsResimulation) { return; } _collisionManager.CheckCollisions(); _grappleAbility.UpdateNetworkData(); _physicsManager.ApplyForces(); } private void HandlePlayerInput() { if (GetInput<NetworkPlayerInputs>(out NetworkPlayerInputs networkPlayerInputs)) { NetworkPlayerInput networkPlayerInput = networkPlayerInputs.GetPlayerInput(_playerNumber); Ray aimRay = networkPlayerInput.GetAimRay(); SetAimRay(aimRay); // Hack: This is messy but we need to set the aim ray even if controls are disabled so that we rotate the turret correctly if (!_areControlsEnabled) { return; } // If the grapple button is pressed if (networkPlayerInput.NetworkButtons.IsSet(PlayerButton.GrappleButton)) { if (!_grappleAbility.IsGrappling) { // We use the aim ray from the Grapple Ability instead of the one from the player input // This is because the player input aim ray doesn't take into account // the player position and rotation // The GrappleAbility handles all of this for us StartGrapple(_grappleAbility.AimRay); } } else { if (_grappleAbility.IsGrappling) { StopGrapple(); } } } } private void RotateTowardsMovement() { if (!_enableCarRotation) { return; } // Rotate the car towards the direction of travel. if (_rigidbody.velocity.x != 0 || _rigidbody.velocity.z != 0) { // Calculate the target rotation based on the direction of the velocity. Vector3 flattenedVelocity = new Vector3(_rigidbody.velocity.x, 0f, _rigidbody.velocity.z); Vector3 normalizedVelocity = flattenedVelocity.normalized; // If we not moving, then don't rotate // Note: if we try to call Quaternion.LookRotation with a zero vector, it will spam the console with useless log messages if (normalizedVelocity == Vector3.zero) { return; } Quaternion targetRotation = Quaternion.LookRotation(flattenedVelocity.normalized, Vector3.up); // Smoothly rotate towards the target rotation. float rotationSpeed = 10.0f; _bumperCar.transform.rotation = Quaternion.Slerp(_bumperCar.transform.rotation, targetRotation, rotationSpeed * Time.deltaTime); } } public void ToggleReady() { RPCSetReady(!_isReady); } public void ResetReady() { RPCSetReady(false); } [Rpc(sources: RpcSources.InputAuthority, targets: RpcTargets.StateAuthority)] private void RPCSetReady(NetworkBool state) { _isReady = state; } protected static void OnReadyUpdated(Changed<PlayerController> changed) { changed.Behaviour._lobbyManager.ReadyChange(changed.Behaviour.PlayerNumber, changed.Behaviour._isReady); } public void SpawnAtLocation(Vector3 location, Quaternion rotation) { _rigidbody.transform.position = location; _rigidbody.transform.rotation = rotation; _rigidbody.velocity = Vector3.zero; _rigidbody.angularVelocity = Vector3.zero; } public void SetAimRay(Ray ray) { _grappleAbility.SetAimRay(ray); } public void ClearAimRay() { _grappleAbility.ClearAimRay(); } public void StartGrapple(Ray ray) { if (_isRespawning) { return; } _grappleAbility.StartGrapple(ray); } public void StopGrapple() { _grappleAbility.StopGrapple(); } /// <summary> /// This function takes in a force vector and applies it to the player as a boost /// </summary> /// <param name="boostForce"></param> public void Boost(Vector3 boostForce, ForceMode forceMode = ForceMode.Impulse) { if (!_areControlsEnabled) { return; } // If the boost is coming from the local player, then we want to send an RPC to the server // to handle the boost if (Object.HasInputAuthority) { _physicsManager.RPCEnqueueForce(boostForce, forceMode); } else if (Object.HasStateAuthority) // we are the host, apply the boost { _physicsManager.EnqueueForce(boostForce, forceMode); } } public void ScaleMomentum(float amount) { _physicsManager.ScaleMomentum(amount); } public void StartNewRound() { Unstun(); _scoreManager.StartNewRound(); } public void GameOver() { FreezeMovement(); _scoreManager.GameOver(); } public void SetRespawning(bool isRespawning) { _isRespawning.Value = isRespawning; if (isRespawning) { DisableControls(); } else { EnableControls(); } } public void Die() { OnPlayerDied?.Invoke(this); } public void FreezeMovement() { _physicsManager.StopMomentum(); } public void DisableControls() { _areControlsEnabled = false; _enableCarRotation = false; _scoreManager.DisableScoreKeeping(); _grappleAbility.DisableGrappleAbility(); _grappleAbility.DisableGrappleAbility(); } public void EnableControls() { _areControlsEnabled = true; _enableCarRotation = true; _isActiveInGame.Value = true; _scoreManager.EnableScoreKeeping(); _grappleAbility.EnableGrappleAbility(); } [Rpc(sources: RpcSources.All, targets: RpcTargets.All)] public void RPCEnableControls() { EnableControls(); } public void StoreMinGameScore() { _scoreManager.StoreScore(); } public void SetAsWinner() { _winnerEffect.PlayEffect(); float duration = 5.0f; float rotationSpeed = 100.0f; float targetRotation = duration * rotationSpeed; _bumperCar.transform.DORotate(new Vector3(0.0f, targetRotation, 0.0f), duration, RotateMode.FastBeyond360) .SetEase(Ease.Linear); } public void Stun() { if (_isStunned || !_canStun) { return; } _isStunned = true; StopGrapple(); _grappleAbility.DisableGrappleAbility(); _stunVisual.SetActive(true); StartCoroutine(UnstunDelay()); } private IEnumerator UnstunDelay() { yield return new WaitForSeconds(_stunDuration); Unstun(); } private void Unstun() { _isStunned = false; _grappleAbility.EnableGrappleAbility(); _stunVisual.SetActive(false); _canStun = false; StartCoroutine(ResetStun()); } private IEnumerator ResetStun() { yield return new WaitForSeconds(_stunCooldown); _canStun = _enableStunMechanic; } public void SetPlayerCamera(PlayerCamera playerCamera) { _playerInputHandler.PlayerInputListener.SetPlayerCamera(playerCamera); } private void HandleCollisionExit(Collider collider, Vector3 collisionPoint) { List<ICollidable> collidables = collider.GetComponents<ICollidable>().ToList(); foreach (ICollidable collidable in collidables) { if (collidable != null) { collidable.CollisionExit(this.gameObject, collisionPoint); } } } private void HandleCollisionStay(Collider collider, Vector3 collisionPoint) { List<ICollidable> collidables = collider.GetComponents<ICollidable>().ToList(); foreach (ICollidable collidable in collidables) { if (collidable != null) { collidable.CollisionStay(this.gameObject, collisionPoint); } } } private void HandleCollisionEnter(Collider collider, Vector3 collisionPoint) { List<ICollidable> collidables = collider.GetComponents<ICollidable>().ToList(); foreach (ICollidable collidable in collidables) { if (collidable != null) { collidable.CollisionEnter(this.gameObject, collisionPoint); } } } public void MiniGameCompleted() { _collisionManager.ClearCollisionTracking(); } }}
Comments