C#贪吃蛇

没事的情况下,写了个C#的贪吃蛇,虽然有点丑,不过基本功能总算完成了,以后再慢慢改进吧。

首先是开始前的界面:



运行中的画面,蓝色代表蛇身,红色代表食物(确实有点丑)


菜单栏中增添了一些功能,在Open中有游戏开始于退出的功能,在Setting中有难度选择与背景音乐播放的功能,另外贪吃蛇还支持暂停与继续功能对应的键盘P(即按P键可以实现暂停功能,再按一次,可实现恢复),空格键有加速功能~

应该没特别大的BUG,还在完善中,有机会我再一步一步完善下,尽量使得其美观。

注意:

1、关于解决屏幕更新闪烁的问题,我新建了个NewPanel类,然后设置了其中的一些参数(网上找到的解决方法)

2、关于蛇的移动,我主要是改变移动方向来实现键盘的操作,也就是说蛇始终在保持自动移动。

部分代码(代码比较丑,请见谅):

NewPanel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SnackGame
{
    public class NewPanel:Panel
    {
        public NewPanel()
        {
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.UserPaint, true);
        }
    }
}

Node(相当于坐标):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SnackGame
{
    public class Node
    {
        private int x;
        private int y;
        public int X { get { ;return x; } }
        public int Y { get { ; return y; } }
        public Node(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

    }
}

Snack类(游戏的核心部分):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;

namespace SnackGame
{
    public class Snack
    {
        public delegate void UpdateResult();
        static int[] movex = { 0, 20, 0, -20 }, movey = { -20, 0, 20, 0 };
        public LinkedList<Node> s;
        public LinkedList<Node> food;
        private List<Node> r;
        private int Height;
        private int Width;
        private bool[,] issnack;
        private bool[,] isfood;
        private int sleeptime=0;
        private Random ran;
        public int LastDirect;
        private bool iswork;
        public UpdateResult Update;
        public UpdateResult Wait;
        public Thread SnackStart;
        public bool Iswork { get { return iswork; } set { iswork = value; } }
        public int SleepTime
        {
            get { return sleeptime; }
            set
            {
                if (value > 0)
                    sleeptime = value;
            }
        }
        public Snack(int Height, int Width)
        {
            s = new LinkedList<Node>();
            food = new LinkedList<Node>();
            r = new List<Node>();
            ran = new Random();
            this.Height = Height;
            this.Width = Width;
            InitSnack();
        }
        public Snack()
        {
            s = new LinkedList<Node>();
            food = new LinkedList<Node>();
            r = new List<Node>();
        }
        private void InitSnack()
        {
            s.AddFirst(new Node((ran.Next() % (Width / 20-1) + 1) * 20, (ran.Next() % (Height / 20-1) + 1) * 20));
            issnack = new bool[Height, Width];
            isfood = new bool[Height, Width];
            LastDirect = ran.Next() % 4;
            while (IsLost(s.First().X + movex[LastDirect], s.First().Y + movey[LastDirect]))
                LastDirect = ran.Next() % 4;
            iswork = false;
            GetFoodPosition();
        }
        private void GetFoodPosition()
        {
            for (int i = 0; i < Height - 1; i += 20)
                for (int j = 0; j < Width - 1; j += 20)
                {
                    if (issnack[i, j])
                        continue;
                    r.Add(new Node(i, j));
                }
            while (true)
            {
                Node ita = r[ran.Next() % r.Count];
                if (!issnack[ita.Y, ita.X])
                {
                    isfood[ita.Y, ita.X] = true;
                    food.AddFirst(ita);
                    break;
                }
            }
        }
        public void Add(Node p)
        {
            s.AddFirst(p);
            issnack[p.Y, p.X] = true;
        }
        public void Del()
        {
            issnack[s.Last().Y, s.Last().X] = false;
            s.RemoveLast();
        }
        public void Move(int pos)
        {
            lock (this)
            {
                int x = s.First().X;
                int y = s.First().Y;
                Console.WriteLine("xxx " + x + " " + y);
                if (IsLost(x + movex[pos], y + movey[pos]))
                {
                    MessageBox.Show("You are Lost!");
                    iswork = false;
                    return;
                }
                Add(new Node(x + movex[pos], y + movey[pos]));
                if (isfood[y + movey[pos], x + movex[pos]])
                {
                    isfood[y + movey[pos], x + movex[pos]] = false;
                    food.Clear();
                    GetFoodPosition();
                }
                else
                    Del();
                Update();
            }
        }
        public void Work()
        {
            while (iswork)
            {
                Wait();
                Move(LastDirect);
                Thread.Sleep(200);
                
            }
        }
        public bool IsLost(int x, int y)
        {
            if (x < 0 || y < 0 || y >= Width-20 || x >= Height-20 || issnack[y, x])
                return true;
            return false;
        }
    }
}

界面部分:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Media;

namespace SnackGame
{
    public partial class MainWindow : Form
    {
        const int pos = 20;
        Snack snack;
        Random ran;
        Thread ThreadSnackGame;
        private System.Windows.Forms.Timer tm=new System.Windows.Forms.Timer();
        public AutoResetEvent autoEvent=new AutoResetEvent(false);
        private SoundPlayer soud;
        private bool isStop;
        private bool musicOn;
        public MainWindow()
        {
            InitializeComponent();
            SetStyle(ControlStyles.UserPaint, true);
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            panel_Map.Size = new Size(Height, Width);
            snack = new Snack();
            panel_Map.Invalidate();
            ThreadSnackGame = new Thread(new ThreadStart(snack.Work));
            ProgressBar.CheckForIllegalCrossThreadCalls = false;
            tm.Interval = 1;
            tm.Tick += new EventHandler(tm_Tick);
            ran = new Random();
            ChangePanelSize(401, 401);
            musicOn = false;
            soud = new SoundPlayer("BackgroundMusic.wav");
        }
        private void Wait()
        {
            autoEvent.WaitOne();
        }
        private void tm_Tick(object sender, EventArgs e)
        {
            autoEvent.Set();
        }
        private void ChangePanelSize(int Height, int Width)
        {
            panel_Map.Size = new Size(Height, Width);
        }
        private void InitSnackGame()
        {
            snack = new Snack(panel_Map.Height, panel_Map.Width);
            ThreadSnackGame.Abort();
            ThreadSnackGame = new Thread(new ThreadStart(snack.Work));
            snack.Update = new Snack.UpdateResult(UpdatePanel);
            snack.Wait = new Snack.UpdateResult(Wait);
            ThreadSnackGame.IsBackground = true;
            isStop = false;

        }
        private void UpdatePanel()
        {
            panel_Map.Invalidate();
        }
        private void SpeedUp()
        {
            snack.SleepTime /= 4;
            Thread.Sleep(200);
            snack.SleepTime *= 4;
        }
        private void Stop()
        {
            isStop = true;
            tm.Stop();
        }
        private void Continue()
        {
            isStop = false;
            tm.Start();
        }
        private void startToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            tm.Start();
            InitSnackGame();
            snack.Iswork = true;
            ThreadSnackGame.Start();
        }

        private void panel_Map_Paint(object sender, PaintEventArgs e)
        {
            int num = 0;
            Graphics g = e.Graphics;
            Pen pen = new Pen(Color.Black, 1);
            g.DrawLine(pen, 0, 0, 500, 0);
            Point[] point_st = new Point[panel_Map.Width / 20 + panel_Map.Height / 20 + 5];
            Point[] point_ed = new Point[panel_Map.Height / 20 + panel_Map.Width / 20 + 5];
            for (int i = 0; i < panel_Map.Width; i += pos)
            {
                point_st[num] = new Point(i, 0);
                point_ed[num++] = new Point(i, panel_Map.Height);
            }
            for (int i = 0; i < panel_Map.Height; i += pos)
            {
                point_st[num] = new Point(0, i);
                point_ed[num++] = new Point(panel_Map.Width, i);
            }
            for (int i = 0; i < point_st.Length; i++)
                g.DrawLine(pen, point_st[i], point_ed[i]);
            foreach (Node node in snack.s)
                g.FillEllipse(Brushes.Blue, node.X, node.Y, 20, 20);
            foreach (Node node in snack.food)
                g.FillEllipse(Brushes.Red, node.X, node.Y, 20, 20);
        }
        private void MainWindow_KeyDown(object sender, KeyEventArgs e)
        {
            int nowdirect = -1;
            if (e.KeyCode == Keys.Space)
            {
                SpeedUp();
                return;
            }
            if (e.KeyCode == Keys.P)
            {
                if (isStop)
                {
                    Continue();
                    return;
                }
                Stop();
                return;
                
            }
            switch (e.KeyCode)
            {
                case Keys.Up: nowdirect = 0; break;
                case Keys.Right: nowdirect = 1; break;
                case Keys.Down: nowdirect = 2; break;
                case Keys.Left: nowdirect = 3; break;
                default: return;
            }
            if (snack.LastDirect != nowdirect && Math.Abs(nowdirect - snack.LastDirect) != 2)
            {
                panel_Map.Invalidate();
                snack.LastDirect = nowdirect;
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void easyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ChangePanelSize(401, 401);
            midToolStripMenuItem.Checked = false;
            hardToolStripMenuItem.Checked = false;

        }

        private void midToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ChangePanelSize(501, 501);
            easyToolStripMenuItem.Checked = false;
            hardToolStripMenuItem.Checked = false;
        }

        private void hardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ChangePanelSize(601, 601);
            easyToolStripMenuItem.Checked = false;
            midToolStripMenuItem.Checked = false;
        }

        private void MusicToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (musicOn == false)
            {
                musicOn = true;
                soud.PlayLooping();
                return;
            }
            soud.Stop();
            musicOn = false;
        }
        
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值