winforms 如何在Windows窗体中循环paint事件以创建简单的游戏循环?

ws51t4hk  于 2022-11-16  发布在  Windows
关注(0)|答案(1)|浏览(204)

我尝试在C# Visual Studio中创建一个简单的snake游戏作为练习。我对Windows窗体应用程序知之甚少,但它似乎是使用箭头访问绘图和用户输入的最简单方法。
这是一个很好的框架,用于一个简单的游戏,像这样的C#?
但这是我真实的的问题。我试图创建一个游戏循环,它每秒循环一次,并改变下一次要画蛇头的位置。但我不知道如何多次调用Paint事件。它似乎调用了一次,然后退出。如果我在()在paint方法内部循环,它每秒绘制一个矩形,但我无法访问KeyEventArgs或其他任何内容,因为正在运行的代码被困在Paint调用内部。
我希望初始的paint调用绘制蛇的起始点,然后循环paint调用,我猜是另一个paint方法(?),它询问控制器最后按下的是哪个按钮,然后在那个方向绘制下一个矩形。* 完成此操作并创建游戏循环的预期方式是什么?*
我将感谢任何信息和知识,以帮助教我这个过程,任何其他的建议或投入是欢迎的!
下面是我目前的代码:'''

public partial class FormMain : Form
    {
        private readonly int pixelSize;
        private readonly int gridSize;
        private readonly int center;
        private string currDirection;

        

    public FormMain()
    {
        pixelSize = 30;
        currDirection = "right";

        // Calculating size of the grid based on the size of the 'pixel'
        gridSize = 640 / pixelSize;

        // Calculating the starting position of the snake in the center of the screen
        center = (gridSize / 2) * pixelSize;

        InitializeComponent();
    }

    private void FormMain_Paint(object sender, PaintEventArgs e)
    {
        // referencing the Graphics object and setting the color of the snake
        Graphics g = e.Graphics;
        Pen seaPen = new Pen(Color.MediumSeaGreen);

        // This draws the initial center rectangle
        Point currentHeadLocation = new Point(center, center);

        Rectangle r;
        // Here's the loop that should happen every second or so, probably in another method.
        while (true)
        {
            r = new Rectangle(currentHeadLocation, new Size(pixelSize, pixelSize));
            g.DrawRectangle(seaPen, r);

            if (currDirection.Equals("right"))
            {
                currentHeadLocation = new Point(currentHeadLocation.X + pixelSize, currentHeadLocation.Y);
            }

            else if (currDirection.Equals("left"))
            {
                currentHeadLocation = new Point(currentHeadLocation.X - pixelSize, currentHeadLocation.Y);
            }

            else if (currDirection.Equals("up"))
            {
                currentHeadLocation = new Point(currentHeadLocation.X, currentHeadLocation.Y - pixelSize);
            }

            else if (currDirection.Equals("down"))
            {
                currentHeadLocation = new Point(currentHeadLocation.X, currentHeadLocation.Y + pixelSize);
            }

            Thread.Sleep(1000);
        }
            
    }

    private void FormMain_KeyDown(object sender, KeyEventArgs e)
    {
        switch(e.KeyCode)
        {
            case Keys.Left:
                currDirection = "left";
                break;
            case Keys.Right:
                currDirection = "right";
                break;
            case Keys.Up:
                currDirection = "up";
                break;
            case Keys.Down:
                currDirection = "down";
                break;
        }

    }
}

'''

v64noz0r

v64noz0r1#

在这种情况下使用Thread.Sleep()几乎总是一个坏主意,因为它会冻结您唯一的线程,也就是UI线程。
您可能希望使用timer
快速示例:

public FormMain()
{
    //Any other init stuff here

    System.Windows.Forms.Timer t = new System.Windows.Forms.Timer(); //Create a timer
    t.interval = 1000; //interval time in ms
    t.Tick += (s, e) => LoopFunctionName(); //Bind a function to the event whenever the timer reaches its interval
}
public void LoopFunctionName()
{
    //Game loop 
}

如果您要胁迫控件重新绘制,只要呼叫Invalidate()即可。

相关问题