Silverlight游戏设计(Game Design):(六)场景编辑器之开源畅想
所有的游戲設計輔助工具都是為了提高游戲開發效率而出現的,Silverlight-2D游戲場景編輯器(QXSceneEditor)同樣也不例外,雖然它不比《魔獸》、《星際》、《帝國》等大作的地圖編輯器擁有強大到甚至可以通過“換膚”直接創造出一款新游戲;但是大家可以通過它,配合上前幾節講述的游戲架設方式幾乎能搭建任意一款2D游戲圖形框架。無論是RPG(角色扮演)、SLG(策略)、RTS(即時戰略)還是ACT(動作)、STG(射擊)、CAG(卡片游戲)等游戲類型,不論精靈是2方向(如:《地下城與勇士》、《三國群英傳》) 4方向(如:《漂流幻境》)還是8方向(如:《破天一劍》)甚至16方向(如:《劍俠世界》中的魔法),不論場景是橫向、縱向、主視角、牽引模式,傾斜的還是垂直的,不論游戲空間是2層的(如:《夢幻諸仙》),3層的(如:《奇跡》)還是N層的(如:《英雄無敵》、《鐵血聯盟》)等等,只要是2D的均可用作場景的布局或架設。
場景編輯器是如何做到如此的高度通用而神乎其神的?在第二節中,我已較詳細的講解了它的核心功能:動態坐標系系統。通過動態修改場景以及它內部的地圖、坐標系等對象的某些參數即可實現場景的任意傾斜度、單元格尺寸、參照系、2D位置,3D旋轉以及主角在位置顯示及移動方面的多模式。至于其中的核心代碼我一再強調其實不過就兩個,是否與第一部第十節的公式吻合大家可自行比對,事實證明它們是正確的,因此也請特別關注它的朋友們放一萬個心:
??????? /// <summary>
??????? /// 將窗口坐標系中的坐標換算成游戲坐標系中的坐標
??????? /// </summary>
??????? public Point GetGameCoordinate(double angle, Point p, uint gridSize) {
??????????? if (angle == 0) {
??????????????? return new Point((int)(p.X / gridSize), (int)(p.Y / gridSize));
??????????? } else {
??????????????? double radian = GetRadian(angle);
??????????????? return new Point(
??????????????????? (int)((p.Y / (2 * Math.Cos(radian)) + p.X / (2 * Math.Sin(radian))) / gridSize),
??????????????????? (int)((p.Y / (2 * Math.Cos(radian)) - p.X / (2 * Math.Sin(radian))) / gridSize)
??????????????? );
??????????? }
??????? }
?
??????? /// <summary>
??????? /// 將游戲坐標系中的坐標換算成窗口坐標系中的坐標
??????? /// </summary>
??????? public Point GetWindowCoordinate(double angle, Point p, uint gridSize) {
??????????? if (angle == 0) {
??????????????? return new Point(p.X * gridSize, p.Y * gridSize);
??????????? } else {
??????????????? double radian = GetRadian(angle);
??????????????? return new Point(
??????????????????? (p.X - p.Y) * Math.Sin(radian) * gridSize,
??????????????????? (p.X + p.Y) * Math.Cos(radian) * gridSize
??????????????? );
??????????? }
??????? }
再回到功能上,僅有以上這些還是不夠的;作為一個場景編輯器,更重要的是作為后續章節中我將為大家展示更多Demo的基礎框架,它還需要擁有更好更強大的功能。
作為場景的編輯器,光能實現坐標系的變化只能算完成了一半,如能加上任意地圖的導入才能算得上動態搭建:
????? //加載地圖
??????????? button.Click += (s, e) => {
??????????????? OpenFileDialog openFileDialog = new OpenFileDialog();
??????????????? openFileDialog.Multiselect = false;
??????????????? openFileDialog.Filter = "圖象文件(*.jpg *.png)|*.jpg;*.png";
??????????????? try {
??????????????????? bool result = (bool)openFileDialog.ShowDialog();
??????????????????? if (!result) {
??????????????????????? return;
?????????????? ?????} else {
??????????????????????? FileInfo fileInfo = openFileDialog.File;
??????????????????????? Stream stream = fileInfo.OpenRead();
??????????????????????? BitmapImage bitmapImage = new BitmapImage();
??????????????????????? bitmapImage.SetSource(stream);
??????????????????????? if (bitmapImage.PixelWidth < this.Width || bitmapImage.PixelHeight < this.Height) {
??????????????????????????? MessageBox.Show(string.Format("地圖載入失敗!圖片規格小于窗口尺寸:{0} * {1}", this.Width, this.Height));
??????????????????????? } else {
??????????????????????????? scene.MapSource = bitmapImage;
??????????????????????????? mapDetailsOutPut.Text = string.Format("寬:{0}px? 高:{1}px", scene.MapWidth = bitmapImage.PixelWidth, scene.MapHeight = bitmapImage.PixelHeight);
???????????????? ???????}
??????????????????????? stream.Close();
??????????????????? }
??????????????? } catch {
??????????????????? MessageBox.Show("地圖載入失敗!請檢查該圖片格式是否正確");
??????????????? }
??????????? };
Silverlight中,我們可以通過OpenFileDialog實現本地資源的導入;Silverlight目前版本僅能支持少數的圖片格式,我們可以通過Filter進行文件類型過濾;由于圖片位于本地機器,因此一旦選取圖片后(bitmapImage.SetSource(stream))我們即刻便會知道圖片的尺寸(bitmapImage.PixelWidth及bitmapImage.PixelHeight),這是非常重要的信息,因為當前游戲窗口的尺寸是800*580,如果地圖圖片的寬、高小于該數值對于游戲中地圖的移動模式是無任何意義的,于是我在邏輯上還做了額外的篩選判斷。
通過不同地圖背景配合上相應的坐標系系統,這才叫場景搭建嘛~:
同時,場景編輯器還應該具備地形的編輯能力;因此,我還在當前版本中定義了5種最常見的地形:障礙、平地、草地、沙漠和河流:
??? /// <summary>
??? /// 地形
??? /// </summary>
??? public enum Terrains {
??????? /// <summary>
??????? /// 障礙
??????? /// </summary>
??????? Obstacle = 0,
??????? /// <summary>
??????? /// 平地
?? ?????/// </summary>
??????? Flat = 1,
??????? /// <summary>
??????? /// 草地
??????? /// </summary>
??????? Grassland = 2,
??????? /// <summary>
??????? /// 沙漠
??????? /// </summary>
??????? Desert = 3,
??????? /// <summary>
??????? /// 河流
??????? /// </summary>
??????? River = 4,
??????? /// <summary>
??????? /// 無
??????? /// </summary>
??????? None = 100,
??? }
接下來我們只需將參照系設定為“方塊”,并選擇相應的繪制對象,即可在地圖的坐標系中通過鼠標左鍵繪制相應的地形:
之前有很多朋友曾提出過這樣的問題:能否讓主角經過不同地形時發出不同的腳步聲?其實答案很簡單。在第三節中我有講到游戲基類的時空結構,為了讓對象能夠發聲,我們得在此基礎上再增加一個聲音屬性,即每一個繼承自GameBase的類都具備有且僅有的一個“聲源”。例如“游戲窗口”擁有游戲的背景音樂;“場景”負責局域環境的背景音效;“精靈”斧頭揮舞的風聲、受傷時的叫喊聲、走路時的腳步聲以及“魔法”施放時的咒語和“魔法”自身的爆破聲等等,哪怕是“面板”,當我們鼠標在“面板”的按鈕上點擊時同樣會聽到清脆的點擊聲,它就是我們偉大的GameBase新增的一個摸不著,看不見的優秀成員sound:
??????? /// <summary>
??????? /// 聲音
??????? /// </summary>
??????? MediaElement sound = new MediaElement() {
??????????? IsHitTestVisible = false,
??????????? Visibility = Visibility.Collapsed,
??????????? AutoPlay = true,
??????? };
當游戲對象需要發出聲音時,只需告訴sound,我要發聲了,并設置好聲音的來源即可:
??????? /// <summary>
??????? /// 發出聲音
??????? /// </summary>
??????? /// <param name="uri">路徑</param>
??????? /// <param name="loop">是否循環</param>
??????? public void MakeSound(string uri, bool loop) {
??????????? sound.Source = new Uri(string.Format(@"../Media/{0}", uri), UriKind.Relative);
??????????? sound.Position = TimeSpan.Zero;
??????????? SoundStart(loop);
??????? }
??????? /// <summary>
??????? /// 開始發音
??????? /// </summary>
??????? public void SoundStart(bool loop) {
??????????? if (loop) { sound.MediaEnded += sound_MediaEnded; }
??????????? sound.Play();
??????? }
趕快啦,帶上您的耳機來體驗吧~嘿嘿。 ^ () ^
看著“精靈”們都活蹦亂跳的,我們此時是否應該考慮讓場景也動感些?于是乎我想到了《WPF/Silverlight深度解決方案》中的HLSL自定義渲染特效之完美攻略。齷齪的事情要發生啦!一不小心,我將該Demo中所有的HLSL特效復制到了場景編輯器中,嘿嘿,見證奇跡的時刻:
??????? 以前我們做的僅僅是對精靈進行渲染,當時很多朋友還看不出個端疑來;但這回換成了整個場景,喜歡回合制RPG的朋友一眼必能看出,這樣的情形太像“踩地雷”時的過渡特效了:主角在地圖上行走時,一旦主動或隨機遇到怪物即會立刻進行場景切換,《仙劍奇俠傳》、《軒轅劍》等無數經典畫面此時又占據了我的思緒,感慨呀……回過神來,這僅僅不過才是6種渲染動畫,如果某天您把HLSL著色語言精通了,Silverlight任意特效玩弄于股掌之間將絕非難事,大家努力加油吧!
要收尾了,應朋友們的要求,我特意將此編輯器中的“動態物體”例如“精靈”等獲取圖片源的方式修改為動態下載,且在下載完成前用一張圖例代替呈現。完整代碼如下:
??????? static Dictionary<string, bool> downLoadImages = new Dictionary<string, bool>();
??????? /// <summary>
??????? /// 設置圖片控件圖片源(還未下載完前用圖例進行設置)
??????? /// </summary>
??????? /// <param name="image">源圖片控件</param>
??????? /// <param name="uri">源圖片路徑</param>
??????? /// <param name="legend">圖例路徑</param>
??????? public void SetImage(Image image, string uri, string legend) {
??????????? if (downLoadImages.ContainsKey(uri)) {
??????????????? if (!downLoadImages[uri]) {
??????????????????? image.Source = new BitmapImage((new Uri(string.Format(@"../SceneEditorImages/{0}", legend), UriKind.Relative))) {
??????????????????????? CreateOptions = BitmapCreateOptions.None
??????????????????? };
??????????????? } else {
??????????????????? image.Source = new BitmapImage((new Uri(string.Format(@"../SceneEditorImages/{0}", uri), UriKind.Relative))) {
??????????????????????? CreateOptions = BitmapCreateOptions.None
??????????????????? };
??????????????? }
??????????? } else {
??????????????? BitmapImage bitmapImage = new BitmapImage((new Uri(string.Format(@"../SceneEditorImages/{0}", uri), UriKind.Relative)));
??????????????? bitmapImage.ImageOpened += (s, e) => {
??????????????????? image.Source = s as BitmapImage;
??????????????????? downLoadImages[uri] = true;
??????????????? };
??????????????? image.Source = bitmapImage;
??????????????? image.Source = new BitmapImage((new Uri(string.Format(@"../SceneEditorImages/{0}", legend), UriKind.Relative))) {
??????????????????? CreateOptions = BitmapCreateOptions.None
??????????????? };
??????????????? downLoadImages.Add(uri, false);
??????????? }
??????? }
您沒看走眼,是的,這就是全部,很簡單對吧。當然,您同樣也可以通過Webclient對圖片素材進行按需下載,替換的相應代碼如下:
??? WebClient webClient = new WebClient();
??? webClient.OpenReadCompleted += (s, e) => {
????? ? BitmapImage bitmapImage = new BitmapImage();
????? ? bitmapImage.SetSource(e.Result);
????? ? image.Source = bitmapImage;
????? ? downLoadImages[uri] = true;
??? };
??? webClient.OpenReadAsync(new Uri(string.Format(@"../SceneEditorImages/{0}", uri), UriKind.Relative), uri);
WebClient下載資源更為穩定,特別是在客戶端網速不正常的情況下效果尤為顯著。以上兩種下載圖片的方式優點很多,例如每張圖片只需下載一次后即可一直使用而無需自定義緩存;另外,它特別適合我第一部教程第50節中談到的用一張圖來描述“精靈”等對象序列幀圖片的下載,因為在完成整張圖下載前,玩家可以看到一張圖例;而一旦該圖下載完成后,那么無論該對象做何動作,進行何種動畫,均不會有一點閃爍或破綻,仿佛加載本地圖片般流暢與完美~。當然了,由于業余時間有限,又不想再重復以前用過的素材,因而導致此場景編輯器中由N*M張圖片組成的“精靈”呈現得無比“閃耀”,這是相當糟糕的事情,更多的留給大家去思考這樣一個問題:基于Silverlight的網絡游戲,它動態加載的素材該如何配置?
最后,還想和大家說說心里話:開源,不是嘩眾取寵,更不是炫耀,而是一種精神。這種精神會永遠推動著你和你身邊的朋友們走得更遠更犀利!Silverlight在2D圖形方面所展示的效果華麗而極至,隨著計算機硬件的發展,如果公元2012年地球還未曾毀滅,我們一同攜手去暢想Web-3D那精彩的虛幻世界~未嘗不是一大幸事。
說到天花亂墜…事實勝過雄辯。該出手了,是時候展示此場景編輯器的強大了,后面的內容更精彩!一同見證吧!
在線演示地址:http://silverfuture.cn
作者: 深藍色右手出處: http://alamiye010.cnblogs.com/
教程目錄及源碼下載: 點擊進入( 歡迎加入WPF/Silverlight小組 WPF/Silverlight博客團隊)
本文版權歸作者和博客園共有,歡迎轉載。但未經作者同意必須保留此段聲明,且在文章頁面顯著位置給出原文連接,否則保留追究法律責任的權利。
原文鏈接: http://www.cnblogs.com/alamiye010/archive/2010/03/09/1681870.html
轉載于:https://my.oschina.net/chen106106/blog/43622
總結
以上是生活随笔為你收集整理的Silverlight游戏设计(Game Design):(六)场景编辑器之开源畅想的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Nature作图也出错 单细胞UMAP/
- 下一篇: 联想服务器TS130主板芯片组,【Thi