15.C#进阶实践项目总结

15.总结


15.1 知识点

主要学习内容

总结目的


强调


15.2 核心要点速览

基于本系列 14 篇正文完整阅读提取,按逻辑分类。

项目概述

项目 说明
目标 控制台俄罗斯方块:场景切换沿用贪吃蛇框架,核心为方块生成、移动、变形、落底、消行、结束判定
核心类 游戏对象类(小方块)、地图类(固定墙+动态墙)、砖块信息类(形态偏移)、搬砖工人类(方块与地图交互)
坐标 一个方块 = 4 个 DrawObject;blocks[0] 为原点,其余位置 = 原点 + BlockInfo 中的相对偏移;横向步长 2,纵向 1

场景与入口

类型 说明
Game w=50,h=35nowScene 当前场景;Start() 死循环调 nowScene.Update()ChangeScene 先 Clear 再 new 对应场景
ISceneUpdate 接口,仅 void Update()
Begin/End 继承 BeginOrEndBaseScene;W/S 选选项、J 确认;Begin 选 0 进游戏/1 退出,End 选 0 回开始/1 退出

绘制与基础类型

类型 说明
IDraw void Draw()
Position 结构体 x,y;重载 ==!=+
DrawObject pos+E_DrawType;Draw 按类型设颜色写「■」;ClearDraw 写两空格;ChangeType 落底时改为墙
E_DrawType Wall/Cube/Line/Tank/Left_Ladder/Right_Ladder/Left_Long_Ladder/Right_Long_Ladder(共 8 种,随机时用 1-7 排除墙)

地图

能力 说明
固定墙 构造里:底边 i+=2 到 Game.w,两侧 0Game.w-2,高度 Game.h-6;存于 walls
动态墙 dynamicWalls;AddWalls(list):遍历改类型为 Wall 并加入,消行逻辑里顺带 ClearDraw、CheckClear、再 Draw
消行 recordInfo[行] 记录每行方块数;满行则该行方块进 delList 再 Remove、上行 y+1、recordInfo 下移、递归 CheckClear;行索引 h-1-pos.y
结束 Map(GameScene);AddWalls 时若某块 pos.y<=0 则 StopThread、ChangeScene(End)、return

方块形态与搬砖工人

能力 说明
BlockInfo 按 E_DrawType 存 List<Position[]>,每元素为一种形态的 3 个相对偏移;索引器越界时回退到首/尾;Count 为形态数
BlockWorker blocks 当前 4 块,blockInfoDic 七种类型对应 BlockInfo,nowBlockInfo+nowInfoIndex 当前形态
随机出新块 (E_DrawType)r.Next(1,8);4 个 DrawObject(type);原点 blocks[0].pos=(24,5) 或 (24,-5);取形态偏移算 blocks[1..3].pos
变形 E_Change_Type Left/Right;Change 前 ClearDraw,改 nowInfoIndex(循环),用 nowBlockInfo[nowInfoIndex] 重算三块 pos 再 Draw
可变形判断 CanChange:用临时索引取形态,算 4 点;若任一点 x<2、x>=Game.w-2、y>=map.h 或与 dynamicWalls 某点同则 false

移动与落底

能力 说明
左右 MoveRL:ClearDraw,偏移 (±2,0),遍历 pos+= 再 Draw;CanMoveRL:模拟偏移后查边界与 dynamicWalls
下落 AutoMove:ClearDraw,各块 pos.y+=1 再 Draw;CanMove:模拟 (0,1),触底或碰动态墙则 AddWalls(blocks)、RandomCreateBlock()、return false
主循环 Update 内:lock(blockWorker){ map.Draw(); blockWorker.Draw(); if(CanMove) AutoMove(); } 然后 Thread.Sleep(200)

输入与线程

能力 说明
问题 Update 里 Sleep 导致输入延迟;双线程同时写控制台需同步
做法 单独输入线程 while(true) 里 KeyAvailable 时 lock(blockWorker) 读键并执行变形/左右/下落;锁内不含 Sleep
优化 InputThread 单例,内部线程死循环调 inputEvent?.Invoke();GameScene 构造时 inputEvent += CheckInputThread,StopThread 时 -= CheckInputThread;场景 new 时不再 new 线程,避免线程堆积

实现顺序建议

  1. 场景框架(Program、Game、ISceneUpdate、Begin/End/GameScene 空壳)。
  2. 绘制基础(IDraw、Position、E_DrawType、DrawObject、ClearDraw、ChangeType)。
  3. 地图(Map 固定墙+动态墙、Draw、AddWalls)。
  4. 形态数据(BlockInfo 各类型多形态偏移、索引器、Count)。
  5. 搬砖工人(blockInfoDic、RandomCreateBlock、Draw)。
  6. 变形(E_Change_Type、nowInfoIndex、Change、ClearDraw、CanChange)。
  7. 左右移动(MoveRL、CanMoveRL)。
  8. 下落与落底(AutoMove、CanMove、AddWalls+RandomCreateBlock)。
  9. 输入线程(Thread、lock(blockWorker)、键位映射)。
  10. 消行(recordInfo、AddWalls 里计数、CheckClear 递归)。
  11. 结束(y<=0 判定、StopThread、Map 持 GameScene)。
  12. 可选:InputThread 单例+事件、新块初始 y 上移、屏幕外不绘制。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏