日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Silverlight2.5DRPG游戲技巧與特效處里:紙娃娃系統(tǒng)

        紙娃娃系統(tǒng),或許大家聽起來并不陌生。隨著2D/3D圖形技術高速崛起,通過在基礎模型上由客戶隨意挑選、任意更換各種造型(素材),即可打造出真正屬于“自我”獨特風格的網(wǎng)絡虛擬形象,QQ秀便是我們耳熟能詳?shù)拇恚N近真實的如(RPG)游戲及虛擬現(xiàn)實中的換裝/換膚系統(tǒng)同樣亦得益于紙娃娃機制。本文將向大家講解如何最好的實現(xiàn)Silverlight 2.5D網(wǎng)絡游戲中的紙娃娃系統(tǒng),以最大程度控制性能損失為前提,將游戲資源占用最小化,綜合效果及用戶體驗最優(yōu)化。

       素材來源于網(wǎng)絡,取《封神榜3》中的角色系統(tǒng)(紙娃娃系統(tǒng))做示例,每個角色大致都包含3個部件:鎧甲(身體)、武器、騎乘(乘具)等,而其中的騎乘道具又由2個部份組成,比如異人(弓手)的翅膀分為左右兩支;甲士(戰(zhàn)士)的坐騎分為前后兩半;而方士(法師)的飛劍則僅為單獨對象:

        2D/2.5D游戲中角色帶翅膀飛行要考慮左右翼與身體的層次關系,騎馬則需要考慮馬頭/馬尾與身體間的層次問題。而且武器長短,角色朝向,行為姿勢等也都可能影響到各部件的層次關系。因此,一些游戲為了簡化設計,同時又不失華麗,于是乎誕生了比如“踏云”,“御劍”,“乘鶴”,“踩蝶”等諸多天馬行空的駕馭模式,這些乘具的共同點就是均被踩在腳上,自然而然處理起來更簡單明了。當然,如果角色是3D模型的話則無需考慮這么多層疊關系。

#p#

用Silverlight編寫代碼

鑒于以上的參考分析,在Silverlight中構造裝備紙娃娃系統(tǒng)框架便會輕松很多。暫時以帶翅膀的弓手為例子,依葫蘆畫瓢,我們首先新建如下幾個類:

       如圖,EquipBase乃裝備(紙娃娃)系統(tǒng)中的核心,所有的裝備部件類比如鎧甲(身體)Armor/武器Weapon/翅膀Wing/坐騎Ride均繼承自該類:

 
 
 
 
  1. ///   
  2. /// 裝備部件基類  
  3. /// 
  4.  
  5. public abstract class EquipBase : ObjectBase {  
  6.  
  7.    ///   
  8.    /// 加載完畢  
  9.    /// 
  10.  
  11.    public event EventHandler Ready;  
  12.  
  13.    ///   
  14.    /// 獲取或設置部件名  
  15.    /// 
  16.  
  17.    protected string partName { get; set; }  
  18.  
  19.    long index = 0; //異步加載與換裝同步協(xié)調(diào)  
  20.         public override int Code {  
  21.             get { return base.Code; }  
  22.             set {  
  23.                 index++;  
  24.                 if (value == -1) { base.Code = value; return; }  
  25.                 string key = string.Format("{0}{1}", partName, value);  
  26.                 if (Res.ContainsKey(key)) {  
  27.                     base.Code = value;  
  28.                     loadConfig(key);  
  29.                 } else {  
  30.                     Downloader downloader = new Downloader();  
  31.                     downloader.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);  
  32.                     downloader.OpenReadAsync(string.Format("{0}{1}.xap", partName, value), string.Format("{0},{1}", index, value), 2000);  
  33.                 }  
  34.             }  
  35.         }  
  36.  
  37.         void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) {  
  38.             Downloader downloader = sender as Downloader;  
  39.             downloader.OpenReadCompleted -= webClient_OpenReadCompleted;  
  40.             string[] str = e.UserState.ToString().Split(',');  
  41.             if (Convert.ToInt64(str[0]) == index) {  
  42.                 int code = Convert.ToInt32(str[1]);  
  43.                 string key = string.Format("{0}{1}", partName, str[1]);  
  44.                 if (!Res.ContainsKey(key)) { Res.Add(key, new StreamResourceInfo(e.Result as Stream, "application/binary")); }  
  45.                 base.Code = code;  
  46.                 loadConfig(key);  
  47.             }  
  48.         }  
  49.  
  50.         Dictionary frameOffset = new Dictionary(); //各幀偏移  
  51.         ///   
  52.         /// 加載配置  
  53.         /// 
  54.  
  55.         void loadConfig(string key) {  
  56.             XElement info = XElement.Load(Application.GetResourceStream(Res[key], new Uri("Info.xml", UriKind.Relative)).Stream).DescendantsAndSelf(partName).Single();  
  57.             FullName = info.Attribute("FullName").Value;  
  58.             //解析各幀偏移  
  59.             IEnumerable  iFrame = info.Element( "Frames").Elements();  
  60.             frameOffset.Clear();  
  61.             foreach (XElement element in iFrame) {  
  62.                 frameOffset.Add(element.Attribute("ID").Value, new Point() {  
  63.                     X = (double)element.Attribute("OffsetX"),  
  64.                     Y = (double)element.Attribute("OffsetY"),  
  65.                 });  
  66.             }  
  67.             if (Ready != null) { Ready(this, null); }  
  68.         }  
  69.  
  70.         bool _IsTurn;  
  71.         ///   
  72.         /// 獲取或設置是否水平翻轉(zhuǎn)  
  73.         /// 
  74.  
  75.         public bool IsTurn {  
  76.             get { return _IsTurn; }  
  77.             set {  
  78.                 if (_IsTurn != value) {  
  79.                     Transform = (_IsTurn = value) ? scaleTransform : null;  
  80.                 }  
  81.             }  
  82.         }  
  83.  
  84.         bool _Flash;  
  85.         ///   
  86.         /// 獲取或設置是否閃光  
  87.         /// 
  88.  
  89.         public bool Flash {  
  90.             get { return _Flash; }  
  91.             set {  
  92.                 if (_Flash != value) {  
  93.                     //if (_Flash = value) {  
  94.                     //    dispatcherTimer.Start();  
  95.                     //} else {  
  96.                     //    this.Opacity = 1;  
  97.                     //    dispatcherTimer.Stop();  
  98.                     //}  
  99.                     this.Opacity = (_Flash = value) ? 0.4 : 1;  
  100.                 }  
  101.             }  
  102.         }  
  103.  
  104.         bool order = false;  
  105.         DispatcherTimer dispatcherTimer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(100) }; //換裝時的閃光特效計時器  
  106.         public EquipBase() {  
  107.             dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);  
  108.         }  
  109.  
  110.         void dispatcherTimer_Tick(object sender, EventArgs e) {  
  111.             if (order) {  
  112.                 this.Opacity = this.Opacity + 0.1;  
  113.                 if (this.Opacity >= 1) { order = false; }  
  114.             } else {  
  115.                 this.Opacity = this.Opacity - 0.1;  
  116.                 if (this.Opacity <= 0.3) { order = true; }  
  117.             }  
  118.         }  
  119.  
  120.         static Dictionary equipRes = new Dictionary();  
  121.  
  122.         ScaleTransform scaleTransform = new ScaleTransform() { ScaleX = -1 };  
  123.         ///   
  124.         /// 呈現(xiàn)幀圖  
  125.         /// 
  126.  
  127.         public void Display(string key) {  
  128.             string resKey = string.Format("{0}{1}{2}", partName, Code, key);  
  129.             if (!equipRes.ContainsKey(resKey)) {  
  130.                 equipRes.Add(resKey, Application.GetResourceStream(Res[string.Format("{0}{1}", partName, Code)], new Uri(string.Format("{0}.png", key), UriKind.Relative)).Stream);  
  131.             }  
  132.             this.StreamSource = equipRes[resKey];  
  133.             this.InternalOffset = frameOffset[key];  
  134.             if (IsTurn) { scaleTransform.CenterX = Center.X - frameOffset[key].X; }  
  135.         }  
  136.  
  137.         public override void Dispose(object sender, EventArgs e) {  
  138.             dispatcherTimer.Stop();  
  139.             dispatcherTimer.Tick -= dispatcherTimer_Tick;  
  140.             base.Dispose(sender, e);  
  141.         }  
  142.     } 

#p#

使用的方法和效果      

       內(nèi)容比較簡明:當角色需要換裝時,通過異步下載的方式獲取該裝備部件的XAP包,一旦下載完畢便將其緩存起來使用。當然,由于是異步,在整個Loading的過程中為了提高用戶體驗,我們可以在角色(Role)身上做些修飾以讓玩家一看就明白該角色正處于換裝Loading,比較有新意的做法是在角色中心添加一些描述性的文字,或使用一些旋轉(zhuǎn)類的動畫(Animation):

       另外,我在其中還增加了一個名為Flash的方法,即當某個裝備部件正處于Loading過程中時,該部件將執(zhí)行時隱時現(xiàn)的Opacity動畫,這種效果最完美了。不過,就目前的Silverlight 4 來說還無法對UIElement的Opacity進行GPU硬件加速,暫時該方案的拓展與取舍/取代問題只能交由大家一同探討。

       然后是關于換裝系統(tǒng)中的素材資源的組織。對于像Silverlight這樣基于動態(tài)加載的游戲開發(fā)技術來說,最大程度減少質(zhì)量損失前提下的資源容量高度濃縮有利于網(wǎng)頁游戲的動態(tài)加載,以及像Windows Phone這樣磁盤空間相對較小的移動設備平臺。以精致的2.5D網(wǎng)游中的角色為例,大都以8方向居多,當然我們也還是能夠僅僅使用5個方向素材即達到減少資源開支的效果(比如對其中的東北、東、東南進行水平翻轉(zhuǎn)):

       此方法通過犧牲少量的性能進行水平翻轉(zhuǎn)達到讓資源總量減少近一半,且畫質(zhì)不打折扣之效果。唯一缺陷就是武器永遠處于同一只手中,無論面朝左或是右;不過就整體而言,這不失為大多數(shù)網(wǎng)頁游戲之首選。另外,對于Silverlight開發(fā)2.5D網(wǎng)頁游戲來說,將圖像資源PNG8化確實必要而關鍵。由于本節(jié)源碼中的素材均來源于網(wǎng)絡,所以效果很一般,如果是由3D美術原創(chuàng)的話,將逐幀圖像導出并處理成顏色過渡均勻,邊線條紋清晰流暢且無鏤空的PNG8精美素材并非難事,最終將再次大幅度降低游戲整體資源及內(nèi)存占用:

       此時,大家應該有注意到本節(jié)中資源的命名規(guī)范與以往有了些變化,形如a-b-c-d.png的形式,對于鎧甲(身體)和武器來說,a代表狀態(tài)(打坐/步行/騎乘);b代表行為動作(停止/移動/攻擊/受傷);c代表朝向;d代表幀號。而對于騎乘道具,比如翅膀和坐騎來說,a代表行為動作;b代表對象代號(比如翅膀1/翅膀2,坐騎前半部分/坐騎后半部分);c和d則與前面一致。當然,這或許僅能符合我個人的思維習慣,自認為如此配置更便于理解和使用,還是那句老話,只要能給程序的編寫帶來便利,結果依舊是仁者見仁,智者見智,并無定論。

       當裝備類及相關資源設置完畢后,我們便可通過一個Role控件作為容器進行統(tǒng)一包裝管理,此時我們創(chuàng)建一個名為RoleBase的角色基類,游戲中一切主體生命對象均由此衍生而來,比如英雄(Hero)/怪物(Monster)/非控對象(NPC)等等:

       大伙是否注意到,與以前編寫的結構有所不同,此時的Sprite的意義得到了更廣泛的延伸,是一次新的詮釋,它指代所有基于場景坐標系布局中的對象(映射到現(xiàn)實世界中即指一切活動著得對象),比方說角色(如英雄,怪物,寵物,動物,NPC,動畫,魔法等),道具(如火焰,植物,飛箭等),特效(如云霧繚繞,打雷閃電,刮風下雨,花葉紛飛)等等,我們均可將其納入“游戲精靈”的行列。外加上對角色的Coordinate(場景中的Point坐標屬性)和Position(游戲畫布中的Point坐標屬性)進行了更完美的協(xié)調(diào),于是整個游戲控件項目(Controls)被大規(guī)模重構,層次關系更趨合理,耦合度降低,重用性更高,更利于后期功能的拓展。

       最后還得特別強調(diào)下,Silverlight游戲中盡量使用小尺寸圖片,因為圖像的尺寸越大越消耗UI線程。就會可能出現(xiàn)讓CPU和FPS不堪重負的情況。


文章題目:Silverlight2.5DRPG游戲技巧與特效處里:紙娃娃系統(tǒng)
瀏覽路徑:http://www.5511xx.com/article/dpchopj.html