C# 贪吃蛇

UML

image-20250104100105069

image-20250104100121568

image-20250104104405816

image-20250104104707355

面向对象的七大原则

image-20250104104814137

image-20250104104917108

单一职责原则

image-20250104110000198

开闭原则

image-20250104110042532

里氏替换原则

image-20250104110135611

依赖倒转原则

image-20250104110159280

迪米特法则

image-20250104110343799

接口隔离原则

image-20250104110434025

合成复用原则

image-20250104110546070

总结

image-20250104110637584

贪吃蛇小项目

image-20250104112202729

image-20250104113234225

image-20250105092004013

BeginOrEndScene

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.lesson1;
namespace 贪吃蛇.lesson1
{
   abstract class BeginOrEndScene : IsceneUpdate
    {
        protected int nowSelIndex = 0;
        protected string strTitle;
        protected string StrOne;
        public abstract void EnterJDoSomthing();
        public void Update()
        {
            // 开始或结束游戏逻辑
            //选择当前选项,监听键盘输入

            Console.ForegroundColor = ConsoleColor.White;
            // 显示标题
            Console.SetCursorPosition(Game.w/2-strTitle.Length,5);
            Console.Write(strTitle);
            Console.SetCursorPosition(Game.w / 2 - StrOne.Length, 8);
            Console.ForegroundColor = nowSelIndex==0?ConsoleColor.Red:ConsoleColor.White;
            Console.Write(StrOne);
            Console.SetCursorPosition(Game.w / 2 -4, 10);
            Console.ForegroundColor = nowSelIndex == 1 ? ConsoleColor.Red : ConsoleColor.White;
            Console.Write("结束游戏");
            switch (Console.ReadKey(true).Key)
            {
                case ConsoleKey.W:
                    --nowSelIndex;
                    if (nowSelIndex <0)
                    {
                        nowSelIndex = 0;
                    }
                    break;
                case ConsoleKey.A:
                    ++nowSelIndex;
                    if (nowSelIndex >1)
                    {
                        nowSelIndex = 1;
                    }
                    break;
                case ConsoleKey.S:
                    ++nowSelIndex;
                    if (nowSelIndex > 1)
                    {
                        nowSelIndex = 1;
                    }
                    break;
                case ConsoleKey.D:
                    --nowSelIndex;
                    if (nowSelIndex < 0)
                    {
                        nowSelIndex = 0;
                    }
                    break;
                case ConsoleKey.J:
                    EnterJDoSomthing();
                    break;


            }

            // 显示下方选项


            // 检测输入


        }

        
    }
}

BeginScene.cs

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


namespace 贪吃蛇.lesson1
{
    internal class BeginScene : BeginOrEndScene

    {
        public BeginScene() {
            strTitle = "贪吃蛇";
            StrOne = "开始游戏";
        }

        public override void EnterJDoSomthing()
        {
            // 按J键做什么
            if (nowSelIndex == 0)
            {
                Game.ChangeScene(E_SceneType.Game);
            }
            else {
                Environment.Exit(0);
            }
        }
    }
}

Draw

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

namespace 贪吃蛇.lesson1
{
    internal interface Draw

    {
        void Draw();
    }
}

EndScene

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

namespace 贪吃蛇.lesson1
{
    internal class EndScene : BeginOrEndScene
    {
        public EndScene() {
            strTitle = "结束游戏";
            StrOne = "回到开始界面";
                
        }
        public override void EnterJDoSomthing()
        {
            // 按J键做什么
            if (nowSelIndex == 0)
            {
                Game.ChangeScene(E_SceneType.Begin);
            }
            else
            {
                Environment.Exit(0);
            }
        }
    }
}

Food

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.lesson1;

namespace 贪吃蛇.lesson1
{
    internal class Food : GameObject
    {
        public Food(Snake snake) {

            RandomPos(snake);
        }

        public override void Draw()
        {
            Console.SetCursorPosition(pos.x, pos.y);
            Console.ForegroundColor = ConsoleColor.DarkCyan;
            Console.Write("卐");
        }
        // 随机位置的行为和蛇的位置有关系

        public void RandomPos( Snake snake) {
            // 得到蛇

            // 随机位置
            Random random = new Random();
            int x = random.Next(2, Game.w/2-1)*2;
            int y = random.Next(1, Game.h / 2 - 4);
            pos = new Position(x, y);
            // 得到蛇
            // 如果重合
            if (snake.CheckSamePos(pos))
            {
                RandomPos(snake);
            }

        }

    }
}

GameObject

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

namespace 贪吃蛇.lesson1
{
    abstract class GameObject : Draw
    {
        // 可以继承接口后,可以把接口中的行为抽象行为
        //供子类实现因为是抽象行为,所以子类中是必须去实现
        // 游戏对象位置
        public Position pos;
        public abstract void Draw();
      
    }
}

游戏主逻辑

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

namespace 贪吃蛇.lesson1
{
    enum E_SceneType
    { 
        /// <summary>
        /// 开始
        /// </summary>
        Begin,
        /// <summary>
        /// 游戏
        /// </summary>
        Game,
        /// <summary>
        /// 结束
        /// </summary>
        End
    
    }
    class Game
    {
        public const int w = 80;
        public const int h = 40;
        public static IsceneUpdate nowSecene;

        public Game()
        {
            Console.CursorVisible = false;
            Console.SetWindowSize(w, h);
            Console.SetBufferSize(w, h);
            ChangeScene(E_SceneType.Begin);

        
        }
        public void Start() {
            while (true)
            {
                if (nowSecene != null)
                {
                    nowSecene.Update();
                }

            }
        }
        public static void ChangeScene(E_SceneType type)
        {
            // 切场景之前把上一个场景绘制清理
            Console.Clear();
            switch (type)
            {
                case E_SceneType.Begin:
                    nowSecene = new BeginScene();

                    break;
                case E_SceneType.Game:
                    nowSecene = new GameScene();
                    break;
                case E_SceneType.End:
                    nowSecene = new EndScene();
                    break;
               
            }
        }

    }
    
}

GameScene.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.lesson1;

namespace 贪吃蛇.lesson1
{
   
    class GameScene: IsceneUpdate
         
    {
      
        int updateIndex = 0;
        int SpeedIndex = 0;
        
        Map map;
        Snake snake;
        Food food;
        public GameScene() { 
        
            map = new Map();
            snake = new Snake(40,10);
            food = new Food(snake);
        }
        public void Update() {
         
            if (updateIndex % 100000 == 0)
            {
                map.Draw();
                food.Draw();
                snake.Move();
                snake.Draw();
                // 检测是否撞墙
                if (snake.CheckEnd(map))
                {
                    Game.ChangeScene(E_SceneType.End);
                }
                snake.CheckEatFood(food);
               
                updateIndex = 0;
            }
            updateIndex += 1;

            // 在控制台中检测玩家输入,让程序不被卡主
            if (Console.KeyAvailable)
            { 
                // 检测输入输出不能在间隔帧里面处理
                switch (Console.ReadKey(true).Key)
                {
                    case ConsoleKey.W:
                        snake.ChangDir(E_MoveDir.up);
                        break;
                    case ConsoleKey.A:
                        snake.ChangDir(E_MoveDir.left);
                        break;
                    case ConsoleKey.S:
                        snake.ChangDir(E_MoveDir.down);
                        break;
                    case ConsoleKey.D:
                        snake.ChangDir(E_MoveDir.right);
                        break;

                }

            }
        }
        // 
    }
}

IsceneUpdate 场景更新接口

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

namespace 贪吃蛇.lesson1
{
    // 场景更新接口
    internal interface IsceneUpdate
    {
        void Update();

    }
}

地图Map

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using 贪吃蛇.lesson1;

namespace 贪吃蛇.lesson1
{
    internal class Map:Draw
    {
        public Wall[] walls;
        public Map() { 
         walls = new Wall[Game.w+(Game.h-3)*2 ];
            int index = 0;
            for (int i = 0; i < Game.w; i+=2)
            {
                walls[index] = new Wall(i,0);
                index++;
            }
            for (int i = 0; i < Game.w; i+=2)
            {
                walls[index] = new Wall(i, Game.h-2);
                index++;

            }
            for (int i = 1; i < Game.h-2; i++)
            {
                walls[index] = new Wall(0,i);
                index++;
            }
            for (int i = 1; i < Game.h - 2; i++)
            {
                walls[index] = new Wall(Game.w-2, i);
                index++;
            }

        }

        public void Draw()
        {
            for (int i = 0; i < walls.Length; i++)
            {
                walls[i].Draw();
            }
           
        }
    }
}

坐标Position

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

namespace 贪吃蛇.lesson1
{
    internal struct Position
    {
        public int x;
        public int y;
        public Position(int x, int y) { 
            this.x = x; this.y = y;
        }
        // 各个游戏对象都会去比较位置是不是重合
        public static bool operator ==(Position a, Position b)
        {
            if (a.x == b.x && a.y == b.y) return true;
            return false;
        }
        public static bool operator !=(Position a, Position b)
        {
            if (a.x == b.x && a.y == b.y) return true;
            return false;
        }
    }
    
}

主接口

using System;
using 贪吃蛇.lesson1;
namespace 贪吃蛇;
class Program
{
    static void Main(string[] args)
    {
        Game games = new Game();
        games.Start();
        //games.ChangeScene(E_SceneType.Game);
   


    }
}

蛇类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.lesson1;
namespace 贪吃蛇.lesson1
{
    enum E_MoveDir
    {
        /// <summary>
        /// 上
        /// </summary>
        up,
        /// <summary>
        /// 下
        /// </summary>
        down,
        /// <summary>
        /// 左
        /// </summary>
        left,
        /// <summary>
        /// 右
        /// </summary>
        right

    }
    internal class Snake : Draw
    {


        SnakeBody[] bodys;
        //记录蛇身体长度
        int nowNum;
        E_MoveDir dir;
        public Snake(int x, int y)
        {
            bodys = new SnakeBody[10000];
            bodys[0] = new SnakeBody(E_SnakeBody_Type.Head, x, y);
            nowNum = 1;
            dir = E_MoveDir.right;

        }
        public void Draw()
        {
            for (int i = 0; i < nowNum; i++)
            {
                bodys[i].Draw();
            }
        }
        public void Move()
        {
            // 擦除最后一个位置
            SnakeBody lastBody = bodys[nowNum - 1];
            Console.SetCursorPosition(lastBody.pos.x, lastBody.pos.y);
            // 擦屁股
            Console.Write("   ");


            // 在蛇头移动之前,从蛇尾开始,不停的让后一个位置等于前一个位置
            for (int i = nowNum-1; i > 0; i--)
            {
                bodys[i].pos = bodys[i-1].pos;
            }

            switch (dir)
            {
                case E_MoveDir.up:
                    --bodys[0].pos.y;
                    break;
                case E_MoveDir.down:
                    ++bodys[0].pos.y;
                    break;
                case E_MoveDir.left:
                    bodys[0].pos.x -= 2;
                    break;
                case E_MoveDir.right:
                    bodys[0].pos.x += 2;
                    break;
                default:
                    break;
            }


        }
        // 改变方向
        public void ChangDir(E_MoveDir dir)
        {

            // 只有头部时候可以直接左转右,右转左,上转下,下转上
            //有身体时,这种情况就不能直接转
            if (dir == this.dir || nowNum > 1 &&
                dir == E_MoveDir.left && dir == E_MoveDir.right ||
                dir == E_MoveDir.right && dir == E_MoveDir.left ||
                dir == E_MoveDir.up && dir == E_MoveDir.down ||
                dir == E_MoveDir.down && dir == E_MoveDir.up
               )
            {
                return;
            }
            this.dir = dir;

        }

        // 撞墙撞身体
        public bool CheckEnd(Map map)
        {
            for (int i = 0; i < map.walls.Length; i++)
            {
                if (bodys[0].pos == map.walls[i].pos)
                {
                    return true;
                }
            }
            for (int i = 1; i < nowNum; i++)
            {
                if (bodys[0].pos == bodys[i].pos)
                {
                    return true;
                }

            }
            return false;
        }
        //吃食物
        // 通过传入一个位置判断这个位置是否和蛇重合
        public bool CheckSamePos(Position position)
        {
            for (int i = 0; i < nowNum; i++)
            {
                if (bodys[i].pos == position)
                {
                    return true;
                }

            }
            return false;


        }
        public void CheckEatFood(Food food)
        {
            if (bodys[0].pos == food.pos ) {
                // 吃到了就应该让食物位置随机,增加蛇的身体长度
                food.RandomPos(this);
                ADDBody();
               

            }
           
           

        }
        // 长身体
        private void ADDBody() {
            SnakeBody frontBody = bodys[nowNum-1];
            // 先长

            bodys[nowNum] = new SnakeBody(E_SnakeBody_Type.Body,frontBody.pos.x,frontBody.pos.y);
            // 加长度
            ++nowNum;
        }
    }
}

蛇身体

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.lesson1;

namespace 贪吃蛇.lesson1
{
    /// <summary>
    /// 蛇身体类型
    /// </summary>
    enum E_SnakeBody_Type
    { 
        /// <summary>
        /// 头
        /// </summary>
       Head,
       /// <summary>
       /// 身体
       /// </summary>
       Body
        
    }

    internal class SnakeBody : GameObject
    {
        private E_SnakeBody_Type Type;
        public SnakeBody( E_SnakeBody_Type type ,int x, int y ) { 
            //
            this.Type = type;
            this.pos = new Position(x,y);
        }
       

        public override void Draw()
        {
            Console.SetCursorPosition(pos.x,pos.y );
            Console.ForegroundColor = Type == E_SnakeBody_Type.Head ? ConsoleColor.Yellow : ConsoleColor.Green;
            Console.Write(Type == E_SnakeBody_Type.Head ? "●" : "◎");



        }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using 贪吃蛇.lesson1;

namespace 贪吃蛇.lesson1
{
    internal class Wall : GameObject
    {

        public  Wall(int x ,int y)
        {
            pos = new Position(x,y);
        }
       

        public override void Draw()
        {
            Console.SetCursorPosition(pos.x,pos.y);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine("▆");
        }
    }
}

posted @ 2025-01-05 09:27  #卧龙先生#  阅读(6)  评论(0编辑  收藏  举报