咨詢電話:023-6276-4481
熱門文章
電 話:023-6276-4481
郵箱:broiling@qq.com
地址:重慶市南岸區(qū)亞太商谷6幢25-2
這個(gè)游戲還算比較大的,所以我打算分幾篇文章來介紹。本節(jié)先介紹基礎(chǔ)的P1的實(shí)現(xiàn)。其實(shí)對(duì)游戲有所了解的都知道格斗游戲算是游戲類型中比較難編寫的,無論是邏輯還是復(fù)雜的技能控制還有碰撞檢測(cè)都是比較復(fù)雜的,所以我盡量做到完美。
[csharp] view plain copy
<Canvas Name="MyCanvas" ></Canvas>
首先我們?cè)谥鹘缑孢x取的布局是Canvas的布局,為什么呢,因?yàn)檫@個(gè)布局在我們家在圖片資源的時(shí)候是非常方便的,可以準(zhǔn)確的控制位置,便于我們進(jìn)行屬性動(dòng)畫的制作。(如果這里不懂可以先自己百度學(xué)習(xí)WPF的布局學(xué)習(xí),其中Grid,Canvas,StackPanel,DockPanel等都是比較重要的,后面我會(huì)更新相關(guān)的文章)。然后定義一個(gè)Image的對(duì)象當(dāng)作P1:
下面我們就來看如何進(jìn)行主角的加載,我們知道在一般的格斗游戲中,角色都不是靜止的站立的,都是會(huì)晃動(dòng)的,也就以為著我們必須加載成動(dòng)畫的樣子。
下面我們來學(xué)習(xí)在WPF中的動(dòng)畫是怎么實(shí)現(xiàn)的:
1.時(shí)間容器的方式(TimeLine可能更準(zhǔn)確的翻譯是時(shí)間線,但是我更喜歡時(shí)間容器的翻譯)
因?yàn)檫@種方式是規(guī)定一個(gè)時(shí)間段,這就是時(shí)間容器的容量,然后把動(dòng)作加入進(jìn)這個(gè)時(shí)間容器,最后再把這個(gè)時(shí)間容器加載進(jìn)入就可以實(shí)現(xiàn)動(dòng)畫效果了,這種一般是實(shí)現(xiàn)屬性動(dòng)畫。什么叫做屬性動(dòng)畫呢,首先我們知道每個(gè)對(duì)象都有各種的屬性,比如說個(gè)按鈕的大小(這就叫做屬性),按鈕的位置(這就叫做屬性),按鈕的顏色等等。所以屬性動(dòng)畫就是在一個(gè)規(guī)定的時(shí)間內(nèi)動(dòng)態(tài)的實(shí)現(xiàn)對(duì)象屬性變化的動(dòng)畫。
[csharp] view plain copy
public partial class MainWindow : Window
{
Rectangle rect;
public MainWindow()
{
InitializeComponent();
rect = new Rectangle();
rect.Stroke = Brushes.Black;
rect.Fill = Brushes.Red;
//這兩句一定要有,雖然沒有在默認(rèn)的情況下是加載到(0,0)但是沒有這兩句設(shè)置這個(gè)屬性,在下面
rect.SetValue(Canvas.LeftProperty,0D);
rect.SetValue(Canvas.TopProperty,0D);
rect.Height = 100;
rect.Width = 100;
MyCanvas.Children.Add(rect);
}
private void MyCanvas_MouseDown(object sender, MouseButtonEventArgs e)
{
Point MoveTO = new Point();
MoveTO = e.GetPosition(MyCanvas);
//故事畫板,上面可以同時(shí)裝載多個(gè)時(shí)間容器
Storyboard MyStory = new Storyboard();
//X軸的移動(dòng)
DoubleAnimation MyXAnimation = new DoubleAnimation(MoveTO.X, TimeSpan.FromMilliseconds(2000));
Storyboard.SetTargetProperty(MyXAnimation, new PropertyPath(Canvas.LeftProperty));
MyStory.Children.Add(MyXAnimation);
MyStory.Begin(rect);
//Y軸的移動(dòng)
DoubleAnimation MyYAnimation = new DoubleAnimation(MoveTO.Y, TimeSpan.FromMilliseconds(2000));
Storyboard.SetTargetProperty(MyYAnimation, new PropertyPath(Canvas.TopProperty));
MyStory.Children.Add(MyYAnimation);
MyStory.Begin(rect);
}
這段代碼是實(shí)現(xiàn)鼠標(biāo)點(diǎn)擊方塊就動(dòng)畫的移動(dòng)到點(diǎn)擊的位置,但是如果你只是這樣寫你會(huì)發(fā)現(xiàn)一個(gè)問題,只在你點(diǎn)擊方塊的內(nèi)部會(huì)產(chǎn)生移動(dòng)而在點(diǎn)擊外面是沒有效果的,為什么呢?因?yàn)槲覀兗尤隒anvas的時(shí)候,如果不對(duì)其進(jìn)行操作是只認(rèn)為只有當(dāng)前控件占領(lǐng)的區(qū)域有效。解決辦法有:
1.在Xaml中加入一個(gè)無效的背景色那么就可以實(shí)現(xiàn)效果了。
[csharp] view plain copy
<Canvas Name="MyCanvas" Background="White" MouseDown="MyCanvas_MouseDown"/>
2.那就不用Canvas中的鼠標(biāo)點(diǎn)擊函數(shù),而用窗體的鼠標(biāo)點(diǎn)擊函數(shù)。這兩種方法的實(shí)現(xiàn)效果都是一樣的,當(dāng)然屬性動(dòng)畫是不止DoubleAnimation的還有其他的屬性,比如PointAnimation等(不過一般都可以用DoubleAnimation來組合),想要深入了解可以上微軟的官網(wǎng)看相關(guān)的文檔(當(dāng)然我后續(xù)也會(huì)更新)。
以上的動(dòng)畫效果我們學(xué)會(huì)了的話,那我們就可以完成主角的走動(dòng)了,沒錯(cuò),很簡(jiǎn)單吧!主角的走動(dòng)只不過是圖片的位置的移動(dòng)罷了,和上面的矩形是一個(gè)效果。但是光有角色的走動(dòng)好似不行的,我們還需要在走動(dòng)的時(shí)候不停的實(shí)現(xiàn)畫面的走動(dòng)效果,還有技能效果。那么下面我們來介紹第二種動(dòng)畫產(chǎn)生的方法。
2.定時(shí)器產(chǎn)生的動(dòng)畫。
在WPF中定時(shí)器有Timer和DispatcherTimer兩種定時(shí)器,但是建議最好使用DispatcherTimer這個(gè)定時(shí)器。如果學(xué)過可視化編程并且進(jìn)行過計(jì)時(shí)器使用的應(yīng)該都知道是個(gè)什么東西。顧名思義就是在一個(gè)規(guī)定的時(shí)間內(nèi)不停的觸發(fā)一個(gè)動(dòng)作,在WPF里面就是在規(guī)定的時(shí)間間隔調(diào)用一個(gè)函數(shù),完成一個(gè)規(guī)定的動(dòng)作。
[csharp] view plain copy
public MainWindow()
{
InitializeComponent();
Spirit = new Image();
Canvas.SetLeft(Spirit,0D);
Canvas.SetBottom(Spirit,150D);
MyCanvas.Children.Add(Spirit);
ResourceAdd();
//站立的計(jì)時(shí)器
DispatcherTimer StandTimer = new DispatcherTimer();
StandTimer.Interval = TimeSpan.FromMilliseconds(80);
StandTimer.Tick += new EventHandler(StandTimer_Tick);
StandTimer.IsEnabled = true;
StandTimer.Start();
計(jì)時(shí)器如果要不停的關(guān)停開啟的話我建議在加載函數(shù)或者這個(gè)函數(shù)里面申請(qǐng),或者申請(qǐng)為全局變量。因?yàn)檫@樣可以避免我們?cè)谄渌瘮?shù)里面不停的申請(qǐng),防止造成不可控制的錯(cuò)誤,這樣我們只需要設(shè)置其IsEnable屬性或者調(diào)用Stop()函數(shù)即可控制計(jì)時(shí)器的關(guān)停和開啟。
[csharp] view plain copy
private void StandTimer_Tick(Object sender,EventArgs s)
{
if (!Is_Using_Skill)
{
switch (Go_Type)
{
case 0: //站立
{
for (int i = 0; i < Stand_Total_Count; i++)
{
if (i == Stand_Real_Count)
{
Spirit.Source = Stand[i];
Stand_Real_Count++;
if (Stand_Real_Count == Stand_Total_Count)