上一個草動效果是完全的隨機搖擺效果,並沒有特定的規律,看起來不是很自然,在實際的遊戲進行過程當中,玩家並不太注意是否真的和現實世界一模一樣,但是作為開發人員,沒有理由拒絕極致,這一次咱們一起做一個風吹過的草動效果。
真實中的風動效果,如下,是一種類似波動的形象,當然了,風完全看不到,那麼為了達到這個效果,應該從一個方向吹過,然後產生搖擺。
問題來了,如何知道風碰到了那些草,可能最簡單的方式是遍曆一下所有的草,看看合格就執行一下動畫,但是效率不可恭維,當螢幕上超過一定數量草的時候,每次的遍曆絕對是一個非常大的開銷,所以可以結合以前我提出的區塊式迴圈概念將判斷操作分成塊來完成,達到效能提升快速執行的效果。
區塊概念如下:
將整個顯示地區劃分成小塊,每個小塊上可能沒有草,可能有草,也可能有很多草,每個格子是一個List,而這些格子正好組成一個數組——元素為List的二維數組,這樣做可以很清晰的知道哪些格子有哪些草,將其劃分以後遍曆也是非常容易。為了達到這個效果,我們寫一個GrassLogic的類來組織和管理這個數組:
GrassLogic代碼
public class GrassLogic
{
List<Grass01>[,] GrassBuffArray;
int ArrayW;
int ArrayH;
int RangeW;
int RangeH;
public GrassLogic(int arrayW, int arrayH, int rangeW, int rangeH)
{
ArrayW = arrayW;
ArrayH = arrayH;
RangeW = rangeW;
RangeH = rangeH;
GrassBuffArray = new List<Grass01>[arrayH, arrayW];
}
public void AddGrass(Grass01 grass)
{
int ty = (int)grass.Y / (RangeH / ArrayH);
int tx = (int)grass.X / (RangeW / ArrayW);
if (GrassBuffArray[ty, tx] == null)
GrassBuffArray[ty, tx] = new List<Grass01>();
GrassBuffArray[ty, tx].Add(grass);
}
}
建立這個邏輯類的時候,我們會傳入數組的寬高和顯示範圍,用來計算草到底在什麼位置,是什麼歸屬,細心的朋友會發現grass帶有了X和Y兩個屬性成員,我們要對Grass01控制項添加相應的屬性。另外我們還要為Grass01的控制項增加一個動畫,以前的搖擺是迴圈的,這次我們需要一個只執行一次的動畫(故事板),開啟Grass01.xaml把下面的代碼添加到<UserControl.Resources>內:
Wave故事板代碼
<Storyboard x:Name="Ani_Wave" AutoReverse="True">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" Storyboard.TargetName="LayoutRoot">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame x:Name="WaveValue" KeyTime="0:0:1" Value="10"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
修改Grass01.xaml.cs裡的代碼:
Grass01類代碼
public Grass01()
{
InitializeComponent();
image.CacheMode = new BitmapCache();
}
public void GrassWave()
{
Ani_Wave.Begin();
}
public double X
{
get { return Canvas.GetLeft(this); }
set { Canvas.SetLeft(this, value); }
}
public double Y
{
get { return Canvas.GetTop(this); }
set { Canvas.SetTop(this, value); Canvas.SetZIndex(this, (int)value); }
}
上面的準備已經就緒,那麼我們如何產生風的自然波動呢,請看示意:
是否有明白了呢,我們只需要做一個X的遊標來標識風吹到了哪裡,對此,我們需要對邏輯類做一些改造:
GrassLogic代碼
public class GrassLogic
{
List<Grass01>[,] GrassBuffArray;
int ArrayW;
int ArrayH;
int RangeW;
int RangeH;
DispatcherTimer WaveTimer = new DispatcherTimer();
public GrassLogic(int arrayW, int arrayH, int rangeW, int rangeH)
{
ArrayW = arrayW;
ArrayH = arrayH;
RangeW = rangeW;
RangeH = rangeH;
GrassBuffArray = new List<Grass01>[arrayH, arrayW];
WaveTimer.Tick += new EventHandler(WaveTimer_Tick);
WaveTimer.Interval = TimeSpan.FromMilliseconds(300);
}
int _marker = 0;
void WaveTimer_Tick(object sender, EventArgs e)
{
_marker += 1;
if (_marker >= ArrayW)
_marker = 0;
for (int i = 0; i < ArrayH; i++)
{
List<Grass01> items = GrassBuffArray[i, _marker];
if (items == null)
continue;
foreach (var item in items)
{
item.GrassWave();
}
}
}
public void AddGrass(Grass01 grass)
{
int ty = (int)grass.Y / (RangeH / ArrayH);
int tx = (int)grass.X / (RangeW / ArrayW);
if (GrassBuffArray[ty, tx] == null)
GrassBuffArray[ty, tx] = new List<Grass01>();
GrassBuffArray[ty, tx].Add(grass);
}
public void StartWave()
{
WaveTimer.Start();
}
}
加入了一個Timer來迴圈邏輯,按照格子逐步的推進,執行下面對應的草的動畫,當推進到底的時候,從頭來過,好了,基本上已經寫完,可能需要在MainPage裡將產生的草添加到GrassLogic邏輯中,使用AddGrass方法即可,其實這裡有一些並不是很嚴謹的地方,例如移除之類的操作,相信各位有自己的玩法,我的方式是直接通過訪問圖層然後進行添加操作,移除也是如此,不過在這裡不在進行這方面的討論,請直接參看最終效果:
原始碼如下:草動系統(二)隨風而動,可以通過上面的滑杆調整擺動的幅度,最高20,最低1,可以看看那種情況更加自然,人物控制使用鍵盤WASD
素材來自《窩窩世界》,窩窩世界是Silverlight開發的回合制MMORPG網頁遊戲。
推薦Silverlight遊戲開發部落格:深藍色右手