发新帖

[Unity3D] 【源码】将Unity官方Space Shooter改为实时联机对战射击游戏

大神级别 2017-10-30 211


将Unity官方射击游戏(Space Shooter)改为实时对战小游戏

经朋友介绍了解到天梯的实时对战服务(Nanolink)基于 UDP 的低延迟可靠连接,确保发送端数据尽快到达接收端。
在天梯实时对战服务官网直接下载.unitypackage SDK,直接双击导入即可,NanolinkSDK 包中也有小实例演示,可以参考。
不多介绍。


下面介绍具体实现


涉及同步数据

  • 玩家飞机位置同步
  • 掉落障碍物(石头,攻击性敌机)同步
  • 分值同步
  • 对战结束胜负同步
  • 存档回放(新功能)



(先介绍一种数据同步 “玩家飞机位置同步“ 简要代码和逻辑吧,其它数据同步都是类似的,主要就是看游戏本身的数据同步点。大家有什么问题也可以留言,一起探讨,握手)



基本 UI 修改
1,复制一架新的战机,分别命名为 Player-0, Player-1。这样命名也是为了跟 Nanolink 实时对战服务返回的玩家索引 getInt("client-index") 一致,方便控制当前玩家的战机。

2,添加 UI 对象,也就是 UI -> Canvas。
添加 4个 Button 入口,“等级匹配", "局域网匹配", "房间号匹配"。这也是 Nanolink 实时对战服务 支持的 3中匹配连接方式。

 



玩家飞机位置同步
鼠标点击 Hierarchy 窗口的 Player-0 对象,可以看到 Space Shooter 战机控制脚本为 Done_PlayerController,下面重点看下这个脚本。( 简要代码 )

1,2个玩家匹配成功后,射击。
2,玩家控制战机的位置,发送数据到 NanoLink 协议

Done_PlayerController.cs

[C#] 
void Update () {
                // 连接上后自动开火
                if (MyClient.isConnected() && Time.time > nextFire) {
                        nextFire = Time.time + fireRate;
 
                        // Instantiate(shot, shotSpawn.position, shotSpawn.rotation);
                        GameObject obj = GameObject.Instantiate(shot, shotSpawn.position, shotSpawn.rotation) as GameObject;
                        obj.name = "Bolt-Player-" + playerIndex; // 当前飞机的id
 
                        GetComponent<AudioSource>().Play ();
                }
 
                ...
 
                #region TouchEvents
                if(Input.touchCount == 1) {
                        Touch touch =Input.touches[0];
                        if(touch.phase == TouchPhase.Moved) {
                                Vector3 touchPosition = Camera.main.ScreenToWorldPoint (new Vector3 (touch.position.x, touch.position.y, 0));
 
                                float diffTime = Time.realtimeSinceStartup - lastMove;
                                float diffX = Mathf.Abs(touchPosition.x - targetPosition.x);
                                float diffZ = Mathf.Abs(touchPosition.z - targetPosition.z);
 
                                // 频率控制
                                if(((diffX >= 0.25f || diffZ >= 0.25f) && diffTime >= 0.05f) || ((diffX > 0.1f || diffZ > 0.1) && diffTime > 0.1f)) {
                                        targetPosition = new Vector3 (touchPosition.x, transform.position.y, touchPosition.z);
                                        bMoved = true;
                                }
                        }
                }
                #endregion
 
 
                if (bMoved) {
                        lastMove = Time.realtimeSinceStartup;
                        fireEvent ();
                }
        }
...
        public void fireEvent() {
                Hashtable values = new Hashtable ();
                values.Add ("name", "move");
 
                // 位置 position
                values.Add ("x", targetPosition.x);
                values.Add ("z", targetPosition.z);
 
                MyClient.send (GameSerialize.toBytes(values));
        }



3,新版Nanolink SDK 优化,调整
新版本SDK 对 NanoClient.cs 进行了分装优化,开发者只需要实现自己的 MyClient.cs 继承 NanoClient。
然后,开发者只需要在代码中实现 已封装好的虚拟函数 (onMessage, onStatusChanged, onConnected, onDisconnected, onEvent )即可。
看了下新版本 SDK, 理论上只需要 实现 onMessage, onEvent两个函数即可,比上一个版本方便多啦。


MyClient.cs

[C#] 
// 篇幅要求长度原因,详细请下载源码查看
public class MyClient : NanoClient {
        protected override void onMessage(byte[] data, byte fromIndex) {
                Hashtable values = GameSerialize.fromBytes (data);
 
                // 事件处理
                onEvent (values, fromIndex);
        }
 
        // 篇幅原因,此处省略10000字
 
        protected override void onDisconnected(int error) {
                // 篇幅原因
 
                // XXX 断开连接后自动保存 存档,用于 “回放上局”
                if(getInt("mode") != 0) {
                        string archivesFilePath = "";
                        string archivesFileName = "archives_file.dat";
#if UNITY_EDITOR
                        archivesFilePath = Application.dataPath;
#else
                        archivesFilePath = Application.persistentDataPath;
#endif
 
                        save (archivesFilePath + "/" + archivesFileName);
                }
        }
 
        // 相应接收到的事件
        void onEvent(Hashtable values, byte playerIndex) {
                string name = (string)values["name"];
                switch(name) {
                case "move":
                        // 篇幅原因
                        break;
                }
        }
}



4,新功能:存档回放
新版本SDK 支持存档回放功能,很赞,联机对战存档文件每分钟才几K,才几K,对才几K 。。。 
这样游戏实现存档回放简直太容易啦。下面分享的 Space Shooter 源码中也实现了 回放的功能。


最后,展示几张实际联机对战截图,把实际发送的基本数据和实际的延迟展示在左上角,可以留意下。我这边显示延迟有时会在10毫秒左右,很夸张。做到这点,简直 666
 


(注意:有开发者跟我说下载.unitypackage,运行不能联机,这是因为之前分享的包,我去掉了个人的appKey, 再分享一个新版本,直接运行就可以联机啦。)
(另外:编译到Android设备时,需要在 Unity 编辑器中配置 "File" - "Build Settings" - "Player Settings" - "Other Settings" - "Internet Access" 改为 Require;

Unity 工程包:
链接: https://pan.baidu.com/s/1eRZ4LGm 密码: irwg


安卓.apk包下载(两台安卓设备直接对战即可):
链接: https://pan.baidu.com/s/1bpeuEjP 密码: syq6


最新回复 (0)
登录后再回复
返回