堆栈溢出异常(C#)

时间:2011-10-20 11:51:32

标签: c# winforms stack-overflow

我正在开发一款可以自行解决的Snake游戏,但是当我激活它时,通常在30次成功点击之后,我的应用程序会在System.drawing.dll或System.Windows中遇到上述异常而崩溃。 Forms.dll。

问题通常出现在命令“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
    }
}

我知道这是很多代码,但由于我不确定问题的根源在哪里,我不得不复制所有代码。

如果你能指出我正确的方向,我将不胜感激。

提前致谢:)

P.S。我知道算法有缺陷,我稍后会谈到。现在我主要担心的是解决崩溃问题。

2 个答案:

答案 0 :(得分:6)

这是因为你继续在你的方法中递归。 e.g:

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

你的方法基本上永远不会结束。

您应该使用计时器并在该计时器内调用SelfSolve()这应该可以解决您的问题。 使用计时器时,您不必自己调用DoEvents,因为winforms计时器会将对方法的调用作为消息发布,消息循环将处理调用和其他消息。

答案 1 :(得分:0)

SelfSolve不应直接调用ManageSnake,而应安排其运行一段时间。否则你会获得无限递归SelfSolve - &gt; ManageSnake - &gt; SelfSolve等。