跳到主要内容
版本:v4

Unity SDK 开发指南

本文介绍如何在 Unity 项目中,于已进入房间后使用自定义消息或帧同步传输对战数据,覆盖 Android、iOS 和 Tap PC。

接入房间和连接前,请先完成快速入门。

状态同步​

自定义消息同步​

通过自定义消息在房间内同步玩家操作或状态,适合回合制、棋牌等对实时性要求不高的场景。流程可概括为:一方发送自定义消息,服务端转发后,房间内对应玩家在回调中解析并更新游戏状态。

自定义消息同步

适合的游戏类型包括:

  • 棋牌类:五子棋、象棋、斗地主、麻将等
  • 回合制:战棋、策略、回合制 RPG 等
  • 休闲类:你画我猜、狼人杀、问答等
  • 合作类:简单多人闯关、合作解谜等

发送自定义消息​

调用限频

该接口 和 更新玩家自定义状态(UpdatePlayerCustomStatus)、更新玩家自定义属性(UpdatePlayerCustomProperties)、更新房间信息(UpdateRoomProperties)共享每秒15次调用限制

开始游戏后,开发者通过将玩家操作数据封装为自定义消息内容同步给其他玩家,每秒最多 15 次,调用示例如下:

using TapSDK.OnlineBattle;

try
{
await TapTapOnlineBattle.SendCustomMessage(
customMsg, // 自定义消息,格式由开发者决定,必须是utf8字符串,最大2048字节
customMsgType, // 消息接收者类型。0:房间内所有玩家,不包括发送者;1:发送给指定玩家
playerIds // 当type==1时有效,发送给该字段指定的玩家,最多20个ID
);
LogMessage(" 发送自定义消息 成功 ");
// 房间内对应玩家通过 OnCustomMessageReceived 回调收到通知
}
catch (TapException e)
{
LogMessage($"发送自定义消息 error {e.Code} {e.Message}");
}

发送成功后,房间内对应玩家会通过 SDK 的 OnCustomMessageReceived 回调收到通知:

/// <summary>
/// 收到玩家自定义消息
/// </summary>
/// <param name="playerId"> 消息发送者玩家ID </param>
/// <param name="msg"> 自定义消息,格式由开发者决定,必须是utf8字符串,最大2048字节 </param>
public void OnCustomMessageReceived(string playerId, string msg)
{
// TODO: 解析 msg,渲染对战状态或其他信息
}

帧同步​

帧数据同步​

高实时性游戏,如格斗、MOBA、FPS,可使用帧同步:房主开始帧同步后,各端发送帧输入同步操作,房主停止帧同步或超时后结束本局。

帧数据同步

  • 开始对战:房主调用开始帧同步,房间内所有玩家进入帧同步状态
  • 对战进行中:玩家发送帧输入进行帧数据同步
  • 结束对战:房主调用停止帧同步,或超过 30 分钟后服务端强制结束
使用限制
  • 帧率为每秒 30 帧
  • 开始帧同步后,最大支持 30 分钟,超过时间后服务端会强制停止帧同步
  • 每个玩家每帧最多允许发送 5 次操作数据

开始帧同步​

当房间内所有玩家状态就绪后,房主开启对战时,调用开始帧同步接口:

using TapSDK.OnlineBattle;

try
{
// 开始帧同步,仅房主可调用
await TapTapOnlineBattle.StartFrameSync();
LogMessage(" 开始帧同步 成功 ");
// 房间内所有玩家会通过 OnFrameSyncStarted 回调收到通知
}
catch (TapException e)
{
LogMessage($"开始帧同步 error {e.Code} {e.Message}");
}

此时房间内所有玩家会通过 SDK 的 OnFrameSyncStarted 回调收到通知:

/// <summary>
/// 开始帧同步
/// </summary>
/// <param name="frameSyncInfo"> 帧同步基础信息 </param>
public void OnFrameSyncStarted(FrameSyncInfo frameSyncInfo)
{
LogMessage($"receive OnFrameSyncStarted {JsonConvert.SerializeObject(frameSyncInfo)}");
}

回调中会返回本次帧同步的基础信息 (FrameSyncInfo),主要包含房间信息(roomInfo) 、随机种子(seed)等

提示

注意:开启帧同步后,禁止执行管理房间的所有操作,包括更新房间信息、更新玩家属性、离开房间、踢出玩家等,否则会收到错误码 26 的异常

发送玩家操作数据​

对战过程中,玩家的操作数据可通过调用如下接口进行同步:

using TapSDK.OnlineBattle;

try
{
// playData 玩家操作数据,utf8字符串格式,最大1024字节
await TapTapOnlineBattle.SendFrameInput(playData);
LogMessage(" 发送玩家 Input 数据 成功 ");
// 房间内其他玩家通过 OnFrameReceived 回调收到通知
}
catch (TapException e)
{
LogMessage($"发送玩家 Input 数据 error {e.Code} {e.Message}");
}

房间内其他玩家会通过 SDK 的 OnFrameReceived 回调收到通知:

/// <summary>
/// 收到帧同步数据回调
/// </summary>
/// <param name="frameData"> 帧数据 </param>
public void OnFrameReceived(FrameData frameData)
{
if (frameData != null && frameData.inputs != null && frameData.inputs.Count > 0)
{
LogMessage($"receive OnFrameReceived {JsonConvert.SerializeObject(frameData)}");
}
}

回调中返回的参数 frameData 会包括当前帧 ID 及多个玩家的多个操作数据,其中 inputs 字段为玩家操作数据集合,集合中每条数据包含了玩家 ID、玩家操作数据、发送时间等信息。

停止帧同步​

当房主结束对战时,开发者通过调用停止帧同步接口结束同步玩家数据:

using TapSDK.OnlineBattle;

try
{
// 停止帧同步,仅房主可调用
await TapTapOnlineBattle.StopFrameSync();
LogMessage(" 停止帧同步 成功 ");
// 房间内其他玩家通过 OnFrameSyncStopped 回调收到通知
}
catch (TapException e)
{
LogMessage($"停止帧同步 error {e.Code} {e.Message}");
}

其他玩家会通过 OnFrameSyncStopped 回调收到通知:

/// <summary>
/// 停止帧同步
/// </summary>
/// <param name="roomId"> 房间 ID </param>
/// <param name="frameSyncId"> 帧同步 ID,房间内唯一 </param>
/// <param name="reason"> 原因 0:房主主动结束,1:因30分钟超时结束 </param>
public void OnFrameSyncStopped(string roomId, int frameSyncId, int reason)
{
LogMessage($"receive OnFrameSyncStopped {roomId}:{frameSyncId}:{reason}");
}

随机数生成器​

为保证玩家对战过程中,对于随机掉落物品或其他奖励的概率保持一致,不同玩家可使用该生成器生成相同序列的随机数。 建议在收到开始帧同步( OnFrameSyncStarted) 的回调中,使用返回的帧同步基础信息 FrameSyncInfo 参数的 seed 字段来初始化随机数生成器。

using TapSDK.OnlineBattle;

// 使用帧同步回调返回的随机种子
int seed = frameSyncInfo.seed;
// 创建生成器
var randomNumberGenerator = TapTapOnlineBattle.NewRandomNumberGenerator(seed);

// 生成随机数
try
{
int value = randomNumberGenerator.RandomInt();
LogMessage(" 生成随机数 成功 " + value);
}
catch (TapException e)
{
LogMessage($"生成随机数 error {e.Code} {e.Message}");
}

// 当对战结束后或已确定不需要生成器时,可调用如下接口销毁随机数生成器
randomNumberGenerator.Free();