多人游戏活动的示例代码

本主题旨在充当多人游戏活动客户端 API 基本用法的快速入门指南。 本主题将讨论如何管理活动、发送邀请和将玩家添加到“最近互动玩家”列表中。

活动
邀请最近的玩家

活动

设置活动

每当游戏开始或加入多人游戏时,都应该创建一个活动。 这样做使 shell 和游戏中的其他玩家都可以看到该玩家的活动,并允许其他玩家有机会加入正在进行的游戏。 如果有玩家想加入游戏的某一活动但该活动尚未运行,则将激活该活动并向其传递连接字符串。

游戏应随着参与者加入或离开而更新活动。 这将为其他玩家提供更丰富的活动视图,并告诉他们活动是否已满。

有关活动字段的信息,请参阅 活动内容

下面是设置活动的代码示例。 这同时适用于创建活动和更新现有活动。

auto async = std::make_unique<XAsyncBlock>();
async->queue = queue;
async->callback = [](XAsyncBlock* async)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // Take ownership of XAsyncBlock.
    HRESULT hr = XAsyncGetStatus(async, false);
};

XblMultiplayerActivityInfo info{};
info.connectionString = "dummyConnectionString";
info.joinRestriction = XblMultiplayerActivityJoinRestriction::Followed;
info.maxPlayers = 10;
info.currentPlayers = 1;
info.groupId = "dummyGroupId";

HRESULT hr = XblMultiplayerActivitySetActivityAsync(
    xblContext,
    &info,
    false,
    async.get()
);

if (SUCCEEDED(hr))
{
    async.release();
}

有关详细信息,请参阅以下内容:

返回到本主题顶部。

获取活动

游戏可能希望了解其他用户的活动。 例如,游戏可能希望通过一个游戏内 UI 显示游戏中玩家的朋友及其活动。

下面是检索活动的代码示例。

auto async = std::make_unique<XAsyncBlock>();
async->queue = queue;
async->callback = [](XAsyncBlock* async)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // Take ownership of XAsyncBlock.

    size_t resultSize{};
    HRESULT hr = XblMultiplayerActivityGetActivityResultSize(async, &resultSize);
    if (SUCCEEDED(hr))
    {
        std::vector<uint8_t> buffer(resultSize);
        XblMultiplayerActivityInfo* activityInfo{};
        size_t resultCount{};
        hr = XblMultiplayerActivityGetActivityResult(async, buffer.size(), buffer.data(), &activityInfo, &resultCount, nullptr);
        if (SUCCEEDED(hr))
        {
            // ...
        }
    }
};

HRESULT hr = XblMultiplayerActivityGetActivityAsync(
    xblContext,
    &xuid,
    1,
    async.get()
);

if (SUCCEEDED(hr))
{
    async.release();
}

有关详细信息,请参阅以下内容:

返回到本主题顶部。

删除活动

当玩家结束或离开多人游戏活动时,游戏应使用以下代码删除活动。

auto async = std::make_unique<XAsyncBlock>();
async->queue = queue;
async->callback = [](XAsyncBlock* async)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // Take ownership of XAsyncBlock.
    HRESULT hr = XAsyncGetStatus(async, false);
};

HRESULT hr = XblMultiplayerActivityDeleteActivityAsync(xblContext, async.get());

if (SUCCEEDED(hr))
{
    async.release();
}

有关详细信息,请参阅以下内容:

返回到本主题顶部。

邀请

在没有 UI 的情况下发送邀请

玩家可能希望直接向一个或多个其他玩家发送邀请。 发送邀请前,游戏应确保已设置活动。 这可确保 shell 和游戏之间的连续性,因为 shell 将根据当前活动发送邀请。

若要在没有 UI 的情况下发送邀请,在使用 XblMultiplayerActivitySetActivityAsync 设置活动后(请参阅上面的示例),游戏应调用 XblMultiplayerActivitySendInvitesAsync API,并传递要邀请的一批玩家和当前活动中使用的相同连接字符串。

有关邀请内容的信息,请参阅发送请求,让其他玩家加入多人游戏体验。

在没有 UI 的情况下发送邀请的代码示例如下所示。

auto async = std::make_unique<XAsyncBlock>();
async->queue = queue;
async->callback = [](XAsyncBlock* async)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // Take ownership of XAsyncBlock.
    HRESULT hr = XAsyncGetStatus(async, false);
};

HRESULT hr = XblMultiplayerActivitySendInvitesAsync(
    xblContext,
    &xuid,
    1,
    true, // Setting false will send the invite to only players on the sender's platform.
    "dummyConnectionString",
    async.get()
);

if (SUCCEEDED(hr))
{
    async.release();
}

有关详细信息,请参阅以下内容:

使用 UI 发送邀请

玩家可能希望直接向一个或多个其他玩家发送邀请。 发送邀请前,游戏应确保已设置活动。 这可确保 shell 和游戏之间的连续性,因为 shell 将根据当前活动发送邀请。

若要使用 UI 发送邀请,在使用 XblMultiplayerActivitySetActivityAsync 设置活动后(请参阅上面的示例),游戏应调用 XGameUiShowMultiplayerActivityGameInviteAsync API 传递请求用户。 它将使用游戏的当前活动,并使用其连接字符串和设置邀请玩家。

有关邀请内容的信息,请参阅发送请求,让其他玩家加入多人游戏体验。

使用 UI 发送邀请的代码示例如下所示。

auto async = std::make_unique<XAsyncBlock>();
async->queue = queue;
async->callback = [](XAsyncBlock* async)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // Take ownership of XAsyncBlock.
    HRESULT hr = XGameUiShowMultiplayerActivityGameInviteResult(async);
    if (hrAsync == S_OK) 
    { 
        // Handle success 
    } 
    else 
    { 
        // Likely will only happen during development - usually indicates 
        // an invalid user was passed in or that there is no multiplayer activity set
    }     
};

HRESULT hr = XGameUiShowMultiplayerActivityGameInviteAsync(
    async.get()
    requestingUser
);

if (SUCCEEDED(hr))
{
    async.release();
}

有关详细信息,请参阅以下内容:

返回到本主题顶部。

接收邀请

若要在玩家接受邀请时得到通知,游戏可以使用 XGameInviteRegisterForEvent 注册邀请通知。 每次接受邀请时,都会通过注册的回调将格式化的 URI 传递给游戏。 可以解析该 URI 以确定邀请的发送者、接收者和连接字符串。 连接字符串特定于游戏,在创建多人活动时设置。 对于使用多人活动服务的游戏,URI 的完整格式如下所示。

平台 格式
主机上的 Microsoft Game Development Kit (GDK) 或 Xbox One 软件开发工具包 ms-xbl-<titleId>://inviteAccept?invitedUser=<xuid>&sender=<xuid>&connectionString=<connectionString>
电脑上的 Microsoft Game Development Kit (GDK) 或 通用 Windows 平台 (UWP) ms-xbl-multiplayer://inviteAccept?invitedUser=<xuid>&sender=<xuid>&connectionString=<connectionString>

不再需要邀请通知时,可使用 XGameInviteUnregisterForEvent注销回调。 用于注册和处理已接受邀请的代码示例如下所示。

void CALLBACK MyXGameInviteEventCallback(
    _In_opt_ void* context,
    _In_ const char* inviteUri)
{
    if (inviteUri != nullptr)
    {
        std::string uri{ inviteUri };
        size_t invitedUserBegin = uri.find("invitedUser=");
        size_t senderBegin = uri.find("sender=");
        std::string invitedUser = uri.substr(invitedUserBegin, uri.find('&', invitedUserBegin) - invitedUserBegin);
        std::string sender = uri.substr(senderBegin, uri.find('&', senderBegin) - senderBegin);
        std::string connectionString = uri.substr(uri.find("connectionString="));

        // ...
    }
}

XTaskQueueRegistrationToken token = { 0 };
HRESULT hr = XGameInviteRegisterForEvent(
    queue,
    nullptr,
    MyXGameInviteEventCallback,
    &token
    );

// ...
bool result = XGameInviteUnregisterForEvent(token, true);

有关详细信息,请参阅以下内容:

返回到本主题顶部。

最近互动玩家

游戏应提交与当前用户有过有意义交互的其他玩家的列表,以便更新用户最近互动过的玩家列表。 该列表是单向的,这意味着每个玩家的客户端只负责更新自己用户的列表,而玩家的列表不会相互影响。

例如,假设一组玩家出现在游戏前的大厅中,并被匹配在一起。 开始匹配时,每个玩家会将大厅中的所有其他 xuids 更新到自己的列表中。 如果有新用户要加入,则可以单独写入该用户。

注意

你可以决定哪些交互是有意义的。 对于一款游戏,可以是在大厅中出现。 对于另一款游戏,可以是一个玩家向另一个玩家射击。 对于第三款游戏,可以只是在屏幕上看到另一个玩家。

在某些情况下,可能不希望一组玩家在匹配会话开始前被看到,因此可以等到希望他们彼此可见时再写入玩家列表。 若要刷新客户端最近互动玩家列表,且需要立即强制刷新,可调用 XblMultiplayerActivityFlushRecentPlayersAsync。 否则,最近互动的玩家列表将每 5 秒自动刷新一次。

下面是关于更新最近互动的玩家列表和刷新更新的代码示例。

更新最近互动的玩家

XblMultiplayerActivityRecentPlayerUpdate update{ xuid };
HRESULT hr = XblMultiplayerActivityUpdateRecentPlayers(xblContext, &update, 1);

有关详细信息,请参阅以下内容:

返回到本主题顶部。

刷新最近互动的玩家

auto async = std::make_unique<XAsyncBlock>();
async->queue = queue;
async->callback = [](XAsyncBlock* async)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async }; // Take ownership of XAsyncBlock.
    HRESULT hr = XAsyncGetStatus(async, false);
};

HRESULT hr = XblMultiplayerActivityFlushRecentPlayersAsync(xblContext, async.get());
if (SUCCEEDED(hr))
{
    async.release();
}

有关详细信息,请参阅以下内容:

返回到本主题顶部。