SceneLobby(main):Add script and setup
This commit is contained in:
8
Assets/Scripts/Duy.meta
Normal file
8
Assets/Scripts/Duy.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 42e6f48f26d671a42a9b398d02557c1f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
113
Assets/Scripts/Duy/LobbyManager.cs
Normal file
113
Assets/Scripts/Duy/LobbyManager.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System.Collections.Generic;
|
||||
using Fusion;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class _LobbyManager : MonoBehaviour
|
||||
{
|
||||
public GameObject lobbyPanel;
|
||||
public GameObject characterSelectionPanel;
|
||||
|
||||
public _BasicSpawner spawner;
|
||||
|
||||
[Header("Character Selection")] public TMP_InputField playerNameInput;
|
||||
|
||||
public Image[] characterPreviewImages;
|
||||
|
||||
|
||||
public int selectedCharacterIndex = 0;
|
||||
|
||||
[Header("Room List")] public GameObject roomListParent;
|
||||
public GameObject roomListItemPrefab;
|
||||
public TMP_InputField roomNameInput;
|
||||
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
async void Start()
|
||||
{
|
||||
lobbyPanel.SetActive(false);
|
||||
characterSelectionPanel.SetActive(true);
|
||||
OnSelectCharacter(selectedCharacterIndex);
|
||||
|
||||
spawner = FindFirstObjectByType<_BasicSpawner>();
|
||||
await spawner.StartLobby();
|
||||
}
|
||||
|
||||
public void OnSelectCharacter(int index)
|
||||
{
|
||||
selectedCharacterIndex = index;
|
||||
// update preview images
|
||||
for (var i = 0; i < characterPreviewImages.Length; i++)
|
||||
{
|
||||
characterPreviewImages[i].color = (i == index)
|
||||
? Color.green
|
||||
: Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnNextButton()
|
||||
{
|
||||
var playerName = playerNameInput.text;
|
||||
if (string.IsNullOrEmpty(playerName))
|
||||
{
|
||||
Debug.LogWarning("Player name cannot be empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
// tạo 1 player _profile tạm thời, sau này sẽ gửi lên server để tạo player object
|
||||
var _profile = new _PlayerProfile()
|
||||
{
|
||||
Name = playerName,
|
||||
Class = (_CharacterClass)selectedCharacterIndex
|
||||
};
|
||||
spawner.SetLocalPlayerProfile(_profile);
|
||||
// đưa lên host để tạo player object, ở đây tạm thời chỉ log ra console
|
||||
Debug.Log($"Player Name: {_profile.Name}, Class: {_profile.Class}");
|
||||
// chuyển sang lobby panel
|
||||
characterSelectionPanel.SetActive(false);
|
||||
lobbyPanel.SetActive(true);
|
||||
}
|
||||
|
||||
// hiển thị danh sách phòng
|
||||
public void DisplayRoomList(List<SessionInfo> sessions)
|
||||
{
|
||||
Debug.Log($"Received {sessions.Count} sessions from lobby");
|
||||
// clear danh sách cũ
|
||||
foreach (Transform child in roomListParent.transform)
|
||||
{
|
||||
Destroy(child.gameObject);
|
||||
}
|
||||
|
||||
if (sessions.Count == 0) return;
|
||||
|
||||
// tạo item mới cho mỗi phòng
|
||||
foreach (var session in sessions)
|
||||
{
|
||||
var item = Instantiate(roomListItemPrefab, roomListParent.transform);
|
||||
var text = item.GetComponentInChildren<TextMeshProUGUI>();
|
||||
text.text = $"{session.Name} ({session.PlayerCount}/{session.MaxPlayers})";
|
||||
var button = item.GetComponentInChildren<Button>();
|
||||
button.onClick.AddListener(() => OnJoinRoom(session.Name));
|
||||
item.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
async void OnJoinRoom(string sessionName)
|
||||
{
|
||||
await spawner.StartClient(sessionName);
|
||||
}
|
||||
|
||||
public async void OnCreateRoomButton()
|
||||
{
|
||||
var roomName = roomNameInput.text;
|
||||
if (string.IsNullOrEmpty(roomName))
|
||||
{
|
||||
Debug.LogWarning("Room name cannot be empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
// tạo phòng mới với tên đã nhập
|
||||
await spawner.StartHost(roomName, SceneRef.FromIndex(1));
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Duy/LobbyManager.cs.meta
Normal file
2
Assets/Scripts/Duy/LobbyManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 258164a5e282e34489a3c62c443c22f0
|
||||
31
Assets/Scripts/Duy/PlayerDataManager.cs
Normal file
31
Assets/Scripts/Duy/PlayerDataManager.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Fusion;
|
||||
using UnityEngine;
|
||||
|
||||
// struct quản lý thông tin
|
||||
public struct _PlayerMetaData : INetworkStruct
|
||||
{
|
||||
public NetworkString<_16> Name;
|
||||
public _CharacterClass Class;
|
||||
}
|
||||
|
||||
public class _PlayerDataManager : NetworkBehaviour
|
||||
{
|
||||
// biến này của Fusion sẽ tự động đồng bộ giữa các client và host,
|
||||
// khi có thay đổi sẽ tự động cập nhật ở tất cả các bên
|
||||
[Networked]
|
||||
public NetworkDictionary<PlayerRef, _PlayerMetaData> Players => default;
|
||||
|
||||
// RPC: phương thức này sẽ được gọi từ client hoặc
|
||||
// host để cập nhật thông tin player, sau đó sẽ được gửi
|
||||
// đến state authority (host) để xử lý và đồng bộ lại cho tất cả các client
|
||||
[Rpc(RpcSources.All, RpcTargets.StateAuthority)]
|
||||
public void RPC_UpdatePlayerMetaData(PlayerRef playerRef, _PlayerMetaData metaData)
|
||||
{
|
||||
Players.Set(playerRef, metaData);
|
||||
}
|
||||
|
||||
public bool TryGetPlayerMetaData(PlayerRef playerRef, out _PlayerMetaData metaData)
|
||||
{
|
||||
return Players.TryGet(playerRef, out metaData);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Duy/PlayerDataManager.cs.meta
Normal file
2
Assets/Scripts/Duy/PlayerDataManager.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3d9934ebd60c9c4ea3e464b77fd7ae0
|
||||
50
Assets/Scripts/Duy/PlayerInfo.cs
Normal file
50
Assets/Scripts/Duy/PlayerInfo.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using Fusion;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
public enum _CharacterClass
|
||||
{
|
||||
Blue,
|
||||
Red
|
||||
}
|
||||
|
||||
public struct _PlayerProfile
|
||||
{
|
||||
public string Name;
|
||||
public _CharacterClass Class;
|
||||
}
|
||||
|
||||
public class PlayerInfo : NetworkBehaviour
|
||||
{
|
||||
[Networked] public string playerName { get; set; }
|
||||
|
||||
public _PlayerDataManager playerDataManager;
|
||||
public TextMeshProUGUI nameText;
|
||||
|
||||
public GameObject[] characterIcons; // mảng chứa icon tương ứng với từng class, có thể gán trong inspector
|
||||
|
||||
// sau khi game object được tạo ra trên mạng,
|
||||
// sẽ gọi phương thức này để khởi tạo thông tin player
|
||||
public override void Spawned()
|
||||
{
|
||||
playerDataManager = FindFirstObjectByType<_PlayerDataManager>(); // tìm PlayerDataManager trong scene
|
||||
}
|
||||
|
||||
// phương thức này sẽ được gọi mỗi frame để cập nhật thông tin hiển thị của player
|
||||
public override void Render()
|
||||
{
|
||||
if (playerDataManager == null) return;
|
||||
if (playerDataManager.TryGetPlayerMetaData(Object.InputAuthority, out var metadata))
|
||||
{
|
||||
var name = metadata.Name;
|
||||
var charClass = metadata.Class;
|
||||
|
||||
nameText.text = $"{name} ({charClass})";
|
||||
|
||||
for (var i = 0; i < characterIcons.Length; i++)
|
||||
{
|
||||
characterIcons[i].SetActive(i == (int)charClass); // hiển thị icon tương ứng với class của player
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Duy/PlayerInfo.cs.meta
Normal file
2
Assets/Scripts/Duy/PlayerInfo.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70abb536cf50f2948882e913634daedf
|
||||
6
Assets/Scripts/Duy/PlayerInputData.cs
Normal file
6
Assets/Scripts/Duy/PlayerInputData.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using Fusion;
|
||||
|
||||
public partial struct _PlayerInputData : INetworkInput
|
||||
{
|
||||
public float direction;
|
||||
}
|
||||
2
Assets/Scripts/Duy/PlayerInputData.cs.meta
Normal file
2
Assets/Scripts/Duy/PlayerInputData.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 731ed4a4b6e0ae64c8194463a76646c7
|
||||
278
Assets/Scripts/Duy/_BasicSpawner.cs
Normal file
278
Assets/Scripts/Duy/_BasicSpawner.cs
Normal file
@@ -0,0 +1,278 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Fusion;
|
||||
using Fusion.Sockets;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
// ghi nhận các input của người chơi, ở đây chỉ có hướng di chuyển
|
||||
|
||||
|
||||
public class _BasicSpawner : MonoBehaviour, INetworkRunnerCallbacks
|
||||
{
|
||||
private NetworkRunner _runner { get; set; }
|
||||
|
||||
public LobbyManager LobbyManager;
|
||||
|
||||
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
|
||||
// dont destroy this object when loading new scenes
|
||||
if(_runner == null) _runner = gameObject.AddComponent<NetworkRunner>();
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
// thông tin profile của player local, sẽ được tạo ra từ lobby và gửi lên host để tạo player object, ở đây tạm thời chỉ tạo 1 profile mặc định
|
||||
public _PlayerProfile LocalPlayerProfile { get; private set; }
|
||||
public void SetLocalPlayerProfile(_PlayerProfile _profile)
|
||||
{
|
||||
LocalPlayerProfile = _profile;
|
||||
}
|
||||
|
||||
// start lobby
|
||||
public async Task StartLobby()
|
||||
{
|
||||
if(_runner == null) _runner = gameObject.AddComponent<NetworkRunner>();
|
||||
_runner.ProvideInput = true;
|
||||
_runner.AddCallbacks(this);
|
||||
var result = await _runner.JoinSessionLobby(SessionLobby.ClientServer);
|
||||
if (result.Ok)
|
||||
{
|
||||
Debug.Log("Joined lobby successfully!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Failed to join lobby: {result.ShutdownReason}");
|
||||
}
|
||||
}
|
||||
|
||||
// tạo phòng
|
||||
public async Task StartHost(string sessionName, SceneRef scene)
|
||||
{
|
||||
var result = await _runner.StartGame(new StartGameArgs()
|
||||
{
|
||||
GameMode = GameMode.Host,
|
||||
SessionName = sessionName,
|
||||
Scene = scene,
|
||||
PlayerCount = 2,
|
||||
SceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>()
|
||||
});
|
||||
if (result.Ok)
|
||||
{
|
||||
Debug.Log("Started host successfully!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Failed to start host: {result.ShutdownReason}");
|
||||
}
|
||||
}
|
||||
|
||||
// tham gia phòng
|
||||
public async Task StartClient(string sessionName)
|
||||
{
|
||||
var result = await _runner.StartGame(new StartGameArgs()
|
||||
{
|
||||
GameMode = GameMode.Client,
|
||||
SessionName = sessionName,
|
||||
SceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>()
|
||||
});
|
||||
if (result.Ok) {
|
||||
Debug.Log("Started client successfully!");
|
||||
}
|
||||
else {
|
||||
Debug.LogError($"Failed to start client: {result.ShutdownReason}");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[SerializeField] private NetworkPrefabRef _playerPrefab;
|
||||
private Dictionary<PlayerRef, NetworkObject> _spawnedCharacters = new Dictionary<PlayerRef, NetworkObject>();
|
||||
|
||||
public void OnPlayerJoined(NetworkRunner runner, PlayerRef player)
|
||||
{
|
||||
// nếu là host
|
||||
if (runner.IsServer)
|
||||
{
|
||||
Vector2 spawnPosition;
|
||||
|
||||
if (player == runner.LocalPlayer)
|
||||
{
|
||||
spawnPosition = new Vector2(-8, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
spawnPosition = new Vector2(8, 0);
|
||||
}
|
||||
|
||||
|
||||
// Create a unique position for the player
|
||||
// var spawnPosition = new Vector2(Random.Range(0, 5), Random.Range(0, 5));
|
||||
var networkPlayerObject = runner.Spawn(
|
||||
_playerPrefab,
|
||||
spawnPosition,
|
||||
Quaternion.identity,
|
||||
player);
|
||||
// Keep track of the player avatars for easy access
|
||||
_spawnedCharacters.Add(player, networkPlayerObject);
|
||||
// if (runner.ActivePlayers.Count() == 2 && !_ballStarted)
|
||||
// {
|
||||
// var ball = FindFirstObjectByType<Ball>();
|
||||
// ball.Launch();
|
||||
// _ballStarted = true;
|
||||
// }
|
||||
|
||||
|
||||
}
|
||||
|
||||
Debug.Log("Player joined: " + player + ", is local player: " + (player == runner.LocalPlayer));
|
||||
if (player == runner.LocalPlayer)
|
||||
{
|
||||
var pdm = FindFirstObjectByType<_PlayerDataManager>();
|
||||
if (pdm == null) return;
|
||||
var metaData = new _PlayerMetaData()
|
||||
{
|
||||
Name = LocalPlayerProfile.Name,
|
||||
Class = LocalPlayerProfile.Class,
|
||||
|
||||
};
|
||||
pdm.RPC_UpdatePlayerMetaData(player, metaData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void OnPlayerLeft(NetworkRunner runner, PlayerRef player)
|
||||
{
|
||||
if (_spawnedCharacters.TryGetValue(player, out NetworkObject networkObject))
|
||||
{
|
||||
runner.Despawn(networkObject);
|
||||
_spawnedCharacters.Remove(player);
|
||||
if (runner.IsServer)
|
||||
{
|
||||
runner.Shutdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsGameReady(NetworkRunner runner)
|
||||
{
|
||||
|
||||
return runner.ActivePlayers.Count() >= 2;
|
||||
}
|
||||
|
||||
public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason)
|
||||
{
|
||||
Debug.Log("Game shutdown: " + shutdownReason);
|
||||
|
||||
|
||||
UnityEngine.SceneManagement.SceneManager.LoadScene("Lobby");
|
||||
}
|
||||
|
||||
public void OnDisconnectedFromServer(NetworkRunner runner, NetDisconnectReason reason)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ReliableKey key, ArraySegment<byte> data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void OnInput(NetworkRunner runner, NetworkInput input)
|
||||
{
|
||||
// collect the input and send it to the runner, which will then be sent to the server and other clients
|
||||
var data = new _PlayerInputData();
|
||||
data.direction = Input.GetAxis("Vertical");
|
||||
input.Set(data);
|
||||
}
|
||||
|
||||
public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnConnectedToServer(NetworkRunner runner)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// khi có update về danh sách phòng,
|
||||
// ví dụ khi có phòng mới được tạo hoặc phòng bị xóa,
|
||||
// host sẽ gửi update này cho tất cả client trong lobby
|
||||
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)
|
||||
{
|
||||
Debug.Log("Session list updated, total sessions: " + sessionList.Count);
|
||||
LobbyManager.DisplayRoomList(sessionList);
|
||||
}
|
||||
|
||||
public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary<string, object> data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnSceneLoadDone(NetworkRunner runner)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnSceneLoadStart(NetworkRunner runner)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void DespawnGO(NetworkObject networkObject)
|
||||
{
|
||||
if (_runner != null && networkObject != null)
|
||||
{
|
||||
_runner.Despawn(networkObject);
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkObject SpawnGO(NetworkPrefabRef prefabRef, Vector2 position,Quaternion rotation, PlayerRef owner = default)
|
||||
{
|
||||
if (_runner != null)
|
||||
{
|
||||
return _runner.Spawn(prefabRef, position, rotation, owner);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/Duy/_BasicSpawner.cs.meta
Normal file
2
Assets/Scripts/Duy/_BasicSpawner.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca752d01bdc2c5e42938776307031da3
|
||||
Reference in New Issue
Block a user