《如何用creator开发三国类单机SLG游戏|社区征文》

前言

  • 大家好,我是鸦哥的弟弟。平时比较喜欢打游戏,三国题材一直是我的菜,中华文化真是博大精深。国内的单机三国游戏,早一点的有三国群英传华夏宏图中华三国志,近几年做的比较好的汉末霸业(支持正版)大部分还是以三国群英传为模板,就是一回合一回合的,我一直想做一个像骑马与砍杀那种机制的游戏,感觉还是挺难的。自己开发这款三国游戏快两年了,玩家也积累了七八个qq群,平时有空的时候就写写,因为还有别的项目,挺忙。我觉得三国游戏的快乐之处在于,手下群英荟萃,肃清万里,总齐八荒,抓将的感觉太快乐了,诸葛亮也是抓了孟获七次,哈哈。

  • 本文主要分成三个部分(游戏模块,游戏场景,后期的debug技巧)来依次介绍单机SLG的开发。熬夜写完,获益可点个赞,谢谢朋友们。

(一)游戏模块

一. 时间模块

二. 事件模块

  • 这里保存了一份事件的对应关系用于全局事件分发(这里记录了未来发生的时间点,时间模块驱动进行触发)

三.AI模块 (主要使用了分层状态机HFSM来做,用时间驱动)

  • 1.这里为什么要使用分层状态机?

  • 单纯的使用状态机控制武将的行为,状态过多,ai对象要处理局部的数据,又要统筹整体的数据,不容易维护ai对象的状态

  • 2.什么是分层状态机HFSM?

  • 这里我用自己的话描述一下,当状态机fsm的状态过多时候,很难维护,这时候可以考虑从逻辑层分离,将同类型的状态机抽离。用大的状态机去管理小的状态机,

  • 3.举例子

  • 在本项目中参考了经典游戏骑马与砍杀的ai逻辑,将状态机分成了

  • 国家层状态机 =>> 领主层状态机

  • 国家层的行为:搜索最佳战略城池(),给领主发工资,修城墙,收税

  • 领主层的行为:根据国家找到的城池建基地,移动基地,训练武将,攻击城池,劝降抓住的武将,给武将发工资等等行为。


四.数据管理(这里主要介绍数据的序列化)

  • 读取/保存玩家的数据是一个单机游戏必备的功能本游戏中有大量的model类,并且使用了Map数据结构进行存储无法直接序列化,还有一个问题,有一些临时缓存的数据并不想序列化到存储数据中,那么怎么办呢?

  • 我这里的作法 临时缓存的数据使用 _开头,具体代码如下,这两个方法写在了model基类

          /**序列化数据 屏蔽掉下划线开头的数据 */
          public toString(): string {
              let keys = Object.keys(this)
              let res: { [key: string]: any } = {};
              for (let i = 0, len = keys.length; i < len; i++) {
                  let k = keys[i];
                  if (k.substring(0, 1) == "_") {
                      continue;
                  }
                  res[k] = this[k];
              }
              return JSON.stringify(res);
          }  
    
          /**读取数据 */
          public initWithData(data: any) {
                if (data instanceof Object) {
                   for (let attr in data) {
                        data.hasOwnProperty(attr) && (this[attr] = (data[attr]))
                   }
             }
             return this;
          }
    

五.存储模块(主要介绍数据的压缩)

这部分没有什么可说的,主要是用了Pako.js进行数据的压缩

六.层级管理
这里依赖资源管理的层级管理。
https://github.com/uer7e67/cocos-creator-ui-manager 这是我自己写的一套UI框架
里面有个导出层级配置的插件,不会写插件的可以研究一下,最简单的例子了
QQ图片20220329012942

七.资源管理

这里使用了常见的引用计数来管理资源

(二)游戏场景

  • 本游戏有三个场景,大地图,城池,和战斗场景。

一.大地图

  • 本游戏中城池有500+个城池,节点3000+,不优化的情况下,网页上还好,原生prefab实例化耗时确实有点长,拖动屏幕移动会卡成幻灯片。那么怎么办呢?

  • 这里主要使用了四叉树,节点池做优化,相信大家对四叉树很了解,论坛有很多前辈用四叉树去优化碰撞,这里详解一下四叉树在slg中的应用。先简单介绍一下四叉树,四叉树这个数据结构,四叉树是一种树状数据结构,在每一个节点上会有四个子区块。四元树常应用于二维空间数据的分析与分类。 它将数据区分成为四个象限。那么我们就可以将大地图分而划之。其实目的是优化地图上的节点数量,这样效率高一点。
    img1
    demo在这里 https://github.com/uer7e67/SlgMapQuadtree 基于2.4.8

二.城池场景

  • 堆ui,动画,没什么好说的

三.战斗场景

  • 也是主要使用了状态机控制,兵种的跑,攻击,行走,idle,死亡。这个也什么好说的。主要是一些算法。这里是战斗效果,感兴趣的朋友可以找我聊聊
    GIF

(三)单机游戏的调试

  • 这里介绍一下我在开发单机游戏的debug技巧,个人游戏没有用到友盟这样的sdk,我们可以让玩家帮办截图之类,可以省去自己反锁的调试。这里介绍的方法主要是调用安卓层的log模块可以方便的发现错误的位置。这里介绍一个很方便的方法,去发现bug。

  • 第一步:js层捕捉错误

           window['__errorHandler'] = function (file, line, msg, error) {
               let report = `拦截错误:文件名:${file},行数:${line},错误提示: ${msg},错误堆栈:${error}   `
               NativeHelpter.showDialog(report);
           }           
           // 通过桥调用
          jsb.reflection.callStaticMethod("org/cocos2dx/javascript/utils", "showToast", "(Ljava/lang/String;)V", msg);
    
  • 第二步:android层编写调用log的方法

           public static void showToast(String text) {
             new Thread(new Runnable(){
              @Override
              public void run() {
                  Looper.prepare();
                  if(toast != null) {
                      toast.setText(text);
                  }
                  else{
                      toast = Toast.makeText(c, text, Toast.LENGTH_LONG);
                  }
                  toast.show();
                  Looper.loop();
              }
          }).start();
      }
    
  • 错误捕捉效果如下

  • END…

42赞

感谢大佬的分享

:+1:,感谢楼主带我发现了学习的地方

1赞

:grinning: :grinning: 一起加油

虽然是个学渣,但是大佬的更新是我快乐的源泉,点个赞 :grinning:

大佬请教下大地图的缩放处理,比如缩放到边界的处理和缩放时整体地图的位置处理

感谢大佬一直以来的坚持

大佬加油,

留个坐标!

谢谢大佬分享

mark mark

这是 991149467 发的第一个帖子 - 让我们欢迎他加入社区!

mark。大佬牛皮

mark,大佬牛皮

大佬牛逼牛逼,厉害:+1::+1::+1:

大佬需要小弟嘛

谢谢大佬。。

大佬牛,求指导

大佬dddd

大佬多发点,我来学

给大佬点赞!