与亲朋好友一起玩在线游戏,如果游戏中有实时语音对讲能力就能够拉进玩家之间的间隔,增加更多乐趣。咱们以经典的中国象棋为例,开发在线语音对讲象棋。本文次要波及如下几个点:

  1. 在线游戏的规定,本文以中国象棋为例。
  2. 借助Zego 音视频 SDK的实时音讯能力,实现在线游戏实时数据传输。
  3. 借助Zego 音视频 SDK的语音能力,实现在线语音。

留神:尽管本文以中国象棋为例,但其余在线小游戏同样能够套用,只是游戏规则不一样而已。

实时语音对讲最终成果如下:

1 中国象棋游戏规则

对于中国象棋的游戏规则,我这里做个简略的介绍。

  1. 车:只能走直线。
  2. 马:只能按字对角走,如果往对角方向的长边有棋子,则不能走。
  3. 象:只能按字对角走,且不能过河。如果字正核心有棋子,则不能走。
  4. 仕:只能在九宫对角线上走。
  5. 帅:只能在九宫外面走,须要留神,单方帅如果在同一条直线上两头必须有棋子,否则不容许在同一条直线。
  6. 跑:如果不吃子,则跟车一样的规定。如果吃子,则须要被吃的子与跑之间有一个棋子。
  7. 兵:没过河时只能后退。过河后,能够左右和后退,但不能后腿。

在玩家每一次下棋时,首先须要验证指标地位是否是无效地位,即是否合乎游戏规则:

// 判断是否能够挪动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;}

如果是合乎规定的行走,再间接将指标地位的棋子移除(必须先判断有棋子且是对方棋子才行)。游戏能够始终这样继续上来,直到有一方的被吃掉, 游戏完结。

2 实时游戏数据传输-zego 音视频 SDK

实时传输游戏数据能够本人基于TCP去实现,但有如下几个毛病:

  1. 单方必须在同一个局域网,或者单方必须用无效的互联网ip地址。
  2. 得要精心保护音讯数据发送与接管,代码量大且不不便保护。

咱们能够借助Zego 音视频 SDK中弱小的实时音讯能力实现实时棋盘同步,具体如何接入能够查看官网文档:
https://doc-zh.zego.im/article/3575。通过这篇官网文档,基本上能够实现Zego 音视频 SDK的接入工作。

2.1 登录/登出游戏实时语聊房间

应用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即可。

2.2 游戏发送实时音讯

有了后面这些筹备工作后,接下来是实现实时棋盘同步。封装一个发送音讯函数:

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个游戏玩家,如果有多个观众,任何观众随时上线即可观看对战。

3 接入实时语音SDK

第2大节实现了Zego 音视频 SDK的接入,接下来实现实时实时语音性能。实时语音实现过程能够看即构官网的实时音视频SDK官网文档https://doc-zh.zego.im/article/7636。
简略来说,最重要的是2步:

  1. 推:语音推流
  2. 拉:语音拉流
留神:所有操作都必须先登录房间胜利后再做,否则会失败。

3.1 语音推流

实时语音推流代码如下:

public void pushStream(String streamId) {    //不论有没有语音推流,先进行语音推流    mEngine.stopPublishingStream();    mEngine.startPublishingStream(streamId);    Log.e(TAG, "已推流:" + streamId); }

这里的streamId倡议RoomID_UserID_后缀模式,以确保唯一性,防止串流

3.2 语音拉流

顾名思义,拉流是拉取对方的实时语音流。那如何晓得对方的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);}

4 实时语音对讲demo/源码分享

实现了在线实时语音对讲的中国象棋对战游戏,其余任何游戏均可间接套用本文的实时音讯同步和实时语音对讲能力。我将这两部份能力封装起来,读者能够间接下载源码复用。
实时语音对讲源码和Demo如下:

源码