这里讲的是关于2D游戏的角色和背景以及物体之间的遮挡关系,用半透明角色处理的讨论和实现方式。这里主要是讨论关于页游《火影忍者》里对于角色和背景物体之间的遮挡处理方式。同时也实现了和他一样的效果(可能)。具体是没分析火影的代码,只是猜测了它的原理然后进行实现的。其他的几种实现方式则简单的讨论,一笔带过(如果有人有兴趣,可以留言,我再单独写篇Blog和相关例子来) 
 实现语言:ActionScript3.0(传统的显示处理,Stage3D可以做到有些不一样,所以不在讨论范围) 
 心急的读者可以直接从第三点开始看我们今天的主题实现内容。
一、需要实现遮挡关系的原因
个人推测和分析,不妥之处请之处讨论。 
 1. 因为AS3传统显示2D图像的时候,没有zbuff缓冲这个概念,所以显示图像的层次关系,是按照addChild的顺序来的. 
 2. 为了实现最大的渲染效率,一般美术会把游戏场景渲染成大的一张图片,然后再切割成小块进行加载显示。整个场景的所有元件,包括背景、树、建筑、河流等等,都是渲染出一张图。 
 那么问题来了,建筑和背景树等物体都渲染地图上,那人物走过来的时候,这个时候的遮挡关系怎么处理呢?所以就会衍生出各种处理这种遮挡关系的技术了。
二、角色物体遮挡的几种做法
首先简单讨论几种实现方式。 
 1. 和角色同层,根据深度重新设置addChild 
 这是比较消耗性能的做法,也是早期很多游戏的做法,表现效果也很好。同时也是一些3D游戏场景的做法(3D有zbuff缓冲)。出一个地图编辑器,然后把导入背景,把各种元件(树、建筑等等)拖到场景去,最后导出。在游戏中人物就和元件参与深度排序,处理遮挡关系。 
 现在一般是采用后面的两种做法了,在一些特别需要表现力的时候,才会单独做成元件,不然都是合在背景里了。 
  
 2. 地图编辑器打格子表明走到的角色半透 
 这个是页游红极一时的做法,大部分rpg和arpg都是这么做的。比如《凡人修真2》和雄霸页游天下的《传奇霸业》,下面传奇霸业的表现效果(刚截的图)。 
  
 具体的实现方式大概走格子走到这个建筑的时候,会检测格子的属性,如果带有半透效果的参数,则设置角色的alpha值。 
 3. 背建筑遮挡的部分才半透,效果高大尚。 
 读者:这个是3D做法吧! 
 当然不是了,通过2D图像混合一样可以做到。(原理估计也是3D那一套。就是提供的遮罩图来擦出下面的的图片)。这个算是比较新颖的做法,目前我就看腾讯的《火影忍者》,其他的就暂时没去查看了(我自己做的游戏是采用这个最新的做法,潮流嘛)。 
 开始还担心性能会比较大损耗,做了简单测试,发现没什么影响。先看火影里的表现效果吧 
  
 仔细看红框里的那个角色,可以发现角色被那个柱子挡住的一半是半透明效果,没挡住的就是原来的颜色。简直酷毙了! 
 立马把火影的缓存搞下来,发现它是加了背景遮罩图,然后类似3D混合图形的做法实现的。后来会详细地讲。(啰嗦了这么久,终于开始正题了)
三、火影的角色遮挡半透实现分析
仔细分析了火影的新手村场景,从缓存了除了提取出背景之外,还有另外一些黑色的古怪图片。背景还是跟其他游戏的做法,古怪的是那个黑色怪图。发现是背景里的一些建筑物的黑色图。下面是缩略图。 
  
 刚开始还以为是逐像素匹配,自己手动实现的(可以做到的),但是效率会残不忍堵。另外想到的就是3D里 
 常用的图像混合处理了。查下AS3的Bitmap的API,还真查找到了。这里只列出会用到的API。
DisplayObject.blendMode属性
BlendMode 类中的一个值,用于指定要使用的混合模式。用到了BlendMode类的两个属性
LAYER : String = "layer"
[静态] 强制为该显示对象创建一个透明度组。ERASE : String = "erase"
[静态] 根据显示对象的 Alpha 值擦除背景。其他的API也有趣,有兴趣的同学可以试试。
四、角色遮挡半透的实现的例子资源
整理了一下相关使用到的资源。实际上问过美术,美术说出这个遮罩图非常容易。我们也实际出了相关的资源。 
 1. 背景图 
 把火影的背景图给拼起来,合成一张1274 * 768的大背景图方便测试 
 2. 透明背景遮罩图 
 同样把透明遮罩剪切出和背景对应部分截取出来,然后对好位置。这个图的透明度决定了角色的显示效果 
 3. 角色资源图 
 
五、简单的代码实现原理过程
- 背景层独立出来,不参与图像混合
- 角色和透明遮罩单独一个容器层,但是这两种都在同一个容器A中
- 容器A的blendMode属性设置为:
//强制为该显示对象创建一个透明度组
blendMode = BlendMode.LAYER;- 角色容器不用设置blendMode,因为在容器A中设置就可以了
- 透明遮罩这个Bitmap需要设置
blendMode = BlendMode.ERASE;确保透明遮罩Bitmap在角色容器的上层就可以了。下面是具体的代码实现过程。
六、详细的代码
看代码实现起来非常简单,代码也非常简洁
package
{
    import flash.display.Bitmap;
    import flash.display.BlendMode;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    /**
     * 地图透明角色测试例子
     * @author sodaChen
     * Date:2017-2-16
     */
    [SWF(width="1274",height="768")]
    public class AlphaMapTest extends Sprite
    {
        /** 背景 **/
        [Embed(source = "res/alpha/bg.jpg")]
        private var bgClass:Class;
        /** 透明遮罩背景 **/
        [Embed(source = "res/alpha/alphaBg.png")]
        private var alphaBgClass:Class;
        /** 角色 **/
        [Embed(source = "res/alpha/role.png")]
        private var roleClass:Class;
        /** 角色容器 ,用来存放角色和透明图像的**/
        private var roleContainer:Sprite;
        /** 角色层,只放角色 **/
        private var roleLayer:Sprite;
        public function AlphaMapTest()
        {
            super();
            addEventListener(Event.ADDED_TO_STAGE,onStage);
        }
        private function onStage(evt:Event):void
        {
            //添加背景
            addChild(new bgClass());
            //添加角色容器
            roleContainer = new Sprite();
            //强制为该显示对象创建一个透明度组
            roleContainer.blendMode = BlendMode.LAYER;
            addChild(roleContainer);
            //创建角色层,其实角色可以不用单独容器,但是必须保证alphaBg在所有角色的最上面
            roleLayer = new Sprite();
            roleContainer.addChild(roleLayer);
            //创建角色并添加到角色容器中
            createRole(300,120);
            createRole(230,550);
            //不会被遮挡的角色
            createRole(400,200);
            //根据显示对象的 Alpha 值擦除背景.这个透明图像必须在最顶层,确保下面的角色会被擦出
            var alphaBg:Bitmap = new alphaBgClass();
            alphaBg.blendMode = BlendMode.ERASE;
            roleContainer.addChild(alphaBg);
        }
        //创建角色
        private function createRole(roleX:int,roleY:int):void
        {
            var role:Sprite = new Sprite();
            var roleBitmap:Bitmap = new roleClass();
            role.x = roleX;
            role.y = roleY;
            role.addChild(roleBitmap);
            roleLayer.addChild(role);
            role.addEventListener(MouseEvent.MOUSE_DOWN,onMouse);
            role.addEventListener(MouseEvent.MOUSE_UP,onMouse);
        }
        private function onMouse(evt:MouseEvent):void
        {
            var role:Sprite = evt.currentTarget as Sprite;
            if(evt.type == MouseEvent.MOUSE_DOWN)
                role.startDrag();
            else
                role.stopDrag();
        }
    }
}最终实现的效果图: 
  
 例子代码下载: 
 2DAS3游戏地图角色遮罩
 
                   
                   
                   
                   
                            
 
                             本文探讨了2D游戏中的角色与背景遮挡问题,并详细分析了一种利用半透明效果处理遮挡的方法,该方法已在页游《火影忍者》中成功应用。
本文探讨了2D游戏中的角色与背景遮挡问题,并详细分析了一种利用半透明效果处理遮挡的方法,该方法已在页游《火影忍者》中成功应用。
           
       
           
                 
                 
                 
                 
                 
                
               
                 
                 
                 
                 
                
               
                 
                 扫一扫
扫一扫
                     
              
             
                   1241
					1241
					
 被折叠的  条评论
		 为什么被折叠?
被折叠的  条评论
		 为什么被折叠?
		 
		  到【灌水乐园】发言
到【灌水乐园】发言                                
		 
		 
    
   
    
   
             
            


 
            