Libgdx粒子效果介绍与使用心得
Libgdx粒子效果介绍与使用心得
我也将这篇文章发表在了知乎。
Libgdx粒子效果介绍与使用心得
概述
前言
我在本学期的面向对象编程课程中,参与到Devotees战棋游戏项目开发中,主要承担美术工作。我在绘制所有的图片素材的同时,编写了一些与视觉效果有关的代码,如粒子特效、分辨率调整,以及部分UI的布局和响应。我们使用的Libgdx不同于游戏引擎,它更接近于底层一些,许多东西不能满足我们的需求,还需要自己“造轮子”,加上没有可视化开发界面,对于视觉效果的调整更是困难重重。在此分享我对于Libgdx粒子效果的一些心得或踩过的坑。
基本概念
在阅读本篇文章前,你需要了解:
Libgdx是免费开源的Java游戏框架,提供了若干用于游戏开发的类;
Actor是Libgdx中的一个类,是游戏场景中的基本元素;
ParticleEffect是Libgdx中的一个类,用于构建粒子效果;
Stage是Libgdx中的一个类,用于展示多个Actor,能够处理视口和事件响应等;
Batch是Libgdx中的一个类,用于统一在屏幕上绘制图像。
粒子效果ParticleEffect
粒子效果在游戏中展示闪光、火焰、爆炸、烟雾等效果时很有用,在Devotees战棋游戏中我将粒子效果用于射弹的飞行以及爆炸效果、近战的刀光(也是以射弹实现的)、还有结算界面的光效。在这里介绍我使用粒子效果的方法:用可视化粒子效果编辑器创建粒子文件、在代码中加载并进一步设置、播放和结束。图1是Devotees中角色“混沌执事”和其射弹爆炸时的样子。
图1 混沌执事的一个粒子效果
粒子效果编辑器
Libgdx提供了可运行的可视化粒子效果编辑器Particle Editor,它的界面如图2所示。
图2 Particle Editor
粒子效果包括一个或若干个粒子发射器Emitter,粒子发射器将在一段时间内发射粒子,从左上角的Effect Emitters面板可以管理发射器,如新建、复制、删除、调整上下层级等;保存和打开操作是针对整个粒子效果文件的。
左下角的面板可以预览目前的粒子效果。
右上角的Editor Properties面板用于调整预览面板的缩放、背景等属性;建议将背景颜色调整为与游戏背景接近的颜色,这样能够更好地估计当前粒子效果在游戏中的实际表现。
右下角的Emitter Properties面板最为重要,在其中可以调整当前选中的发射器的属性,来改变整个粒子效果的外观。
常用属性设置
粒子发射器ParticleEmitter的常用属性如表1所示。
表1 发射器常用属性
属性名 | 说明 |
---|---|
Image | 每个粒子的材质,在图3中的粒子效果中,多个发射器均使用了一张由5个像素点组成的图片为材质 |
Count | 发射器的最大、最小粒子数 |
Duration | 发射器的持续时间,单位为ms |
Emission | 发射器每秒发射的粒子数 |
Life | 粒子的持续时间 |
X Size | 粒子的大小,如果Y Size属性未被激活则等比例缩放 |
Velocity | 粒子运动速度 |
Angle | 粒子发射角度 |
Rotation | 粒子自转角度 |
Tint | 粒子颜色 |
Transparency | 粒子不透明度 |
Continuous | 粒子发射器是否持续发射,默认为false,如果为true则Duration为无穷大,且isComplete()永远为false |
Attatched | 粒子是否对齐于发射器,默认为false,如果为true则粒子随发射器移动而移动 |
图3 以十字为材质的粒子效果
大多数属性都可以设置HighMin、HignMax、LowMin、LowMax四个值,以及一条变化曲线,发射器大致遵循这样的规则:在产生一个粒子时,在HighMin-HighMax中随机选择一个值h作为变化曲线的上限,在LowMin-LowMax中随机选择一个值l作为变化曲线的下限,并根据曲线在粒子的生命Life中根据变化曲线在上下限之间进行变化,得到某一时刻该粒子的这项属性值。
注意Attatched这个属性。Libgdx中的粒子效果默认参照屏幕坐标系,即每个粒子在生成后参照屏幕进行运动,而不管发射器如何运动;在Devotees中,我们有时需要拖动整个地图,如果地图拖到了一边,而粒子却纹丝不动,这无疑是非常奇怪的,加上我只做了几个直线发射的射弹,不需要太复杂的运动,因此在我的项目中勾选了这一项,并设置发射器跟随地图移动,这样粒子也就以地图为参照系运动了。
在添加发射器和材质、完成属性设置后点击保存,我们就得到了一个粒子效果文件,之后将把它加载到游戏中。
考虑到许多属性需要动态设置,如弹道需要根据游戏内的发射位置和目标位置设置其方向,因此利用代码而不是编辑器来设置属性也是必要的,一般来讲设置代码像是这样的形式:
explode.getEmitters().get(i).getAngle().setHighMax(dir+EXPLODEANGLE);
通过getEmitters().get(i)得到该粒子特效的第i个发射器,getAngle()得到发射器的Angle属性,setHighMax()将设置这一属性的HighMax值为dir+EXPLODEANGLE。
将粒子效果加入游戏
总地来说,将粒子效果加入游戏步骤包括:在一个Actor类中创建ParticleEffect类的实例,并重写draw方法,使粒子效果显示出来,再在Stage中加入这个Actor的实例。
这里需要用到的方法如表2所示,除了构造方法外其他方法返回类型均为void。
表2 绘制粒子效果相关方法
方法名 | 参数 | 说明 |
---|---|---|
ParticleEffect() | ParticleEffect的构造方法,创建一个空的粒子效果 | |
ParticleEffect.load(FileHandle effectFile, FileHandle imagesDir) | effectFile是粒子效果文件,而imagesDir是粒子材质所在地址(由于同一个粒子效果可能有多种材质) | 从文件中加载粒子效果 |
ParticleEffect.Start() | 开始播放粒子效果 | |
ParticleEffect.setPosition(float x, float y) | x,y是横纵坐标 | 设置粒子效果的位置 |
ParticleEffect.draw(Batch batch, float deltaTime) | batch,delta是距离上一次绘制经过的时间 | 绘制粒子效果 |
注意start()这个方法的使用,应当确保其在整个粒子效果的使用过程中仅调用一次,因为似乎执行的结果是将粒子效果接下来的待运行时间加上Duration,如果多次调用则会使其实际上的发射时间为n*Duration,导致意料之外的情况发生。
以Devotees中Bullet类的代码为例进行说明。
第一部分:
public class Bullet extends Actor {
...
protected ParticleEffect effect;
protected ParticleEffect explode;
...
/***
* 生成射弹
* @param unit 产生射弹的单位种类
* @param from 发射方块
* @param to 目标方块
* @param atk 伤害
*/
public Bullet(UnitCategory unit, Block from, Block to,int atk){
...
effect=new ParticleEffect();
explode=new ParticleEffect();
String indx=unit.toString();
effect.load(Gdx.files.internal(indx+