Visual Studio控制台中的文本垂直行距与可执行文件生成的控制台不一致

编程语言 2026-07-08

我在Visual Studio中做一个ASCII蛇游戏,当我用F5运行并构建时它可以工作,但当我运行生成的.exe文件或该文件的快捷方式时,字符之间的竖直间距太大,某些行甚至超出了屏幕/标题栏。如何在.exe文件以及桌面快捷方式的格式上解决这个问题?如果你需要我的代码,下面有。我已经尝试过设置缓冲区和设置窗口尺寸,但都没有效果。截图中水平的x 之间只有一个空格字符,垂直方向除了行距之外没有其他空格。

更新:我又做了更多测试,发现它在控制台中按预期行之间多写了一行。我也在朋友的电脑上运行过,它对他而言没问题,但在我这里却不行。

图片:

这是它不应该是这样的时候,且被拉伸了:

这是它不应该是这样的时候,它被拉伸了

在这个版本中,x之间的水平间距与正确版本中的竖向间距相同,但竖直间距错误。

这是正确的,但只有在 Visual Studio 下才能这样运行:

这是正确的,但只有在 **Visual Studio** 下才能这样运行

代码:

代码:

using System;
using System.Data;
using System.Net.Http.Headers;
using System.Security.Cryptography;
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;
            }
        }
    }
}

解决方案

我修好了。问题在于无论使用哪种控制台系统,只要文本到达缓冲区末端就会自动换行。我在代码中也把每行末尾设成换行,因此在Visual Studio之外的控制台里每行之间多出了一行。因此解决办法是把需要打印的所有文本拼成一个大字符串,输出时不带任何换行符。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章