Visual Studio开发ASCII蛇形游戏.exe运行时控制台垂直间距异常求助
问题:ASCII蛇形游戏控制台垂直间距异常
- 在Visual Studio中按F5运行/构建时显示完全正常
- 直接运行生成的.exe文件或其桌面快捷方式时,控制台字符垂直间距过大,部分行超出屏幕范围;经测试确认是预期行之间多输出了一行空行
- 已尝试设置控制台缓冲区和窗口尺寸,无效果;程序在朋友的电脑上运行正常
异常显示(拉伸状态)

水平方向'x'间距与正常版本一致,但垂直方向行之间多出空行,导致整体显示被拉长
Visual Studio中正常显示

仅在Visual Studio内部运行时显示符合预期
游戏代码
using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace Snake_Game { public static class Program { public static ScreenCompiler screen; public static List<SnakePart> parts = new List<SnakePart>(); public static Apple[,] food; public static int partNum; public static void UpdateFood() { for (int x = 0; x < screen.screenx; x++) { for (int y = 0; y < screen.screeny; y++) { if (food[x, y] != null) { food[x, y].Update(); } } } } static void Main() { Console.WriteLine("Hit enter to start."); Console.ReadLine(); Console.WriteLine("Use W, A, S, and D to control the snake."); Thread.Sleep(1000); Console.Clear(); Console.SetWindowSize(120, 30); Console.SetBufferSize(120, 30); Console.SetCursorPosition(0, 0); Console.Clear(); Thread.Sleep(1000); Console.CursorVisible = false; Console.Beep(600, 60); Console.Beep(900, 60); Console.Beep(1200, 100); screen = new ScreenCompiler(120, Console.LargestWindowHeight); food = new Apple[screen.screenx, screen.screeny]; parts.Add(new SnakePart(20, 5, 0, 0)); parts.Add(new SnakePart(19, 5, 1, 0)); parts.Add(new SnakePart(18, 5, 2, 0)); partNum = 3; int tick = 20; Random rng = new Random(); while (true) { ConsoleKeyInfo key = new ConsoleKeyInfo('\0', ConsoleKey.None, false, false, false); if (Console.KeyAvailable) { key = Console.ReadKey(); } if (key.Key == ConsoleKey.W) { if (parts[0].dir != 3 && parts[0].dir != 1) { parts[0].dir = 1; Console.Beep(600, 20); } } if (key.Key == ConsoleKey.A) { if (parts[0].dir != 0 && parts[0].dir != 2) { parts[0].dir = 2; Console.Beep(600, 20); } } if (key.Key == ConsoleKey.S) { if (parts[0].dir != 1 && parts[0].dir != 3) { parts[0].dir = 3; Console.Beep(600, 20); } } if (key.Key == ConsoleKey.D) { if (parts[0].dir != 2 && parts[0].dir != 0) { parts[0].dir = 0; Console.Beep(600, 20); } } int boost = partNum; if (boost > 50) { boost = 50; } Thread.Sleep(80 - boost); Console.SetCursorPosition(0, 0); screen = new ScreenCompiler(Console.WindowWidth, Console.WindowHeight); string score = "Score: " + partNum; for (int i = 0; i < score.Length; i++) { screen.lines[0][i] = score[i]; } tick--; if (tick <= 0) { tick = 20; int x = rng.Next(1, screen.screenx); int y = rng.Next(1, screen.screeny); food[x, y] = new Apple(x, y); new Thread(() => { Console.Beep(1000, 20); }).Start(); } for (int i = parts.Count - 1; i > -1; i--) { parts[i].Update(); } for (int i = screen.screeny - 1; i > -1; i--) { Console.WriteLine(screen.lines[i]); } } } } public class ScreenCompiler { public StringBuilder[] lines; public int screenx; public int screeny; public ScreenCompiler(int screenx, int screeny) { this.screenx = screenx; this.screeny = screeny; lines = new StringBuilder[screeny]; StringBuilder def = new StringBuilder(); for (int i = 0; i < screenx; i++) { def.Append(' '); } for (int i = 0; i < screeny; i++) { lines[i] = new StringBuilder(def.ToString()); } } } public class SnakePart { public int count; public int x; public int y; public int? dir; public SnakePart(int x, int y, int count, int? dir = null) { if (count == 0 && dir == null) { throw new ArgumentException("dir is required when part count is 0"); } this.x = x; this.y = y; this.count = count; this.dir = dir; } public void Update() { if (count == 0) { if (dir == 0) { x += 1; Program.UpdateFood(); x += 1; Program.UpdateFood(); } else if (dir == 1) { y += 1; Program.UpdateFood(); } else if (dir == 2) { x -= 1; Program.UpdateFood(); x -= 1; Program.UpdateFood(); } else { y -= 1; Program.UpdateFood(); } try { if (Program.screen.lines[y][x] == 'x') { Console.WriteLine("Game Over!"); Console.Beep(900, 100); Console.Beep(700, 100); Console.Beep(500, 150); Environment.Exit(0); } Program.screen.lines[y][x] = 'c'; } catch { Console.WriteLine("Game Over!"); Console.Beep(900, 100); Console.Beep(700, 100); Console.Beep(500, 150); Environment.Exit(0); } } else { SnakePart s = Program.parts[count - 1]; if (s.x > x && s.x - x != 0) { dir = 0; } else if (s.x < x && s.x - x != 0) { dir = 2; } else if (s.y > y && s.y - y != 0) { dir = 1; } else { dir = 3; } x = s.x; y = s.y; try { Program.screen.lines[y][x] = 'x'; } catch { Console.WriteLine("Game Over!"); Console.Beep(900, 100); Console.Beep(700, 100); Console.Beep(500, 150); Environment.Exit(0); } } } } public class Apple { public int x; public int y; public Apple(int x, int y) { this.x = x; this.y = y; } public void Update() { Program.screen.lines[y][x] = 'a'; if (Math.Abs(Program.parts[0].x - x) <= 2 && Math.Abs(Program.parts[0].y - y) <= 1) { int newx = 0; int newy = 0; if (Program.parts[Program.parts.Count - 1].dir == 0) { newx = -1; } else if (Program.parts[Program.parts.Count - 1].dir == 1) { newy = -1; } else if (Program.parts[Program.parts.Count - 1].dir == 2) { newx = 1; } else if (Program.parts[Program.parts.Count - 1].dir == 3) { newy = 1; } Program.parts.Add(new SnakePart(Program.parts[Program.parts.Count - 1].x + newx, Program.parts[Program.parts.Count - 1].y + newy, Program.partNum)); Program.partNum++; Console.Beep(800, 200); Program.food[x, y] = null; } } } }
解决方案
1. 修复渲染时的换行重复问题
问题核心是Console.WriteLine会自动添加换行符,加上控制台环境差异,导致每行之间多出空行。把渲染循环代码替换为:
// 替换原有的Console.WriteLine循环 Console.Write(string.Join(Environment.NewLine, screen.lines));
或者手动控制换行:
for (int i = screen.screeny - 1; i > -1; i--) { Console.Write(screen.lines[i]); if (i > 0) Console.Write(Environment.NewLine); }
2. 统一窗口与屏幕尺寸初始化
你初始设置了窗口大小为120x30,但随后用Console.LargestWindowHeight初始化ScreenCompiler,导致屏幕行数远大于窗口高度,加剧显示混乱。修改初始化代码:
// 替换原screen初始化代码,和窗口尺寸保持一致 screen = new ScreenCompiler(120, 30);
同时锁定窗口大小,避免用户拉伸:
Console.SetWindowSize(120, 30); Console.SetBufferSize(120, 30); // 强制锁定窗口尺寸 Console.WindowWidth = 120; Console.WindowHeight = 30;
3. 调整控制台属性设置
右键.exe快捷方式 → 属性:
- 切换到「选项」标签,取消勾选「快速编辑模式」
- 切换到「字体」标签,选择
Consolas或Lucida Console等宽字体,调整字号确保垂直间距正常
内容的提问来源于stack exchange,提问作者CJTheGoldfish
相关产品推荐
相关产品推荐

