近期刚好有做2D游戏的点光源效果,然后就扩展一下。研究了一下战争迷雾的效果。主要是想实现相似魔兽争霸那种人物走动,然后黑色的战争迷雾随着人物的移动渐渐打开的效果。使用具有渐变透明图片作为光源来使得战争迷雾呈现出平滑的效果。

本文后面介绍了两个简单的实现方法。效果有细微的区别。有兴趣的同学能够分别研究。最后也有完整展示代码和提供样例下载。

一、常见的战争迷雾效果

早期的红警的战争迷雾大家应该也比較熟悉,只是看起来没那么平滑,应该是採用图块拼出来。能够明显看得出一些方方块块。



可见早期魔兽争霸2也是没那么平滑的。

后面出的一些有些的战争迷雾就会有比較平滑的过渡效果了。比方英雄联盟,魔兽3(这两个是3D的)。可是也有2D也做得比較平滑(看图的最后一个截图)

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VqdW4xMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

二、实现的简单原理解说

由于是做2D游戏,所以思路基本上是2D,可是同一时候也有3D思想,比如图层混合方式处理等。主要原理就是依据图片的alpha值来进行反向擦除(alpha为1时全然擦除,alpha越小则越不透明。实现渐变过程效果)。最后用了两种比較简单的方法来实现了这样的效果。两者有微弱的区别。这里採用的是AS3实现的,源代码也提供了几种渐变图片,能够作为点光源来擦亮迷雾。能够替换上去看各种效果的。

  1. 遮罩擦除做法

    最先想到的原理。是基于之前实现相似点光源效果的做法。通过一层带有alpha值遮罩图来擦掉相应的战争迷雾,就是移动版增大的点光源效果。首先人物背景。然后一层战争迷雾在最顶层,人物带了个点光源。然后人物移动的时候,不会把那个点光源层进行绘制,那么光源层就会原来越大。那个迷雾自然就会越来越大了。

    下图:刚開始是一个圆圈,然后随着人物移动,圆圈会扩大。

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VqdW4xMA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="这里写图片描写叙述" title="">

    得到这个图之后。就是对黑色战争迷雾层依据alpha进行擦了。

  1. //一个专门做点光源的顶层容器
  2. var topContainer:Sprite = new Sprite();
  3. //强制为该显示对象创建一个透明度组
  4. topContainer.blendMode = BlendMode.LAYER;
  5. //依据显示对象的 Alpha 值擦除迷雾
  6. openFogBitmap.blendMode = BlendMode.ERASE;

合成遮罩图来去除迷雾的代码是,最后一个參数true是合并alpha:

  1. bitmapData.copyPixels(bitmapData,pointRect,new Point(role.x,role.y),null,null,true);

这样尾随人物移动不断地把遮罩扩大。除了最開始的合成遮罩图,后面的处理跟之前讲的新手引导遮罩和点光源实现机制一样。后面会给出相关的代码。

只是这样的实现是有点不好的是合并alpha,这样会导致范围突然变亮(由于alpha相加大于1,就所有擦了,大部分亮了,也就是会有个逐渐变亮的效果,使得战争迷雾开启效果没那么真实)。

终于表现效果例如以下图:



2. 直接擦出战争迷雾方法(橡皮擦功能)

实际測试了下,对遮罩擦除做法这个效果不太惬意。于是再研究了一下,想到了橡皮效果,直接用点光源图片把战争迷雾一点点擦掉又怎样呢?赶紧细致看了相关api,还真有相似的实现效果。

主要还是bitmapData的draw方法。重点是这种方法的第四个參数,

  1. source:IBitmapDrawable 要绘制到 BitmapData 对象的显示对象或 BitmapData 对象
  2. matrix:Matrix (default = null) 一个 Matrix 对象。用于缩放、旋转位图或转换位图的坐标。

  3. colorTransform:flash.geom:ColorTransform (default = null) 一个 ColorTransform 对象
  4. blendMode:String (default = null) 指定要应用于所生成位图的混合模式。

所以我们每次在战争迷雾这个层次这里每次依据玩家移动,调用draw方法把角色带的点光源图片给draw进入战争迷雾的BitmapData中,然后设置为依据alpha的參数来擦出,露出终于的背景即可了。

  1. BlendMode.ERASE //提供混合模式可视效果的常量值的类。
  2. //设置须要draw的坐标位置
  3. var matrix:Matrix = new Matrix(1,0,0,1,role.x,role.y);
  4. fogBitmapData.draw(pointBitmap,matrix,null,BlendMode.ERASE);

终于效果图:

代码实现

代码已经有比較详细的凝视了,这里不做解释。详细自己看代码了。能够执行两个样例来比較。

代码样例源代码下载:2D游戏战争迷雾的实现样例(AS3版本号)

1. 遮罩擦除做法代码。FogLightTest.as

  1. /**
  2. * 战争迷雾遮罩灯效果測试样例
  3. * @author sodaChen
  4. * Date:2017-2-16
  5. */
  6. [SWF(width="1274",height="768")]
  7. public class FogLightTest extends Sprite
  8. {
  9. /** 背景 **/
  10. [Embed(source = "res/alpha/bg.jpg")]
  11. private var bgClass:Class;
  12. //点光源图片
  13. [Embed(source = "res/alpha/light4.png")]
  14. private var shadowClass:Class;
  15. /** 打开的迷雾图像源,用来擦出迷雾 **/
  16. private var openFogBitmap:Bitmap;
  17. /** 原始点光源图片。用来确定一个角色视野范围的 **/
  18. private var pointBitmap:Bitmap;
  19. /** 存放已经开启的迷雾图片 **/
  20. private var pointBitmapDatas:Vector.<uint>;
  21. /** 点光源的大小范围 **/
  22. private var pointRect:Rectangle;
  23. private var role:Sprite;
  24. /** 光源的移动 **/
  25. private var speed:int = 10;
  26. public function FogLightTest()
  27. {
  28. addEventListener(Event.ADDED_TO_STAGE,onStage);
  29. }
  30. private function onStage(evt:Event):void
  31. {
  32. //加入背景
  33. addChild(new bgClass());
  34. /////////////////////////////文本的正式測试代码啦/////////////////////////////
  35. //新建一个专门做点光源的顶层容器
  36. var topContainer:Sprite = new Sprite();
  37. topContainer.mouseEnabled = false;
  38. //强制为该显示对象创建一个透明度组
  39. topContainer.blendMode = BlendMode.LAYER;
  40. addChild(topContainer);
  41. //创建黑色的迷雾
  42. var mask:Shape = new Shape();
  43. mask.graphics.beginFill(0x000000);
  44. mask.graphics.drawRect(0,0,1274,768);
  45. mask.graphics.endFill();
  46. topContainer.addChild(mask);
  47. //制作点光源,用来擦亮迷雾,详细的擦出在以下的鼠标事件那里
  48. pointBitmap = new shadowClass();
  49. //创建擦亮迷雾后的视野图片
  50. pointRect = new Rectangle(0,0,pointBitmap.bitmapData.width,pointBitmap.bitmapData.height);
  51. openFogBitmap = new Bitmap(new BitmapData(1274,768,true,0));
  52. //复制最開始的位置
  53. openFogBitmap.bitmapData.copyPixels(pointBitmap.bitmapData,pointRect,new Point(450,300));
  54. //依据显示对象的 Alpha 值擦除迷雾
  55. openFogBitmap.blendMode = BlendMode.ERASE;
  56. topContainer.addChild(openFogBitmap);
  57. /** 移动中的主角 **/
  58. role = new Sprite();
  59. role.x = 450; role.y = 300;
  60. topContainer.addChild(role);
  61. stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown);
  62. }
  63. private function onKeyDown(evt:KeyboardEvent):void
  64. {
  65. //4个方向键的控制
  66. if(evt.keyCode == Keyboard.DOWN) role.y += speed;
  67. else if(evt.keyCode == Keyboard.UP) role.y -= speed;
  68. else if(evt.keyCode == Keyboard.LEFT) role.x -= speed;
  69. else if(evt.keyCode == Keyboard.RIGHT) role.x += speed;
  70. //临时不考虑性能,不停地写新的图像数据
  71. openFogBitmap.bitmapData.copyPixels(pointBitmap.bitmapData,pointRect,new Point(role.x,role.y),null,null,true);
  72. }
  1. 直接擦出战争迷雾方法(橡皮擦功能)代码,EraserFogTest.as
  1. /**
  2. * 迷雾战争擦除效果
  3. * @author sodaChen
  4. * Date:2017-2-16
  5. */
  6. [SWF(width="1274",height="768")]
  7. public class EraserFogTest extends Sprite
  8. {
  9. /** 背景 **/
  10. [Embed(source = "res/alpha/bg.jpg")]
  11. private var bgClass:Class;
  12. //点光源图片
  13. [Embed(source = "res/alpha/light4.png")]
  14. private var shadowClass:Class;
  15. /** 打开的迷雾图像源。用来擦出迷雾 **/
  16. private var openFogBitmap:Bitmap;
  17. /** 光源,擦亮迷雾的范围 **/
  18. private var pointBitmap:Bitmap;
  19. private var role:Sprite;
  20. /** 光源的移动 **/
  21. private var speed:int = 10;
  22. /** 迷雾的图像数据源 **/
  23. private var fogBitmapData:BitmapData;
  24. public function EraserFogTest()
  25. {
  26. addEventListener(Event.ADDED_TO_STAGE,onStage);
  27. }
  28. private function onStage(evt:Event):void
  29. {
  30. //加入背景
  31. addChild(new bgClass());
  32. /////////////////////////////文本的正式測试代码啦/////////////////////////////
  33. //新建一个专门做点光源的顶层容器
  34. var topContainer:Sprite = new Sprite();
  35. topContainer.mouseEnabled = false;
  36. //强制为该显示对象创建一个透明度组
  37. topContainer.blendMode = BlendMode.LAYER;
  38. addChild(topContainer);
  39. //创建黑色的迷雾
  40. var mask:Shape = new Shape();
  41. //颜色能够选自己喜欢的
  42. mask.graphics.beginFill(0x000000);
  43. mask.graphics.drawRect(0,0,1274,768);
  44. mask.graphics.endFill();
  45. fogBitmapData = new BitmapData(1274,768);
  46. fogBitmapData.draw(mask);
  47. topContainer.addChild(new Bitmap(fogBitmapData));
  48. //制作点光源。用来擦亮迷雾,详细的擦出在以下的鼠标事件那里
  49. pointBitmap = new shadowClass();
  50. /** 移动中的主角 **/
  51. role = new Sprite();
  52. role.x = 450; role.y = 300;
  53. topContainer.addChild(role);
  54. //默认位置
  55. openFog();
  56. stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown);
  57. }
  58. private function onKeyDown(evt:KeyboardEvent):void
  59. {
  60. //4个方向键的控制
  61. if(evt.keyCode == Keyboard.DOWN) role.y += speed;
  62. else if(evt.keyCode == Keyboard.UP) role.y -= speed;
  63. else if(evt.keyCode == Keyboard.LEFT) role.x -= speed;
  64. else if(evt.keyCode == Keyboard.RIGHT) role.x += speed;
  65. openFog();
  66. }
  67. private function openFog():void
  68. {
  69. //设置须要draw的坐标位置
  70. var matrix:Matrix = new Matrix(1,0,0,1,role.x,role.y);
  71. //正常的daw方法,主要參数是后面的BlendMode.ERASE。
  72. 依据pointBitmap的透明度来擦除fogBitmapData
  73. fogBitmapData.draw(pointBitmap,matrix,null,BlendMode.ERASE);
  74. }

2D游戏平滑的迷雾战争效果的更多相关文章

  1. 2d游戏和 3d游戏的区别

    2D游戏和3D游戏的主要区别 一.总结 一句话总结:2D中的单位就是贴图,3D中的单位还有高 1. 3D 和 2D 游戏的区别主要体现在呈现画面和文件体积上: 2. 借助 3D 引擎可以提升 2D 游 ...

  2. 《C++游戏开发》笔记十三 平滑过渡的战争迷雾(一) 原理:Warcraft3地形拼接算法

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9611887 作者:七十一雾央 新浪微博:http:/ ...

  3. 平滑过渡的战争迷雾(一) 原理:Warcraft3地形拼接算法

    本系列文章由七十一雾央编写,转载请注明出处.  http://blog.csdn.net/u011371356/article/details/9611887 作者:七十一雾央 新浪微博:http:/ ...

  4. Unity 2D游戏开发教程之2D游戏的运行效果

    Unity 2D游戏开发教程之2D游戏的运行效果 2D游戏的运行效果 本章前前后后使用了很多节的篇幅,到底实现了怎样的一个游戏运行效果呢?或者说,游戏中的精灵会不会如我们所想的那样运行呢?关于这些疑问 ...

  5. 【Unity3D】利用Shader以及更改Mesh实现2D游戏的动态阴影效果

    最近看到一个非常有趣的益智小游戏,是一个盗贼进入房子偷东西的, 其实这种游戏市面上已经很多了,吸引我的是那个类似手电筒的效果, 主角走到哪里,光就到哪里,被挡住的地方还有阴影.有点类似策略游戏里的战争 ...

  6. WEBGL 2D游戏引擎研发系列 第一章 <新的开始>

    WEBGL 2D游戏引擎研发系列 第一章 <新的开始> ~\(≥▽≤)/~HTML5游戏开发者社区(群号:326492427) 转载请注明出处:http://html5gamedev.or ...

  7. UWP简单示例(三):快速开发2D游戏引擎

    准备 IDE:VisualStudio 2015 Language:VB.NET/C# 图形API:Win2D MSDN教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面 ...

  8. 浅谈2D游戏设计模式3 - 冒险地图之美(1)

    冒险岛之所以能长久的存在,很大一部分原因是因为它的美工设计的非常的精细,以及独特,那么独特以及美究竟体现在哪些方面呢? 今天我就带大家来分析几幅地图吧. 好吧,我们就拿上面这幅美景来分析吧. 1.阳光 ...

  9. IOS 2D游戏开发框架 SpriteKit

    最近发现Xcode自带的2D游戏开发框架SpriteKit可以直接引入到APP中进行混合开发,这就是说可以开发出既带业务应用又带游戏的苹果APP,咋怎么觉得这是一个自己的小发现....呵呵....., ...

随机推荐

  1. php使用memcached详解

    一.memcached 简介 在很多场合,我们都会听到 memcached 这个名字,但很多同学只是听过,并没有用过或实际了解过,只知道它是一个很不错的东东.这里简单介绍一下,memcached 是高 ...

  2. ubantu对pycharm创建快捷方式

    如果你刚开始没有建立快捷方式自己建立一个快捷方式,方法如下 终端输入:sudo gedit /usr/share/applications/Pycharm.desktop粘贴模板: [Desktop ...

  3. codeforces 869C The Intriguing Obsession【组合数学+dp+第二类斯特林公式】

    C. The Intriguing Obsession time limit per test 1 second memory limit per test 256 megabytes input s ...

  4. Codeforces 702C Cellular Network(二分)

    题目链接:http://codeforces.com/problemset/problem/702/C 题意: 在数轴上有N个城市和M个信号塔,给你这N个城市以及M个塔在数轴上的位置,求M个塔可以覆盖 ...

  5. 洛谷P2419 [USACO08JAN]牛大赛Cow Contest

    对于一个能够确定名次的点,可以注意到,对于该点,入度和出度的数量加起来等于N-1(这样还是不够准确的确切的说是,能够到达这个点的数量和这个点能够到达的数量的和 floyd不仅可以求两个点之间的最短路径 ...

  6. Codeforces 863F - Almost Permutation

    863F - Almost Permutation 题意 给出每个位置可以放的数字的范围,定义 \(cost = \sum_{i=1}^{n}(cnt(i))^2\) ,其中 \(cnt(i)\) 为 ...

  7. [Atcoder Regular Contest 060] Tutorial

    Link: ARC060 传送门 C: 由于难以维护和更新平均数的值: $Average->Sum/Num$ 这样我们只要用$dp[i][j][sum]$维护前$i$个数中取$j$个,且和为$s ...

  8. 【bitset】hdu4920 Matrix multiplication

    先把两个矩阵全都mod3. S[i][j][k]表示第i(0/1)个矩阵的行/列的第k位是不是j(1/2). 然后如果某两个矩乘对应位上为1.1,乘出来是1: 1.2:2: 2.1:2: 2.2:1. ...

  9. 小白的Python之路 day4 不同目录间进行模块调用(绝对路径和相对路径)

    一.常用模块调用函数功能解释 1.__file__ 功能:返回自身文件的相对路径 你从pycharm的执行结果可以看出,在pycharm执行atm.py文件时,是从绝对路径下去执行的,而你从cmd下去 ...

  10. 找出能被5或6整除,但是不能被两者同时整除的数 Exercise05_11

    /** * @author 冰樱梦 * 时间:2018年下半年 * 题目:找出能被5或6整除,但是不能被两者同时整除的数 * */ public class Exercise05_11 { publi ...