与亲朋好友一起玩在线游戏,如果游戏中有实时语音能力可以拉进玩家之间的距离,添加更多乐趣。我们以经典的中国象棋为例,开发在线语音象棋。本文主要涉及如下几个点:
- 在线游戏的规则,本文以中国象棋为例。
- 借助
Zego SDK
的实时消息能力,实现在线游戏实时数据传输。- 借助
Zego SDK
的语音能力,实现在线语音。
注意:虽然本文以中国象棋为例,但其他在线小游戏同样可以套用,只是游戏规则不一样而已。
最终效果如下:
关于中国象棋的游戏规则,我这里做个简单的介绍。
日
字对角走,如果往对角方向的长边有棋子,则不能走。田
字对角走,且不能过河。如果田
字正中心有棋子,则不能走。在玩家每一次下棋时,首先需要验证目标位置是否是有效位置,即是否符合游戏规则:
// 判断是否可以移动
public static boolean canMove(Chessboard chessboard, int fromX, int fromY, int toX, int toY) {
//不能原地走
if (fromX == toX && fromY == toY)
return false;
Chess chess = chessboard.board[fromY][fromX];
// 首先,确保目标位置不是自己的子
Chess[][] board = chessboard.board;
if (board[toY][toX] != null && board[toY][toX].isRed() == chessboard.isRed) {
return false;
}
switch (chess.type) {
case RED_SHUAI:
case BLACK_SHUAI:
return canShuaiMove(chessboard, fromX, fromY, toX, toY);
case RED_SHI:
case BLACK_SHI:
return canShiMove(chessboard, fromX, fromY, toX, toY);
case RED_XIANG:
case BLACK_XIANG:
return canXiangMove(chessboard, fromX, fromY, toX, toY);
case RED_MA:
case BLACK_MA:
return canMaMove(chessboard, fromX, fromY, toX, toY);
case RED_CHE:
case BLACK_CHE:
return canCheMove(chessboard, fromX, fromY, toX, toY);
case RED_PAO:
case BLACK_PAO:
return canPaoMove(chessboard, fromX, fromY, toX, toY);
case RED_ZU:
case BLACK_ZU:
return canZuMove(chessboard, fromX, fromY, toX, toY);
}
return true;
}
如果是符合规则的行走,再直接将目标位置的棋子移除(必须先判断有棋子且是对方棋子才行)。游戏可以一直这样持续下去,直到有一方的帅
被吃掉, 游戏结束。
实时传输游戏数据可以自己基于TCP
去实现,但有如下几个缺点:
- 双方必须在同一个局域网,或者双方必须用有效的互联网
ip
地址。- 得要精心维护消息数据发送与接收,代码量大且不方便维护。
我们可以借助Zego SDK
中强大的实时消息能力实现实时棋盘同步,具体如何接入可以查看官方文档:
https://doc-zh.zego.im/article/3575。通过这篇官方文档,基本上可以完成Zego SDK
的接入工作。
使用Zego SDK
之前必须要先完成登录房间,因为不管是实时语音还是实时消息,都是以房间为单位的。假设读者已经按照官方文档教程创建好引擎对象mEngine
。接下来是登录实现代码:
public boolean loginRoom(String userId, String userName, String roomId, String token) {
ZegoUser user = new ZegoUser(userId, userName);
ZegoRoomConfig config = new ZegoRoomConfig();
config.token = token; // 请求开发者服务端获取
config.isUserStatusNotify = true;
mEngine.loginRoom(roomId, user, config, (int error, JSONObject extendedData) -> {
// 登录房间结果,如果仅关注登录结果,关注此回调即可
});
Log.e(TAG, "登录房间:" + roomId);
return true;
}
登出操作比较简单mEngine.logoutRoom(roomId);
指定房间ID即可。
有了前面这些准备工作后,接下来是实现实时棋盘同步。封装一个发送消息函数:
public void sendMsg(String roomId, ArrayList<ZegoUser> userList, Msg msg) {
String msgPack = msg.toString();
// 发送自定义信令,`toUserList` 中指定的用户才可以通过 onIMSendCustomCommandResult 收到此信令
// 若 `toUserList` 参数传 `null` 则 SDK 将发送该信令给房间内所有用户
mEngine.sendCustomCommand(roomId, msgPack, userList, new IZegoIMSendCustomCommandCallback() {
/**
* 发送用户自定义消息结果回调处理
*/
@Override
public void onIMSendCustomCommandResult(int errorCode) {
//发送消息结果成功或失败的处理
Log.e(TAG, "消息发送结束,回调:" + errorCode);
}
});
}
其中,roomId
表示房间号,userList
表示接收人列表,msg
是我们自定义的一个实体类。创建一个表示实时棋盘界面的实体类:
public class MsgBoard extends Msg {
public boolean isRedPlaying; //接下来是否是红方下棋
public byte[][] board; //当前棋局面
public int fromX;
public int fromY;
public int toX;
public int toY;
public MsgBoard(int msgType, String fromUserId, boolean isRedPlaying, byte[][] board, int fromX, int fromY, int toX, int toY) {
super(msgType, fromUserId);
this.board = board;
this.isRedPlaying = isRedPlaying;
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
}
}
每个玩家下完棋后,将当前棋子位置发出去(如果有服务器,为了安全,这个工作最好让服务器去做)。这样,可以实现不局限于2个游戏玩家,如果有多个观众,任何观众随时上线即可观看对战。
第2小节完成了Zego SDK
的接入,接下来完成实时语音功能。实时语音实现过程可以看官方文档https://doc-zh.zego.im/article/7636。简单来说,
最重要的是2步:
注意:一切操作都必须先登录房间成功后再做,否则会失败。
实时语音推流代码如下:
public void pushStream(String streamId) {
//不管有没有推流,先停止推流
mEngine.stopPublishingStream();
mEngine.startPublishingStream(streamId);
Log.e(TAG, "已推流:" + streamId);
}
这里的streamId
建议RoomID_UserID_后缀
形式,以确保唯一性,避免串流
。
顾名思义,拉流是拉取对方的实时语音流。那如何知道对方的streamID
呢?可以监听如下回调函数:
public void onRoomStreamUpdate(String roomID,
ZegoUpdateType updateType,
ArrayList<ZegoStream> streamList,
JSONObject extendedData) ;
房间里面一旦有新的流推送或有流停止推送都会触发这个回调函数。我们根据updateType
参数来判断是新增还是删除:
if(updateType == ZegoUpdateType.ADD){
//表示有新增流
} else if (updateType == ZegoUpdateType.DELETE) {
//表示有流停止推送
}
一旦判断有新增流,那么可以直接拉取对方流,拉流和停止拉流代码如下:
public void pullStream(String streamId) {
mEngine.startPlayingStream(streamId);
}
public void stopPullStream(String streamId) {
mEngine.stopPlayingStream(streamId);
}
实现了在线语音中国象棋对战游戏,其他任何游戏均可直接套用本文的实时同步和实时语音能力。我将这两部份能力封装起来,读者可以直接下载源码复用。
源码如下:
https://github.com/KaleTom/OnlineGame
近期有开发规划的开发者可上即构官网查看,恰逢即构七周年全线音视频产品1折的优惠,适合有预算要求的中小型企业和个人开发工作室。
笔者为大家争取到小福利:联系商务获取RTC产品优惠,发送“RTC七周年福利"有惊喜!