WPF貪喫蛇遊戲開發

目錄

 

源碼可以在github上獲取https://github.com/ZombieAllen/WPF.git

基於WPF的貪喫蛇遊戲設計

1 引言

2 功能設計

2.1遊戲區域

2.2 貪喫蛇動畫

2.3 鍵盤控制方向

2.4遊戲區隨機出現蛇果(不能出現在蛇身上)

2.5碰撞監控

2.5.1 與果實碰撞

2.5.2 與邊界或者蛇身碰撞

2.6 界面優化1

2.7 高分榜

2.8 界面優化2

3 總結


源碼可以在github上獲取https://github.com/ZombieAllen/WPF.git

 

基於WPF的貪喫蛇遊戲設計

摘要:針對現有的網上關於WPF以及C#開發缺乏系統化的學習資料,現在設計一款大家耳熟能詳的貪喫蛇的小遊戲,來比較好的把XMAL界面設計,XML文件的信息寫入與讀取,C#面向對象的程序設計整合到一個遊戲裏。

 

關鍵字:WPF;C#;XML;界面設計;Visual Studio 2019

 

1 引言

      隨着工廠信息化以及數字化的飛速發展,對於工廠的自動化工程師,掌握一門高級的開發語言,來開發界面美觀的windows客戶端,實現數據的採集,存儲,展示已經變得越來越必須。跨學科的人才需求也在日漸加大。

      C#語言是現如今比較流行的一門面向對象的編程語言,在微軟新一代界面設計技術WPF的加持下,設計出一款界面美觀,功能強大的windows客戶端應用變得非常方便。

      這款基於WPF的貪喫蛇遊戲,會利用Canvas來繪製界面的背景以及蛇和果實,並利用障眼法來實現蛇的動畫效果,並利用事件來實現方向控制,最後會利用xml技術來存儲高分榜,遊戲開始的時候可以列出玩家排名。

 

2 功能設計

2.1遊戲區域

      首先我們打開Visual Studio2019 , 新建WPF項目

短短的幾行xmal代碼,就實現了遊戲窗口

 

接下來我們在這個Canvas區域畫出網格,來規範蛇以及果實出現的位置

技巧:通過isOdd變量的值通過嵌套For循環來在畫布上畫出一個個顏色相間的方塊。

最終實現的代碼以及效果

        private void Window_ContentRendered(object sender, EventArgs e)

        {

            DrawGameArea();

        }

        private void DrawGameArea()

        {

            for (int y = 0; y < GameArea.ActualHeight; y+=squareSize)

            {

                for (int x = 0; x < GameArea.ActualWidth; x += squareSize)

                {

                    Rectangle rectangle = new Rectangle() { Width = squareSize, Height = squareSize };

                    rectangle.Fill = isOdd ? Brushes.White : Brushes.WhiteSmoke;

                    GameArea.Children.Add(rectangle);

                    Canvas.SetLeft(rectangle, x);

                    Canvas.SetTop(rectangle, y);

                    isOdd = !isOdd;

                }

                isOdd = !isOdd;

            }

        }  

 

2.2 貪喫蛇動畫

這裏我們會接觸第一個面向對象設計的套路:類-à實例

對於一條蛇來說,C#自身並沒有這個實例。 這時候我們需要自己創建一個SnakePart的類,然後進行實例化出一條蛇。

實現方法:

在項目裏添加一個SnakePart的類,定義其主要屬性:UI元素,位置,是否是蛇頭

代碼如下

namespace WPF貪喫蛇遊戲設計

{

    public  class SnakePart

    {

        public UIElement  uIElement { get; set; }

        public Point point { get; set; }

        public Boolean isHead { get; set; }

    }

}

 

然後我們用泛型集合List把一個個蛇的部分串起來,就成了一條蛇了。

List<SnakePart> snakeParts = new List<SnakePart>();

 

那麼我們先畫一條靜態的蛇

定義蛇的初始位置以及長度

        //初始位置

        Point startPos = new Point(120, 120);

        //初始長度

        int snakeLength = 3;

 

然後判斷是否是蛇頭來畫不同顏色的方框,並把方框添加到蛇的uIElement上,然後在Canvas裏畫出來

具體實現代碼:

        private void DrawSnake(Point startPos, int snakelength)

        {

            Boolean isHead = false;

            double nextX = startPos.X;

            double nextY = startPos.Y;

            for (int i = 0; i < snakelength; i++)

            {

                if (i < snakelength - 1)

                {

                    isHead = false;

                    DrawSnake_sub(isHead, nextX, nextY);

                    nextX += squareSize;

                }

                else

                {

                    isHead = true;

                    DrawSnake_sub(isHead, nextX, nextY);

                }

            }

        }

        private void DrawSnake_sub(Boolean isHead , double nextX,double nextY)

        {

            

                Rectangle rectangle = new Rectangle() { Width = squareSize, Height = squareSize };

                rectangle.Fill = isHead ? snakeHeadColor : snakeBodyColor;

                SnakePart snakepart = new SnakePart();

                snakepart.uIElement = rectangle;

                snakeParts.Add(snakepart);

                GameArea.Children.Add(rectangle);

                Canvas.SetLeft(rectangle, nextX);

                Canvas.SetTop(rectangle, nextY);

        }

然後在頁面渲染的時候調用

DrawSnake(startPos, snakeLength);

這樣我們就初始化了一條蛇,具體實現結­­­­­果如下(紅色爲蛇頭,綠色爲蛇身)

 

接下來我們的任務就是讓蛇動起來:控制蛇的方向和蛇的速度

蛇的方向:

首先我們定義一個枚舉類型SnakeDirection,來表示蛇移動的四個方向。

namespace WPF貪喫蛇遊戲設計

{

  public  enum SnakeDirection

    {

        left,

        top,

        right,

        down

    }

}

然後我們設定蛇的初始行進方向爲向右

接下來我們定義蛇的行進速度,這時候就得用到定時器以及事件了

首先我們實例化一個定時器dispatch

        //定時器

        DispatcherTimer dispatcher = new DispatcherTimer();

       

爲其綁定一個事件MoveSnake(),定時器的間隔時間設定以及開始計時

  dispatcher.Interval = TimeSpan.FromMilliseconds(1000);

  dispatcher.Tick += Dispatcher_Tick;

  dispatcher.Start();

 

接下來就是MoveSnake函數的編寫了。

對於蛇的移動來說,其實用到的就是障眼法,分爲4步

  1. 移去蛇尾
  2. 在原先蛇頭的位置畫蛇身
  3. 移去原先的蛇頭
  4. 根據蛇頭原先的位置,在其行進方向一個單元格的位置重新畫一個蛇頭

 

具體實現代碼

        private void MoveSnake()

        {

            //移去最後一節身子

            GameArea.Children.Remove(snakeParts[0].uIElement);

            snakeParts.Remove(snakeParts[0]);

            //獲取原先蛇頭的位置,並重新畫一個身子

            double exHeadPosX = snakeParts[snakeParts.Count-1].point.X;

            double exHeadPosY = snakeParts[snakeParts.Count - 1].point.Y;

            DrawSnake_sub(false, exHeadPosX, exHeadPosY);

            //移去原先的蛇頭

            GameArea.Children.Remove(snakeParts[snakeParts.Count - 2].uIElement);

            snakeParts.Remove(snakeParts[snakeParts.Count - 2]);

            //重新畫一個蛇頭

            DrawSnake_sub(true, exHeadPosX+squareSize, exHeadPosY);

        }

經過測試,蛇就可以沿着向右的方向每隔1s移動一格了

 

2.3 鍵盤控制方向

首先在窗體上定義Key_Up事件

KeyUp="Window_KeyUp"

然後在事件處理函數裏定義不同的key值對應的操作

提示:對於貪喫蛇遊戲來說,不存在直接回頭的操作。

代碼如下:

        private void Window_KeyUp(object sender, KeyEventArgs e)

        {

            switch (e.Key)

            {

                case Key.Left:

                    if (snakeDirection!=SnakeDirection.right && snakeDirection != SnakeDirection.left)

                    {

                        snakeDirection = SnakeDirection.left;

                        MoveSnake();

                    }

                    break;

                case Key.Up:

                    if (snakeDirection!=SnakeDirection.down && snakeDirection != SnakeDirection.up)

                    {

                        snakeDirection = SnakeDirection.up;

                        MoveSnake();

                    }

                    break;

                case Key.Right:

                    if (snakeDirection != SnakeDirection.right && snakeDirection != SnakeDirection.left)

                    {

                        snakeDirection = SnakeDirection.right;

                        MoveSnake();

                    }

                    break;

                case Key.Down:

                    if (snakeDirection != SnakeDirection.down && snakeDirection != SnakeDirection.up)

                    {

                        snakeDirection = SnakeDirection.down;

                        MoveSnake();

                    }

                    break;

                default:

                    break;

            }

        }

根據在遊戲過程中獲取到的snakeDirection的值,我們把之前添加蛇頭的邏輯做了些修改,增加了方向的判斷

代碼如下:

//重新畫一個蛇頭

            switch (snakeDirection)

            {

                case SnakeDirection.left:

                    DrawSnake_sub(true, exHeadPosX - squareSize, exHeadPosY);

                    break;

                case SnakeDirection.up:

                    DrawSnake_sub(true, exHeadPosX , exHeadPosY - squareSize);

                    break;

                case SnakeDirection.right:

                    DrawSnake_sub(true, exHeadPosX + squareSize, exHeadPosY);

                    break;

                case SnakeDirection.down:

                    DrawSnake_sub(true, exHeadPosX , exHeadPosY + squareSize);

                    break;

                default:

                    break;

            }

這樣就實現了蛇根據鍵盤的輸入來進行移動的程序

實現效果如下:

2.4遊戲區隨機出現蛇果(不能出現在蛇身上)

原理:生成一個squaresize整數倍的數來定位蛇果的位置,然後通過canvas畫出來,當然蛇果的位置不能出現在蛇身上以及出遊戲邊界

 

實現代碼:

        private void GenerateFood()

        {

            start:

            Random random = new Random();

            double foodPosX = random.Next(0, (int)GameArea.ActualWidth / squareSize)*squareSize;

            double foodPosY = random.Next(0, (int)GameArea.ActualHeight / squareSize) * squareSize;

            foreach (var snakePart in snakeParts)

            {

                if (snakePart.point.X==foodPosX && snakePart.point.Y==foodPosY)

                {

                    goto start;

                }

            }

            Ellipse food = new Ellipse() { Width = squareSize, Height = squareSize };

            food.Fill = Brushes.Chocolate;

            GameArea.Children.Add(food);

            Canvas.SetLeft(food, foodPosX);

            Canvas.SetTop(food, foodPosY);

        }

 

實現效果如下

 

2.5碰撞監控

碰撞監控的效果:蛇與果實碰撞則果實消失,蛇身長度+1。如果蛇與邊界碰撞,遊戲結束

2.5.1 與果實碰撞

先來實現蛇與果實碰撞,蛇身長度+1的邏輯

思路:判斷蛇頭與蛇果的位置重合,則清除果實,重新生成果實,返回一個值,根據這個值來判斷是否需要去掉蛇尾

代碼實現:

        private int CollisionCheck()

        {

            if (snakeParts[snakeParts.Count-1].point.X==foodPosX && snakeParts[snakeParts.Count - 1].point.Y==foodPosY)

            {

                GameArea.Children.Remove(food);

                GenerateFood();

                return 1;

            }

            else

            {

                return 0;

            }

        }

原來的MoveSnake函數裏增加一個判斷條件,來決定是否需要砍掉蛇尾

代碼如下:

        private void MoveSnake()

        {

            if (CollisionCheck()!=1)

            {

                //移去最後一節身子

                GameArea.Children.Remove(snakeParts[0].uIElement);

                snakeParts.Remove(snakeParts[0]);

 

            }

實現效果如下:

2.5.2 與邊界或者蛇身碰撞

如果蛇頭與蛇身碰撞,或者蛇頭超出邊界,則遊戲結束。

在CollisionCheck方法裏添加如下代碼:

            else

            {

                foreach (var snakeBody in snakeParts.Take(snakeParts.Count - 1))

                {

                    if (snakeBody.point.X == snakeParts[snakeParts.Count - 1].point.X && snakeBody.point.Y == snakeParts[snakeParts.Count - 1].point.Y)

                    {

                        EndGame();

                    }

                }

                if (snakeParts[snakeParts.Count - 1].point.X >= GameArea.ActualWidth ||

                   snakeParts[snakeParts.Count - 1].point.X < 0 ||

                   snakeParts[snakeParts.Count - 1].point.Y >= GameArea.ActualHeight ||

                   snakeParts[snakeParts.Count - 1].point.Y < 0)

                {

                    EndGame();

                }

                return 0;

            }

併爲EndGame方法添加內容,當遊戲結束的時候,停止定時器,並且彈出提示框

        private void EndGame()

        {

            //dispatcher.Stop();

            dispatcher.IsEnabled = false;

            dispatcher.Stop();

            MessageBox.Show("遊戲結束","WPF貪喫蛇遊戲",MessageBoxButton.OK,MessageBoxImage.Warning);

        }

 

最終的效果

 

 

2.6 界面優化1

基本功能實現後,我們來對界面來美化一下。

首先我們重新設計下游戲結束的時候要彈出的窗體樣式

在Canvas裏添加如下代碼:

            <Border x:Name="bdr_EndGame" Visibility="Collapsed" Panel.ZIndex="1" BorderThickness="3" BorderBrush="AliceBlue" Width="400" Height="400" Margin="200" Background="Azure" Padding="100">

                <StackPanel>

                    <TextBlock FontSize="30" Foreground="Red" TextAlignment="Center" Margin="0,20">遊戲結束</TextBlock>

                    <TextBlock  FontSize="30" Foreground="Green" TextAlignment="Center" Margin="0,10">您的得分是:</TextBlock>

                    <TextBlock x:Name="txt_score" FontSize="30" Foreground="Black" TextAlignment="Center" Width="90"></TextBlock>

                </StackPanel>

            </Border>

然後我們得到如下效果

然後我們在後端替換下原來的messagebox.設定該border的屬性爲visual

bdr_EndGame.Visibility = Visibility.Visible;

爲了顯示最終的得分,我們需要在程序裏定義一個變量score,然後每次蛇頭與食物重合的時候,score+1,然後把這個值轉換成string類型,傳給txt_score.Text

txt_score.Text = Score.ToString();

最終當遊戲結束的時候,顯示的效果入下圖所示

 

接下來我們實現的功能是讓遊戲具有開始畫面,當用戶按下“S”鍵,遊戲開始。

當遊戲結束的時候,用戶按下”S”鍵,遊戲又重複開始。

 

首先我們設計下開始的畫面

對應的XMAL代碼如下:

            <Border x:Name="bdr_Welcome" Visibility="Visible" Panel.ZIndex="1" BorderThickness="3" BorderBrush="AliceBlue" Width="600" Height="600" Margin="100" Background="Azure" Padding="100">

                <StackPanel>

                    <TextBlock FontSize="50" Foreground="Red" TextAlignment="Center" Margin="0,20">WPF貪喫蛇</TextBlock>

                    <TextBlock FontSize="20" Foreground="Red" TextAlignment="Center" Margin="0,30" TextWrapping="Wrap">大多數遊戲都會通關,但貪喫蛇不一樣,像極了人的一生,不停奔波,不停索取,但,最終只會死亡</TextBlock>

                    <TextBlock  FontSize="20" Foreground="Green" TextAlignment="Center" Margin="0,40">“S”鍵開始這段結局已註定的遊戲</TextBlock>

                </StackPanel>

            </Border>

 

在程序後臺,我們定義一個變量isGameRunning來作爲遊戲的運行狀態。

我們首先來讓程序接受鍵盤S的輸入

case Key.S:

                    if (isGameRuning==false)

                    {

                         StartGame();

 

                    }

                    break;

當程序接收到鍵盤的key_up事件,並且是又S鍵觸發的

我們就執行StartGame方法

大體思路:如果蛇和果實都還有殘餘在畫布上,我們首先會清除這部分Ui元素,初始化遊戲,然後開始計時。

 

實現代碼如下:

        private void StartGame()

        {

            //歡迎畫面消失

            bdr_Welcome.Visibility = Visibility.Collapsed;

            //清除上一局遊戲裏的蛇身

            if (snakeParts.Count!=0)

            {

                int snakeLength = snakeParts.Count;

                for (int i = 0; i < snakeLength; i++)

                {

                    GameArea.Children.Remove(snakeParts[0].uIElement);

                    snakeParts.Remove(snakeParts[0]);

                }

            }

            //清除上一局遊戲裏的食物

            if (food!=null)

            {

                GameArea.Children.Remove(food);

                food = null;

            }

 

            bdr_EndGame.Visibility = Visibility.Collapsed;

 

            //初始方向l

            snakeDirection = SnakeDirection.right;

            snakeDirectionPre = SnakeDirection.right;

            //重新生成蛇身以及食物

            DrawSnake(startPos, snakeLength);

            GenerateFood();

            //開始計時

            dispatcher.Interval = TimeSpan.FromMilliseconds(500);

            dispatcher.Start();

            isGameRuning = true;

 

        }

 

到現在爲止,這已經是一個完整的WPF貪喫蛇程序了。

2.7 高分榜

對於一個遊戲來說,遊戲分數的記錄,以及高分榜的排序也是吸引玩家的關鍵,可以讓玩家有成就感,當他的名字出現在高分榜上。

現在我們就來實現這個功能

首先我們創建一個HighScore的類,代碼如下

    public class HighScore

    {

        public string Name { get; set; }

        public int Score { get; set; }

}

 

在後臺的定義下一個泛型集合highScoreList以及xmlName

        //高分榜

        List<HighScore> highScoreList = new List<HighScore>();

        //xml文件路徑

        string xmlName = "HighScoreList.xml";

接下來的思路是:當程序載入的時候,判斷在程序的路徑下是否存在這個名爲xml的文件,如果沒有就創建一個,如果有就讀取文件內容到highScoreList這個列表裏。

對應的代碼:

if (File.Exists(xmlName) == false)

            {

                CreateXMLFile();

            }

            else

            {

                StreamReader read = new StreamReader(xmlName);

                ReadXML(read);

            }

對應的CreateXMLFile方法和ReadXML的方法代碼:

CreateXMLFile方法

        private void CreateXMLFile()

        {

            //創建名爲xmlName的文件流

            Stream write = new FileStream(xmlName, FileMode.Create);

            //設定xml的內部格式

            GenerateXML(write);

        }

        private void GenerateXML(Stream write)

        {

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<HighScore>));

            

            xmlSerializer.Serialize(write, highScoreList);

         

            write.Close();

        }

 

ReadXMLFile方法

        private void ReadXML(StreamReader readStream)

        {

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<HighScore>));

           

            highScoreList = (List<HighScore>)xmlSerializer.Deserialize(readStream);

            highScoreList = new List<HighScore>(SortByScore(highScoreList));

            Item_TopList.ItemsSource = highScoreList.Take(5);

            readStream.Close();

        }

 

當遊戲結束的時候,需要判斷下這次的成績score是否在highScoreList這個集合的top5,如果是,需要彈出一個讓玩家輸入名字的對話框。不是則直接彈出成績的對話框。

實現代碼:

        private IOrderedEnumerable<HighScore> SortByScore(List<HighScore> highscorelist)

        {

           var   highScoreOrderList= highscorelist.OrderByDescending(x => x.Score);

            return highScoreOrderList;

        }

在我們程序載入並讀取XML文件的時候,我們會把highScoreList的元素按照score降序排列,並重新賦給highScoreList,當遊戲結束的時候,我們只需要比較這次的成績score和highScoreList[4].score的大小,如果大於則彈出輸入名字的對話框,不是則顯示成績

對應代碼:

            if (isGameRuning==false)

            {

                if (highScoreList.Count!=0 && score > highScoreList[4].Score)

                {

                    bdr_AddHighScore.Visibility = Visibility.Visible;

                }

 

 

            }

            else

            {

                bdr_TopList.Visibility = Visibility.Collapsed;

                bdr_AddHighScore.Visibility = Visibility.Collapsed;

            }

        }

 

現在我們設計下兩個界面,輸入姓名的對話框以及高分榜的排名

輸入姓名的對話框:

 

XMAL代碼:

            <Border x:Name="bdr_AddHighScore" Visibility="Visible" Panel.ZIndex="1" BorderThickness="3" BorderBrush="AliceBlue" Width="600" Height="600" Margin="100" Background="Azure" Padding="100">

                <StackPanel>

                    <TextBlock FontSize="50" Foreground="Red" TextAlignment="Center" Margin="0,20">恭喜進入高分榜</TextBlock>

                    <TextBlock FontSize="20" Foreground="Red" TextAlignment="Center" Margin="0,30" TextWrapping="Wrap">請輸入您的名字</TextBlock>

                    <TextBox x:Name="txt_PlayName"  FontSize="20" Foreground="Green" TextAlignment="Center" Margin="0,40" Width="200"></TextBox>

                    <Button FontSize="20" Foreground="Green"  Margin="0,10" Width="200" Background="Transparent" Click="btn_submit" >提交</Button>

                </StackPanel>

            </Border>

 

高分榜對話框:

 

對應的XMAL代碼:

            <Border x:Name="bdr_TopList"  Visibility="Visible" Panel.ZIndex="1" BorderThickness="3" BorderBrush="AliceBlue" Width="600" Height="600" Margin="100" Background="Azure" Padding="100">

                <StackPanel>

                    <TextBlock FontSize="50" Foreground="Red" TextAlignment="Center" Margin="0,20">高分榜</TextBlock>

                    <ItemsControl x:Name="Item_TopList" >

                        <ItemsControl.ItemTemplate>

                            <DataTemplate>

                                <DockPanel>

                                    <TextBlock DockPanel.Dock="Left" TextAlignment="Left" FontSize="30" Text="{Binding Name}"></TextBlock>

                                    <TextBlock DockPanel.Dock="Right" TextAlignment="Right" FontSize="30" Text="{Binding Score}"></TextBlock>

                                </DockPanel>

                            </DataTemplate>

                        </ItemsControl.ItemTemplate>

                    </ItemsControl>

                </StackPanel>

            </Border>

 

接下來就是輸入姓名對話框彈出後,我們需要把輸入的姓名以及對應的結果寫入highScoreList裏,輸入完成後,當按下提交按鈕,則會跳轉到高分榜的界面。再次按下“S”鍵,則遊戲重新開始

對應代碼:

        private void btn_submit(object sender, RoutedEventArgs e)

        {

            AddInfoToXML(txt_PlayName.Text);

 

            StreamReader read = new StreamReader(xmlName);

            ReadXML(read);

            bdr_TopList.Visibility = Visibility.Visible;

            bdr_AddHighScore.Visibility = Visibility.Collapsed;

        }

        private void AddInfoToXML(string name)

        {

            HighScore highScore = new HighScore() {Name = name,Score = score };

            highScoreList.Add(highScore);

            highScoreList = new List<HighScore>(SortByScore(highScoreList));

            Stream write= new FileStream(xmlName, FileMode.Open);

            GenerateXML(write);

        }

        private void GenerateXML(Stream write)

        {

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(List<HighScore>));

           

            xmlSerializer.Serialize(write, highScoreList);

         

            write.Close();

        }

這樣我們利用XML的數據存儲屬性就完成了高分榜功能的製作。像這樣數據量不大的情況下,沒有必要用專業的數據庫來做,XML輕量易操作,用在小型的程序裏特別適合

2.8 界面優化2

最後一點工作:我們美化下窗體。

隱去windows默認的窗體外框,重新在Canvas上Dock一個stackPanel

XMAL代碼如下:

        <StackPanel DockPanel.Dock="Top" Background="Black">

            <Grid>

                <Grid.ColumnDefinitions>

                    <ColumnDefinition Width="*"></ColumnDefinition>

                    <ColumnDefinition Width="*"></ColumnDefinition>

                    <ColumnDefinition Width="auto"></ColumnDefinition>

                </Grid.ColumnDefinitions>

                <Grid.RowDefinitions>

                    <RowDefinition Height="40"></RowDefinition>

                    <RowDefinition Height="40"></RowDefinition>

                </Grid.RowDefinitions>

 

                <TextBlock Grid.Row="0" Grid.Column="0" FontSize="30" Foreground="White" FontWeight="Bold">貪喫蛇遊戲</TextBlock>

                <TextBlock Grid.Row="0" Grid.Column="1" FontSize="30" Foreground="White" FontWeight="Bold">作者:Zombie</TextBlock>

                <Button Grid.Row="0" Grid.Column="2" FontSize="30" Background="Transparent" Foreground="White" Click="btn_Close">X</Button>

 

                <TextBlock Grid.Row="1" Grid.Column="0" FontSize="30" Foreground="Yellow" FontWeight="Bold"  x:Name="txt_current_score"></TextBlock>

                <TextBlock Grid.Row="1" Grid.Column="1" FontSize="30" Foreground="Yellow" FontWeight="Bold"  x:Name="txt_current_speed"></TextBlock>

            </Grid>

        </StackPanel>

 

界面效果如下:

 

並增加了遊戲難度,沒喫一個果實,速度提高50,最快是時間間隔100ms

實現代碼:

                speed = speed > 100 ? speed - 50 : 100;

                dispatcher.Interval = TimeSpan.FromMilliseconds(speed);

 

並最終在標題欄的第二行顯示出分數以及速度

效果如下:

高分榜:

 

3 總結

到這裏,我們就實現了一個比較完整的貪喫蛇遊戲。貪喫蛇遊戲在各個計算機語言設計中都是一個綜合性比較強的項目。其中涉及了泛型,集合,Lambda表達式,Canvas這些比較難的概念,也有動畫實現的小技巧。還涉及到利用XML進行數據的存儲,調用來實現高分榜的部分。WPF特有的 XMAL語言,可以很好的實現非常精緻的畫面,以及和後端代碼的分離。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章