C#初学者练手项目:从零实现控制台贪吃蛇
1. 为什么我建议每个C#初学者都从贪吃蛇开始练手如果你刚学完C#的变量、循环和条件判断正对着控制台里那几行Console.WriteLine发呆不知道该拿这些语法做点什么——我的建议很直接写一个贪吃蛇。不是因为它简单恰恰是因为它麻雀虽小五脏俱全。一个最简易的贪吃蛇代码量大概在两百到三百行之间但它逼着你把数组、循环、条件分支、随机数、控制台光标定位、键盘输入这些东西全部串起来用一遍。你写完之后会发现之前零散学的语法点突然连成了一条线。我见过不少初学者一上来就想做带图形界面的项目结果卡在窗体设计器里出不来连最基本的游戏循环都没搞明白。贪吃蛇的好处在于它把游戏循环这个核心概念用最朴素的方式摆在你面前清屏、画蛇、画食物、读键盘、判断碰撞、更新位置然后重复。这个循环就是所有游戏的骨架你把它吃透了以后学任何游戏框架都会觉得眼熟。这篇文章面向的是刚接触C#不久、想通过一个完整小项目把基础知识用起来的人。我会从零开始把每一步的设计理由、代码写法、容易踩的坑都讲清楚。你不需要任何游戏开发经验只要会写for循环和if判断就能跟上。代码我全部实测跑过用的是.NET 6以上的控制台项目Visual Studio或者VS Code都能直接跑。2. 动手之前先把这几个设计问题想明白2.1 用控制台还是用窗体这是个关键选择初学者最容易纠结的就是我到底该用Console还是WinForms。我的答案很明确第一版一定用控制台。原因有三层。第一控制台没有UI设计器的干扰你的注意力全部在逻辑上这对建立编程思维至关重要。第二控制台的画面本质上就是一个二维字符网格蛇的坐标、食物的坐标、墙壁的坐标全部可以用int x, y来表示这让你能非常直观地理解游戏世界就是一堆坐标点这个本质。第三控制台版本的调试成本极低你不需要处理控件重绘、线程冲突这些复杂问题。等你把控制台版本写通了再迁移到WinForms或者Unity你会发现只是把在光标位置打印字符换成了在画布上绘制矩形核心逻辑一行都不用改。这个迁移路径是最平滑的。2.2 蛇到底用什么数据结构来存这是整个项目里最重要的一个设计决策。我见过有人用ListPoint有人用数组还有人用队列。对于初学者版本我推荐用ListPoint配合一个固定大小的数组来做但更简单的方式是直接用List。为什么因为蛇的移动本质上是头部加一节尾部减一节没吃到食物时或者头部加一节尾部不动吃到食物时。用List的话Insert(0, newHead)加RemoveAt(lastIndex)就能完美表达这个逻辑。但这里有个性能上的小坑List的Insert(0, ...)是O(n)操作因为要把后面所有元素往后挪。对于一条长度几十节的蛇来说这点开销完全可以忽略但如果你以后想做更复杂的游戏就要考虑用LinkedList或者环形缓冲区。初学阶段可读性优先于性能用List没问题。2.3 游戏循环的节奏怎么控制控制台游戏最大的问题是怎么让画面动起来又不闪。如果你用while(true)死循环加Console.Clear()画面会疯狂闪烁根本没法玩。正确的做法是用Thread.Sleep()控制帧率同时用Console.SetCursorPosition()只重绘变化的部分而不是整个清屏。我的经验是贪吃蛇的刷新间隔设在100到150毫秒之间比较合适。太快了蛇跑得你反应不过来太慢了又显得卡顿。这个值可以做成一个变量方便你调试时调整。另外键盘输入不能用Console.ReadLine()因为那会阻塞整个循环。要用Console.KeyAvailable配合Console.ReadKey(true)来非阻塞地读取按键。3. 从零搭建核心代码逐块拆解3.1 游戏区域的坐标系统设计先定义游戏区域的宽高。我一般用宽40、高20这个尺寸在大多数终端里都能完整显示不会出现换行错位。坐标原点设在左上角(0, 0)x向右递增y向下递增。这个坐标系和数组的索引方式一致处理起来最顺手。const int Width 40; const int Height 20;墙壁的处理有两种方案一种是画一圈边框字符蛇撞到边界就死另一种是不画边框蛇从右边出去就从左边进来穿墙模式。初学者版本我建议用撞墙死亡因为逻辑更简单而且能让你清楚地处理边界判断。// 判断是否撞墙 bool HitWall(Point p) { return p.X 0 || p.X Width - 1 || p.Y 0 || p.Y Height - 1; }注意这里用了 0和 Width - 1因为第0行和第0列要留给边框。这个细节很容易写错写成 0的话蛇会跑到边框外面去画面就乱了。3.2 蛇的移动逻辑与方向缓冲蛇的移动方向用一个枚举来表示enum Direction { Up, Down, Left, Right }这里有个初学者必踩的坑如果你直接根据当前按键改变方向当蛇向右移动时玩家快速按下上再按左蛇会在同一帧内先转向上再转向左结果就是蛇直接掉头撞到自己。解决办法是引入一个方向缓冲机制——每帧只允许改变一次方向而且新方向不能和当前方向相反。Direction currentDir Direction.Right; Direction nextDir Direction.Right; // 在读取键盘时 if (key.Key ConsoleKey.UpArrow currentDir ! Direction.Down) nextDir Direction.Up; // ... 其他方向同理 // 在更新逻辑开始时 currentDir nextDir;这个当前方向和下一方向分离的设计是很多初学者想不到但非常关键的技巧。它保证了蛇不会在一帧内做出非法转向。3.3 食物的随机生成与合法性校验食物生成看起来简单其实有个隐蔽的坑随机生成的位置可能正好在蛇身上。如果你不检查食物就会消失在蛇的身体里玩家永远吃不到。Point GenerateFood(ListPoint snake) { Random rand new Random(); Point food; do { food new Point(rand.Next(1, Width - 1), rand.Next(1, Height - 1)); } while (snake.Contains(food)); return food; }这里用do-while循环反复生成直到位置不在蛇身上为止。当蛇很短的时候这个循环几乎一次就成功当蛇很长的时候可能会循环很多次。对于初学者版本蛇最长也就几十节游戏区域有几百个格子效率完全没问题。但你要知道这个写法在蛇极长时会有性能问题进阶版本可以用收集所有空格子然后随机选一个的方式优化。另外Random对象不要在循环里反复new因为如果时间间隔太短多次new Random()可能产生相同的种子导致食物位置重复。把Random声明为类的成员变量全局只用一个实例。3.4 碰撞检测撞墙、撞自己、吃食物每帧更新蛇的位置后要做三次判断顺序很重要Point newHead GetNextHead(snake[0], currentDir); // 1. 先判断撞墙 if (HitWall(newHead)) { GameOver(); } // 2. 再判断撞自己注意尾巴那一节即将移走可以不算 if (snake.Take(snake.Count - 1).Contains(newHead)) { GameOver(); } // 3. 判断是否吃到食物 if (newHead food) { snake.Insert(0, newHead); // 头加一节尾不动 food GenerateFood(snake); score; } else { snake.Insert(0, newHead); // 头加一节 snake.RemoveAt(snake.Count - 1); // 尾减一节 }这里有个精妙之处判断撞自己时我用了Take(snake.Count - 1)排除了尾巴。为什么因为尾巴在这一帧会移走如果新头正好移动到尾巴的位置实际上不会撞到因为尾巴已经让开了。这个细节如果你不注意蛇在追着自己尾巴转圈时会莫名其妙死掉玩家会觉得是bug。4. 让画面不闪、按键不卡控制台渲染的实战技巧4.1 双缓冲思路在控制台里的简化实现控制台没有真正的双缓冲但我们可以用只重绘变化区域来达到类似效果。具体做法是维护一个和游戏区域等大的字符数组作为上一帧画面每帧计算新画面只把和上一帧不同的位置用Console.SetCursorPosition加Console.Write更新。对于初学者版本其实有更简单的办法不清屏而是用空格覆盖旧蛇身的位置。但这样代码会复杂。我的折中方案是每帧只清空蛇尾移走的那一格和食物被吃掉的那一格其他位置不动。这样画面几乎不闪。// 蛇尾移走时把那一格清空 Console.SetCursorPosition(oldTail.X, oldTail.Y); Console.Write( );但要注意如果蛇尾移走的位置正好是墙壁或者食物就不能清空。所以清空之前要判断一下。这个逻辑稍微有点绕但写一次就明白了。4.2 键盘输入的非阻塞读取前面提到用Console.KeyAvailable这里展开说下具体写法while (Console.KeyAvailable) { ConsoleKeyInfo key Console.ReadKey(true); switch (key.Key) { case ConsoleKey.UpArrow: if (currentDir ! Direction.Down) nextDir Direction.Up; break; // ... 其他方向 } }用while而不是if是为了把这一帧内积累的所有按键都处理掉避免按键丢失。ReadKey(true)的参数true表示不把按键回显到屏幕上否则你的游戏画面上会多出一堆箭头字符。这里还有个体验上的细节方向键和WASD最好都支持。有些人的键盘方向键位置不顺手用WASD会更舒服。加几个case的事但体验提升明显。4.3 帧率控制与游戏速度的动态调整int baseDelay 120; // 毫秒 int delay Math.Max(50, baseDelay - score * 3); Thread.Sleep(delay);这段代码让蛇随着得分增加而加速每吃一个食物快3毫秒但最快不低于50毫秒。这个动态难度是贪吃蛇让人上瘾的关键——前期轻松后期紧张。你可以根据自己的手感调整baseDelay和加速系数。我试过baseDelay150、每分减5毫秒节奏也很舒服。注意Thread.Sleep的精度受系统调度影响实际间隔可能比设定值略长。对于贪吃蛇这种对精度要求不高的游戏完全够用。如果你以后做需要精确计时的游戏要用Stopwatch配合忙等待或者专门的游戏循环库。5. 那些只有真正写过才会知道的坑5.1 光标定位越界导致的异常Console.SetCursorPosition(x, y)如果传入的坐标超出了控制台窗口的实际大小会抛出ArgumentOutOfRangeException。而控制台窗口大小是可以被用户拖拽改变的。如果你把游戏区域设成40x20但用户把窗口拖得很小程序就会崩溃。解决办法有两个一是在程序启动时用Console.SetWindowSize强制设置窗口大小并提示用户不要调整二是在每次SetCursorPosition之前做边界检查。初学者版本我建议用第一种简单粗暴但有效Console.SetWindowSize(Width 2, Height 2); Console.SetBufferSize(Width 2, Height 2);注意SetWindowSize和SetBufferSize在某些系统上有限制窗口不能小于某个最小值。如果设置失败会抛异常所以最好用try-catch包一下失败了就提示用户手动调整窗口。5.2 蛇身字符和食物字符的视觉区分蛇头、蛇身、食物、墙壁这四个元素要用不同的字符和颜色区分。我的习惯是蛇头用蛇身用o食物用*墙壁用#。颜色方面蛇头用绿色蛇身用深绿色食物用红色墙壁用灰色。这样一眼就能看清游戏状态。Console.ForegroundColor ConsoleColor.Green; Console.Write(); Console.ResetColor();记得每次改完颜色要ResetColor()否则后面的输出都会带着颜色画面会很乱。这个坑我踩过调试了半天才发现是颜色没重置。5.3 游戏结束后的重开逻辑初学者版本很容易忽略游戏结束后怎么办。如果直接return退出程序玩家想再玩一局就得重新运行体验很差。正确的做法是把游戏主逻辑包在一个外层循环里游戏结束后询问玩家是否重开。while (true) { RunGame(); // 一局游戏 Console.SetCursorPosition(0, Height 1); Console.Write(游戏结束按R重开按Q退出); var key Console.ReadKey(true).Key; if (key ConsoleKey.Q) break; }这里要注意重开之前要把分数、蛇、食物全部重置。我建议把这些状态封装成一个GameState类重开时直接new一个新实例比手动重置每个变量更不容易出错。5.4 分数显示和最高分记录分数显示在游戏区域上方或下方用Console.SetCursorPosition定位到固定位置输出。最高分可以存在内存里程序关闭就丢失也可以写到一个文本文件里下次启动时读取。对于初学者版本存内存就够了但写文件是个很好的练习涉及File.ReadAllText和File.WriteAllText你可以试试。// 读取最高分 int highScore 0; if (File.Exists(highscore.txt)) int.TryParse(File.ReadAllText(highscore.txt), out highScore); // 保存最高分 if (score highScore) File.WriteAllText(highscore.txt, score.ToString());int.TryParse比int.Parse安全因为文件内容可能被手动改坏TryParse不会抛异常。6. 从能跑到好用几个提升体验的进阶思路6.1 用结构体封装坐标让代码更清爽Point是.NET自带的但它是引用类型实际上System.Drawing.Point是结构体但需要引用额外的程序集。我建议自己定义一个简单的结构体struct Position { public int X; public int Y; public Position(int x, int y) { X x; Y y; } public static bool operator (Position a, Position b) a.X b.X a.Y b.Y; public static bool operator !(Position a, Position b) !(a b); public override bool Equals(object obj) obj is Position p this p; public override int GetHashCode() HashCode.Combine(X, Y); }重写和Equals之后List.Contains才能正确判断两个坐标是否相同。如果你不重写Contains用的是引用比较永远返回false食物生成会死循环。这个坑非常隐蔽我第一次写的时候就卡在这里。6.2 把游戏逻辑和渲染分离初学者容易把更新蛇的位置和在屏幕上画蛇混在一起写。更好的做法是分成两个方法Update()只改数据Render()只负责画。这样调试的时候你可以单独测试Update()的逻辑不用管画面。void Update() { /* 移动蛇、判断碰撞、生成食物 */ } void Render() { /* 根据当前数据画画面 */ }这个分离思想是游戏开发的基础你现在养成习惯以后学任何引擎都会受益。6.3 用枚举代替魔法数字方向用枚举游戏状态也用枚举enum GameState { Running, Paused, GameOver }这样代码里就不会出现if (state 1)这种看不懂的写法。可读性提升不是一点半点。6.4 暂停功能的实现暂停很简单用一个GameState判断暂停时不执行Update()但继续响应键盘。按空格切换暂停状态。这个功能代码量很小但很实用尤其是你调试的时候。if (state GameState.Paused) { // 只处理键盘不更新逻辑 Thread.Sleep(50); continue; }7. 我踩过的三个真实坑和修复过程7.1 蛇追尾巴时莫名死亡前面提到过判断撞自己时要把尾巴排除。我当时的代码是snake.Contains(newHead)结果蛇在追自己尾巴转圈时新头的位置正好是尾巴的位置Contains返回true游戏结束。玩家明明没撞到却死了。修复方法就是snake.Take(snake.Count - 1).Contains(newHead)。这个bug我找了半个小时最后是打印出蛇的所有坐标才定位到的。7.2 快速连按方向键导致蛇掉头这个坑前面也说了用方向缓冲解决。但还有个变种如果玩家在蛇向右移动时快速按上然后按左在缓冲机制下nextDir先被设为Up然后被设为Left。但Left和当前方向Right相反所以第二个按键被忽略了蛇只会向上转。这其实是正确行为但玩家可能觉得我按了左怎么没反应。解决办法是在按键处理时用nextDir而不是currentDir来判断是否相反case ConsoleKey.LeftArrow: if (nextDir ! Direction.Right) nextDir Direction.Left; break;这样连续按上再按左nextDir是UpLeft和Up不相反所以nextDir变成Left蛇会先向上再向左符合玩家预期。7.3 食物生成在蛇身上导致死循环前面说过do-while加Contains。但如果Contains因为没重写Equals而永远返回false这个循环就永远不会退出程序卡死。我当时的症状是吃到食物后程序无响应。排查方法是加了一行Console.WriteLine在循环里发现疯狂输出立刻定位到Contains失效。修复就是重写Equals和GetHashCode。8. 写完这个之后你还能往哪个方向继续折腾贪吃蛇写完之后你手里其实已经有了一套最小可用的游戏框架游戏循环、状态管理、输入处理、碰撞检测、渲染。基于这个框架你可以做很多扩展。比如加障碍物——在游戏区域随机放几个固定的墙撞到就死这只需要在碰撞检测里多加一个判断。比如加特殊食物——吃到一个金色的食物加3分但存在时间只有5秒这需要引入计时器。比如做双人对战——两条蛇各自用不同的按键控制撞到对方身体就输这需要把蛇的数据结构从单个List改成两个List碰撞检测也要互相判断。再往远了说你可以把这个控制台版本迁移到WinForms用Graphics.DrawRectangle画方块用Timer控制帧率用KeyDown事件处理输入。核心逻辑几乎不用改只是把Console.SetCursorPosition换成Graphics的绘制调用。这个过程会让你深刻体会到逻辑和渲染分离的好处。我个人在实际操作中的体会是贪吃蛇这个项目最大的价值不在于它本身多好玩而在于它逼着你把C#的基础语法在一个有反馈的环境里用一遍。你写的时候会遇到各种为什么蛇不动了为什么食物不见了为什么按键没反应每一个问题的排查过程都比你看十页教程学到的多。所以别怕写错写错了调试调试通了你就真的会了。

相关新闻

Oracle数据库卡顿排查:alert日志与AWR/ASH时间线还原实战

Oracle数据库卡顿排查:alert日志与AWR/ASH时间线还原实战

最近有个刚转DBA的朋友问我一个问题:业务反馈数据库卡顿,他第一件事就是翻alert日志,结果翻了大半天,连个ORA-报错都没看到,彻底不知道下一步该干嘛了。这个场景我太熟悉了——排查卡顿相关日志,核心压根不…

2026/10/14 4:43:56 阅读更多 →
QBE示例查询:从填表到SQL的查询思维入门

QBE示例查询:从填表到SQL的查询思维入门

“QBE”这个词,如果你不是数据库方向的老鸟,可能第一眼有点陌生。它是 Query By Example 的缩写,中文常译作“示例查询”,一种在关系数据库发展早期非常有代表性的查询方式。简单说,SQL 是靠写一串命令来查数据&#x…

2026/10/14 4:43:56 阅读更多 →
Poppy协议解读:AI代理必须亮明身份,透明化接入实战

Poppy协议解读:AI代理必须亮明身份,透明化接入实战

最近AI圈有件值得专门聊聊的事:一家长期深耕对话式AI的团队,公开了一份叫“Poppy协议”的行为约束规范。名字听上去挺植物系,实际内容是给所有AI代理立下一套“必须表明自己不是人类”的规则。核心就一句话:AI代理可以继续干活&am…

2026/10/14 4:42:56 阅读更多 →

最新新闻

电商AI视觉生产流水线:12个可编排图像生成Skill开源实践

电商AI视觉生产流水线:12个可编排图像生成Skill开源实践

1. 这不是又一个“AI画图工具”,而是电商视觉生产流水线的底层能力拆解你有没有遇到过这样的场景:运营同事凌晨两点发来消息,“明天大促主图要换,三套风格,带卖点文案,尺寸必须是800800和1200628双规格&…

2026/10/14 5:25:13 阅读更多 →
JavaScript正则方法全解析:从exec到replaceAll的实战指南

JavaScript正则方法全解析:从exec到replaceAll的实战指南

写正则的人最怕的不是正则写不出来,而是同一个需求,每个方法看起来都“差不多能用”,但真上线之后,Bug一个接一个。我见过好几次这样的情况:有人用match想拿捕获组,结果返回了一堆字符串;有人在…

2026/10/14 5:25:13 阅读更多 →
Apache Mesos 0.28.0 特性深度解析:net_cls 网络隔离、统一容器化与 v1 Executor HTTP API

Apache Mesos 0.28.0 特性深度解析:net_cls 网络隔离、统一容器化与 v1 Executor HTTP API

云原生 【免费下载链接】mesos Apache Mesos 项目地址: https://gitcode.com/gh_mirrors/mesos2/mesos 点击查看 免费下载 Apache Mesos 0.28.0 是 Mesos 发展历程中承上启下的一个重要版本:它在 Linux cgroups 网络隔离、标量资源精度、动态预留资源元…

2026/10/14 5:25:13 阅读更多 →
人体供暖系统:科学激活产热机制抵御寒冬

人体供暖系统:科学激活产热机制抵御寒冬

1. 寒冬里的主动发热之道最近几年冬天越来越难熬,特别是南方没有集中供暖的地区。作为一个在杭州生活了十年的北方人,我深刻体会到南方湿冷的威力——那种冷是往骨头缝里钻的。开空调太干燥,电热毯又只能局部取暖,于是我开始研究如…

2026/10/14 5:25:13 阅读更多 →
UE5 C++单播代理实战:DECLARE_DELEGATE与TDelegate全面解析

UE5 C++单播代理实战:DECLARE_DELEGATE与TDelegate全面解析

做游戏逻辑的时候,最常干的一件事就是把“某个行为”传递给“另一个系统”。按键按下的那一刻要通知谁,异步加载完关卡要提醒谁,血量掉到某个阈值要唤起谁——这些在UE5 C里最直接的落地方案就是代理(Delegate)。其中单…

2026/10/14 5:25:13 阅读更多 →
VC++ FTP服务器与客户端完整源码解析:从协议到断点续传实战

VC++ FTP服务器与客户端完整源码解析:从协议到断点续传实战

简介:一套面向VC/MFC与网络通信初学者的FTP客户端与服务器完整示例工程,基于VC6.0调试通过。工程同时提供控制台版本的FTP服务器和MFC界面客户端,源码头文件结构清晰,关键功能均以类接口形式开放,便于在此基础上扩展成…

2026/10/14 5:24:12 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →