近期刚好有做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进行擦了。

//一个专门做点光源的顶层容器
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);
}
  1. 直接擦出战争迷雾方法(橡皮擦功能)代码,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游戏平滑的迷雾战争效果的更多相关文章

  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. JavaScript 之 定时器 延迟器

    1:setTimeout("function()",time) setTimeout("function()",time) 设置一个超时对象,执行到到该代码时会 ...

  2. Android动画之仿美团加载数据等待时,小人奔跑进度动画对话框(附顺丰快递员奔跑效果)

    Android动画之仿美团加载数据等待时,小人奔跑进度动画对话框(附顺丰快递员奔跑效果) 首句依然是那句老话,你懂得! finddreams :(http://blog.csdn.net/finddr ...

  3. 关于android studio3.0版本后引入资源问题error: failed linking file resources

    最近更新阿里短视频的SDK,导入demo项目时,发现两个问题: 1.频繁报错AAPT2 error: file not found.以为直接Sync重新编译就可以,但是仍旧频繁提醒引入资源错误. 查找 ...

  4. (7)case语句

    (1)case 语法 case "变量" in 模式1) 命令序列1 ;; 模式2) 命令序列2 ;; 模式3) 命令序列3 ;; *) 无匹配后命令序列 esac (2)多系统配 ...

  5. 【转】Celery 分布式任务队列快速入门

    Celery 分布式任务队列快速入门 本节内容 Celery介绍和基本使用 在项目中如何使用celery 启用多个workers Celery 分布式 Celery 定时任务 与django结合 通过 ...

  6. .NET Core CLI

    NET Core 命令 一. 帮助命令 dotnet help 使用情况: dotnet [sdk-options] [command] [command-options] [arguments] 执 ...

  7. The 15th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple - J CONTINUE...?

    CONTINUE...? Time Limit: 1 Second      Memory Limit: 65536 KB      Special Judge DreamGrid has  clas ...

  8. Codeforces 856B - Similar Words

    856B - Similar Words 题意 如果一个字符串可以通过去掉首位字母得到另一个字符串,则称两个字符串相似. 给出一个字符串集合,求一个新的字符串集合,满足新集合里的字符串是原字符串集合中 ...

  9. 洛谷——P2128 赤壁之战

    P2128 赤壁之战 题目描述 赤壁之战,黄盖率舰满载薪草膏油诈降曹军. 受庞统所授的连环计,曹军战船之间由铁索相连,没有两艘战船在同一位置,也没有铁索两两相交或穿过战船.每艘船都有其一定的战略价值. ...

  10. 【母函数】hdu2082 找单词

    普通型母函数详解见这里:http://www.wutianqi.com/?p=596 裸题,存个板子. #include<cstdio> #include<cstring> u ...