C#实践小游戏--俄罗斯方块

发布于:2025-06-27 ⋅ 阅读:(19) ⋅ 点赞:(0)

整体游戏架构
​​​​​

游戏主循环(Game)
├─ 场景系统
│  ├─ 开始场景(BeginScene)
│  ├─ 游戏场景(GameScene)
│  └─ 结束场景(EndScene)

├─ 方块系统
│  ├─ 方块控制器(BlockWorker)
│  ├─ 方块形态数据(BlockInfo)
│  └─ 绘制单元(DrawObject)

├─ 地图系统(Map)
├─ 输入系统(InputCheak)
├─ 坐标系统(Position)
└─ 接口规范(IDraw, ISceneUpdate)

这个俄罗斯方块游戏采用经典的三层架构:

  1. 表现层:场景渲染、用户输入

  2. 逻辑层:游戏规则、方块行为、碰撞检测

  3. 数据层:方块形态数据、地图状态、坐标计算

各模块通过接口解耦,实现了良好的扩展性和可维护性。

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

namespace 俄罗斯方块
{
    interface ISceneUpdate
    {
        void Update();
    }
}

ISceneUpdate.cs

  • 作用:场景更新接口

  • 核心功能

    • 定义场景更新接口Update()

    • 确保所有场景实现统一的更新逻辑

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

namespace 俄罗斯方块
{
    abstract class BeginOrEndBaseScene:ISceneUpdate
    {
        protected int selIndex = 0;
        protected string strTilte;
        protected string strOne;

        public abstract void EnterJDoing();
        public void Update()
        {
            //开始和结束场景的游戏逻辑
            //选择当前的选项,然后监听键盘输入wsj
            //后续在控制台输出的文本都会显示为白色,直至再次对ForegroundColor属性进行修改
            Console.ForegroundColor = ConsoleColor.White;
            //显示标题
            Console.SetCursorPosition(Game.w / 2 - strTilte.Length, 5);
            Console.Write(strTilte);
            //显示下方的选项
            Console.SetCursorPosition(Game.w / 2 - strOne.Length, 8);
            Console.ForegroundColor = selIndex == 0 ? ConsoleColor.Red : ConsoleColor.White;
            Console.Write(strOne);
            Console.SetCursorPosition(Game.w / 2 - 4, 10);
            Console.ForegroundColor = selIndex == 1 ? ConsoleColor.Red : ConsoleColor.White;
            Console.Write("结束游戏");
            //检测输入
            switch (Console.ReadKey(true).Key)
            {
                case ConsoleKey.W:
                    --selIndex;
                    if (selIndex < 0)
                        selIndex = 0;
                    break;
                case ConsoleKey.S:
                    ++selIndex;
                    if (selIndex > 1)
                        selIndex = 1;
                    break;
                case ConsoleKey.J:
                    EnterJDoing();
                    break;
            }
        }
    }
}

BeginOrEndBaseScene.cs

  • 作用:游戏开始/结束场景的抽象基类

  • 核心功能

    • 处理场景选择逻辑(W/S键选择选项)

    • 显示标题和选项文本

    • 定义抽象方法EnterJDoing()供子类实现具体行为

    • 统一管理场景的输入处理和界面绘制

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

namespace 俄罗斯方块
{

    class BeginScene : BeginOrEndBaseScene
    {
        public BeginScene ()
        {
            strTilte = "俄罗斯方块";
            strOne = "开始游戏";
        }
        public override void EnterJDoing()
        {
            if(selIndex ==0)
            {
                Game.ChangeScene(E_SceneType.Game);
            }
            else
            {
                Environment.Exit(0);
            }
        }
    }
}

BeginScene.cs

  • 作用:游戏开始场景

  • 核心功能

    • 继承自BeginOrEndBaseScene

    • 设置开始界面文本("俄罗斯方块"、"开始游戏")

    • 实现开始游戏和退出游戏的功能选择逻辑

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

namespace 俄罗斯方块
{
    class EndScene : BeginOrEndBaseScene
    {
        public EndScene()
        {
            strTilte = "游戏结束";
            strOne = "回到开始界面";
        }
        public override void EnterJDoing()
        {
            if(selIndex ==0)
            {
                Game.ChangeScene(E_SceneType.Begin);
            }
            else
            {
                Environment.Exit(0);
            }
        }
    }
}


EndScene.cs

  • 作用:游戏结束场景

  • 核心功能

    • 继承自BeginOrEndBaseScene

    • 设置结束界面文本("游戏结束"、"回到开始界面")

    • 实现返回开始界面或退出游戏的功能

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

namespace 俄罗斯方块
{
    interface IDraw
    {
        void Draw();
    }
}

 IDraw.cs

  • 作用:绘制接口

  • 核心功能

    • 定义统一的绘制接口Draw()

    • 确保所有可绘制对象实现统一接口
       

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

namespace 俄罗斯方块
{
    enum E_SceneType
    {
        Begin,
        Game,
        End,
    }
    class Game
    {
        //要想得到控制台的数值,就要把Game类中的成员用const修饰为常量,方便其他类使用
        public const int w = 50;
        public const int h = 35;

        public static ISceneUpdate nowScene;

        public Game ()
        {
            //隐藏光标
            Console.CursorVisible = false;
            //设置游戏窗口大小
            Console.SetWindowSize(w, h);
            //设置缓冲区
            Console.SetBufferSize(w, h);

            ChangeScene(E_SceneType.Begin);
        }
        public void StartGame()
        {
            while (true)
            {
                if (nowScene !=null)
                {
                    nowScene.Update();
                }
            }
        }
        public static void ChangeScene(E_SceneType type)
        {
            //切换场景之前先清理之前场景内容
            Console.Clear();
            switch (type)
            {
                case E_SceneType.Begin:
                    nowScene = new BeginScene();
                        break;
                case E_SceneType.Game:
                    nowScene = new GameScene();
                    break;
                case E_SceneType.End:
                    nowScene = new EndScene();
                    break;
            }
        }
    }
}

Game.cs

  • 作用:游戏主控制器

  • 核心功能

    • 初始化游戏窗口和缓冲区

    • 管理场景切换(开始→游戏→结束)

    • 维护游戏主循环

    • 提供全局常量(窗口宽高)

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

namespace 俄罗斯方块
{
    class GameScene : ISceneUpdate
    {
        Map map;
        BlockWorker blockWorker;
        //Thread inputThread;
        //bool isRunning = true;
        public GameScene ()
        {
            map = new Map(this);
            blockWorker = new BlockWorker();
            //inputThread = new Thread(CheakInputThread);
            设置成后台线程,生命周期由主线程决定
            //inputThread.IsBackground = true;
            //inputThread.Start();
            InputCheak.Instance.action += CheakInputThread;
        }
        private void CheakInputThread()
        {
            //while (true)
            //{
                if (Console.KeyAvailable)
                {
                    //为了避免影响主线程,在输入 后加锁
                    lock(blockWorker)
                    {
                        switch (Console.ReadKey(true).Key)
                        {
                            case ConsoleKey.LeftArrow:
                                if (blockWorker.IsChange(E_ChangeDir.Left, map))
                                    blockWorker.Change(E_ChangeDir.Left);
                                break;
                            case ConsoleKey.RightArrow:
                                if (blockWorker.IsChange(E_ChangeDir.Right, map))
                                    blockWorker.Change(E_ChangeDir.Right);
                                break;
                            case ConsoleKey.A:
                                if (blockWorker.IsMoveRL(E_ChangeDir.Left, map))
                                    blockWorker.MoveRL(E_ChangeDir.Left);
                                break;
                            case ConsoleKey.D:
                                if (blockWorker.IsMoveRL(E_ChangeDir.Right, map))
                                    blockWorker.MoveRL(E_ChangeDir.Right);
                                break;
                            case ConsoleKey.S:
                                if (blockWorker.IsMove(map))
                                    blockWorker.AutoMove();
                                break;
                        }
                    }
                    
                //}
            }
        }
        public void StopThread()
        {
            //isRunning = false;
            //inputThread = null;
            InputCheak.Instance.action -= CheakInputThread;
        }
        public void Update()
        { 
            lock (blockWorker)
            {
                map.Draw();
                blockWorker.Draw();
                if (blockWorker.IsMove(map))
                    blockWorker.AutoMove();
            }
            Thread.Sleep(200);
            
        }
       
    }
}

GameScene.cs

  • 作用:游戏主场景

  • 核心功能

    • 整合地图和方块控制器

    • 实现输入监听线程(处理玩家操作)

    • 管理游戏主循环的更新逻辑

    • 协调方块移动和地图渲染

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

namespace 俄罗斯方块
{
    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 pos1,Position pos2)
        {
            if (pos1.x == pos2.x && pos1.y == pos2.y)
                return true;
            return false;
        }
        public static bool operator !=(Position pos1, Position pos2)
        {
            if (pos1.x == pos2.x && pos1.y == pos2.y)
                return false;
            return true;
        }
        public static Position operator +(Position pos1, Position pos2)
        {
            Position pos = new Position(pos1.x + pos2.x, pos1.y + pos2.y);
            return pos;
        }
    }
}

 Position.cs

  • 作用:坐标系统

  • 核心功能

    • 定义二维坐标结构

    • 重载坐标运算操作符(==, !=, +)

    • 提供便捷的坐标计算功能

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

namespace 俄罗斯方块
{
    class Map:IDraw 
    {
        public GameScene gameScene;
        //固定墙壁
        public List<DrawObject> wallList = new List<DrawObject>();
        //动态墙壁
        public List<DrawObject> dymaicWallList = new List<DrawObject>();
        //声明一个数组来记录每一行的位置
        public int[] recordInfo;

        //方便 外部访问地图数值
        public int w;
        public int h;
        public Map(GameScene scene)
        {
            this.gameScene = scene;
            h = Game.h - 6;
            w = 0;
            for (int i = 0; i < Game.w; i +=2)
            {
                wallList.Add(new DrawObject(E_DrawType.Wall, i, Game.h - 6));
                ++w;
            }
            w -= 2;
            for (int i = 0; i < Game.h - 6; i++)
            {
                wallList.Add(new DrawObject(E_DrawType.Wall, 0, i));
                wallList.Add(new DrawObject(E_DrawType.Wall, Game.w - 2, i));
            }
            recordInfo = new int[h];
        }

        public void Draw()
        {
            for (int i = 0; i < wallList .Count; i++)
            {
                wallList[i].Draw();
            }
            //绘制动态墙壁
            for (int i = 0; i < dymaicWallList .Count ; i++)
            {
                dymaicWallList[i].Draw();
            }
        }
        public void ClearDraw()
        {
            for (int i = 0; i < dymaicWallList.Count; i++)
            {
                dymaicWallList[i].Clear();
            }
        }

        //外部添加动态墙壁的函数
        public void AddWalls(List<DrawObject>walls)
        {
            for (int i = 0; i < walls .Count ; i++)
            {
                //传递方块进来,将方块类型改为墙壁类型
                walls[i].ChangeType(E_DrawType.Wall);
                dymaicWallList.Add(walls[i]);
               
                //当方块顶满了,需要结束游戏
                if (walls [i].pos .y<0)
                {
                    //关闭多线程
                    gameScene.StopThread();
                    Game.ChangeScene(E_SceneType.End);
                    return;
                }
                recordInfo[h - 1 - walls[i].pos.y] += 1;
            }
            //先把之前的动态小方块擦掉
            ClearDraw();
            //检测移除
            CheakClear();
            //再绘制动态小方块
            Draw();
        }
        public void CheakClear()
        {
            List<DrawObject> delList = new List<DrawObject>();
            for (int i = 0; i < recordInfo .Length ; i++)
            {
                if(recordInfo [i]==w)
                {
                    //这一行的所有小方块移除
                    for (int j = 0; j < dymaicWallList .Count ; j++)
                    {
                        //当前通过动态方块的y计算他在哪一行如果行号和当前记录索引一致
                        //就证明应该删除
                        if(i==h-1-dymaicWallList [j].pos .y )
                        {
                            //移除这个方块,为了安全移除,添加一个记录列表
                            delList.Add(dymaicWallList[j]);

                        }
                        //让这行之上的所有小方块下移一格
                        else if(h-1-dymaicWallList [j].pos .y >i)
                        {
                            ++dymaicWallList[j].pos.y; 
                        }
                    }
                    //移除待删除的小方块
                    for (int j = 0; j < delList .Count ; j++)
                    {
                        dymaicWallList.Remove(delList[j]);
                    }

                    //3.记录小方块数量的数组从上到下迁移
                    for (int j = i; j < recordInfo .Length -1; j++)
                    {
                        recordInfo[j] = recordInfo[j + 1];
                    }
                    //置空最顶的计数
                    recordInfo[recordInfo.Length - 1] = 0;
                    //垮掉一行后,再从头检验是否跨层
                    CheakClear();
                    break;
                }
            }
        }
    }
}

Map.cs

  • 作用:游戏地图管理器

  • 核心功能

    • 管理静态墙壁和动态方块(已落地方块)

    • 实现行消除检测和消除后的方块下落

    • 处理方块落地后的地图更新

    • 检测游戏结束条件(方块堆到顶部)

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

namespace 俄罗斯方块
{
    class BlockInfo
    {
        private List<Position[]> list;
        public BlockInfo(E_DrawType type)
        {
            list = new List<Position[]>();
            switch (type)
            {
                case E_DrawType.Cube:
                    list.Add(new Position[3]{new Position(2,0),new Position (0,1),new Position (2,1)});
                    break;
                case E_DrawType.Line:
                    list.Add(new Position[3] { new Position(0, -1), new Position(0, 1), new Position(0, 2) });
                    list.Add(new Position[3] { new Position(-4,0), new Position(-2,0), new Position(2,0) });
                    list.Add(new Position[3] { new Position(0,-2), new Position(0,-1), new Position(0, 1) });
                    list.Add(new Position[3] { new Position(-2,0), new Position(2,0), new Position(4,0) });
                    break;
                case E_DrawType.Tank:
                    list.Add(new Position[3] { new Position(-2,0), new Position(2,0), new Position(0,1) });
                    list.Add(new Position[3] { new Position(-2,0), new Position(0,-1), new Position(0,1) });
                    list.Add(new Position[3] { new Position(-2,0), new Position(0,-1), new Position(2,0) });
                    list.Add(new Position[3] { new Position(2,0), new Position(0, -1), new Position(2, 0) });
                    break;
                case E_DrawType.Left_Ladder:
                    list.Add(new Position[3] { new Position(0,-1), new Position(2, 0), new Position(2,1) });
                    list.Add(new Position[3] { new Position(-2, 1), new Position(2,0), new Position(0, 1) });
                    list.Add(new Position[3] { new Position(-2,-1), new Position(-2,0), new Position(0,1) });
                    list.Add(new Position[3] { new Position(-2,0), new Position(0,-1), new Position(-2,-1) });
                    break;
                case E_DrawType.Right_Ladder:
                    list.Add(new Position[3] { new Position(0, -1), new Position(-2, 0), new Position(-2, 1) });
                    list.Add(new Position[3] { new Position(-2, -1), new Position(0, -1), new Position(2,0) });
                    list.Add(new Position[3] { new Position(2, -1), new Position(2, 0), new Position(0, 1) });
                    list.Add(new Position[3] { new Position(0,1), new Position(2,1), new Position(-2, 0) });
                    break;
                case E_DrawType.Legy_Long_Ladder:
                    list.Add(new Position[3] { new Position(-2,-1), new Position(0,-1), new Position(0,1) });
                    list.Add(new Position[3] { new Position(2,-1), new Position(-2,0), new Position(2,0) });
                    list.Add(new Position[3] { new Position(0, -1), new Position(2, 1), new Position(0, 1) });
                    list.Add(new Position[3] { new Position(2,0), new Position(-2, 0), new Position(-2, 1) });
                    break;
                case E_DrawType.Right_Long_Ladder:
                    list.Add(new Position[3] { new Position(0, -1), new Position(0, 1), new Position(2, -1) });
                    list.Add(new Position[3] { new Position(2, 0), new Position(-2, 0), new Position(2, 1) });
                    list.Add(new Position[3] { new Position(0, -1), new Position(-2, 1), new Position(0, 1) });
                    list.Add(new Position[3] { new Position(2, -1), new Position(-2, 0), new Position(2, 0) });
                    break;
                default:
                    break;
            }
        }
        //索引器
        public Position[] this[int index]
        {
            get
            {
                if (index < 0)
                    return list[0];
                else if (index >= list.Count)
                    return list[list.Count-1];
                else
                    return list[index];
            }
        }
        //外部访问list长度属性
        public int Count { get => list.Count; }
    }
}

BlockInfo.cs

  • 作用:方块形态数据管理

  • 核心功能

    • 存储所有方块类型(7种)的各种旋转形态坐标

    • 通过索引器提供不同旋转状态的坐标数据

    • 管理方块形态的数量和访问逻辑

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

namespace 俄罗斯方块
{
    enum E_ChangeDir
    {
        Left,
        Right,
    }
    class BlockWorker:IDraw 
    {
        public List<DrawObject> blocks;
        public Dictionary<E_DrawType, BlockInfo> blockInfoDic;
        public BlockInfo nowBlcockInfo;
        
        //记录当前形状
        public int nowBlockIndex;
        public BlockWorker()
        {
            //初始化方块信息
            blockInfoDic = new Dictionary<E_DrawType, BlockInfo>()
            {
                {E_DrawType .Cube ,new BlockInfo(E_DrawType .Cube) },
                {E_DrawType .Line ,new BlockInfo (E_DrawType.Line ) },
                {E_DrawType .Tank ,new BlockInfo (E_DrawType.Tank ) },
                {E_DrawType .Left_Ladder ,new BlockInfo (E_DrawType.Left_Ladder) },
                {E_DrawType .Right_Ladder ,new BlockInfo (E_DrawType.Right_Ladder) },
                {E_DrawType .Legy_Long_Ladder ,new BlockInfo (E_DrawType.Legy_Long_Ladder ) },
                {E_DrawType .Right_Long_Ladder ,new BlockInfo (E_DrawType.Right_Long_Ladder ) }
            };
            //随机一个方块
            RandomCreateBlock();
        }

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

        public void RandomCreateBlock()
        {
            //随机方块类型
            Random r = new Random();
            E_DrawType type = (E_DrawType)r.Next(1, 8);
            //每次新建一个砖块,其实是创建4个小方形
            blocks = new List<DrawObject>()
            {
                new DrawObject (type),
                new DrawObject(type),
                new DrawObject (type),
                new DrawObject (type),
            };
            //初始化方块信息
            //原点位置 我们随机 方块list中第0个位置就是原点的位置
            blocks[0].pos = new Position(24, -5);
            //其他三个方块的位置
            //取出方块的形态信息来进行具体的随机
            //应该把取出来的方块具体形态信息 存起来 之后用于变形
            nowBlcockInfo = blockInfoDic[type];
            //随机几种形态中的一种来设置方块的信息
            nowBlockIndex = r.Next(0, nowBlcockInfo.Count);
            //取出其中一种形态的坐标信息
            Position[] pos = nowBlcockInfo[nowBlockIndex];
            for (int i = 0; i < pos .Length ; i++)
            {
                //取出来的pos是相对原点方块的坐标 所以需要进行计算
                blocks[i + 1].pos = blocks[0].pos + pos[i]; 
            }
        }
        public void ClearDraw()
        {
            for (int i = 0; i < blocks .Count ; i++)
            {
                blocks[i].Clear();
            }
        }
        public void Change(E_ChangeDir type)
        {
            ClearDraw();
            switch (type)
            {
                case E_ChangeDir.Left:
                    --nowBlockIndex;
                    if (nowBlockIndex < 0)
                        nowBlockIndex = nowBlcockInfo.Count - 1;
                    break;
                case E_ChangeDir.Right:
                    ++nowBlockIndex;
                    if (nowBlockIndex >= nowBlcockInfo .Count)
                        nowBlockIndex = 0;
                    break;
            }
            Position[] pos = nowBlcockInfo[nowBlockIndex];
            for (int i = 0; i < pos.Length; i++)
            {
                //取出来的pos是相对原点方块的坐标 所以需要进行计算
                blocks[i + 1].pos = blocks[0].pos + pos[i];
            }
            Draw();
        }
        public bool IsChange(E_ChangeDir type,Map map)
        {
            //要想判断是否可以变形,首先要模拟变形
            //判断是否超出墙壁
            int tempIndex = nowBlockIndex;
            Position tempPos;
            Position[] nowPos = nowBlcockInfo[tempIndex];
            for (int i = 0; i < nowPos .Length ; i++)
            {
                tempPos = blocks[0].pos + nowPos[i];
                if (tempPos .x < 2 || tempPos.x >= Game .w-2 || tempPos.y >= map.h)
                    return false;
            }
            //判断是否和地图上的动态方块重合
            for (int i = 0; i < nowPos .Length; i++)
            {
                tempPos = blocks[0].pos + nowPos[i];
                for (int j = 0; j < map.dymaicWallList .Count ; j++)
                {
                    if (tempPos == map.dymaicWallList[j].pos)
                        return false;
                }
            }
            return true;
        }
        public void MoveRL(E_ChangeDir type)
        {
            ClearDraw();
            //得到方块偏移量
            Position pos = new Position(type == E_ChangeDir.Left ? -2 : 2, 0);
            for (int i = 0; i < blocks.Count ; i++)
            {
                blocks[i].pos += pos; 
            }
            Draw();
        }
        public bool IsMoveRL(E_ChangeDir type,Map map)
        {
            //判断和墙壁不能重合
            Position movePos = new Position(type == E_ChangeDir.Left ? -2 : 2, 0);
            Position pos;
            for (int i = 0; i < blocks .Count ; i++)
            {
                pos = blocks[i].pos + movePos;
                if (pos.x < 2 || pos.x >= Game.w - 2)
                    return false;
            }
            //判断和动态方块不能重合
            for (int i = 0; i < blocks.Count ; i++)
            {
                pos = blocks[i].pos + movePos;
                for (int j = 0; j <map.dymaicWallList .Count  ; j++)
                {
                    if (pos == map.dymaicWallList[j].pos)
                        return false;
                }
            }
            return true;
        }
        //让方块自动往下移动
        public void AutoMove()
        {
            ClearDraw();
            Position downMove = new Position(0, 1);
            for (int i = 0; i < blocks .Count ; i++)
            {
                blocks[i].pos += downMove;
            }
            Draw();
        }
        //让方块碰到边界时停下逻辑判断
        public bool IsMove(Map map)
        {
            Position movePos = new Position(0, 1);
            Position pos;
            for (int i = 0; i < blocks .Count ; i++)
            {
                pos = blocks[i].pos + movePos;
                if (pos.y >= map.h)
                {
                    //停下来,给予地图动态方块
                    map.AddWalls(blocks);
                    //随机创建新的方块
                    RandomCreateBlock();
                    return false;
                }
            }
            //不能让方块下落碰到动态方块
            for (int i = 0; i < blocks .Count ; i++)
            {
                pos = blocks[i].pos + movePos;
                for (int j = 0; j < map .dymaicWallList .Count ; j++)
                {
                    if (pos == map.dymaicWallList[j].pos)
                    {
                        //停下来,给予地图动态方块
                        map.AddWalls(blocks);
                        //随机创建新的方块
                        RandomCreateBlock();
                        return false;
                    }
                }
            }
            return true;
        }
    }
}

BlockWorker.cs

  • 作用:方块行为控制中心

  • 核心功能

    • 管理当前活动方块的状态

    • 处理方块的创建、旋转、移动和下落

    • 检测方块与地图的碰撞

    • 实现方块变形和移动的物理规则

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

namespace 俄罗斯方块
{
    enum E_DrawType
    {
        Wall,
        Cube,
        Line,
        Tank,
        Left_Ladder,
        Right_Ladder,
        Legy_Long_Ladder,
        Right_Long_Ladder,
    }
    class DrawObject : IDraw
    {
        public Position pos;
        public E_DrawType type;
        public DrawObject(E_DrawType type)
        {
            this.type = type;
        }
        public DrawObject(E_DrawType type,int x,int y):this(type)
        {
            this.pos = new Position(x, y);
        }
        public void Clear()
        {
            if (pos.y < 0)
                return;
            Console.SetCursorPosition(pos.x, pos.y);
            Console.Write("  ");
        }
        public void Draw()
        {
            if (pos.y < 0)
                return;
            Console.SetCursorPosition(pos.x, pos.y);
            switch (type)
            {
                case E_DrawType.Wall:
                    Console.ForegroundColor = ConsoleColor.Red;
                    break;
                case E_DrawType.Cube:
                    Console.ForegroundColor = ConsoleColor.Blue;
                    break;
                case E_DrawType.Line:
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    break;
                case E_DrawType.Tank:
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    break;
                case E_DrawType.Left_Ladder:
                case E_DrawType.Right_Ladder:
                    Console.ForegroundColor = ConsoleColor.DarkCyan;
                    break;
                case E_DrawType.Legy_Long_Ladder:
                case E_DrawType.Right_Long_Ladder:
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    break;
            }
            Console.Write("■");
        }
        public void ChangeType(E_DrawType type)
        {
            this.type = type;
        }
    }
}

DrawObject.cs

  • 作用:游戏对象渲染单元

  • 核心功能

    • 定义所有可绘制对象的类型(墙壁、各种方块)

    • 管理对象的屏幕位置和绘制颜色

    • 实现对象的绘制和清除方法

    • 处理对象类型转换(如方块落地变为墙壁)

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

namespace 俄罗斯方块
{
    class InputCheak
    {
        public event Action action;
        public Thread inputThread;
        private static InputCheak instance = new InputCheak();

        public static InputCheak Instance
        {
            get
            {
                return instance;
            }
        }
        private InputCheak ()
        {
            inputThread = new Thread(CheakInput);
            inputThread.IsBackground = true;
            inputThread.Start();
        }
        private void  CheakInput()
        {
            while (true)
            {
                action?.Invoke();
            }
        }
        
    }
}

InputCheak.cs

  • 作用:输入监听管理器

  • 核心功能

    • 单例模式实现全局输入监听

    • 使用独立线程持续检测键盘输入

    • 通过事件机制将输入传递给游戏场景

using System;

namespace 俄罗斯方块
{
    class Program
    {
        static void Main(string[] args)
        {
            Game game = new Game();
            game.StartGame();
        }
    }
}

Program.cs

  • 作用:程序入口

  • 核心功能

    • 创建游戏实例

    • 启动游戏主循环


网站公告

今日签到

点亮在社区的每一天
去签到