角色和背景遮擋半透明效果的實現
這裡講的是關於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 類中的一個值,用於指定要使用的混合模式。
- 1
- 2
用到了BlendMode類的兩個屬性
LAYER : String = "layer"
[靜態] 強制為該顯示物件建立一個透明度組。
- 1
- 2
ERASE : String = "erase"
[靜態] 根據顯示物件的 Alpha 值擦除背景。
- 1
- 2
其他的API也有趣,有興趣的同學可以試試。
四、角色遮擋半透的實現的例子資源
整理了一下相關使用到的資源。實際上問過美術,美術說出這個遮罩圖非常容易。我們也實際出了相關的資源。
1. 背景圖
把火影的背景圖給拼起來,合成一張1274 * 768的大背景圖方便測試
2. 透明背景遮罩圖
同樣把透明遮罩剪切出和背景對應部分截取出來,然後對好位置。這個圖的透明度決定了角色的顯示效果
3. 角色資源圖
五、簡單的程式碼實現原理過程
- 背景層獨立出來,不參與影象混合
- 角色和透明遮罩單獨一個容器層,但是這兩種都在同一個容器A中
- 容器A的blendMode屬性設定為:
//強制為該顯示物件建立一個透明度組
blendMode = BlendMode.LAYER;
- 1
- 2
- 角色容器不用設定blendMode,因為在容器A中設定就可以了
- 透明遮罩這個Bitmap需要設定
blendMode = BlendMode.ERASE;
- 1
確保透明遮罩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();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85