未発表パーティゲーム BasicSpawner.cs
- msandfrey3
- Aug 12, 2024
- 3 min read
using System.Collections.Generic;using PartyGame.Character.Player;using PartyGame.Multiplayer.Inputs;using UnityEngine;using UnityEngine.InputSystem;using Fusion;namespace PartyGame.Multiplayer{ public class PlayerSpawner : NetworkBehaviour, IPlayerJoined, IPlayerLeft { [SerializeField] private Transform[] _spawnPoints; [SerializeField] private NetworkPrefabRef _playerPrefab; [SerializeField] private NetworkPrefabRef _playerPrefab2; [SerializeField] private NetworkPrefabRef _playerPrefab3; [SerializeField] private NetworkPrefabRef _playerPrefab4; [SerializeField] private NetworkInputManager _inputManager; [SerializeField] private Character.Player.Players _netPlayers; [Networked(OnChanged = nameof(OnSpawnedCharsChanged))] [Capacity(4)]//set to 4 because of max 4 players private NetworkDictionary<NetworkObject, PlayerRef> _spawnedChars => default; [Networked(OnChanged = nameof(OnSpawnedCharsChanged))] [Capacity(4)]//set to 4 because of max 4 players private NetworkLinkedList<NetworkObject> _spawnedList => default; private PlayerRef _localRef; private NetworkPrefabRef _prefabToSpawn; private List<Gamepad> _connectedPads = new List<Gamepad>(); public override void Render() { // Cheat code to force more players to get added to the scene if (Input.GetKeyDown(KeyCode.A)) { if (Runner.IsSinglePlayer) { RPCLocalPlayerJoined(_localRef); SetupPlayerObject(_localRef); } } } public override void Spawned() { _localRef = Runner.LocalPlayer; if (GetPlayerCount() > Runner.SessionInfo.MaxPlayers) { Debug.Log("Too many players. No spawn."); return; } //setup for main network player if (Object.HasStateAuthority) { foreach (PlayerRef pRef in Runner.ActivePlayers) { NetworkPlayerJoined(pRef); SetupPlayerObject(pRef); } } else { SetupPlayerObject(_localRef); } if (Runner.IsSinglePlayer) { //local setup //if move this above network player setup limits players, and extras that join just watch int x = _inputManager.GetUnassignedGamepadCount(); for (int i = 0; i < x; i++) { RPCLocalPlayerJoined(_localRef); SetupPlayerObject(_localRef); } } //listen to when devices are added to add more players InputSystem.onDeviceChange += OnDeviceChange; } private void OnDeviceChange(InputDevice device, InputDeviceChange change) { if (change == InputDeviceChange.Added) { if (device is Gamepad) { Gamepad pad = (Gamepad)device; if (_inputManager.ConnectedPads.Contains(pad)) { return; } //unplugging and then replugging causes both added and reconnected to trigger //this makes another player ready to party but it has no controller to pilot it _inputManager.AddGamepad(pad); bool success = _inputManager.TryAssignController(pad); //dont spawn online right now if (!success && Runner.IsSinglePlayer) { RPCLocalPlayerJoined(_localRef); SetupPlayerObject(_localRef); } } } } //the host calls this when a player is spawned public void PlayerJoined(PlayerRef player) { if (!HasStateAuthority) return; if (Runner.GetPlayerObject(player) != null) return; NetworkPlayerJoined(player); } public void NetworkPlayerJoined(PlayerRef player)//for network players and host/main client { SetPrefabToSpawn(); NetworkObject networkPlayer = SpawnNewPlayer(player); if (networkPlayer == null) { Debug.LogError("The network player could not be spawned."); return; } // Set Player Object to facilitate access across systems. Runner.SetPlayerObject(player, networkPlayer); TrackPlayer(networkPlayer, player); } /// <summary> /// This will only be called when disconnected from the server. /// If a controller disconnects the player will still be shown. /// If we want to allow added local players to drop out we will need /// specific code for that. /// </summary> /// <param name="player"></param> public void PlayerLeft(PlayerRef player) { if (!HasStateAuthority) { return; } if (!_spawnedChars.ContainsValue(player)) { return; } //use ref to find all the objects to remove List<NetworkObject> objectsToRemove = new List<NetworkObject>(); foreach (KeyValuePair<NetworkObject, PlayerRef> netObj in _spawnedChars) { if (netObj.Value == player) { objectsToRemove.Add(netObj.Key); } } foreach (NetworkObject netObj in objectsToRemove) { _spawnedChars.Remove(netObj); PlayerController playerController = netObj.GetComponent<PlayerController>(); _netPlayers.RemovePlayer(playerController); PlayerInputHandler playerInputHandler = netObj.GetComponent<PlayerInputHandler>(); _inputManager.RemovePlayer(playerInputHandler); Runner.Despawn(netObj); } } /// <summary> /// This is used to spawn in additional local players. /// It will only spawn a new player if the player count /// is under the max amount of players allowed. /// </summary> /// <returns></returns> [Rpc(sources: RpcSources.All, targets: RpcTargets.StateAuthority)] public void RPCLocalPlayerJoined(PlayerRef player) { SetPrefabToSpawn(); NetworkObject localPlayer = SpawnNewPlayer(player); if (localPlayer == null) { Debug.Log("I spawn a nobody, you waste-a your time."); return; } TrackPlayer(localPlayer, _localRef); } private void SetupPlayerObject(PlayerRef player) { foreach (KeyValuePair<NetworkObject, PlayerRef> netObjPlayerPair in _spawnedChars) { if (netObjPlayerPair.Value == player) { NetworkObject networkPlayerObject = netObjPlayerPair.Key; if (networkPlayerObject == null) continue; if (_localRef == networkPlayerObject.InputAuthority) { Setup(networkPlayerObject); PlayerInputHandler playerInputHandler = networkPlayerObject.GetComponent<PlayerInputHandler>(); _inputManager.RegisterNewLocalPlayer(playerInputHandler); } } } } private void Setup(NetworkObject networkPlayerObject) { int localID = GetPlayerCount(); PlayerController playerController = networkPlayerObject.GetComponent<PlayerController>(); if (playerController.IsActiveInGame) { return; } playerController.LocalID = localID; playerController.RPCEnableControls(); //this could probably be simplified, unless we will only spawn a single prefab type TODO int playerNumber = localID; networkPlayerObject.name += playerNumber.ToString(); string actionPrefix = "Player" + playerNumber.ToString() + "."; string actionMap = (actionPrefix + "GameActionMap"); PlayerInputHandler playerInputHandler = networkPlayerObject.GetComponent<PlayerInputHandler>(); playerInputHandler.PlayerInputListener.SetGameActionMap(actionPrefix, actionMap); } private NetworkObject SpawnNewPlayer(PlayerRef player) { Vector3 spawnPosition = _spawnPoints[GetSpawnIndex()].position; return Runner.Spawn(_prefabToSpawn, spawnPosition, Quaternion.identity, player); } private void TrackPlayer(NetworkObject networkObject, PlayerRef player) { if (!_spawnedChars.ContainsKey(networkObject)) { _spawnedChars.Add(networkObject, player); int index = GetSpawnIndex(); if (index >= _spawnedList.Count) { _spawnedList.Add(networkObject); } else { _spawnedList.Set(GetSpawnIndex(), networkObject); } } //track with players PlayerController playerController = networkObject.GetComponent<PlayerController>(); _netPlayers.AddNewPlayer(playerController); } private int GetSpawnIndex() { int i = 0; foreach (NetworkObject no in _spawnedList) { if (no == null) return i; i++; } return i; } protected static void OnSpawnedCharsChanged(Changed<BasicSpawner> changed) { changed.Behaviour.SetPrefabToSpawn(); } private void SetPrefabToSpawn() { //create a list/array of these prefabs int index = GetSpawnIndex(); switch (index) { case 0: _prefabToSpawn = _playerPrefab; break; case 1: _prefabToSpawn = _playerPrefab2; break; case 2: _prefabToSpawn = _playerPrefab3; break; case 3: _prefabToSpawn = _playerPrefab4; break; default: break; } } private int GetPlayerCount() { return _spawnedChars.Count; } private int GetLocalPlayerCount() { int count = 0; foreach (KeyValuePair<NetworkObject, PlayerRef> character in _spawnedChars) { if(character.Value == _localRef) { count++; } } return count; } }}
Comments