部落 #

Nakama 可用于创建群组,又称为部落,这是一种小社区,其中玩家可以结队或一起出去玩。

通过 Pirate Panic,我们将学习如何让玩家:

  • 创建新部落
  • 加入或解散部落
  • 搜索公开部落
  • 自定义共享部落信息,例如名称和徽章
  • 与部落中的其他成员聊天

本教程不涵盖私密群组,这些群组要求新玩家提交加入请求然后才会被允许加入。您可以通过官方 Nakama 文档对此做进一步了解。

部落服务器模块 #

在进入 Unity 客户端实现之前,让我们先看看服务器端。

与其他模块一样,我们可以为特定事件注册自定义服务器行为,例如当有人创建新部落时。对于群组,我们关注以下各项:

  • registerAfterJoinGroup
  • registerAfterKickGroupUsers
  • registerAfterLeaveGroup
  • registerAfterPromoteGroupUsers
  • registerAfterAddFriends
  • registerBeforeDeleteGroup

请参阅这些事件的完整列表

发送通知 #

例如,当新玩家加入时,向部落中的每个人发送通知的函数如下所示:

clans.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
enum ClanNotificationCode {
    Refresh = 2,
    Delete = 3
}

function sendGroupNotification(nk: nkruntime.Nakama, groupId: string, code: ClanNotificationCode, subject: string) {
    const members = nk.groupUsersList(groupId, 100);
    const count = (members.groupUsers ?? []).length;
    if (count < 1) {
        return;
    }

    const notifications: nkruntime.NotificationRequest[] = new Array(count);
    members.groupUsers?.forEach(function {
        const n: nkruntime.NotificationRequest = {
            code: code,
            content: {},
            persistent: false,
            subject: subject,
            userId: user.user.userId,
        }
        notifications.push(n);
    });

    nk.notificationsSend(notifications);
}

此处我们创建自定义通知代码来区分不同类型的通知。这些可以是任意正数。然后我们用 groupUsersList 获取所有成员的列表,且对于列表中的每个用户,我们用 user.user.id 获取他们的 ID,将 NotificationRequest 发送给他们。

设置运行时挂钩 #

现在,我们需要调用我们刚刚创建的函数,这样每次有人加入群组时,Nakama 都会自动调用它:

clans.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
/**
* Send an in-app notification to all clan members when a new member joins.
*/
const afterJoinGroupFn: nkruntime.AfterHookFunction<void, nkruntime.JoinGroupRequest> =
    function(
        ctx: nkruntime.Context,
        logger: nkruntime.Logger,
        nk: nkruntime.Nakama,
        data: void, request: nkruntime.JoinGroupRequest) {
            sendGroupNotification(nk, request.groupId ?? "", ClanNotificationCode.Refresh, "New Member Joined!");
        }

此处我们处理 JoinGroupRequest,其中包含 groupId,我们可以用来判断应当将此通知发送到何处。

我们可以使用类似的代码将通知功能扩展到其他事件,例如,如果有人被踢出,则通知群组中的每个人:

clans.ts

1
2
3
4
5
6
7
/**
* Send an in-app notification to all clan members when one or more members are kicked.
*/
const afterKickGroupUsersFn: nkruntime.AfterHookFunction<void, nkruntime.KickGroupUsersRequest> =
        function(ctx: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama, data: void, request: nkruntime.KickGroupUsersRequest) {
    sendGroupNotification(nk, request.groupId ?? "", ClanNotificationCode.Refresh, "Member(s) Have Been Kicked!");
}

注册挂钩 #

使函数按预期工作的最后一步是在主模块中注册它们。对于我们刚刚创建的每个函数,我们可以按如下方式添加它们:

main.ts

1
2
3
4
5
6
    initializer.registerAfterKickGroupUsers(afterKickGroupUsersFn);
    initializer.registerAfterLeaveGroup(afterLeaveGroupFn);
    initializer.registerAfterPromoteGroupUsers(afterPromoteGroupUsersFn);
    initializer.registerAfterAddFriends(afterAddFriendsFn);
    initializer.registerBeforeDeleteGroup(beforeDeleteGroupFn);
    ...

此处的每个 register 函数都来自运行时事件列表,我们传入的参数是我们刚才在 clans.ts 中创建的函数之一。

创建客户端 #

接下来,我们将在 Unity 中创建一个界面,供玩家与服务器交互。在 Pirate Panic 中形如:

ClansPanel
ClansPanel

本教程并不详细介绍 Unity UI 组件的创建。请参阅官方 Unity UI 教程,对此做进一步了解。

Pirate Panic 项目中有完整的部落代码示例。

创建部落 #

为创建新部落,我们使用 CreateGroupAsync(session, name, ...) 函数,其中 session 是一个服务器连接,name 是新的部落。该函数还包含额外的可选参数,我们可以使用这些参数来存储信息,例如描述或化身图像。

对于 Pirate Panic 部落创建面板,其形如:

ClanCreationPanel.cs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
private async void CreateClan()
{
    string name = _clanName.text;

    try
    {
        IApiGroup group = await _connection.Client.CreateGroupAsync(_connection.Session, name, "A super great clan.", _avatarImage.name);
        if (OnClanCreated != null)
        {
            OnClanCreated(group);
        }
    }
    catch (ApiResponseException e)
    {
        Debug.LogError("Error creating clan: " + e.Message);
    }
}

在上述片段中:

  • _clanName:Unity 文本框,玩家可在此输入新部落的名称。此处我们获取其文本。
  • _connection:较早在代码中初始化的 GameConnection 对象。
  • 提供的两个可选参数是描述和化身名称。
  • 创建部落后,即调用 OnClanCreated 函数。此属性分配给 [ClansMenuUI.cs] 中的 Awake

最后,我们用这个异步函数包裹住一个函数,并将其绑定到一个按钮动作:

ClanCreationPanel.cs

1
2
3
4
5
6
7
8
...
_doneButton.onClick.AddListener(() =>
    { Hide(); });
...
public override void Hide (bool isMuteSoundManager = false) {
    CreateClan();
    base.Hide(isMuteSoundManager);
}

部落聊天 #

我们可以创建一个频道,让整个群组互相聊天。在 Pirate Panic 中,其形如:

ClansChatPanel
ClansChatPanel

为进行部落聊天,我们在加入聊天频道时传入上方部落的群组 ID,这样部落中的每个人都会呆在同一频道中。

为加入聊天频道,我们使用 JoinChatAsync

ClansMenuUI.cs

1
2
3
4
5
private async void StartChat(ClanMenuUIState state)
    ...
    channel = await _connection.Socket.JoinChatAsync(state.UserClan.Id, ChannelType.Group, persistence: true, hidden: true);
    ...
}

此处我们加入 ID 为 state.UserClan.Id 的群组频道。 此频道是持久的,消息将被保存到数据库中,即使您断开连接再重新连接,消息也会显示。玩家以隐藏成员形式加入,即他们不出现在成员列表中。

可为不同类型的聊天室配置这些设置。在实时聊天文档中进一步了解不同的设置。

玩家加入聊天频道后,发送和接收消息的方式与直接消息相同。

退出或解散部落 #

当玩家不想继续呆在部落中时,有两种可能的操作:退出解散

ClansMainPanel
ClansMainPanel

退出部落会让部落继续处于活动状态,只有当部落中还有另外一个 superadmin(所有者)时,才可以退出。解散部落后,将从服务器删除部落,并删除所有成员。

例如,退出部落:

ClansMenuUI.cs

1
await _connection.Client.LeaveGroupAsync(_connection.Session, _state.DisplayedClan.Id);

此处,_state_ClansMenuUIState,包含当前玩家屏幕显示内容信息的自定义类(以 ClansMenuUIState.cs 定义)。DisplayedClan.Id 是玩家想要退出的部落的 ID。

解散部落:

ClansMenuUI.cs

1
await _connection.Client.DeleteGroupAsync(_connection.Session, _state.UserClan.Id);

下一主题 #

存储

Related Pages