前言
-
大家好,我是鸦哥的弟弟。平时比较喜欢打游戏,三国题材一直是我的菜,中华文化真是博大精深。国内的单机三国游戏,早一点的有三国群英传,华夏宏图,中华三国志,近几年做的比较好的汉末霸业(支持正版)大部分还是以三国群英传为模板,就是一回合一回合的,我一直想做一个像骑马与砍杀那种机制的游戏,感觉还是挺难的。自己开发这款三国游戏快两年了,玩家也积累了七八个qq群,平时有空的时候就写写,因为还有别的项目,挺忙。我觉得三国游戏的快乐之处在于,手下群英荟萃,肃清万里,总齐八荒,抓将的感觉太快乐了,诸葛亮也是抓了孟获七次,哈哈。
-
本文主要分成三个部分(游戏模块,游戏场景,后期的debug技巧)来依次介绍单机SLG的开发。熬夜写完,获益可点个赞,谢谢朋友们。
(一)游戏模块
一. 时间模块
- 主要功能是累计时间,驱动事件和AI模块
二. 事件模块
- 这里保存了一份事件的对应关系用于全局事件分发(这里记录了未来发生的时间点,时间模块驱动进行触发)
三.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框架
里面有个导出层级配置的插件,不会写插件的可以研究一下,最简单的例子了
七.资源管理
这里使用了常见的引用计数来管理资源
(二)游戏场景
- 本游戏有三个场景,大地图,城池,和战斗场景。
一.大地图
-
本游戏中城池有500+个城池,节点3000+,不优化的情况下,网页上还好,原生prefab实例化耗时确实有点长,拖动屏幕移动会卡成幻灯片。那么怎么办呢?
-
这里主要使用了四叉树,节点池做优化,相信大家对四叉树很了解,论坛有很多前辈用四叉树去优化碰撞,这里详解一下四叉树在slg中的应用。先简单介绍一下四叉树,四叉树这个数据结构,四叉树是一种树状数据结构,在每一个节点上会有四个子区块。四元树常应用于二维空间数据的分析与分类。 它将数据区分成为四个象限。那么我们就可以将大地图分而划之。其实目的是优化地图上的节点数量,这样效率高一点。
demo在这里 https://github.com/uer7e67/SlgMapQuadtree 基于2.4.8
二.城池场景
- 堆ui,动画,没什么好说的
三.战斗场景
- 也是主要使用了状态机控制,兵种的跑,攻击,行走,idle,死亡。这个也什么好说的。主要是一些算法。这里是战斗效果,感兴趣的朋友可以找我聊聊
(三)单机游戏的调试
-
这里介绍一下我在开发单机游戏的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…