国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

使用WPF和WWF開發猜單詞游戲

2019-11-17 04:58:42
字體:
來源:轉載
供稿:網友
摘要 本文介紹使用新的Windows PResentation Foundation提供的3D圖形和可用于Workflow Foundation(經由DmRules)中的函數庫來開發一個簡單的猜單詞游戲。本文意在向讀者展示.Net 3.0開發交互式3D應用程序的簡易性。注:圖1顯示了本游戲的一個運行快照。

使用WPF和WWF開發猜單詞游戲(圖一)
圖1.猜字游戲運行過程中

  一、 簡介

  .Net 3.0為程序員提供了大量的新工具。其實,其最終目的是使得所有程序員都能夠輕松地開發3D應用程序。Vista把圖形處理功能交給了視頻卡來完成(大多數情況下,我們很可能已經購買了這樣的視頻卡)。這使得我們不必自己處理以前非常昂貴的計算問題而且不必擔心因此減弱性能。

  首先確定我必須確定我開發的DmRules庫能否應用于程序中。游戲的原始界面很簡單,是以Windows表單實現的,這足以滿足游戲的需要了。而且,這個界面還可以向你展示DmRules庫的工作原理。我決定使用WPF來實現一些3D內容;為運行本游戲,你需要安裝.Net 3.0。

  二、 游戲規則

  這個游戲很簡單。在Yahoo Games中有一個我很喜歡玩的稱作"Text Twist"的游戲,這里描述的游戲使用的規則與之很類似。基本上是首先提供給你一個由6個字母組成的單詞。最終,你必須猜測這個單詞。你還可以通過查找其它多于兩個字母長度的單詞得分,只要它們使用的字母出現在原始單詞中就行。

  你可以使用很多種方法來編寫這個游戲的規則。在這個游戲中,每個人都有一組規則。例如,一個人可以決定,假如你設法找到不是原始單詞的10個單詞,那么你仍應該贏得這一回合。其他玩家在猜測中提供多少字母方面可能更看重得分。得分,游戲規則,單詞列表,時間限制……所有這些都可以使用規則來進行控制。這也正是為什么我選擇這個游戲作為使用DmRules的一個例子。

  DmRules庫答應你在App.config文件中編寫規則。這些規則是針對每一種類型設計的。這影響到我在該游戲中設計這些類的方式。規則被應用于兩個方面:用戶作的猜測類(SingleGuess)和當前游戲類(Game)。

  (一) SingleGuess類

  一個猜測是用戶選擇的一個字母序列。在一次猜測中,我需要決定兩個方面:猜測正確嗎?假如猜測是正確的,它值多少點(得多少分)?

  為了確定猜測的正確性,我編寫了一組規則。每一條規則都是使用App.config文件(如下代碼所示)實現的。你已經看出,你可以把這些表達式編寫成實際的xml。如此我們可以在以后很輕易地改變這些規則而不需要重新進行編譯。

  1. 假如猜測有不到3個字母,那么它是不正確的。

<DmRule cond="this._GuessText.Length < 3" name="More than 2 letters"
haltAfterThen="true" priority="1000">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._IsCorrect" right="false" />
<DmCdStmt xsi:type="Assignment" left="this._ErrorText"
right=""Word must have at least 3 letters"" />
</ThenStmts>
</DmRule>
  2. 假如猜測使用不是在系統提供字母列表中的字母,那么它是不正確的。

<DmRule cond="!this._Game.HasLetters(this._GuessText)"
name="Has correct letters" haltAfterThen="true" priority="990">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._IsCorrect" right="false" />
<DmCdStmt xsi:type="Assignment" left="this._ErrorText"
right=""Letters not in scrambled word"" />
</ThenStmts>
</DmRule>
  3. 假如猜測已經完成,那么它是不正確的。

<DmRule cond="this._Game.GuessesMade.Contains(this._GuessText)"
name="Already guessed" haltAfterThen="true" priority="980">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._IsCorrect" right="false" />
<DmCdStmt xsi:type="Assignment" left="this._ErrorText"
right=""You've already guessed that word"" />
</ThenStmts>
</DmRule>
  4. 假如猜測的單詞在字典中,那么它是正確的。否則,不正確。

<DmRule cond="DictUtil.IsWordInList(this._GuessText)" name="Is in dictionary"
haltAfterElse="true" priority="970">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._IsCorrect" right="true" />
</ThenStmts>
<ElseStmts>
<DmCdStmt xsi:type="Assignment" left="this._IsCorrect" right="false" />
<DmCdStmt xsi:type="Assignment" left="this._ErrorText"
right=""Word is not in dictionary"" />
</ElseStmts>
</DmRule>
  你可能已經注重到,上面規則中的優先權(priority)屬性。必須把它添加到DmRules上,因為Workflow Foundation的規則系統并不能保證規則被以任何特定順序執行,除非明確地指定一種優先權。相應的數字越高,將越早執行該規則。優先權也可以是負數。

  另外,還有haltAfterThen和haltAfterElse屬性。有時,根據一種特定規則的計算方式,或者因為運行任何其它的規則可能效率不高或者因為其它規則能夠以一種你不想使用的方式修改狀態,你可能想停止運行規則。在給定上面說明的規則優先權的情況下,一旦猜測被確定是不正確的,那么應該立即停止運行相應的規則。Workflow Foundation實際上提供了一種規則語句,其中有一條能夠被插入到一個規則列表的任何位置的暫停(halt)命令。但是,把一條halt語句插入到上面配置文件中間對系統不無副影響,因為在一條規則中不答應存在循環或條件。因此,我決定僅使用屬性并且把halt語句添加到規則列表的最后。

  SingleGuess類中還有更多的規則。這些規則必須處理一個正確猜測的得分方式。得分是基于在該單詞中有多少個字母以及是否猜測匹配原始單詞。為了進行下一個回合的游戲,我決定假如你正確猜測了一個6個字母的單詞,那么你已經過了這一關。如你所見,這是輕易改變的:

<DmRule cond="this._GuessText == this._Game.OriginalWord" name="Guessed original word">
<ThenStmts>
<DmCdStmt xsi:type="EXPrStmt" expr="this._Game.Complete()"/>
<DmCdStmt xsi:type="Assignment" left="this._Score" right="40"/>
</ThenStmts>
<ElseStmts/>
</DmRule>
<DmRule
cond="this._GuessText != this._Game.OriginalWord && this._GuessText.Length == 6"
name="Guessed six-letter word">
<ThenStmts>
<DmCdStmt xsi:type="ExprStmt" expr="this._Game.Complete()"/>
<DmCdStmt xsi:type="Assignment" left="this._Score" right="25"/>
</ThenStmts>
<ElseStmts/>
</DmRule>
<DmRule cond="this._GuessText.Length == 3" name="Score 3-letter">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._Score" right="10"/>
</ThenStmts>
<ElseStmts/>
</DmRule>
<DmRule cond="this._GuessText.Length == 4" name="Score 4-letter">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._Score" right="15"/>
</ThenStmts>
<ElseStmts/>
</DmRule>
<DmRule cond="this._GuessText.Length == 5" name="Score 5-letter">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._Score" right="20"/>
</ThenStmts>
<ElseStmts/>
</DmRule>
  (二) Game類

  這個游戲類負責決定是否用戶應該移動到下一級還是失敗了。我決定使這個游戲基于時間進行設計。我在前三級中建立了一個單詞列表,這些單詞比較輕易猜出。此后,我僅隨機地從字典中選擇一個由6個字母組成的單詞。猜測這些單詞可能很困難,特定是當其中的一半我從未聽說過時。你可能決定根據需要改變這些規則。添加更多級別的單詞列表,改變答應的時間數,答應用戶在不同環境下進入到下一級等。
我在這個游戲中創建的規則列舉如下:

  1. 假如原始單詞是一個空字符串(我用于指示當前級別已經完成)而且已經完成的游戲級別小于3,那么選取一個新單詞,清除猜測列表,把時限設置為30秒,并且把級別設置為未完成。

<DmRule
cond="this._OriginalWord == "" && this._GamesPlayed < 3"
name="Unassigned original word, level one" priority="1000">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._OriginalWord"
right="DictUtil.FindGuessWord(6, Level.One)"/>
<DmCdStmt xsi:type="ExprStmt" expr="this.Scramble()"/>
<DmCdStmt xsi:type="ExprStmt" expr="this._GuessesMade.Clear()"/>
<DmCdStmt xsi:type="Assignment" left="this._TimeLeft"
right="TimeSpan.FromSeconds(30)"/>
<DmCdStmt xsi:type="Assignment" left="this._IsComplete" right="false"/>
</ThenStmts>
<ElseStmts />
</DmRule>
  2. 假如原始單詞是一個空字符串并且當游戲相應的字母數大于或等于3時,那么從字典中隨機選取一個單詞,清除創建的猜測列表,把時間設置為30秒,并且把級別設置為未完成。

<DmRule
cond="this._OriginalWord == "" && this._GamesPlayed >= 3"
name="Unassigned original word, above level one" priority="990">
<ThenStmts>
<DmCdStmt xsi:type="Assignment" left="this._OriginalWord"
right="DictUtil.FindGuessWord(6, Level.Zero)"/>
<DmCdStmt xsi:type="ExprStmt" expr="this.Scramble()"/>
<DmCdStmt xsi:type="ExprStmt" expr="this._GuessesMade.Clear()"/>
<DmCdStmt xsi:type="Assignment" left="this._TimeLeft"
right="TimeSpan.FromSeconds(30)"/>
<DmCdStmt xsi:type="Assignment" left="this._IsComplete" right="false"/>
</ThenStmts>
<ElseStmts />
</DmRule>
  3. 假如時間已到并且游戲完成,那么應該發出信號以指示該用戶已經順利完成這一回合。

<DmRule cond="this._TimeLeft.TotalSeconds == 0 && this._IsComplete"
name="Time ran out, game complete" priority="800">
<ThenStmts>
<DmCdStmt xsi:type="ExprStmt" expr="this.SUCcess()"/>
</ThenStmts>
<ElseStmts />
</DmRule>
  4. 假如時間已到并且游戲未完成,那么應該發出信號以指示該用戶這一回合失敗。

<DmRule cond="this._TimeLeft.TotalSeconds == 0 && !this._IsComplete"
name="Time ran out, game not complete" priority="790">
<ThenStmts>
<DmCdStmt xsi:type="ExprStmt" expr="this.Failure()"/>
</ThenStmts>
<ElseStmts />
</DmRule>
  Success()和Failure()方法都以簡單地激活Game類中的一個事件的方式結束。UI必須訂閱該事件以進行響應。

  三、 原始Windows表單接口

使用WPF和WWF開發猜單詞游戲(圖二)
圖2.最初設計的表單界面

  假如你認為圖2中的這個3D界面太丑陋,那么你只注重一下這個接口好了——至少它能夠實現我們的目的。我們在此看到的內容有:一個已經猜測出的單詞列表,得分,待猜測的單詞,這一回合中剩下的時間,一個指示器告訴我們是否我們已經過了這一回合,一個要輸入猜測內容的文本框,一個按鈕用于改變要猜測單詞,還有一個按鈕用于提交猜測單詞。

  這個接口也包括在本文相應的源碼中。當時間一到,彈出一個消息框指示你可以點擊進入到下一回合或告訴你要猜測的單詞,并且讓你開始一次新游戲。四、 WPF中的3D圖形

  在本文開始的圖像已經向你展示了3D接口看上去的感覺。被猜測的單詞對應一組特定的點位置,你可以點擊這些字母來選擇它們。選擇的字母將翻到它在用戶構建的單詞中的相應位置上。還有一個按鈕用于清除當前猜測內容,另外一個按鈕用于輸入猜測。當猜測結束或被清除后,字母翻轉回它們在被猜測單詞中的原來位置。還有一個時鐘指示剩余的時間,還有一個已經猜測的單詞的列表,并且指示用戶的得分情況。

  在下一節中,我將討論我的實現中碰到的一些有趣的事情。由于WPF僅僅提供一種3D環境而沒有任何現成的原型可以使用;因此,相應的編程工作自然(與其它的3D編程)有些不同。

  (一) 創建字母

  每個字母實質上是一個擠壓的立方體。我使其看起來象一個亂寫的字母。為此,我只是取得一種隨機的木紋理并且使用一個工具程序把字母繪制到其上。這個工具程序名為CreateTextures,也一起包含到本文相應的源碼中。該工具基本上負責打開樹根紋理并且把一個字母繪制到該紋理上。你必須設想使字母包裝起一個正方體。因此,下面圖3是字母"P"相應的紋理看上去的樣子:

使用WPF和WWF開發猜單詞游戲(圖三)
圖3.相應于字母"P"的紋理

  其中,一個P是顛倒的,另一個是朝后的。理解這些的最輕易的方式是,把紋理圖像想像為一張禮品包裝紙。設想你正在使用它包裝一本書。把書的頂部放到這兩個P之間,然后把書豎起來。然后,拿起包裝紙,把書包起來。

  現在,我的包裝紙實際上應該被翻轉過來了,但是這應該不難理解。對一個3D對象實現紋理包裝是很簡單的。就象設計對象本身一樣簡單。你只需考慮對象的3D坐標,當然這有時也有一定的難度。

  我使用一個LetterFactory類創建這些字母。在XAML中,你要為你的三維網格物體定義點,三角指數,法線和紋理坐標。假如你看過任何的微軟的3D編程示例,你會注重到它們通常以XAML形式創建這些三維網格物體。但是,我喜歡以編碼方式來實現。讀取一個三維網格物體非常困難,因為要把所有的相關信息"打包"到一個組XML屬性中。無論如何,假如你對這些三維網格物體創建方式感愛好的話,請認真分析相應的源碼。

  (二) 決定是否用戶點擊了一個字母

  創建完字母后,我現在需要了解何時用戶點擊了它。這是我在實現任何其它內容之前必須要實現的。為此,我很輕松地在MSDN中找到一個實現這種操作的例子。WPF的確使實現用戶點擊了哪個三維網格物體的實現非常輕易。首先,把下列代碼添加到你的表單的構造函數中:

this.myViewport.MouseLeftButtonDown+=new MouseButtonEventHandler(HitTest);

  這里的myViewport是你的窗口中的3D視圖。下面是HitTest方法相應的代碼:

public void HitTest(object sender, System.Windows.Input.MouseButtonEventArgs args) {
 Point mouseposition = args.GetPosition(myViewport);
 PointHitTestParameters pointparams = new PointHitTestParameters(mouseposition);
 VisualTreeHelper.HitTest(myViewport, null, HTResult, pointparams);
}
  HitTest方法使用一個代理處理實際結果。HTResult方法按如下方式工作:

public HitTestResultBehavior HTResult(System.Windows.Media.HitTestResult rawresult) {
 RayHitTestResult rayResult = rawresult as RayHitTestResult;
 if (rayResult != null) {
  RayMeshGeometry3DHitTestResult rayMeshResult = rayResult as
  RayMeshGeometry3DHitTestResult;
  if (rayMeshResult != null) {
   GeometryModel3D hitgeo = rayMeshResult.ModelHit as GeometryModel3D;
    ...
}
}
return HitTestResultBehavior.Continue;
}  
  上面的變量hitgeo是被點擊的模型。此代碼是很輕易使用的;直接使用這些現成的代碼,你就能夠確定用戶點擊了哪個三維網格物體而不用擔心在3D空間和2D空間之間的坐標翻譯問題并且不需要進行任何數學矢量計算。WPF早已考慮到你的需要了。事實上,你在上面的代碼中看到的HitTestResult還可以用于實現用戶交互以外的內容。例如,它可以用于進行碰撞檢測或決定一個用戶的瞄準線。
  (三) 實現字母動畫

  動畫是Windows Presentation Foundation提供的另一種酷特征。你可以非常輕易地實現簡單的動畫效果。但是,你首先應該了解一些基本的3D概念。變換是3D游戲編程中常用操作。旋轉,平移,投映和縮放都屬于變換。我們在這個應用程序中不使用任何縮放,而由WPF負責處理投影問題。因此,我們可只關注旋轉和平移的問題。使用這些技術,我們就可以實現我們的字母的動畫效果:從一個位置翻轉到另一個位置。

  我的基本要求是,檢測何時用戶點擊了被猜測單詞中的一個字母。當這發生時,我想把這個字母移動到用戶正在構造的單詞上。為了充分利用3D效果,我想讓字母翻轉360度。你會看到實現這些是多么輕易。

  我們一共要實現三種變換:旋轉360度,沿Y軸平移和沿X軸平移。其中,最輕易的是沿Y軸平移,因為這個值是靜態的。

TranslateTransform3D tt3d = new TranslateTransform3D(new Vector3D(0, 0, 0));
DoubleAnimation da = new DoubleAnimation(-4, new Duration(TimeSpan.FromSeconds(1)));
tt3d.BeginAnimation(TranslateTransform3D.OffsetYProperty, da);
  我們使用一個0矢量創建一個平移。動畫在經過一段時間后會改變平移;所以,我們不需要把該矢量設置為其它非0值。實際動畫使用一個值和一個時限(TimeSpan)值。在這種情況中,我想每秒移動-4單位。BeginAnimation調用指示,我想沿哪個軸移動這-4單位-在此是沿著Y軸。實際實現的是,把字母往下移動4個單位,這將耗費一秒鐘。

  下一個變換是沿著X軸的一個平移變換。根據字母來源于該被猜測單詞中的位置以及它要移動到猜測單詞的特定位置,可以改變這個平移。

double oldX = double.Parse(str[1]);
double newX = (_CurrGuess.Length + 1) * -2.5;
TranslateTransform3D tt3d2 = new TranslateTransform3D(new Vector3D(0, 0, 0));
da = new DoubleAnimation(newX - oldX, new Duration(TimeSpan.FromSeconds(1)));
tt3d2.BeginAnimation(TranslateTransform3D.OffsetXProperty, da);
  這里的執行非常相似于上面情況,只是要確定要移動多少單位和沿什么軸移動。因此,讓我們繼續討論更令人感愛好的旋轉變換:

RotateTransform3D myRotateTransform = new RotateTransform3D(
new AxisAngleRotation3D(new Vector3D(1, 0, 0), 1));
DoubleAnimation myAnimation = new DoubleAnimation();
myAnimation.From = 0;
myAnimation.To = 360;
myAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(1000));
myAnimation.RepeatBehavior = new RepeatBehavior(1);
myRotateTransform.Rotation.BeginAnimation(AxisAngleRotation3D.AngleProperty,
myAnimation);
  我們沿一個軸實現旋轉。上面的矢量指示,它位于X軸上。AxisAngleRotation3D構造函數的第二個參數是一個角度值(為1)。該動畫每次運動1度,這很輕易理解。我使動畫從第0幀(相應于0度)移動到第360幀(相應于360度)。我還想使其它一切都在一秒內完成。

  現在,最后一步是把所有變換施加到hitgeo對象:

(hitgeo.Transform as Transform3DGroup).Children.Insert(1, myRotateTransform);
(hitgeo.Transform as Transform3DGroup).Children.Add(tt3d);
(hitgeo.Transform as Transform3DGroup).Children.Add(tt3d2);
  代碼看上去有點希奇,但是為了實現多種變換,你必須把字母的Transform屬性賦值為一個Transform3DGroup(其實,這是相應于一組變換)。我是在創建字母時實現這一點的,我想保留對字母施加的原始變換并且再添加上一些新的變換。

  必須以特定順序來實現變換操作。例如,我們想在平移之前實現旋轉。為了理解這一點,你可以設想一下太空中的月亮。地球能夠繞自己的軸進行自轉(旋轉周期為24小時),月亮繞著地球旋轉。這兩種旋轉的區別是:月亮首先平移到地球外的某個位置處,然后再進行旋轉;而沿著地球軸的旋轉仍然發生,也就是月亮繞著地球轉。

  無論如何,最終結果是,必須把旋轉插入到一組變換中的一個特定位置。在本例中,只需把平移添加到變換的最后。最終,我們得到一個翻動其位置的字母("T")(見圖4):

使用WPF和WWF開發猜單詞游戲(圖四)
圖4.翻動字母("T")的動畫效果

  (四) 制作3D按鈕

  按鈕是任何接口的一個基本組成部分。在我們的3D環境中,我們沒有現成的工具可用。因此,我決定自己制作按鈕。我的前提是,我需要在我點擊鼠標時能夠"按"的某種東西。由于實現動畫平移很簡單,所以,我們可以使用這一技術來實現實際的"按"動作。

  我的第一個考慮是,用戶怎么能夠知道按鈕被"按下"了呢?在一般的Windows UI實現中,因為陰影的變化效果而使按鈕看上去被"按下"了。假如我在3D環境的左上方加入一個光源,也許我能夠實現這一效果。但是,為此,我也需要對此作一些變化以使按鈕看上去好象"彈起"。這也意味著,我需要為該按鈕預備一個平面。所以,我想使用另一種更為輕易些的方案。

  我使用的方案是,制造另外一個擠壓了的立方體。一方面,我要繪制該按鈕的文本。當被點擊時,該按鈕將"推入",然后再恢復到其原始位置。作為一種參考實現,我創建了一個很大的灰色多邊形用作背景。按鈕位于這個背景多邊形上面。當"按下"該按鈕時,實際上是"按下"該多邊形。我想,WPF應該默認地使用了Z緩沖區技術,因為最終結果是,當按下按鈕時,該按鈕看上去被"壓入"了多邊形里面。

  但是,這樣以來問題出現了:我該如何把文本放到按鈕上面呢?辦法是,得到一個圖像,然后把文本繪制到該圖像上去,并且把該圖像包到按鈕作為一個紋理。因此,首先,我創建一個文本:

FormattedText ft = new FormattedText(text,
new CultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(new FontFamily("Arial"), FontStyles.Normal,
FontWeights.Normal, new FontStretch()),
24D,
Brushes.Black);
  注重,這里的text變量中存儲著我想編寫的文本。我選擇使用黑色Arial,24pt字體。這基本上確定了一個文本框,并且能夠相應于文本大小來調整該文本框大小。我可以使用這個尺寸來決定我想如何縮放我的按鈕的尺寸。你會在ButtonFactory的實現代碼中看到類似如下的內容:

buttonModel.Geometry = CreateButtonMesh((ft.Width + 4) / (ft.Height));
  當我創建這個三維網格物體時,我改變它的寬度以匹配在文本中的寬高比。這防止字母看起來有點拉長。接下來,我們要創建一個DrawingVisual對象,用它來實現紋理效果。我們將繪制一個淺藍色的矩形來表示按鈕的背景顏色,然后繪制文本。

DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawRectangle(Brushes.LightGray, new Pen(Brushes.LightGray, 1),
new Rect(0, 0, ft.Width + 4, ft.Height * 4));
drawingContext.DrawText(ft, new Point(2, ft.Height * 1.5));
drawingContext.Close();
  現在,我們只需使該圖像可見,并且把該圖像作為一個材質應用到我們的三維網格上即可。

RenderTargetBitmap bmp = new RenderTargetBitmap((int)ft.Width + 4,
(int)(ft.Height * 4), 0, 0, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
buttonModel.Material = new DiffuseMaterial(new ImageBrush(bmp));
更多的請看:http://www.QQread.com/windows/2003/index.Html
  (五) 得分板

  下一個問題是,怎么顯示當前的得分。既然我能夠把格式化的文本放到一個圖像上面,并且能夠把它伸展到一個按鈕三維網格物體上,那么我考慮到,我應該能夠使用一個常規的多邊形并且使用當前得分把一個紋理繪制到它上面。這是一個相當簡單的過程。我以很類似于創建按鈕的方式創建該得分板,除了該多邊形具有一個固定大小外。紋理正相應于改變的內容。因此,在每次得分改變時,我都使用下面的方法來更新它:

private void UpdateScore() {
if (bmpScore != null) {
FormattedText ft = new FormattedText(_CurrGame.Score.ToString(),
new CultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(new FontFamily("Arial"), FontStyles.Normal,
FontWeights.Normal, new FontStretch()),
16D,
Brushes.DarkRed);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawRectangle(Brushes.LightGray,
new Pen(Brushes.LightGray, 1), new Rect(0, 0, ft.Width + 4, ft.Height * 4));
drawingContext.DrawText(ft, new Point(120 - ft.Width - 2, 2));
drawingContext.Close();
bmpScore = new RenderTargetBitmap(120, 25, 0, 0, PixelFormats.Pbgra32);
bmpScore.Render(drawingVisual);
scoreBoard.Material = new DiffuseMaterial(new ImageBrush(bmpScore));
}
}
  我想,對于改變得分來說,也許僅改變紋理位圖本身就足夠了。然而,這看起來卻無任何效果。既然得分不是在一秒內改變許多次,我想,這就足夠了:使用變化的紋理為該三維網格物體創建一種新材質。

  (六) 顯示時間

  實現用戶接口的另一個要害因素是向用戶顯示他猜測單詞還剩多少時間。我想使用我實現得分板一樣的思路來顯示該回合中還剩下多少分鐘多少秒。但是,這看起來并不那么有趣。我想,也許我可以模擬一個數字顯示,但是這可能過于復雜。最后,我決定顯示一個模擬時鐘。在這種時鐘上,可以很輕易地向你顯示你在本游戲中還剩下多少時間。而且,它的執行很簡單,因為我們僅需要使該時鐘的鐘針動起來即可。

  我的第一項任務是創建一只鐘。現在,我可以很輕易地僅創建一個矩形并且在其上加上時鐘紋理。但是,我想,我應該使用三維網格物體制作一個真正的圓圈。運用數學知識來解決這個問題是很有意思的,也許我以后還會再給它加上一些動畫效果。無論如何,我使用正弦和余弦函數創造了一個具有適當的紋理坐標的圓圈三維網格物體。

MeshGeometry3D mg3d = new MeshGeometry3D();
mg3d.Positions.Add(new Point3D(0, 0, 0));
mg3d.TextureCoordinates.Add(new Point(0.5, 0.5));
for (double d = 0; d <= 360; d += 5) {
double x = 4.0 * Math.Sin(d / 180.0 * Math.PI);
double y = 4.0 * Math.Cos(d / 180.0 * Math.PI);
mg3d.Positions.Add(new Point3D(x, y, 0));
x = x / 8.0 + 0.5;
y = y / 8.0 + 0.5;
mg3d.TextureCoordinates.Add(new Point(x, y));
}
for (int i = 1; i <= 360 / 5 + 1; i++) {
mg3d.TriangleIndices.Add(0);
mg3d.TriangleIndices.Add(i);
mg3d.TriangleIndices.Add(i + 1);
}
  作為一名喜歡進行優化的程序員,這個例程的優化使我大大為難。但是,由于僅調用一次,所以,我決定不費心再使其運行稍快些。我創建的第一個點位于圓形的中心,其它的點組成沿著各個方向的三角形。如你所見,創建一個圓圈三維網格物體非常輕易。

使用WPF和WWF開發猜單詞游戲(圖五)
圖5.時鐘動畫效果

  接下來,我們要實現時鐘中間的表針。我創建了一個很簡單的三維網格物體,通過使用一個三角形并且在其上施加一個旋轉動畫。我僅需要繞著Z軸旋轉它,這是非常輕易的,在此不再贅述。最終動畫效果見圖5。

  五、 總結

  在本文開始,我已說明在本游戲中我使用了我的DmRules庫。然后,我們通過一個具體例子介紹了如何使用Windows Presentation Foundation進行3D編程。
最后,本文中的小游戲向你介紹了進行Windows Vista編程非常有意義的內容。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 石屏县| 当涂县| 靖安县| 深水埗区| 平潭县| 静宁县| 临洮县| 乌兰察布市| 清苑县| 板桥市| 依兰县| 玛多县| 平舆县| 绥化市| 红桥区| 诏安县| 华宁县| 怀远县| 新安县| 兴安县| 威信县| 台东县| 凤冈县| 林周县| 广东省| 涞源县| 宜宾市| 汉川市| 呼伦贝尔市| 江陵县| 大港区| 淮南市| 丹江口市| 辽宁省| 雷波县| 赞皇县| 元氏县| 蓬安县| 义马市| 集贤县| 瓮安县|