Unity SDK 开发指南
本文介绍如何在 Unity 项目中接入多人联机,覆盖 Android、iOS 和 Tap PC。
集成 SDK
集成前准备
- 参考 开发者中心配置 创建应用、配置包名与签名证书
- 参考 Unity 集成指南 完成基础接入,对于 Tap PC 平台,使用前还需接入启动校验
- 多人联机 SDK 依赖 TapTap 登录开发指南 ,接入前需确保已接入
权限说明
Android 权限说明
该模块在 Android 平台需要如下权限:
| 权限 | 使用目的 | 权限申请时机 |
|---|---|---|
| 网络权限 | 用于正常网络访问 | 用户首次使用该功能时会申请权限 |
iOS 权限说明
该模块在 iOS 平台需要如下权限:
| 权限 | 使用目的 | 权限申请时机 |
|---|---|---|
| 网络权限 | 用于正常网络访问 | 用户首次使用该功能时会申请权限 |
SDK 获取
远程依赖示例
NPMJS 方式:在 Packages/manifest.json 中添加:
"dependencies":{
"com.taptap.sdk.core":"4.11.0",
"com.taptap.sdk.login":"4.11.0",
"com.taptap.sdk.onlinebattle":"4.11.0"
}
GitHub 方式:在 Packages/manifest.json 中添加:
"dependencies":{
"com.taptap.sdk.core":"https://github.com/taptap/tapsdk-unity-dist.git?path=/Core#4.11.0",
"com.taptap.sdk.login":"https://github.com/taptap/tapsdk-unity-dist.git?path=/Login#4.11.0",
"com.taptap.sdk.onlinebattle":"https://github.com/taptap/tapsdk-unity-dist.git?path=/OnlineBattle#4.11.0"
}
本地文件导入
在 下载页 下载并导入以下 unitypackage 文件:
TapSDK_Core.unitypackage(TapTapSDK 核心模块,必选)TapSDK_Login.unitypackage(TapTapSDK 登录模块,必选)TapSDK_OnlineBattle.unitypackage(TapTapSDK 多人联机模块,必选)
业务流程接入
主要业务模块及流程如下图,开发者可根据该图了解不同功能接口调用时机:

连接管理
注册回调
通过实现 SDK 通知回调接口 ITapOnlineBattleCallback 来接收玩家、房间信息及同步消息回调,渲染对应场景游戏页面,示例如下:
using TapSDK.OnlineBattle;
public class OnlineBattlePanel : DemoBaseController, ITapOnlineBattleCallback
{
/// 注册回调
public void RegisterCallback()
{
TapTapOnlineBattle.RegisterOnlineBattleCallback(this);
}
#region SDK 回调实现
/// <summary>
/// 收到玩家自定义消息
/// </summary>
/// <param name="playerId"> 消息发送者玩家ID </param>
/// <param name="msg"> 自定义消息,格式由开发者决定,必须是utf8字符串,最大2048字节 </param>
public void OnCustomMessageReceived(string playerId, string msg)
{
// TODO: 解析 msg,渲染对战状态或其他信息
}
/// <summary>
/// 与服务端连接断开,建议当错误码为网络异常时进行重连
/// </summary>
/// <param name="code"> 错误码,参考 <see cref="TapOnlineBattleConstant"/> </param>
/// <param name="msg"> 错误信息 </param>
public void OnDisconnected(int code, string msg)
{
// 当错误码为网络异常时进行重连
}
/// <summary>
/// 玩家更新自定义属性
/// </summary>
/// <param name="playerId"> 更新了自定义属性的玩家ID </param>
/// <param name="properties"> 新的属性值 </param>
public void OnPlayerCustomPropertiesChanged(string playerId, string properties)
{
LogMessage($"receive OnPlayerCustomPropertiesChanged {playerId}:{properties}");
}
/// <summary>
/// 玩家更新自定义状态
/// </summary>
/// <param name="playerId"> 更新了自定义状态的玩家ID </param>
/// <param name="status"> 新的状态 </param>
public void OnPlayerCustomStatusChanged(string playerId, int status)
{
LogMessage($"receive OnPlayerCustomStatusChanged {playerId}:{status}");
}
/// <summary>
/// 玩家进入房间
/// </summary>
/// <param name="roomId"> 房间ID </param>
/// <param name="playerInfo"> 玩家信息 </param>
public void OnPlayerEntered(string roomId, TapSDK.OnlineBattle.PlayerInfo playerInfo)
{
LogMessage(
$"receive OnPlayerEntered {roomId}:{JsonConvert.SerializeObject(playerInfo)}"
);
}
/// <summary>
/// 玩家被踢出
/// </summary>
/// <param name="roomId"> 被踢玩家所属房间ID </param>
/// <param name="playerId"> 被踢玩家ID </param>
public void OnPlayerKicked(string roomId, string playerId)
{
LogMessage($"receive OnPlayerKicked {roomId}:{playerId}");
}
/// <summary>
/// 玩家离开房间
/// </summary>
/// <param name="roomId"> 房间ID </param>
/// <param name="roomOwnerId"> 房主ID。如果离开的是房主,则roomOwnerId为新房主ID;反之,为原房主ID</param>
/// <param name="playerId"> 离开房间的玩家ID </param>
public void OnPlayerLeft(string roomId, string roomOwnerId, string playerId)
{
LogMessage($"receive OnPlayerLeft {roomId}:{roomOwnerId}:{playerId}");
}
/// <summary>
/// 玩家离线
/// </summary>
/// <param name="roomId"> 房间ID </param>
/// <param name="roomOwnerId"> 房主ID。如果离线的是房主,则roomOwnerId为新房主ID;反之,为原房主ID</param>
/// <param name="playerId"> 离线玩家ID </param>
public void OnPlayerOffline(string roomId, string roomOwnerId, string playerId)
{
LogMessage($"receive OnPlayerOffline {roomId}:{roomOwnerId}:{playerId}");
}
/// <summary>
/// 房间属性变更
/// </summary>
/// <param name="id"> 房间 ID </param>
/// <param name="name"> 房间名称 </param>
/// <param name="customProperties"> 房间自定义属性 </param>
public void OnRoomPropertiesChanged(string id, string name, string customProperties)
{
LogMessage($"receive OnRoomPropertiesChanged {id}:{name}:{customProperties}");
}
/// <summary>
/// 开始帧同步
/// </summary>
/// <param name="frameSyncInfo"> 帧同步基础信息 </param>
public void OnFrameSyncStarted(FrameSyncInfo frameSyncInfo)
{
LogMessage($"receive OnFrameSyncStarted {JsonConvert.SerializeObject(frameSyncInfo)}");
}
/// <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)}");
}
}
/// <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}");
}
/// <summary>
/// 对战服务端异常,开发者需要退出对战、房间、队伍等状态,此时处于 connect 之后的状态
/// </summary>
public void OnBattleServiceError()
{
LogMessage("receive OnBattleServiceError");
}
#endregion
}
建立连接
当玩家登录成功后,需建立连接后才能调用其他主要 API 业务接口,连接成功时会返回用户 ID 。示例如下:
using TapSDK.OnlineBattle;
try
{
string playerId = await TapTapOnlineBattle.Connect();
LogMessage("Connect success " + playerId);
}
catch (TapException e)
{
LogMessage($"Connect error {e.Code} {e.Message}");
}
断开连接
当用户不再需要使用对战服务时,可调用该接口断开连接。当用户登出、重新登录时, SDK 会自动调用该接口断开连接。
using TapSDK.OnlineBattle;
try
{
await TapTapOnlineBattle.Disconnect();
LogMessage(" Disconnect success ");
}
catch (TapException e)
{
LogMessage($"Disconnect error {e.Code} {e.Message}");
}
房间管理

- 房间:玩家联机的虚拟空间,每个房间有唯一的房间 ID
- 房主:创建房间的玩家,拥有踢人、修改房间属性等权限;房主离开后,服务端会自动选择房间内一个玩家为新房主
- 监听回调:玩家进入或离开房间时,SDK 会通过回调通知房间内其他玩家
房间信息
当通过不同方式进入房间后,SDK 会返回房间内具体信息,包括房间属性和房间内所有玩家属性,具体参数如下:
| 参数名 | 类型 | 说明 |
|---|---|---|
| id | string | 房间 ID |
| name | string | 房间名称,如果创建或更新时未设置,默认为空字符串 |
| type | string | 房间类型 |
| ownerId | string | 房主 ID ,当原房主离开房间且房间内有其他玩家时,该值会变更为房间内其他玩家 |
| status | int | 0-未开始帧同步,1-帧同步中 |
| customProperties | string | 自定义房间属性 |
| maxPlayerCount | int | 房间最大支持人数 |
| players | List | 房间内玩家信息集合 |
| createTime | string | 房间创建时间,1970 年开始的秒数 |
其中玩家信息如下:
| 参数名 | 类型 | 说明 |
|---|---|---|
| id | string | 玩家 ID |
| status | int | 玩家状态:0-离线、1-在线 |
| customStatus | int | 自定义玩家状态,开发者可随意设置任何值,意义由开发者自行判断 |
| customProperties | string | 自定义玩家属性,开发者可以随意设置任何数据,最大为 2048 字节 |
进入房间
进入房间有三种不同的方式,创建房间、匹配房间以及获取房间列表后加入指定房间等,通过创建房间加入时会自动成为房主。
创建房间
在创建和匹配房间时,需要设置房间配置(必选)和玩家配置(可选),具体参数如下:
房间配置
| 参数名 | 类型 | 说明 | 是否必选 |
|---|---|---|---|
| maxPlayerCount | int | 房间最大支持人数,取值范围为 1 ~ 20 | 是 |
| type | string | 房间类型,最大 32 字节 | 是 |
| name | string | 房间名称,最大 64 字节,当匹配房间时,无需设置该参数 | 否 |
| customProperties | string | 自定义房间属性,最大 2048 字节 | 否 |
| matchParams | Dictionary | 房间匹配参数,最大支持 3 个 K/V 对, K/V 取值由开发者决定,K 最大 32 字节,V 最大 64 字节 | 否 |
玩家配置
| 参数名 | 类型 | 说明 | 是否必选 |
|---|---|---|---|
| customStatus | int | 自定义玩家状态,开发者可随意设置任何值,意义由开发者自行判断 | 否 |
| customProperties | string | 自定义玩家属性,开发者可以随意设置任何数据,最大为 2048 字节 | 否 |
请求成功后,会返回对应房间的具体信息,示例如下:
using TapSDK.OnlineBattle;
// 定义匹配参数
Dictionary<string, string> matchParams = null;
// 定义房间配置
var config = new CreateRoomConfig()
{
// 房间配置
roomConfig = new RoomConfig()
{
maxPlayerCount = roomMaxPlayerCount, // 房间最大支持人数,取值范围为[1, 20],必填
type = roomType, // 房间类型,最大32字节,必填
name = roomName, // 房间名称,最大64个字节,选填
customProperties = roomProperty, // 自定义房间属性,最大2048字节,选填
matchParams = matchParams, // 房间匹配参数,选填,最大支持3个K/V对, K/V取值由开发者决定,K最大32字节,V最大64字节
},
// 玩家配置
playerConfig = new PlayerConfig()
{
customStatus = playerCustomStatus, // 自定义玩家状态,整型,选填
customProperties = playerProperty, // 自定义玩家属性,选填
},
};
try
{
RoomInfo data = await TapTapOnlineBattle.CreateRoom(config);
LogMessage(" 创建房间成功 " + JsonConvert.SerializeObject(data));
}
catch (TapException e)
{
LogMessage($"创建房间 error {e.Code} {e.Message}");
}
匹配房间
匹配房间时使用的配置参数和创建房间一致,当没有满足条件的房间存在时,会自动创建一个新房间, 匹配成功后返回对应的房间信息。
using TapSDK.OnlineBattle;
// 定义匹配参数
Dictionary<string, string> matchParams = null;
// 定义房间配置
var config = new MatchRoomConfig()
{
// 房间配置
roomConfig = new RoomConfig()
{
maxPlayerCount = roomMaxPlayerCount, // 房间最大支持人数,取值范围为[1, 20],必填
type = roomType, // 房间类型,最大32字节,必填
customProperties = roomProperty, // 自定义房间属性,最大2048字节,选填
matchParams = matchParams, // 房间匹配参数,选填,最大支持3个K/V对, K/V取值由开发者决定,K最大32字节,V最大64字节
},
// 玩家配置
playerConfig = new PlayerConfig()
{
customStatus = playerCustomStatus, // 自定义玩家状态,整型,选填
customProperties = playerProperty, // 自定义玩家属性,选填
},
};
try
{
RoomInfo data = await TapTapOnlineBattle.MatchRoom(config);
LogMessage(" 匹配房间成功 " + JsonConvert.SerializeObject(data));
// 如果此时是加入已存在的房间,房间内其他玩家会通过 OnPlayerEntered 回调收到通知
}
catch (TapException e)
{
LogMessage($"匹配房间 error {e.Code} {e.Message}");
}
如果此时是加入已存在的房间,房间内其他玩家会通过 SDK 的 OnPlayerEntered 回调收到通知:
public void OnPlayerEntered(string roomId, TapSDK.OnlineBattle.PlayerInfo playerInfo)
{
LogMessage(
$"receive OnPlayerEntered {roomId}:{JsonConvert.SerializeObject(playerInfo)}"
);
}
获取房间列表
开发者可通过具体房间类型获取对应房间列表数据,示例如下:
using TapSDK.OnlineBattle;
try
{
RoomListData data = await TapTapOnlineBattle.GetRoomList(
roomType, // 房间类型
offset, // 请求偏移量,默认为 0
limit // 请求获取的房间数量,默认为 20
);
LogMessage(" 查询房间列表成功 " + JsonConvert.SerializeObject(data));
}
catch (TapException e)
{
LogMessage($"查询房间列表 error {e.Code} {e.Message}");
}
首次请求时,请求参数中 offset 传 0 即可。拉取下一页房间列表时,请传递上一次请求结果中的 offset 字段的值。
返回结果 RoomListData 包含三个字段 :
offset:用于请求下一页房间列表的offset值hasMore:表示是否还有更多房间,true 表示有更多房间,false 表示没有rooms: 房间列表数据,包含对应类型房间的信息集合
rooms 中各房间信息字段如下:
| 参数名 | 类型 | 说明 |
|---|---|---|
| id | string | 房间 ID |
| name | string | 房间名称,如果创建或更新时未设置,默认为空字符串 |
| type | string | 房间类型 |
| status | int | 0-未开始帧同步,1-帧同步中 |
| customProperties | string | 自定义房间属性 |
| maxPlayerCount | int | 房间最大支持人数 |
| createTime | string | 房间创建时间,1970 年开始的秒数 |
加入房间
使用目标房间的房间 ID 可加入对应房间,成功后,会返回包含所有玩家的具体房间信息。示例如下:
using TapSDK.OnlineBattle;
// 玩家配置
var playerConfig = new PlayerConfig()
{
customStatus = joinPlayerStatus, // 自定义玩家状态,整形,选填。开发者可随意设置任何值,意义由开发者自行判断
customProperties = joinPlayerProperty, // 自定义玩家属性,选填。开发者可以随意设置任何数据,最大长度为2048字节
};
try
{
RoomInfo data = await TapTapOnlineBattle.JoinRoom(
joinRoomId, // 房间ID
playerConfig // 玩家配置,选填
);
LogMessage(" 加入房间成功 " + JsonConvert.SerializeObject(data));
// 其他玩家会通过 OnPlayerEntered 回调收到通知
}
catch (TapException e)
{
LogMessage($"加入房间 error {e.Code} {e.Message}");
}
加入成功后其他玩家也会通过 OnPlayerEntered 回调收到通知:
public void OnPlayerEntered(string roomId, TapSDK.OnlineBattle.PlayerInfo playerInfo)
{
LogMessage(
$"receive OnPlayerEntered {roomId}:{JsonConvert.SerializeObject(playerInfo)}"
);
}
管理房间
更新房间信息
只有房主可更新当前房间信息,包含名称和自定义属性等,示例如下:
using TapSDK.OnlineBattle;
try
{
await TapTapOnlineBattle.UpdateRoomProperties(
updateRoomName, // 房间名称
updateRoomProperty // 房间自定义属性,最大支持 2048 字节
);
LogMessage(" 更新房间属性 成功 ");
// 所有玩家会通过 OnRoomPropertiesChanged 回调收到通知
}
catch (TapException e)
{
LogMessage($"更新房间属性 error {e.Code} {e.Message}");
}
更新成功后所有玩家会通过 SDK 的 OnRoomPropertiesChanged 回调收到通知:
/// <summary>
/// 房间属性变更
/// </summary>
/// <param name="id"> 房间 ID </param>
/// <param name="name"> 房间名称 </param>
/// <param name="customProperties"> 房间自定义属性 </param>
public void OnRoomPropertiesChanged(string id, string name, string customProperties)
{
LogMessage($"receive OnRoomPropertiesChanged {id}:{name}:{customProperties}");
}
更新玩家自定义状态
每个玩家均可更新自身的当前自定义状态,用于标识玩家在房间或对战过程中的关键状态,例如未就绪、已就绪等,示例如下:
using TapSDK.OnlineBattle;
try
{
// updatePlayerStatus 玩家自定义状态,例如 0 未就绪 1 已就绪
await TapTapOnlineBattle.UpdatePlayerCustomStatus(updatePlayerStatus);
LogMessage(" 更新玩家状态 成功 ");
// 房间内玩家会通过 OnPlayerCustomStatusChanged 回调收到通知
}
catch (TapException e)
{
LogMessage($"更新玩家状态 error {e.Code} {e.Message}");
}
更新成功后,房间内玩家会通过 SDK 的 OnPlayerCustomStatusChanged 回调收到通知:
/// <summary>
/// 玩家更新自定义状态
/// </summary>
/// <param name="playerId"> 更新了自定义状态的玩家ID </param>
/// <param name="status"> 新的状态 </param>
public void OnPlayerCustomStatusChanged(string playerId, int status)
{
LogMessage($"receive OnPlayerCustomStatusChanged {playerId}:{status}");
}
更新玩家自定义属性
每个玩家均可更新自身的自定义属性数据,可用于设置玩家的基础用户信息、游戏等级等数据,示例如下:
using TapSDK.OnlineBattle;
try
{
await TapTapOnlineBattle.UpdatePlayerCustomProperties(
updatePlayerProperty // 玩家属性,最大支持 2048 字节
);
LogMessage(" 更新玩家属性 成功 ");
// 房间内玩家会通过 OnPlayerCustomPropertiesChanged 回调收到通知
}
catch (TapException e)
{
LogMessage($"更新玩家属性 error {e.Code} {e.Message}");
}
更新成功后,房间内玩家会通过 SDK 的 OnPlayerCustomPropertiesChanged 回调收到通知:
/// <summary>
/// 玩家更新自定义属性
/// </summary>
/// <param name="playerId"> 更新了自定义属性的玩家ID </param>
/// <param name="properties"> 新的属性值 </param>
public void OnPlayerCustomPropertiesChanged(string playerId, string properties)
{
LogMessage($"receive OnPlayerCustomPropertiesChanged {playerId}:{properties}");
}
离开房间
当房间内玩家需要离开当前房间时,可调用如下接口:
using TapSDK.OnlineBattle;
try
{
await TapTapOnlineBattle.LeaveRoom();
LogMessage(" 离开房间成功 ");
// 房间内其他玩家通过 OnPlayerLeft 收到通知
}
catch (TapException e)
{
LogMessage($"离开房间 error {e.Code} {e.Message}");
}
调用成功后,房间内其他玩家通过 SDK 的 OnPlayerLeft 收到通知,如果离开的玩家是房主,则会重新指定房间内其他玩家为房主。
/// <summary>
/// 玩家离开房间
/// </summary>
/// <param name="roomId"> 房间ID </param>
/// <param name="roomOwnerId"> 房主ID。如果离开的是房主,则roomOwnerId为新房主ID;反之,为原房主ID</param>
/// <param name="playerId"> 离开房间的玩家ID </param>
public void OnPlayerLeft(string roomId, string roomOwnerId, string playerId)
{
LogMessage($"receive OnPlayerLeft {roomId}:{roomOwnerId}:{playerId}");
}
踢出玩家
当房主需要将玩家踢出房间时,可调用如下接口:
using TapSDK.OnlineBattle;
try
{
// kickPlayerId 玩家 ID
await TapTapOnlineBattle.KickRoomPlayer(kickPlayerId);
LogMessage(" 踢出玩家 成功 ");
}
catch (TapException e)
{
LogMessage($"踢出玩家 error {e.Code} {e.Message}");
}
调用成功后,对应玩家会通过 SDK 的 OnPlayerKicked 回调收到通知:
/// <summary>
/// 玩家被踢出
/// </summary>
/// <param name="roomId"> 被踢玩家所属房间ID </param>
/// <param name="playerId"> 被踢玩家ID </param>
public void OnPlayerKicked(string roomId, string playerId)
{
LogMessage($"receive OnPlayerKicked {roomId}:{playerId}");
}
房间内数据传输
进入房间后,可通过发送自定义消息或发送帧输入(房主开启帧同步后)同步游戏数据。
- 自定义消息:适合回合制、棋牌等对实时性要求不高的场景
- 帧同步:适合格斗、MOBA、FPS 等高实时性游戏
详细用法见数据传输。