在上一篇公眾號文章《》中,我們已通過 Passport Login 實現(xiàn)了用戶登錄功能。本節(jié)教程將延續(xù)上一節(jié)的開發(fā)脈絡(luò),基于已搭建的 Passport 服務(wù)器環(huán)境,繼續(xù)為你的游戲項目添加核心功能——從角色創(chuàng)建到角色管理的全流程實現(xiàn)。
從基礎(chǔ)功能搭建到角色體系擴展,一步步為你的游戲角色「建立完整身份檔案」,讓角色系統(tǒng)真正「立起來」!
教程視頻
項目工程獲取與學(xué)習(xí)指引
1. 初始項目工程下載
倉庫地址:
https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson1-start
分支名稱:lesson1-start 分支
分支說明:請先下載 lesson1-start 分支的項目工程,并確保您已經(jīng)按照《》中的步驟,成功實現(xiàn)了用戶登錄功能。然后,再接著學(xué)習(xí)本節(jié)教程的內(nèi)容。
倉庫地址:
https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson1-end
分支名稱:lesson1-end 分支
分支說明:lesson1-end 分支包含本節(jié)所有功能的完整實現(xiàn)代碼,建議在學(xué)習(xí)完成后參考或用于調(diào)試對照。
教程學(xué)習(xí)大綱
1.獲取 Passport 創(chuàng)建的域
2. 判斷域中是否已經(jīng)創(chuàng)建過角色
3. 域中如果無角色,則創(chuàng)建新角色
4. 域中如果已有角色,則直接獲取已創(chuàng)建過的角色
5. 在玩家信息界面上同步更新顯示角色的昵稱
教程操作步驟
接下來我們來看看,如何創(chuàng)建并管理你的角色!
1. 獲取 Passport 創(chuàng)建的域
登錄完成后,可以創(chuàng)建一個角色進入游戲,需要先判斷指定的域下是否創(chuàng)建了角色。
域的概念:
域:對應(yīng)游戲中區(qū)服的概念,可以根據(jù)開發(fā)者的需求來實現(xiàn)滾服或者合服。我們的游戲設(shè)計并不是強養(yǎng)成類型,不需要滾服,所以只需要創(chuàng)建一個默認的域(Realm)就可以滿足需求。
在 Identity.cs 腳本中添加代碼:
定義變量 _defaultRealmID 用于緩存用戶所屬的默認服務(wù)器的域 ID。
定義變量 CurrentPersona 表示用戶的身份信息,如用戶名、頭像等,用于全局訪問當前登錄用戶的身份數(shù)據(jù)。
添加方法 GetRealmID:在方法中,會先調(diào)用 PassportSDK 提供的 GetRealms 方法獲取已經(jīng)創(chuàng)建的域的列表,然后從域列表中根據(jù)需要選擇一個域,在這里我們暫時先使用域列表的第一個域。大家也可以根據(jù)自己的需求,選擇你想要使用的某一個域。
using System.Linq;
using Passport;
using Unity.Passport.Runtime;
using System.Threading.Tasks;
namespace TwentyFour.Scripts.Features.Player
{
public class Identity
{
private static string _defaultRealmID = "";
public static Persona CurrentPersona;
public static async Task
GetRealmID() { if (!string.IsNullOrEmpty(_defaultRealmID)) return _defaultRealmID; var realms = await PassportSDK.Identity.GetRealms(); if (realms.Any()) { _defaultRealmID = realms[0].RealmID; } return _defaultRealmID; } } }
我們可以進入 UOS 網(wǎng)頁端 Passport 的「服務(wù)器」模塊,可以看到默認已經(jīng)幫我們創(chuàng)建了一個域了。大家也可以點擊按鈕「創(chuàng)建新的域」來實現(xiàn)構(gòu)建一個域。
2. 判斷域中是否創(chuàng)建過角色
在用戶進入主頁時,需要驗證用戶是否已創(chuàng)建角色。所以在 LoadGameData.cs 腳本中,先注釋掉 Start 中對 Init 方法的調(diào)用,然后創(chuàng)建協(xié)程方法 CheckPersona來判斷這個功能。
調(diào)用之前定義的 Identity 腳本類中的方法 GetRealmID,來異步獲取用戶所屬的默認域 ID,等待異步任務(wù)完成后,若獲取到有效的域 ID,則將其存入 realmID 變量,供下一步使用;
然后再調(diào)用 Passport SDK 的接口 GetPersonaByRealm,異步獲取指定域 ID 下用戶的角色信息,在使用 WaitUntil 確保獲取角色數(shù)據(jù)的任務(wù)完成后,輸出打印下獲取到的 Persona 是否為 null,用于調(diào)試。若為 null,說明用戶在該域下未創(chuàng)建角色。
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TwentyFour.Scripts.Features.Save;
using TwentyFour.Scripts.Gameplay.GameMode.StageMode;
using Passport;
using Unity.Passport.Runtime;
using System.Threading.Tasks;
using System;
using TwentyFour.Scripts.Features.Player;
using Logger = TwentyFour.Scripts.Utilities.Logger;
namespace TwentyFour.Scripts.Gameplay.HomePage
{
public class LoadGameData : MonoBehaviour
{
public GameObject createPersonaDialog;
public Text progressTextTmp;
void Start()
{
StartCoroutine(CheckPersona());
}
IEnumerator CheckPersona()
{
string realmID = String.Empty;
Task
task = Identity.GetRealmID(); yield return new WaitUntil(()=>task.IsCompleted); if (!string.IsNullOrEmpty(task.Result)) realmID = task.Result; Task getPersonaTask = PassportSDK.Identity.GetPersonaByRealm(realmID); yield return new WaitUntil(()=>getPersonaTask.IsCompleted); Logger.Log("getPersonaTask.Result == null :" + (getPersonaTask.Result == null)); } //...... } }
運行項目后,可以在控制臺看到輸出的日志信息:Result 為 null,說明并沒有創(chuàng)建過角色。
3. 域中無角色,則創(chuàng)建新角色
3.1 激活創(chuàng)建角色的彈窗
如果 getPersonaTask.Result 為空,說明域中沒有角色,我們需要先激活創(chuàng)建角色的彈窗。
在 LoadGameData.cs 腳本的 CheckPersona 方法中,則先激活創(chuàng)建角色的彈框?qū)ο?createPersonaDialog 。
public class LoadGameData : MonoBehaviour
{
public GameObject createPersonaDialog;
public Text progressTextTmp;
//......
IEnumerator CheckPersona()
{
string realmID = String.Empty;
Task
task = Identity.GetRealmID(); yield return new WaitUntil(()=>task.IsCompleted); if (!string.IsNullOrEmpty(task.Result)) realmID = task.Result; Task getPersonaTask = PassportSDK.Identity.GetPersonaByRealm(realmID); yield return new WaitUntil(()=>getPersonaTask.IsCompleted); Logger.Log("getPersonaTask.Result == null :" + (getPersonaTask.Result == null)); if (getPersonaTask.Result == null) { Logger.Log("當前域無角色,請創(chuàng)建新角色"); createPersonaDialog.SetActive(true); } } }
在 Hierarchy 窗口中,找到 LoadGameData 對象,為其身上的腳本 LoadGameData.cs 中的變量 createPersonaDialog 賦值:
然后運行測試,在 Game 窗口中看到了 UI 的彈窗。
接著,我們要開始創(chuàng)建角色了。
3.2 定義委托表示角色創(chuàng)建完成的回調(diào)
在 LoginController.cs 腳本中定義一個委托,來實現(xiàn)當角色創(chuàng)建完成后,返回創(chuàng)建的角色的時候使用。
public class LoginController : MonoBehaviour
{
//......
public delegate void CreatePersonaCompleteCallback(Persona persona);
}3.3 添加創(chuàng)建角色的腳本
在 Login 腳本文件夾下,再創(chuàng)建一個新的腳本 CreatePersona.cs,來實現(xiàn)創(chuàng)建角色的功能。
CreatePersona.cs 腳本代碼邏輯如下:
定義變量 personaNameText,指向 UI 中用戶輸入角色名稱的輸入框組件;
同時獲取下 LoginController.cs 腳本中的委托變量,用于觸發(fā)角色創(chuàng)建成功時的回調(diào);
在 Create 方法中,先獲取到已經(jīng)創(chuàng)建好的域,存儲在 realmID 變量中。然后調(diào)用 PassportSDK 提供的 CreatePersona 方法,在指定的域 realmID 中來創(chuàng)建一個角色,并賦值給 persona 變量;
角色創(chuàng)建成功后,將創(chuàng)建的角色 persona 通過委托返回;
同時會使用 try...catch... 捕獲 Passport 遇到的異常,并在 UI 界面上顯示出錯誤信息。
using Passport;
using Unity.Passport.Runtime;
using Unity.UOS.TwentyFour;
using UnityEngine.UI;
using UnityEngine;
using Unity.Passport.Runtime.UI;
namespace TwentyFour.Scripts.Features.Player
{
public class CreatePersona : MonoBehaviour
{
public InputField personaNameText;
public LoginController.CreatePersonaCompleteCallback OnCreatePersonaComplete;
///
/// 創(chuàng)建 Persona
///
public async void Create()
{
if (string.IsNullOrEmpty(personaNameText.text))
{
Debug.LogError("Empty Persona name");
}
try
{
var realmID = await Identity.GetRealmID();
Persona persona = await PassportSDK.Identity.CreatePersona(personaNameText.text, realmID);
Debug.Log("成功創(chuàng)建角色");
OnCreatePersonaComplete(persona);
}
catch (PassportException e)
{
Debug.Log(e.Code);
UIMessage.Show(e.ErrorMessage, MessageType.Error);
}
}
}
}將 CreatePersona.cs 腳本拖拽給場景中的 CreatePersonaDialog 對象,并為面板上的 personaNameText 變量賦值:
找到創(chuàng)建角色的面板(CreatePersonaDialog)上的「確定」按鈕(Button_Ok):
給按鈕(Button_Ok)對象,綁定 CreatePersona.cs 腳本中的 Create 方法。
3.4 創(chuàng)建角色完成后加載游戲關(guān)卡
繼續(xù)在 LoadGameData.cs 腳本中添加代碼:
創(chuàng)建角色框?qū)ο蠹せ铒@示以后,獲取到它身上的 CreatePersona.cs 腳本組件,并將之前定義的委托對象綁定到當前腳本類中的 OnCreatePersonaComplete 方法;
在回調(diào)方法 OnCreatePersonaComplete 中,將全局身份管理類 Identity.cs 的 CurrentPersona 屬性,設(shè)置為新創(chuàng)建的角色;
同時,在角色創(chuàng)建完成的回調(diào)方法中,還會調(diào)用新添加的協(xié)程方法 SelectPersonaAndInit。并在方法內(nèi)調(diào)用協(xié)程方法 Init() ,來加載關(guān)卡的數(shù)據(jù)進行闖關(guān)。
public class LoadGameData : MonoBehaviour
{
//......
IEnumerator CheckPersona()
{
//......
if (getPersonaTask.Result == null)
{
Logger.Log("當前域無角色,請創(chuàng)建新角色");
createPersonaDialog.SetActive(true);
var createPersonaController = createPersonaDialog.GetComponent ();
createPersonaController.OnCreatePersonaComplete = OnCreatePersonaComplete;
}
}
void OnCreatePersonaComplete(Persona p)
{
Identity.CurrentPersona = p;
Logger.LogInfo($"創(chuàng)建角色成功,角色ID:{Identity.CurrentPersona.PersonaID}");
StartCoroutine(SelectPersonaAndInit());
}
IEnumerator SelectPersonaAndInit()
{
yield return StartCoroutine(Init());
}
//......
}3.5 運行游戲進行測試,開啟敏感詞檢測
在 Game 窗口創(chuàng)建角色的彈窗中,輸入角色的昵稱。
開通敏感詞檢測功能:
在 Passport 的「用戶管理」頁面,可以開啟角色對用戶名/角色名的敏感詞檢測。
開啟敏感詞檢測后,在輸入了敏感詞信息時,會在 Game 窗口和 Console 窗口看到提示的“無效的名字” 的錯誤,表明所輸入的名稱并未通過敏感詞檢測,可以重新輸入一個昵稱。
重新輸入昵稱點擊「確定」后,就可以進入游戲主頁面,選擇闖關(guān)了。
在 Passport 的「角色管理」頁面,可以看到創(chuàng)建過的名稱為 Player1 的角色。
4. 域中已有角色,則直接獲取已創(chuàng)建的角色
在 LoadGameData.cs 腳本中繼續(xù)添加判斷:
如果用戶已經(jīng)創(chuàng)建過角色,則通過 getPersonaTask.Result 直接獲取創(chuàng)建好的角色;
然后調(diào)用協(xié)程方法 SelectPersonaAndInit,直接來跳轉(zhuǎn)到游戲闖關(guān)頁面。
public class LoadGameData : MonoBehaviour
{
//......
IEnumerator CheckPersona()
{
if (getPersonaTask.Result == null)
{
Logger.Log("當前域無角色,請創(chuàng)建新角色");
//......
}
else
{
Identity.CurrentPersona = getPersonaTask.Result;
yield return StartCoroutine(SelectPersonaAndInit());
Logger.Log($"當前角色為:{Identity.CurrentPersona.DisplayName}");
}
}
}大家可以自行再次運行測試下,已經(jīng)有角色后,是不會再彈出創(chuàng)建角色的輸入框的。
5. 在玩家信息界面上同步更新顯示角色的昵稱
在下圖所示的路徑下,創(chuàng)建一個新的文件夾 PlayerInfo,并在該文件夾下創(chuàng)建一個新的腳本 PlayerInfoPanel.cs,來實現(xiàn)將用戶創(chuàng)建的角色昵稱同步顯示在玩家的信息面板上。
腳本中 PlayerInfoPanel.cs 代碼如下:
定義變量 playerName,用來更新顯示昵稱;
新添加一個方法 GetPlayerInfo,將 Identity.cs 腳本中之前存儲的角色( CurrentPersona) 的昵稱顯示在 UI 文本框上;
同時,會在 PlayerInfoPanel 面板打開時自動調(diào)用的 OnEnable 方法中,調(diào)用 GetPlayerInfo 方法,來更新 UI 的顯示。
using System;
using UnityEngine;
using UnityEngine.UI;
namespace TwentyFour.Scripts.Features.Player
{
public class PlayerInfoPanel : MonoBehaviour
{
public Text playerName;
private void OnEnable()
{
GetPlayerInfo();
}
private void GetPlayerInfo()
{
playerName.text = Identity.CurrentPersona?.DisplayName;
}
}
}找到 MainScene 場景中的 PlayerInfoPanel 對象,將腳本 PlayerInfoPanel.cs 拖拽到它身上,并為 Inspector 面板上的 playerName 變量賦值:
運行項目后,可以看到如下所示的效果,已經(jīng)可以更新顯示用戶昵稱了。
管理創(chuàng)建過的角色
刪除角色
在 Passport 的「角色管理」頁面,可以看到所有已創(chuàng)建過的角色信息,以及該角色所屬的用戶 ID。如果想刪除某個角色的話,可以點擊角色信息最右側(cè)的「刪除角色」的按鈕。
大家在彈窗中,一定要仔細閱讀提示信息后,再點擊「確認刪除」按鈕哦!剛才選中的角色就被成功刪除了。
刪除用戶
接下來,大家先看下我選中的這條角色信息,可以看到 1000001004 角色是屬于 1000001002 用戶的。
在 Passport 的「用戶管理」頁面,可以看到登錄過的所有用戶。我們點擊「用戶管理」頁面上的 1000001002 用戶最右側(cè)的「刪除用戶」按鈕:
會有彈窗再次提醒大家,是否真的要刪除該用戶的。因為刪除用戶時,也會把該用戶剛才創(chuàng)建的角色一起刪除的。如果你確定要刪除,就點擊「確認刪除」的按鈕。
當我們成功刪除了指定用戶 1000001002 后,在「用戶管理」頁面已經(jīng)沒有該用戶了,而且在「角色管理」頁面可以看到該用戶下的角色也已經(jīng)一起被刪除了。
下節(jié)教程預(yù)告
教程主題——《火拼24》系列教程二:動態(tài)調(diào)控游戲關(guān)卡難度
《火拼24》下一篇教程,將聚焦使用 Remote Config 動態(tài)調(diào)控游戲關(guān)卡難度的實戰(zhàn)技巧,教你如何通過遠程配置靈活調(diào)整游戲關(guān)卡難度參數(shù),無需發(fā)布新版本即可優(yōu)化玩家體驗!
小貼士:為方便大家提前學(xué)習(xí),教程二的分支代碼已同步更新,可提前下載查閱或本地調(diào)試。
教程二:初始項目工程(供學(xué)習(xí)參考)
https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson2-start
教程二:完整示例工程參考(可直接運行)
https://cnb.cool/unity/uos/Rush24Tutorial/-/tree/lesson2-end
Unity Online Services (UOS) 是一個專為游戲開發(fā)者設(shè)計的一站式游戲云服務(wù)平臺,提供覆蓋游戲全生命周期的開發(fā)、運營和推廣支持。
了解更多 UOS 相關(guān)信息:
官網(wǎng):https://uos.unity.cn
技術(shù)交流 QQ 群:823878269
Unity 官方微信
第一時間了解Unity引擎動向,學(xué)習(xí)進階開發(fā)技能
每一個“點贊”、“在看”,都是我們前進的動力
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.