欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【C#】贪吃蛇小游戏

程序员文章站 2022-07-02 17:52:19
...

【C#】贪吃蛇小游戏

自学了几天C#,尝试写了一个贪吃蛇小游戏,比较详细地做了注释,实现:

(1)贪吃蛇基本功能

(2)长按加速

(3)计分板


XAML代码及界面

<Window x:Class="贪吃蛇.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:贪吃蛇"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="400" ResizeMode="NoResize" KeyDown="Window_KeyDown" KeyUp="Window_KeyUp" >
    <Canvas x:Name="map" Margin="0" Background="White">
        <Label x:Name="showScore" Canvas.Left="340" Canvas.Top="10" Height="27" Width="44" Background="#FFC7C7C7"/>
    </Canvas>
</Window>
【C#】贪吃蛇小游戏


C#代码


using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;

namespace 贪吃蛇
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {

        DispatcherTimer timer = new DispatcherTimer();//适用于UI界面的计时器
        DispatcherTimer keytimer = new DispatcherTimer();//用于判定键盘长按

        //界面300*400
        const int SIDE = 10;//每个格子的边长
        int row;//行数
        int column;//列数
        int score;//得分

        Random rNumber = new Random();//随机数

        Border food = new Border();//食物

        Snake snake = new Snake();//生成一条蛇

        public MainWindow()//初始化即主程序
        {
            InitializeComponent();//初始化窗体内容

            //行列数生成
            row = 300 / SIDE;
            column = 400 / SIDE;

            score = 0;//分数初始为0

            //食物初始化
            food.Width = food.Height = SIDE;//食物大小
            food.CornerRadius = new CornerRadius(90);//通过边缘角度设置食物形状:圆形
            food.Background = new RadialGradientBrush(Colors.Black, Colors.Black);//食物颜色:黑色
            //生成第一颗食物
            Canvas.SetLeft(food, rNumber.Next(0, column - 4) * SIDE);
            Canvas.SetTop(food, rNumber.Next(0, row - 4) * SIDE);
            map.Children.Add(food);
            Canvas.SetZIndex(food,1);//设置食物所在层数

            //计时器设置
            timer.Interval = TimeSpan.FromMilliseconds(200);//设置计时器事件间隔,即界面刷新速度,直接设置
            timer.Start();//计时器启动
            timer.Tick += timer_Tick;

            //蛇位置初始化            
            Canvas.SetLeft(snake[0], 2 * SIDE);Canvas.SetTop(snake[0], 0); map.Children.Add(snake[0]);
            Canvas.SetZIndex(snake[0], 2);//设置蛇头所在层数
            Canvas.SetLeft(snake[1], 1 * SIDE); Canvas.SetTop(snake[1], 0); map.Children.Add(snake[1]);
            Canvas.SetLeft(snake[2], 0); Canvas.SetTop(snake[2], 0); map.Children.Add(snake[2]);//记得“map.Children.Add”把元素加入窗口

            //得分板初始化
            showScore.Content = score;
        }

        //新食物生成
        public void NewFoodGenerate()
        {
            //删除已存在食物
            map.Children.Remove(food);
            //随机生成食物位置
            Canvas.SetLeft(food, rNumber.Next(0, column - 4) * SIDE);
            Canvas.SetTop(food, rNumber.Next(0, row - 4) * SIDE);
            //将食物加入Canvas
            map.Children.Add(food);
            //本应加入程序防止食物生成在体内,但性能可能有限制
        }

        //计时器每一个计时周期内的时间处理程序
        void timer_Tick(object sender, EventArgs e)
        {            
            //蛇身自动移动
            for (int n = snake.Count - 1; n >= 1; n--)
            {
                //吃食物增长长度
                if ((Canvas.GetLeft(snake[0]) == Canvas.GetLeft(food)) && (Canvas.GetTop(snake[0]) == Canvas.GetTop(food)))
                {
                    snake.Add();
                    map.Children.Add(snake[snake.Count - 1]);
                    NewFoodGenerate();
                    n = snake.Count - 1;
                    score++;
                    showScore.Content = score;//更改得分
                }
                Canvas.SetLeft(snake[n], Canvas.GetLeft(snake[n - 1]));
                Canvas.SetTop(snake[n], Canvas.GetTop(snake[n - 1]));                
            }
            
            //蛇头移动
            switch (snake[0].Tag.ToString())
            {
                case "W":
                    Canvas.SetTop(snake[0], Canvas.GetTop(snake[0])-SIDE);                                      
                    break;//待拓展出错处理程序
                case "A":
                    Canvas.SetLeft(snake[0], Canvas.GetLeft(snake[0]) - SIDE);
                    break;
                case "S":
                    Canvas.SetTop(snake[0], Canvas.GetTop(snake[0]) + SIDE);
                    break;
                case "D":
                    Canvas.SetLeft(snake[0], Canvas.GetLeft(snake[0]) + SIDE);
                    break;
            }
            //最后再检测是否失败
            if (Fail())
            {
                MessageBox.Show($"最终得分:{score}");
                timer.Stop();
                Close();
            }
        }

        //失败鉴定程序
        public bool Fail()
        {
            //碰壁
            if(Canvas.GetLeft(snake[0])<0|| Canvas.GetLeft(snake[0])> (column - 4) * SIDE
                || Canvas.GetTop(snake[0])<0|| Canvas.GetTop(snake[0])> (row - 4) * SIDE)
            {                
                return true;
            }
            //碰到自己
            for(int n = 1; n < snake.Count; n++)
            {
                if(Canvas.GetLeft(snake[0])== Canvas.GetLeft(snake[n])&& Canvas.GetTop(snake[0])== Canvas.GetTop(snake[n]))
                {                   
                    return true;
                }                    
            }
            return false;
        }

        //获取键盘值,输入则得值
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            string key = e.Key.ToString();//一个事件间隔内只能输入一个键
            if (key == "W" && snake[0].Tag.ToString() != "S")
            {
                snake[0].Tag = "W";
            }
            if (key == "A" && snake[0].Tag.ToString() != "D")
            {
                snake[0].Tag = "A";
            }
            if (key == "S" && snake[0].Tag.ToString() != "W")
            {
                snake[0].Tag = "S";
            }
            if (key == "D" && snake[0].Tag.ToString() != "A")
            {
                snake[0].Tag = "D";
            }

            keytimer.Interval = TimeSpan.FromMilliseconds(400);//400ms后开始加速
            keytimer.IsEnabled=true;//计时器启动
            keytimer.Tick += keytimer_Tick;//事件关联到事件处理程序上
        }
        //加速事件处理程序
        void keytimer_Tick(object sender, EventArgs e)
        {
            timer.Interval = TimeSpan.FromMilliseconds(100);//加速
        }
        //结束加速
        private void Window_KeyUp(object sender, KeyEventArgs e)
        {
            timer.Interval = TimeSpan.FromMilliseconds(200);//还原速度
            keytimer.IsEnabled=false;
        }
    }

    public class Snake : CollectionBase//继承链表类
    {
        const int SIDE = 10;//每个格子的边长

        //生成蛇节点
        public Border CreateSnakeNode()
        {
            Border snakeNode = new Border();
            snakeNode.Width = snakeNode.Height = SIDE;
            snakeNode.Background = new RadialGradientBrush(Colors.Red, Colors.Red);
            return snakeNode;
        }

        //重载Add,贪吃蛇游戏只需自动增加相同的节点即可
        public void Add()
        {
            List.Add(CreateSnakeNode());
        }

        //初始化的蛇有三个节点
        public Snake()
        {
            Add();
            Add();
            Add();
            this[0].Background = new RadialGradientBrush(Colors.White,Colors.Red);//标记蛇头
            this[0].Tag = "D";//初始蛇向右走
        }

        //重载[]
        public Border this[int nodeIndex]
        {
            get { return (Border)List[nodeIndex]; }
        }
    }
}


改进:可以做些界面联动,AI

 

参考:

Hui110110  C#中的贪吃蛇

http://blog.csdn.net/hui110110/article/details/52431657

 

Yang-Fei  [C#].NET中几种Timer的使用

https://www.cnblogs.com/yang-fei/p/6169089.html

 

绿意无痕  C# WPF Border控件总结

http://blog.csdn.net/lvyiwuhen/article/details/53212450

 

yongh701C#】按钮长按

http://blog.csdn.net/yongh701/article/details/50134379