Libgdx学习笔记:自己封装各种粒子特效

实现的思路:缓存池+(Image或者CHActor) + Actions

例:实现星星右中心点向圆形周围扩散,且星星不断的旋转,缩小,到达圆上时消失。

这个需求里面对于单个星星包含的Action有:

moveTo 移动

roatateBy 旋转

scaleTo 缩小

我们使用Actions.parallel(...)来同时执行上面三个Action。当然我们再执行上面所有Action还需要加上最后的RunnableAction.用来处理粒子结束后的其他工作(释放星星对象到缓存池)。

单个星星的运动过程了解后,剩下的就简单了,我们约定使用30个星星来实现这个效果,在360度的范围随机30次,得到各个星星的运动目标位置,随机整个运动时长。OK。加入舞台,就可以了。

同样,如果我需要一个烟花效果呢?

  1. 确定一个矩形范围
  2. 在矩形范围随机位置,播放上面的星星效果,这就是个烟花释放的效果。

理解了这种思路,其他的粒子的效果都不在话下了,自由扩展吧!!!


下面为本人封装两种粒子效果:

package com.oahcfly.chgame.core.helper;

import java.util.Random;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Action;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Pool;
import com.badlogic.gdx.utils.Pool.Poolable;
import com.badlogic.gdx.utils.Pools;
import com.oahcfly.chgame.core.Chao;
import com.oahcfly.chgame.core.actions.CHScheduleAction;
import com.oahcfly.chgame.core.mvc.CHActor;

/**
 * 
 * <pre>
 * 
 * 可自由扩展的粒子播放器
 * <设置粒子图片路径即可>
 * date: 2015年3月26日
 * </pre>
 * 
 * @author caohao
 */
public class CHAutoParticle implements Poolable {
	private Random random = new Random();

	private Pool<CHActor> starPool = null;

	// 半径
	private int cradius = 100;

	public void setRadius(int radius) {
		cradius = radius;
	}

	private String imgString;

	// 设置图片路径assets目录下
	public void setImagePath(final String imgPath) {
		this.imgString = imgPath;
		starPool = (Pool<CHActor>) Pools.get(CHActor.class);
	}

	private CHActor getActor() {
		CHActor chActor = starPool.obtain();
		Texture texture = Chao.game.getTexture(imgString);
		chActor.setBgTexture(texture);
		chActor.setSize(50, 50);
		chActor.setOrigin(com.badlogic.gdx.utils.Align.center);
		float r = (float) ((Math.random() * 0.4f) + 0.7f);
		float g = (float) ((Math.random() * 0.4f) + 0.7f);
		float b = (float) ((Math.random() * 0.4f) + 0.7f);
		chActor.setColor(r, g, b, 1);
		return chActor;
	}

	/**
	 * 
	 * @param imgPath
	 *            图片路径
	 */
	public CHAutoParticle(final String imgPath) {
		setImagePath(imgPath);
	}

	public CHAutoParticle() {

	}

	/**
	 * 
	 * <pre>
	 *   <由中心向周围扩散并且旋转缩小>
	 *    播放粒子效果
	 * date: 2015年3月26日
	 * </pre>
	 * 
	 * @author caohao
	 * @param stage
	 * @param centerX
	 *            中心点位置X
	 * @param centerY
	 *            中心点位置Y
	 */
	public void playCircleParticle(Stage stage, float centerX, float centerY) {
		// 半径范围
		float initRadius = cradius;
		// 星星数量
		float starNum = 30;
		float initStarDuration = 0.3f;
		for (int i = 0; i < starNum; i++) {
			// 随机角度
			int degree = random.nextInt(360) + 1;
			// 随机运行时间
			float starDuration = (float) (initStarDuration + random.nextInt(5) / 10f);
			// 随机半径
			float radius = initRadius + random.nextInt(10);
			final CHActor starImg = getActor();
			starImg.setPosition(centerX, centerY, Align.center);
			starImg.setScale(1);
			// 目标点
			float targetX = centerX + (float) (radius * Math.cos(Math.toRadians(degree)));
			float targetY = centerY + (float) (radius * Math.sin(Math.toRadians(degree)));

			final boolean islast = i == starNum - 1;
			// 运动同时进行旋转,缩小
			Action parallelAction = Actions.parallel(Actions.moveTo(targetX, targetY, starDuration),
					Actions.rotateBy(360, starDuration), Actions.scaleTo(0.1f, 0.1f, starDuration));
			starImg.addAction(Actions.sequence(parallelAction, Actions.run(new Runnable() {

				@Override
				public void run() {
					// 释放加移除
					starPool.free(starImg);
					starImg.remove();
					if (islast) {
						Pool<CHAutoParticle> pool = Pools.get(CHAutoParticle.class);
						pool.free(CHAutoParticle.this);
					}
				}
			})));
			stage.addActor(starImg);
		}
	}

	/**
	 * 
	 * <pre>
	 * <烟花效果>
	 * 
	 * date: 2015年3月26日
	 * </pre>
	 * 
	 * @author caohao
	 * @param stage
	 * @param rangeRectangle
	 *            烟花范围
	 */
	public void playFireWorks(final Stage stage, final Rectangle rangeRectangle, final int playCount,
			final Runnable callbackRunnable) {
		Action runnableAction = Actions.run(new Runnable() {

			int count;

			@Override
			public void run() {
				count++;
				if (count > playCount) {
					for (Action action : stage.getRoot().getActions()) {
						if (action instanceof CHScheduleAction) {
							((CHScheduleAction) action).finish();
						}
					}
					return;
				}
				for (int i = 0; i < 10; i++) {
					int x = (int) (random.nextInt((int) rangeRectangle.width) + rangeRectangle.x);
					int y = (int) (random.nextInt((int) rangeRectangle.height) + rangeRectangle.y);
					playCircleParticle(stage, x, y);
				}
			}
		});

		Runnable runnable = new Runnable() {

			@Override
			public void run() {
				// TODO Auto-generated method stub
				if (callbackRunnable != null) {
					callbackRunnable.run();
				}

				Pool<CHAutoParticle> pool = Pools.get(CHAutoParticle.class);
				pool.free(CHAutoParticle.this);

			}
		};
		CHScheduleAction scheduleAction = new CHScheduleAction(0.5f, playCount, runnableAction);
		scheduleAction.setCallbackRunnable(runnable);
		stage.addAction(scheduleAction);
	}

	@Override
	public void reset() {
		// TODO Auto-generated method stub
		cradius = 100;
		if (starPool != null) {
			starPool.clear();
		}
	}

	public static CHAutoParticle obtain(String imgPath) {
		Pool<CHAutoParticle> pool = Pools.get(CHAutoParticle.class);
		CHAutoParticle chAutoParticle = pool.obtain();
		chAutoParticle.setImagePath(imgPath);
		return chAutoParticle;
	}
}


基于libGdx二次封装的CHGame框架 :

https://git.oschina.net/oahcfly/CHGame


时间: 2024-11-18 23:26:48

Libgdx学习笔记:自己封装各种粒子特效的相关文章

Libgdx学习笔记:封装自己的Actor

为什么要去封装我们自己的Actor? 答:Actor本身可能无法满足我们的开发需求,或者无法支持各种各样的效果,由此需要在其基础上进行拓展. 下面贴出本人二次封装的CHActor代码,供大家参考:   1.CHActor使用了对象缓存池,自动管理释放,很好的解决了游戏中使用大量对象导致帧数较低的问题.    2.自行设置绘制的纹理,而不必使用Image.创建过多的Image会导致帧数下降的很厉害.   3.可自由继承CHActor,方便自己再次扩展. 用法: CHActor chactor  =

Libgdx学习笔记: 游戏如何在androidx86 2.2的vbox虚拟机测试运行

这个问题我花了一天半的时间才解决,换了无数个libgdx的版本,0.98.0.99 1.0 还有最新未发布的版本都测试了,虚拟机的版本也换了很多个,都不行 最后总结出来. vBox虚拟机上的androidx86 无论哪个版本,至少我测试的2.2 4.0 4.1 都无法成功运行 libgdx 的opengl es2.0版本的程序 先说下我为什么一定要虚拟机,因为androidAVD带的模拟器不能多个模拟器进行socket交互,我说的是超过2个,只有2个可以端口映射,3个以上就没办法了,而现在我做的

MiZ702学习笔记12&mdash;&mdash;封装一个普通的VGA IP

还记得<MiZ702学习笔记(番外篇)--纯PL VGA驱动>这篇文章中,用verilog写了一个VGA驱动.我们今天要介绍的就是将这个工程打包成一个普通的IP,目的是为后面的一篇文章做个铺垫. 打包成一个普通的IP的目的,可以直接将这个IP粘贴到Block文件中.(和用文本实例化是一个意思).应为我们调用zynq的核的时候一般是用Block的形式,为了zynq和我们的VGA模块更方便的组织起来,就需要这种IP打包方式. 为什么是强调是普通的IP,这个主意是区分带AXI接口的IP,这个在后面介

Libgdx学习笔记:Simple text input

官方Wiki:https://github.com/libgdx/libgdx/wiki/Simple-text-input 实现接口TextInputListener public class MyTextInputListener implements TextInputListener {       @Override    public void input (String text) {    }       @Override    public void canceled () 

Java学习笔记2——封装

封装 将类的某些信息隐藏在内部,通过该类提供的方法实现对隐藏信息的操作和访问.好处:1)只能通过规定的方法访问数据:2)隐藏类的实例细节,方便修改和实现.封装的实习步骤: public class Telphone{    private float screen;    private float cpu;    private float mem;       public float getScreen(){       return screen; }    public void se

JavaSE 学习笔记之封装(四)

封 装(面向对象特征之一):是指隐藏对象的属性和实现细节,仅对外提供公共访问方式. 好处:将变化隔离:便于使用:提高重用性:安全性. 封装原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对其访问. 封装是为了解决数据的安全性 继承是为了解决代码的重用性 多态是为了解决代码的扩展性 this:代表对象.就是所在函数所属对象的引用. this到底代表什么呢?哪个对象调用了this所在的函数,this就代表哪个对象,就是哪个对象的引用. 开发时,什么时候使用this呢? 在定义功能时

MongoDB学习笔记~自己封装的Curd操作(查询集合对象属性,更新集合对象)

回到目录 我不得不说,mongodb官方驱动在与.net结合上做的不是很好,不是很理想,所以,我决定对它进行了二次封装,这是显得很必然了,每个人都希望使用简单的对象,而对使用复杂,麻烦,容易出错的对象尽而远之,这是正常的,人都是喜欢懒惰的,就像程序员,也是一样,喜欢偷懒,可能说,偷懒是程序员进步的一个标志,呵呵. 下面我是总结的几种标准的操作,主要是针对我封装的官方驱动而方的(MongoOfficialRepository<TEntity>) 1  插入对象和子对象 /// <summa

Unity3D学习笔记(9)—— 粒子光环

参考网站首页的光环效果:http://i-remember.fr/en 利用Unity做了一个类似的光环:(后面还有进阶效果哦~) 可以观察到光环有最小半径和最大半径,并且光环的中间部分比边缘有更多的粒子.眼尖的可以发现这个光环至少有2层,外环顺时针旋转,内环逆时针旋转.除此以外,每个粒子都会游离,并不是规规矩矩地转圈. 我是这么设计的: 1. 所有粒子运动由程序控制. 2. 使用参数方程 x = cos(t), y = sin(t) 计算粒子位置,其中t是角度. 3. 使用PingPong函数

MongoDB学习笔记~自己封装的Curd操作(按需更新的先决条件)

回到目录 我们上一讲中介绍了大叔封装的Mongo仓储,其中介绍了几个不错的curd操作,而对于按需更新内部子对象,它是有条件的,即你的子对象不能为null,也就是说,我们在建立主对象时,应该为子对象赋一下初值,即new一下它,呵呵. 正确的mongo集合 对于赋过初值的子对象,在按需要更新时,有以下两种要注意一下 1 子对象的_id,如果已经存在,就更新它的值 2 子对象的_id,如果不存在,或者没有显示为_id赋值,则添加一条新的记录,即_id从新生成 而对于实体更新不存在这个问题,实体里的值