简体   繁体   English

堆栈溢出异常(C#)

[英]Stack Overflow Exception (C#)

I'm currently working on a Snake game that can solve itself, but when I activate it, usually after 30~ successful hits, my application crashes with the aforementioned exception either in System.drawing.dll or in System.Windows.Forms.dll. 我目前正在开发可以解决自身问题的Snake游戏,但是当我激活它(通常在成功击中30次之后)时,我的应用程序因System.drawing.dll或System.Windows.Forms.dll中的上述异常而崩溃。

The problem usually occurs in the command "Application.DoEvents()", but it has occured in several other places too. 该问题通常发生在命令“ Application.DoEvents()”中,但是它也发生在其他几个地方。

    using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Threading;
using System.IO;

namespace Snake
{
    enum Directions
    {
        Right = 1,
        Left = -1,
        Up = 2,
        Down = -2,
        NoDirection = 0
    }

    public partial class GameForm : Form
    {
        #region Data Members

        SnakeGame gmGame;
        Point pCurrFood;
        Directions dirFirstDirection;
        Directions dirSecondDirection;
        Directions dirHelpDirection;
        Color DEFAULT_COLOUR = Color.White;
        const int SEGMENT_HEIGHT = 10;
        const int SEGMENT_WIDTH = 10;

        #endregion

        #region Ctor

        public GameForm()
        {
            InitializeComponent();
            this.gmGame = new SnakeGame();
            this.dirFirstDirection = Directions.NoDirection;
            this.dirSecondDirection = Directions.NoDirection;
        }

        #endregion

        #region Other Methods

        private void PaintSegment(Graphics gGraphics, Point pnPoint, Color cColour)
        {
            Pen Pen = new Pen(cColour);
            Rectangle Rectangle = new Rectangle(pnPoint.X,
                                                pnPoint.Y,
                                                SEGMENT_HEIGHT,
                                                SEGMENT_WIDTH);
            gGraphics.DrawRectangle(Pen, Rectangle);
            Brush Brush = new SolidBrush(cColour);
            gGraphics.FillRectangle(Brush, Rectangle);
        }

        private void PlaceNewFood()
        {
            Random rRand = new Random();
            int nHeight = rRand.Next(this.panel1.Size.Height);
            int nWidth = rRand.Next(this.panel1.Size.Width);

            while ((nHeight % 10 != 0) || (nWidth % 10 != 0))
            {
                nHeight = rRand.Next(this.panel1.Size.Height - 10);
                nWidth = rRand.Next(this.panel1.Size.Width - 10);

                while (this.gmGame.SnakeQueue.Contains(new Point(nWidth, nHeight)))
                {
                    nHeight = rRand.Next(this.panel1.Size.Height);
                    nWidth = rRand.Next(this.panel1.Size.Width);
                }
            }

            this.pCurrFood = new Point(nWidth, nHeight);
            this.PaintSegment(this.panel1.CreateGraphics(), this.pCurrFood, Color.Red);
        }

        private void SelfSolve()
        {

            this.dirFirstDirection = (Directions)(Math.Sign(this.gmGame.SnakeHead.Y -
                                                            this.pCurrFood.Y) * 2);
            this.dirSecondDirection = (Directions)Math.Sign(this.pCurrFood.X -
                                                            this.gmGame.SnakeHead.X);

            this.ManageSnake(this.dirFirstDirection, this.dirSecondDirection);
        }

        private bool WillCollide(Point pnPointToCheck)
        {
            return ((pnPointToCheck.X > this.panel1.Size.Width) ||
                    (pnPointToCheck.Y > this.panel1.Size.Height) ||
                    (pnPointToCheck.X * pnPointToCheck.Y < 0) ||
                    (this.gmGame.SnakeQueue.Contains(pnPointToCheck)));
        }

        private void ManageSnake(Directions dirFirstSnakeDirection,
                                 Directions dirSecondSnakeDirection)
        {
            Point pnNewHead = this.gmGame.SnakeHead;

            switch (dirFirstSnakeDirection)
            {
                case (Directions.Down):
                {
                    if (this.WillCollide(new Point(pnNewHead.X, pnNewHead.Y + SEGMENT_HEIGHT)))
                    {
                        this.ManageSnake(Directions.NoDirection, dirSecondSnakeDirection);
                    }
                    else
                    {
                        pnNewHead.Y += SEGMENT_HEIGHT;
                        dirHelpDirection = Directions.Down;
                    }

                    break;
                }
                case (Directions.Up):
                {
                    if (this.WillCollide(new Point(pnNewHead.X, pnNewHead.Y - SEGMENT_HEIGHT)))
                    {
                        this.ManageSnake(Directions.NoDirection, dirSecondSnakeDirection);
                    }
                    else
                    {
                        pnNewHead.Y -= SEGMENT_HEIGHT;
                        dirHelpDirection = Directions.Up;
                    }

                    break;
                }
                case (Directions.NoDirection):
                {
                    switch (dirSecondSnakeDirection)
                    {
                        case (Directions.Right):
                        {
                            if (this.WillCollide(new Point(pnNewHead.X + SEGMENT_WIDTH, pnNewHead.Y)))
                            {
                                this.ManageSnake(this.dirHelpDirection, dirSecondSnakeDirection);
                            }
                            else
                            {
                                pnNewHead.X += SEGMENT_WIDTH;
                            }

                            break;
                        }
                        case (Directions.Left):
                        {
                            if (this.WillCollide(new Point(pnNewHead.X - SEGMENT_WIDTH, pnNewHead.Y)))
                            {
                                this.ManageSnake(this.dirHelpDirection, dirSecondSnakeDirection);
                            }
                            else
                            {
                                pnNewHead.X -= SEGMENT_WIDTH;
                            }

                            break;
                        }
                    }

                    break;
                }
            }

            this.gmGame.AddSegment(pnNewHead);

            if (this.gmGame.SnakeHead.Equals(this.pCurrFood))
            {
                this.lblScoreNum.Text = (int.Parse(this.lblScoreNum.Text) + 1).ToString();
                this.PlaceNewFood();
            }
            else
            {
                this.PaintSegment(this.panel1.CreateGraphics(),
                                  (Point)this.gmGame.SnakeQueue.Peek(),
                                  DEFAULT_COLOUR);
                this.gmGame.RemoveSegment();
            }

            this.PaintSegment(this.panel1.CreateGraphics(),
                              this.gmGame.SnakeHead,
                              Color.Green);
            Thread.Sleep(5);
            Application.DoEvents();
            this.SelfSolve();
        }

        #endregion

        #region Events

        private void GameForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                this.PlaceNewFood();
                this.SelfSolve();
            }
            else if (e.KeyCode == Keys.Escape)
            {
                this.Close();
            }
            else if (e.KeyCode == Keys.Space)
            {
                MessageBox.Show("Frozen, press OK to continue");
            }
        }

        private void GameForm_ClientSizeChanged(object sender, EventArgs e)
        {
            this.PaintSegment(this.panel1.CreateGraphics(), new Point(210, 250), Color.Green);
            this.PaintSegment(this.panel1.CreateGraphics(), new Point(220, 250), Color.Green);
            this.PaintSegment(this.panel1.CreateGraphics(), new Point(230, 250), Color.Green);
            this.PaintSegment(this.panel1.CreateGraphics(), new Point(240, 250), Color.Green);
            this.PaintSegment(this.panel1.CreateGraphics(), new Point(250, 250), Color.Green);
        }

        #endregion
    }
}

I know it's a lot of code, but since I'm not sure where's the root of the problem, I had to copy all of it. 我知道这是很多代码,但是由于我不确定问题的根源在哪里,所以我不得不全部复制。

I'd greatly appreciate it if you could point me in the right direction. 如果您能指出正确的方向,我将不胜感激。

Thanks in advance :) 提前致谢 :)

PS I know that the algorithm has flaws, I'll get to that later. PS:我知道该算法有缺陷,我将在后面介绍。 Right now my main concern is solving the crash. 目前,我主要关心的是解决崩溃问题。

This is because you keep on going recursive in your method. 这是因为您继续在方法中进行递归。 eg: 例如:

      Thread.Sleep(5); 
      Application.DoEvents(); 
      this.SelfSolve(); 

Your method will basically never end. 您的方法将永远不会结束。

You should use a timer and within that timer, call SelfSolve() This should solve your problem. 您应该使用一个计时器,并在该计时器内调用SelfSolve(),这应该可以解决您的问题。 When using a timer you dont have to call DoEvents yourself since a winforms timer anyways posts a call to your method as a message and the message loop will handle the invocation and other messages. 使用计时器时,您不必自己调用DoEvents,因为无论如何Winforms计时器都会将对方法的调用作为消息发布,并且消息循环将处理调用和其他消息。

SelfSolve should not call ManageSnake directly, but rather schedule its run for some later moment. SelfSolve不应直接调用ManageSnake ,而应安排稍后运行。 Otherwise you get infinite recursion SelfSolve -> ManageSnake -> SelfSolve etc. 否则,您将获得无限递归SelfSolve > ManageSnake > SelfSolve等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM