top of page

未発表パーティゲーム 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();
        }
    }
}

Recent Posts

See All

Comments


© 2024 by Matthew Sandfrey. Proudly created with Wix.com

bottom of page