欢迎光临散文网 会员登陆 & 注册

Egret学习笔记

2023-07-31 19:45 作者:是傀猫猫啦  | 我要投稿

egret是一个H5游戏引擎,而且用的人少,社区也不完善.学习egret的时候遇到不少困难,好在最终都能解决.这个引擎的公司已经跑路了,相信以后egret会慢慢退出历史舞台.

本文记录了我个人学习egret中的一些知识点,以及使用egret+EUIEditor进行小游戏开发的整个过程

1.知识点

1.1 skin

skin是一个游戏组件配置文件,用来以规范的方式预制一些组件,这包括:决定他们的位置,位置约束关系,各种可以预配置的属性. 加载skin以后,通过一些方法,可以将指定的类和skin绑定,绑定以后,在类中直接声明和skin中的组件形同类型和ID的变量,就可以将变量与skin中的组件绑定.

想要使用skin,需要在创建项目的时候选择"eui"项目,制作skin需要用到插件"Egret UI Editor".Editor的使用方法和绑定skin的流程会在之后给出

editor界面和一个典型的skin,它由一些组件组成

1.2 egret事件

egret的事件和传统的事件系统没有区别:发送事件是一个向上级抛出信息的过程,在父级对子物体加监听可以实现事件的传递.想要传递事件,我们在一个对象内部发送事件,然后在它的父对象中通过引用对子对象加监听,这样父对象就可以根据子对象的事件来处理逻辑,如果要多级传递,那么就在父对象的事件处理逻辑中发送消息给祖父对象,以此类推.

egret自带的事件类位于egret.Event中,这里定义了一系列事件类型参数,它们都是字符串类型.和UI有关的事件则一般在eui.UIEvent中

1.3 eui.DisplayObject和节点树

几乎所有能够呈现在界面上的组件都继承这个类或者它的子类,继承它的容器类DisplayObjectContainer及其子类则更加常用.可以把它看作一个UI节点树上的节点,有了节点,才能在节点上放东西,才能最终展示出来.子节点的一些属性(比如位置)受到父节点影响.

节点树的最上层是stage,它位于主函数Main.ts中,它就是游戏的展示界面

将物体添加到节点树上可以在任何一个节点中用addchild()添加,这样做就是把被添加的物体变成当前节点的子节点

1.4 Main.ts

项目的入口类.新建的项目自带这个文件,其中由很多乱七八糟的东西,其中有一些是不需要的.如果简单理一下主函数逻辑,那就是:createChildren()->runGame()->loadResource()&createGameScene()->分别处理加载资源组的逻辑和初始化游戏场景的逻辑,对于初学者来说,关注createGameScene()就好,在这里可以添加需要的展示物体,直接this.addchild()就可以,或者是this.stage.addchild().在示例项目中,createGameScene()里面写了大量的展示物体调整代码,这些逻辑应该写在一个单独的类里面.

1.5List

对于游戏中点阵的实现,我最终选用了List组件.和大多数UI系统的List一样,它提供一个布局,并定义一个作为基本单位的图形组件,也提供了一些接口允许对其中任何一个单位进行操作和交互判定.在Eui中,List的基本单位叫ItemRenderer,一般用一个继承这个类的类作为List的ItemRenderer,也可以直接将一个皮肤设置为ItemRenderer.

List的另一个重要成员是dataProvider,它是存放List数据提供者的成员.ItemRenderer是显示单元的数据,dataProvider是显示的单元的内容的数据.一般来说,可以用一个eui.ArrayCollection封装你的数据,在我的项目里,数据是由继承ItemRenderer的类组成的数组构成,根据renderer和provider,List将每一个元素按照布局显示出来

需要特别注意的是,List强制使用布局,而布局强制限定每个元素的位置,所以要是想设计特定的布局(在我的项目里表现为六边形网格),你必须封装ItemRenderer,然后将实际的呈示单元作为继承类的一个成员,List可以正常识别到这个呈示单元的.

2.从0开始的Egret小游戏开发流程

2.1 项目基本配置

  • 创建新项目

选择eui项目,勾选需要的组件,编辑参数,这些参数都很清晰明了,不必多说

进入项目,推荐使用vscode或者Egret插件Egret Wing编写代码.

项目中有一些自带的脚本和配置文件资源文件等,不用管他们

  • 添加需要的素材

将游戏素材放进resource/assets文件夹,自己的素材可以在目录下面新建文件夹.

进入Main.ts,删除createGameScene的内容和LoadTheme(好像是叫这个)等用不到的代码.到此,初始配置完成

2.2 UI Editor制作皮肤

进入Editor,,左上角资源管理器是你的资源文件(resource)的文件夹视图,如果你的资源管理器里面没有你的素材,右键-项目设置-添加资源和皮肤的路径

在右边的资源库中添加素材到中间的舞台,组合出需要的skin.点击这些组件,右边有他们的属性,左下角则是当前skin的配置信息.注意,常用属性中的ID就是一会在类中用来组件和变量绑定的标识符,建议都起一个名字

保存以后在你保存的目录下面可以看到和皮肤同名的exml文件,它其实就是皮肤配置文件.你也可以不使用Editor而是直接手写exml,它们没有区别

2.3皮肤绑定

创建一个类,继承eui.component(它也是继承自DisplayObjectContainer),在其中直接定义和组件ID同名的变量,然后在构造时将skinName属性设置成exml文件所在的位置,在绑定完毕后即可直接使用.注意,有必要使用加载事件等方式确保调用在绑定结束后才开始,否则会报错(因为使用了未初始化的变量)

2.4编写UI逻辑

这里我使用事件系统编写UI逻辑.首先有一个写成单例的场景管理类UIManager,它存放和管理所有用到的场景,并提供一个场景加载函数.因为它是所有场景的上级,而触发场景切换的逻辑一般都在子场景中的组件,所以在子类或孙类调用切换场景的方法肯定是逻辑错误的,所以我们使用事件层层传递.

以失败场景举例,失败场景中的按钮添加一个监听,被点击时发送一个包含场景切换信息的事件,在UIManager中,对失败场景加了监听,所以能读取到这个事件,并获取事件的信息,然后加载对应场景

MyUIEvent是我封装了egret.Event,然后添加了需要的信息

UIManager这里我最开始犯了一个工程问题:使用单例的类一般有两种情况,一种是作为顶层的管理类,另一种是作为底层的工具类.我希望UIManager作为一个管理类,而对loadScene,却像一个底层的工具类接口,所有组件都直接调用它,这显然是不合适的

2.5 使用List实现点阵和其交互逻辑

首先准备一个作为List单位的节点GameNode和作为作为List数据源的节点管理者NodeManager

GameNode继承了ItemRenderer,并且有一些属性由于逻辑处理,dataChanged方法是继承来的,用于在数据初始化和更新的时候进行一些操作,我这里是让偶数行的点偏移一定位置,实现六边形网格的效果.

对于具体的呈示器,我通过绑定皮肤设置了每个单位的样式,实际移动也是移动它的位置,因为GameNode本身作为ItemRenderer受限于布局,是不能移动位置的.

接下来是交互逻辑,GameNode只有改变自身点的能力,这个方法被管理者调用,sendMessage用于发送事件

2.6 游戏GamePlay部分的逻辑

类GameScene负责游戏GamePlay界面的所有逻辑.

首先是一些数据和构造函数.这些数据主要就是用来操控游戏元素的,以及和Skin绑定的元素.需要注意的是这个dataMatrix,设计数据矩阵的目的是分离数据层和实体层,这样实体层只需要new出来一次,而每次数据更新和逻辑判断(比如猫判断下一个落点)都只使用这个数据数组.然后根据dataMatrix更新实体就可以

初始化和更新的方法,每次想要重置关卡,只需要调用initData()

更新逻辑和事件系统,接受到节点发出的事件,GameScene开始走一遍更新逻辑,如有必要,向上发送事件,这主要用在切换场景.

2.7 编写猫逻辑

Cat这个类同时包含了猫的表现层和逻辑层的代码,也就是说,负责显示动画的方法和猫寻找路径的逻辑写在一个类中,这不是一个好的习惯,但是限于项目大小这么做没问题.

一些属性和构造函数,构造函数中监听是否被添加到舞台上,catInit负责初始化的内容

初始化主要对数据做初始化,把该使用的资源加载好.

需要注意的是加载动画的代码,这部分使用game扩展库实现,具体看代码,知道怎么用就可以

路径规划函数,寻找下一个位置,这个过程中也需要判断自己是否已经被围住,如果被围住则不需要寻找出路,节省算力.

judgeState不仅包含判断状态的逻辑,也包含寻找出路的逻辑,这段逻辑本来应该分离,但是用到的属性和数据高度重合,所以就放在一起.

寻路的算法使用DFS深度优先搜索,以当前最短路径为标准剪枝

3.效果展示:

主界面

游戏界面

被围住:

胜利

下一关:

失败:



Egret学习笔记的评论 (共 条)

分享到微博请遵守国家法律