`

Android游戏开发之爆炸效果

阅读更多

    在做Android游戏MagicBubble开发的时候,在连通两个Bubbles的时候,Bubble会以水泡爆破的情形消失。为了实现这一效果,我查找了不少资料,希望能找到一些标准的实现方面,花了不少时间,发觉Android关于游戏开发的资料实在太少了,更不用说标准做法了,没办法,只能按照自己的思路来实现这一效果。

    我的思路是这样的(仅供参考,希望有更好做法的朋友跟我们共享一下):在FrameLayout里面加入一ImageView,再定义一个爆炸的Animation,不需要的时候,ImageView就隐藏起来,需要的时候,就把ImageView移动到需要的地方,再StartAnimation,这样,就可以实现爆炸的效果。

   下面是简化后的程序的代码,程序的效果如下:点中屏幕中任意地方,就在点击地方显示爆炸效果。

 

首先是Animation的定义,定义一个Frame Animation,依次播放5帧动画,每帧动画持续时间为50毫秒:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/explode1" android:duration="50" />
    <item android:drawable="@drawable/explode2" android:duration="50" />
    <item android:drawable="@drawable/explode3" android:duration="50" />
    <item android:drawable="@drawable/explode4" android:duration="50" />
    <item android:drawable="@drawable/explode5" android:duration="50" />  
</animation-list>

 接着是主程序代码:

package com.ray.bubble;

import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.FrameLayout;
import android.widget.ImageView;

public class BubbleExplosion extends Activity {
	private FrameLayout fl;
	private ExplosionView exv1;
	private AnimationDrawable exa1;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //set full screen
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN ,
                      WindowManager.LayoutParams. FLAG_FULLSCREEN);
        fl = new FrameLayout(this);
        fl.setBackgroundResource(R.drawable.bg);
        
        exv1 = new ExplosionView(this);
		exv1.setVisibility(View.INVISIBLE);
	    exv1.setBackgroundResource(R.anim.explosion);
	    exa1 = (AnimationDrawable)exv1.getBackground();
		fl.addView(exv1);
		fl.setOnTouchListener(new LayoutListener());
        setContentView(fl);
    }
    
    class ExplosionView extends ImageView{

		public ExplosionView(Context context) {
			super(context);
		}
		//handle the location of the explosion
		public void setLocation(int top,int left){
			this.setFrame(left, top, left+40, top+40);
		}	
    }
    
    class LayoutListener implements OnTouchListener{

		public boolean onTouch(View v, MotionEvent event) {
			//firstly, u have to stop the animation,if the animation
			//is starting ,u can not start it again!
			exv1.setVisibility(View.INVISIBLE);
			exa1.stop();
			float x = event.getX();
			float y = event.getY();
			exv1.setLocation((int)y-20, (int)x-20);
			exv1.setVisibility(View.VISIBLE);
			exa1.start();
			return false;
		}
    	
    }
}

 配合Android的SurfaceView,Animation可以实现很好的过渡效果,SurfaceView的用法很简单,可参考:

http://rayleung.iteye.com/blog/420410

分享到:
评论
30 楼 biner 2011-08-10  
强大的楼主
29 楼 wangzx1983 2010-07-30  
正好需要学习这方面的技术,把代码下下来看看,感谢几位老大的无私奉献。
28 楼 mncc 2010-03-22  
那么问一下,如果屏幕上有多个地方需要上Animation,比如说飞行射击的时候,或者是多个物体碰撞的时候,这个时候应该怎么弄?View只能定义一个Animation啊?
27 楼 hone033 2010-02-09  
这位老大写得不错,多谢楼主分享
26 楼 yicw 2010-01-08  
在这里学到了不少知识,谢谢几位老大的无私奉献
25 楼 healthjava 2009-10-08  
一直在考虑SurfaceView的动画显示问题。看了vlinux的代码豁然开朗。顶
24 楼 lordhong 2009-09-21  
学习一下... 希望有一天开发出自己心仪的游戏
23 楼 raymondlueng 2009-09-21  
vlinux 写道
回来的路上就在想,是不是对SurfaceView的理解严重有误呢。一下飞机马上就开始实现设想,终于找到解决办法了。
使用SurfaceView就命中注定了一切从头开始自己动手创建、动手释放、动手画,不应该再抱有类似AnimationDrawable一样用法的幻想。

写了一个DEMO,Kuba这类的游戏要做也只是时间问题。

作为绘画核心的DrawRunning线程
/**
 * 绘画线程
 * 
 * @author vlinux
 * 
 */
public class DrawRunning implements Runnable {

	private List<AnimationDraw> animationDraws;//所有需要画动画的集合
	private List<AnimationDraw> buffers;//缓存前台传入需要展示的动画
	private SurfaceHolder surfaceHolder;
	private boolean running;

	public DrawRunning(SurfaceHolder surfaceHolder) {
		this.surfaceHolder = surfaceHolder;
		animationDraws = new ArrayList<AnimationDraw>();
		buffers = new ArrayList<AnimationDraw>();
		running = true;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (running) {
			synchronized (surfaceHolder) {
				Canvas canvas = null;
				try {
					canvas = surfaceHolder.lockCanvas(null);
					doDraw(canvas);
				} finally {
					if (null != canvas) {
						surfaceHolder.unlockCanvasAndPost(canvas);
					}// if
				}// try
			}// syn
		}// while
	}

	private void doDraw(Canvas canvas) {
		synchronized(this) {
			//检查缓存中是否有需要加入的动画
			if( !buffers.isEmpty() ) {
				animationDraws.addAll(buffers);//加入animationDraws
				buffers.clear();//清空缓存
			}//if
		}//syn
		if( animationDraws.isEmpty() ) {
			return;//如果animationDraws里面是空的那就不用画了
		}//if
		//---这里开始绘画
		Iterator<AnimationDraw> bombIt = animationDraws.iterator();
		while (bombIt.hasNext()) {
			AnimationDraw bomb = bombIt.next();
			Bitmap nextFrame = bomb.nextFrame();
			if (null == nextFrame) {
				//下一Frame为null,说明动画序列已经结束
				//该动画已经完成,从动画集合中删除
				bombIt.remove();
				continue;//while
			}// if
			canvas.drawBitmap(nextFrame, bomb.getX(), bomb.getY(), null);
		}// while
	}

	public void addAnimationDraw(AnimationDraw bomb) {
		synchronized(this) {
			//尽量减少这个的同步响应时间,因为这个方法是前台响应的
			//多0.1秒都会直接反应到用户感知
			buffers.add(bomb);//将需要显示动画的内容加入到缓存
		}//syn
	}

	public void stopDrawing() {
		running = false;
	}

}

这段代码写得好,很好的思路,非常感谢!
22 楼 vlinux 2009-09-20  
回来的路上就在想,是不是对SurfaceView的理解严重有误呢。一下飞机马上就开始实现设想,终于找到解决办法了。
使用SurfaceView就命中注定了一切从头开始自己动手创建、动手释放、动手画,不应该再抱有类似AnimationDrawable一样用法的幻想。

写了一个DEMO,Kuba这类的游戏要做也只是时间问题。

作为绘画核心的DrawRunning线程
/**
 * 绘画线程
 * 
 * @author vlinux
 * 
 */
public class DrawRunning implements Runnable {

	private List<AnimationDraw> animationDraws;//所有需要画动画的集合
	private List<AnimationDraw> buffers;//缓存前台传入需要展示的动画
	private SurfaceHolder surfaceHolder;
	private boolean running;

	public DrawRunning(SurfaceHolder surfaceHolder) {
		this.surfaceHolder = surfaceHolder;
		animationDraws = new ArrayList<AnimationDraw>();
		buffers = new ArrayList<AnimationDraw>();
		running = true;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (running) {
			synchronized (surfaceHolder) {
				Canvas canvas = null;
				try {
					canvas = surfaceHolder.lockCanvas(null);
					doDraw(canvas);
				} finally {
					if (null != canvas) {
						surfaceHolder.unlockCanvasAndPost(canvas);
					}// if
				}// try
			}// syn
		}// while
	}

	private void doDraw(Canvas canvas) {
		synchronized(this) {
			//检查缓存中是否有需要加入的动画
			if( !buffers.isEmpty() ) {
				animationDraws.addAll(buffers);//加入animationDraws
				buffers.clear();//清空缓存
			}//if
		}//syn
		if( animationDraws.isEmpty() ) {
			return;//如果animationDraws里面是空的那就不用画了
		}//if
		//---这里开始绘画
		Iterator<AnimationDraw> bombIt = animationDraws.iterator();
		while (bombIt.hasNext()) {
			AnimationDraw bomb = bombIt.next();
			Bitmap nextFrame = bomb.nextFrame();
			if (null == nextFrame) {
				//下一Frame为null,说明动画序列已经结束
				//该动画已经完成,从动画集合中删除
				bombIt.remove();
				continue;//while
			}// if
			canvas.drawBitmap(nextFrame, bomb.getX(), bomb.getY(), null);
		}// while
	}

	public void addAnimationDraw(AnimationDraw bomb) {
		synchronized(this) {
			//尽量减少这个的同步响应时间,因为这个方法是前台响应的
			//多0.1秒都会直接反应到用户感知
			buffers.add(bomb);//将需要显示动画的内容加入到缓存
		}//syn
	}

	public void stopDrawing() {
		running = false;
	}

}
21 楼 raymondlueng 2009-09-15  
vlinux 写道
是,那个代码我干掉了,我想完善点再丢上来的。总觉得真相就在手边了。

好,一起加油!
20 楼 vlinux 2009-09-15  
是,那个代码我干掉了,我想完善点再丢上来的。总觉得真相就在手边了。
19 楼 raymondlueng 2009-09-15  
vlinux 写道
不知道你是否有玩过一款叫做  “Buka" 的游戏,你觉得密集touch所产生那群蓝色光晕是多个View的效果么?

多个隐藏View,恩.你是想要做一个隐藏的View池?总觉得这不是一个最好的解决办法的说。

玩过Buka,还挺喜欢的,我也的确认为隐藏View做不出Buka这样的游戏,我认为隐藏VIew是对于一些比较简单动画的 游戏,是个方便高效的方法而已,我看了你的代码,代码并不是你说的用SurfaceVIew来实现动画啊!
18 楼 vlinux 2009-09-15  
不知道你是否有玩过一款叫做  “Buka" 的游戏,你觉得密集touch所产生那群蓝色光晕是多个View的效果么?

多个隐藏View,恩.你是想要做一个隐藏的View池?总觉得这不是一个最好的解决办法的说。
17 楼 raymondlueng 2009-09-15  
vlinux 写道
raymondlueng 写道
vlinux 写道
这个方法可行性不高,因为同一时间只有一个动画存在,如果是要多个动画出现,就挂了

使用过多个动画效果同时显示,没性能问题,请问您有没更好的方法,分享一下啦!



多个动画效果同时显示,根据你的例子来看,一个动画必须绑定一个View吧。但是爆炸是随机发生的事件。比如说我touch一下屏幕就要有一个爆炸动画出现,如果我在短时间是大量的touch那一个View的劣势就显示出来了。

如果你是打算用动态添加View,那肯定要有性能代价。

其实也不用的,我这个做法是从flash游戏的开发受启发的,你可以同时隐藏多个view,需要的时候就把其显现出来,大量的touch毕竟也是有些的,View的复用也是蛮高的!
16 楼 raymondlueng 2009-09-15  
vlinux 写道
初涉这块领地,也正在努力探索。
分两个思路来讨论一下

1.改进你的方法。
你的的方法是利用Android自带的Frame-By-Frame例子的,缺点就是Android目前依靠配置无法从一张动画序列图中截取部分来显示动画。所以这样就造成了必须准备一张张单独的图片,这对一个游戏拥有大量动作且Android的res目录不支持子目录的情况下来看是不大雅观的。

我用AnimationDrawable稍做了一些改进。


2.直接用SurfaceView开线程画。用线程+SurfaceView无疑是最好的办法了。不过我目前卡死在这里,因为每帧画出的图案就永久生效了。不像之前的Animation是可以重叠,当动画消失之后还原背景。非常令我苦闷,不知道你有没有在SurfaceView做动画的好办法。



我一开始做游戏动画的时候就是用surfaceview+线程来实现的,正如你所说的,动画消失后还要还原背景,在画面上画任何一点东西,都要导致整个画面重画,如果画动画的时候,有用户交换(比如说拖动某个物体,会导致画面闪烁非常严重),似乎这个办法也不是解决之道
15 楼 vlinux 2009-09-15  
raymondlueng 写道
vlinux 写道
这个方法可行性不高,因为同一时间只有一个动画存在,如果是要多个动画出现,就挂了

使用过多个动画效果同时显示,没性能问题,请问您有没更好的方法,分享一下啦!



多个动画效果同时显示,根据你的例子来看,一个动画必须绑定一个View吧。但是爆炸是随机发生的事件。比如说我touch一下屏幕就要有一个爆炸动画出现,如果我在短时间是大量的touch那一个View的劣势就显示出来了。

如果你是打算用动态添加View,那肯定要有性能代价。
14 楼 vlinux 2009-09-15  
初涉这块领地,也正在努力探索。
分两个思路来讨论一下

1.改进你的方法。
你的的方法是利用Android自带的Frame-By-Frame例子的,缺点就是Android目前依靠配置无法从一张动画序列图中截取部分来显示动画。所以这样就造成了必须准备一张张单独的图片,这对一个游戏拥有大量动作且Android的res目录不支持子目录的情况下来看是不大雅观的。

我用AnimationDrawable稍做了一些改进。


2.直接用SurfaceView开线程画。用线程+SurfaceView无疑是最好的办法了。不过我目前卡死在这里,因为每帧画出的图案就永久生效了。不像之前的Animation是可以重叠,当动画消失之后还原背景。非常令我苦闷,不知道你有没有在SurfaceView做动画的好办法。


13 楼 raymondlueng 2009-09-14  
vlinux 写道
这个方法可行性不高,因为同一时间只有一个动画存在,如果是要多个动画出现,就挂了

使用过多个动画效果同时显示,没性能问题,请问您有没更好的方法,分享一下啦!
12 楼 vlinux 2009-09-14  
这个方法可行性不高,因为同一时间只有一个动画存在,如果是要多个动画出现,就挂了
11 楼 fkpwolf 2009-09-06  
爆炸这个好像是游戏里面挺难解决的一个问题,如果要真是模拟爆炸的话,大多是预先设好了所有爆炸的画面,当然这个画面是一样的

相关推荐

Global site tag (gtag.js) - Google Analytics