2D游戏平滑的迷雾战争效果
来源:互联网 发布:seo sem 区别 编辑:程序博客网 时间:2024/04/27 15:29
最近刚好有做2D游戏的点光源效果,然后就扩展一下,研究了一下战争迷雾的效果。主要是想实现类似魔兽争霸那种人物走动,然后黑色的战争迷雾随着人物的移动渐渐打开的效果。使用具有渐变透明图片作为光源来使得战争迷雾呈现出平滑的效果。本文后面介绍了两个简单的实现方法,效果有细微的差别,有兴趣的同学可以分别研究。最后也有完整展示代码和提供例子下载。
一、常见的战争迷雾效果
早期的红警的战争迷雾大家应该也比较熟悉,不过看起来没那么平滑,应该是采用图块拼出来。可以明显看得出一些方方块块。
可见早期魔兽争霸2也是没那么平滑的。
后面出的一些有些的战争迷雾就会有比较平滑的过渡效果了。比如英雄联盟,魔兽3(这两个是3D的)。但是也有2D也做得比较平滑(看图的最后一个截图)
二、实现的简单原理讲解
由于是做2D游戏,所以思路基本上是2D,但是同时也有3D思想,例如图层混合方式处理等。主要原理就是根据图片的alpha值来进行反向擦除(alpha为1时完全擦除,alpha越小则越不透明,实现渐变过程效果)。最后用了两种比较简单的方法来实现了这种效果,两者有微弱的差别。这里采用的是AS3实现的,源码也提供了几种渐变图片,可以作为点光源来擦亮迷雾,可以替换上去看各种效果的。
- 遮罩擦除做法
最先想到的原理,是基于之前实现类似点光源效果的做法。通过一层带有alpha值遮罩图来擦掉对应的战争迷雾,就是移动版增大的点光源效果。首先人物背景,然后一层战争迷雾在最顶层,人物带了个点光源,然后人物移动的时候,不会把那个点光源层进行绘制,那么光源层就会原来越大。那个迷雾自然就会越来越大了。
下图:刚开始是一个圆圈,然后随着人物移动,圆圈会扩大。
得到这个图之后,就是对黑色战争迷雾层根据alpha进行擦了。
//一个专门做点光源的顶层容器var topContainer:Sprite = new Sprite();//强制为该显示对象创建一个透明度组topContainer.blendMode = BlendMode.LAYER;//根据显示对象的 Alpha 值擦除迷雾openFogBitmap.blendMode = BlendMode.ERASE;
合成遮罩图来去除迷雾的代码是,最后一个参数true是合并alpha:
bitmapData.copyPixels(bitmapData,pointRect,new Point(role.x,role.y),null,null,true);
这样跟随人物移动不断地把遮罩扩大。除了最开始的合成遮罩图,后面的处理跟之前讲的新手引导遮罩和点光源实现机制一样,后面会给出相关的代码。不过这种实现是有点不好的是合并alpha,这样会导致范围突然变亮(因为alpha相加大于1,就全部擦了,大部分亮了,也就是会有个逐渐变亮的效果,使得战争迷雾开启效果没那么真实)。最终表现效果如下图:
2. 直接擦出战争迷雾方法(橡皮擦功能)
实际测试了下,对遮罩擦除做法这个效果不太满意。于是再研究了一下,想到了橡皮效果,直接用点光源图片把战争迷雾一点点擦掉又如何呢?赶紧仔细看了相关api,还真有类似的实现效果。主要还是bitmapData的draw方法,重点是这个方法的第四个参数,
source:IBitmapDrawable — 要绘制到 BitmapData 对象的显示对象或 BitmapData 对象 matrix:Matrix (default = null) — 一个 Matrix 对象,用于缩放、旋转位图或转换位图的坐标。。 colorTransform:flash.geom:ColorTransform (default = null) — 一个 ColorTransform 对象blendMode:String (default = null) — 指定要应用于所生成位图的混合模式。
所以我们每次在战争迷雾这个层次这里每次根据玩家移动,调用draw方法把角色带的点光源图片给draw进入战争迷雾的BitmapData中,然后设置为根据alpha的参数来擦出,露出最终的背景就行了。
BlendMode.ERASE //提供混合模式可视效果的常量值的类。//设置需要draw的坐标位置var matrix:Matrix = new Matrix(1,0,0,1,role.x,role.y);fogBitmapData.draw(pointBitmap,matrix,null,BlendMode.ERASE);
最终效果图:
代码实现
代码已经有比较详细的注释了,这里不做解释,具体自己看代码了。可以运行两个例子来比较。
代码例子源码下载:2D游戏战争迷雾的实现例子(AS3版本)
1. 遮罩擦除做法代码,FogLightTest.as
/** * 战争迷雾遮罩灯效果测试例子 * @author sodaChen * Date:2017-2-16 */ [SWF(width="1274",height="768")] public class FogLightTest extends Sprite { /** 背景 **/ [Embed(source = "res/alpha/bg.jpg")] private var bgClass:Class; //点光源图片 [Embed(source = "res/alpha/light4.png")] private var shadowClass:Class; /** 打开的迷雾图像源,用来擦出迷雾 **/ private var openFogBitmap:Bitmap; /** 原始点光源图片,用来确定一个角色视野范围的 **/ private var pointBitmap:Bitmap; /** 存放已经开启的迷雾图片 **/ private var pointBitmapDatas:Vector.<uint>; /** 点光源的大小范围 **/ private var pointRect:Rectangle; private var role:Sprite; /** 光源的移动 **/ private var speed:int = 10; public function FogLightTest() { addEventListener(Event.ADDED_TO_STAGE,onStage); } private function onStage(evt:Event):void { //添加背景 addChild(new bgClass()); /////////////////////////////文本的正式测试代码啦///////////////////////////// //新建一个专门做点光源的顶层容器 var topContainer:Sprite = new Sprite(); topContainer.mouseEnabled = false; //强制为该显示对象创建一个透明度组 topContainer.blendMode = BlendMode.LAYER; addChild(topContainer); //创建黑色的迷雾 var mask:Shape = new Shape(); mask.graphics.beginFill(0x000000); mask.graphics.drawRect(0,0,1274,768); mask.graphics.endFill(); topContainer.addChild(mask); //制作点光源,用来擦亮迷雾,具体的擦出在下面的鼠标事件那里 pointBitmap = new shadowClass(); //创建擦亮迷雾后的视野图片 pointRect = new Rectangle(0,0,pointBitmap.bitmapData.width,pointBitmap.bitmapData.height); openFogBitmap = new Bitmap(new BitmapData(1274,768,true,0)); //复制最开始的位置 openFogBitmap.bitmapData.copyPixels(pointBitmap.bitmapData,pointRect,new Point(450,300)); //根据显示对象的 Alpha 值擦除迷雾 openFogBitmap.blendMode = BlendMode.ERASE; topContainer.addChild(openFogBitmap); /** 移动中的主角 **/ role = new Sprite(); role.x = 450; role.y = 300; topContainer.addChild(role); stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown); } private function onKeyDown(evt:KeyboardEvent):void { //4个方向键的控制 if(evt.keyCode == Keyboard.DOWN) role.y += speed; else if(evt.keyCode == Keyboard.UP) role.y -= speed; else if(evt.keyCode == Keyboard.LEFT) role.x -= speed; else if(evt.keyCode == Keyboard.RIGHT) role.x += speed; //暂时不考虑性能,不停地写新的图像数据 openFogBitmap.bitmapData.copyPixels(pointBitmap.bitmapData,pointRect,new Point(role.x,role.y),null,null,true); }
- 直接擦出战争迷雾方法(橡皮擦功能)代码,EraserFogTest.as
/** * 迷雾战争擦除效果 * @author sodaChen * Date:2017-2-16 */ [SWF(width="1274",height="768")] public class EraserFogTest extends Sprite { /** 背景 **/ [Embed(source = "res/alpha/bg.jpg")] private var bgClass:Class; //点光源图片 [Embed(source = "res/alpha/light4.png")] private var shadowClass:Class; /** 打开的迷雾图像源,用来擦出迷雾 **/ private var openFogBitmap:Bitmap; /** 光源,擦亮迷雾的范围 **/ private var pointBitmap:Bitmap; private var role:Sprite; /** 光源的移动 **/ private var speed:int = 10; /** 迷雾的图像数据源 **/ private var fogBitmapData:BitmapData; public function EraserFogTest() { addEventListener(Event.ADDED_TO_STAGE,onStage); } private function onStage(evt:Event):void { //添加背景 addChild(new bgClass()); /////////////////////////////文本的正式测试代码啦///////////////////////////// //新建一个专门做点光源的顶层容器 var topContainer:Sprite = new Sprite(); topContainer.mouseEnabled = false; //强制为该显示对象创建一个透明度组 topContainer.blendMode = BlendMode.LAYER; addChild(topContainer); //创建黑色的迷雾 var mask:Shape = new Shape(); //颜色可以选自己喜欢的 mask.graphics.beginFill(0x000000); mask.graphics.drawRect(0,0,1274,768); mask.graphics.endFill(); fogBitmapData = new BitmapData(1274,768); fogBitmapData.draw(mask); topContainer.addChild(new Bitmap(fogBitmapData)); //制作点光源,用来擦亮迷雾,具体的擦出在下面的鼠标事件那里 pointBitmap = new shadowClass(); /** 移动中的主角 **/ role = new Sprite(); role.x = 450; role.y = 300; topContainer.addChild(role); //默认位置 openFog(); stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown); } private function onKeyDown(evt:KeyboardEvent):void { //4个方向键的控制 if(evt.keyCode == Keyboard.DOWN) role.y += speed; else if(evt.keyCode == Keyboard.UP) role.y -= speed; else if(evt.keyCode == Keyboard.LEFT) role.x -= speed; else if(evt.keyCode == Keyboard.RIGHT) role.x += speed; openFog(); } private function openFog():void { //设置需要draw的坐标位置 var matrix:Matrix = new Matrix(1,0,0,1,role.x,role.y); //正常的daw方法,主要参数是后面的BlendMode.ERASE。根据pointBitmap的透明度来擦除fogBitmapData fogBitmapData.draw(pointBitmap,matrix,null,BlendMode.ERASE); }
- 2D游戏平滑的迷雾战争效果
- 2D游戏的战争迷雾实现方式
- 《C++游戏开发》笔记十四 平滑过渡的战争迷雾(二) 实现:真正的迷雾来了
- 《C++游戏开发》笔记十三 平滑过渡的战争迷雾(一) 原理:Warcraft3地形拼接算法
- cocos2dx 游戏当中的战争迷雾
- 战争迷雾效果
- Unity3D战争迷雾效果
- 游戏中的战争迷雾
- 游戏中的战争迷雾
- 游戏中的战争迷雾
- 平滑过渡的战争迷雾(二) 实现:真正的迷雾来了
- cocos2dx 实现战争迷雾效果
- 战争迷雾的实现
- 战争迷雾效果实现方案的flash演示及源码
- 战争迷雾2
- 游戏地图拼接与战争迷雾的实现
- 【VC++游戏开发#二】2D篇 —— 平滑的幻灯片放映效果
- 【笨木头Cocos2dx 041】战争迷雾效果 第4章_真正的迷雾来了!
- androidStudio性能优化
- 自定义ViewGroup可折叠控件,类似CoordinatorLayout的效果
- 【JAVA之多线程】3.线程同步
- 异常分类
- 如何区分[]与{}
- 2D游戏平滑的迷雾战争效果
- [转]PAT甲级练习1081. Rational Sum (20)
- HTML5的优点
- repeat和tile扩充数组
- 一个爬取沪深两市融资融券标的融资融券交易数据的小爬虫
- [Spark]Spark Streaming 指南二 初始化StreamingContext
- App Launch Time Measurement
- UVa 10815 Andy's First Dictionary 【set】【字典序】
- 给mysql授权多个数据库权限