我已经编写并修改了经典蛇游戏的源代码。随着水平的增加,产生更多的苹果(例如1级将生成1个苹果,2级将生成2个苹果,依此类推。)当我达到5级时,正在生成5个苹果,以及我的大量增加进程内存,从400MB到2GB。这就是弹出“ArgumentException”错误并且游戏崩溃的地方。很抱歉我的编码不好,因为我还在学习。
错误显示在我的draw()方法中,我每500ms调用一次以刷新电路板。
Board.cs中的draw()方法发生错误
public void draw(Position p, Image pic)
{
squares[p.getRowNo(), p.getColNo()].Image = pic;
}
form1.cs中的刷新方法
private void refresh(Object myObject, EventArgs myEventArgs)
{
mySnake.move(mode); //Move the snake based on mode
mainBoard.draw();
apples.draw(); //<----- draw apples
mySnake.draw();
//increment the duration by amount of time that has passed
duration += speed;
timerLBL.Text = Convert.ToString(duration / 1000); //Show time passed
//Check if snake is biting itself. If so, call GameOver.
if (mySnake.checkEatItself() == true)
{
GameOver();
}
else if (apples.checkIFSnakeHeadEatApple( mySnake.getHeadPosition()) == true)
{
score += apples.eatAppleAtPostion(mySnake.getHeadPosition());
scoreLBL.Text = Convert.ToString(score);
if (apples.noMoreApples() == true)
{
EatenAllApple();
clock.Stop();
level++;
gotoNextLevel(level);
MessageBox.Show("Press the start button to go to Level " + level, "Congrats");
}
else
{
//Length the snake and continue with the Game
mySnake.extendBody();
}
}
}
Overal Board.cs
class Board
{
int maxRow = 10, maxCol = 20; //Max 10 rows, and 20 columns in the board
int squareSize = 30; //Each square is 30px by 30px
PictureBox[,] squares;
public Board(Form mainForm)
{
squares = new PictureBox[maxRow, maxCol];
for (int row = 0; row < maxRow; row++)
{
for (int col = 0; col < maxCol; col++)
{
squares[row, col] = new PictureBox();
squares[row, col].Location = new Point(col * squareSize, row * squareSize);
squares[row, col].Height = squareSize;
squares[row, col].Width = squareSize;
squares[row, col].SizeMode = PictureBoxSizeMode.StretchImage;
squares[row, col].BackColor = Color.Black;
squares[row, col].BorderStyle = BorderStyle.FixedSingle;
mainForm.Controls["boardPanel"].Controls.Add(squares[row, col]);
}
}
mainForm.Controls["controlPanel"].Location = new Point(mainForm.Controls["boardPanel"].Location.X, mainForm.Controls["boardPanel"].Location.Y + mainForm.Controls["boardPanel"].Height + 20);
}
//setter
public void setMaxColNo(int x)
{
maxCol = x;
}
public void setMaxRowNo(int x)
{
maxRow = x;
}
//getter
public int getMaxColNo()
{
return maxCol-1; //Last Column No is 19, not 20
}
public int getMaxRowNo()
{
return maxRow-1; //Last Row No is 9, not 10
}
public int getMinColNo()
{
return 0; // 0 is the smallest Col number of the board
}
public int getMinRowNo()
{
return 0; // 0 is the smallest Row number of the board
}
public void draw()
{
for (int row = 0; row < maxRow; row++)
{
for (int col = 0; col < maxCol; col++)
{
squares[row, col].Image = null ;
}
}
}
public void draw(Position p, Image pic)
{
squares[p.getRowNo(), p.getColNo()].Image = pic;
}
}
Rewards.cs(根据@AxelWass的要求)
class Rewards
{
List<Position> appleList;
Board mainBoard;
public Rewards(int size, Board mainBoard)
{
this.mainBoard = mainBoard;
appleList = new List<Position>();
for (int i=0;i< size;i++)
{
int rowNo, colNo;
//Generate an apple at random position but not duplicated
do
{
//Generate a random number between 1 and MaxRowNo
rowNo = (new Random()).Next(1, mainBoard.getMaxRowNo()+1);
//Generate a random number between 1 and MaxColNo
colNo = (new Random()).Next(1, mainBoard.getMaxColNo()+1);
} while (isDuplicate(rowNo, colNo) == true);
appleList.Add(new Position(rowNo, colNo));
}
}
private Boolean isDuplicate(int row, int col)
{
Boolean result = false;
for (int i=0;i< appleList.Count;i++)
{
if (appleList[i].getRowNo() == row && appleList[i].getColNo() == col)
result = true;
}
return result;
}
public void draw()
{
for (int i = 0; i < appleList.Count; i++)
{
mainBoard.draw(appleList[i], Properties.Resources.apple);
}
}
public Boolean checkIFSnakeHeadEatApple(Position snakeHead)
{
Boolean result = false;
for (int i = 0; i < appleList.Count; i++)
{
if (snakeHead.getRowNo() == appleList[i].getRowNo() && snakeHead.getColNo() == appleList[i].getColNo())
result = true;
}
return result;
}
public Boolean checkIFSnakeEatApple(Position snakeHead)
{
Boolean result = false;
for (int i = 0; i < appleList.Count; i++)
{
if (snakeHead.getRowNo() == appleList[i].getRowNo() && snakeHead.getColNo() == appleList[i].getColNo())
result = true;
}
return result;
}
public int eatAppleAtPostion(Position p)
{
for (int i = 0; i < appleList.Count; i++)
{
if (p.getRowNo() == appleList[i].getRowNo() && p.getColNo() == appleList[i].getColNo())
appleList.RemoveAt(i);
//snakeEatApple();
}
return 50; //50 points per apple
}
public Boolean noMoreApples()
{
if (appleList.Count > 0)
return false;
else
return true;
}
/*public void snakeEatApple()
{
System.Media.SoundPlayer EatenApple = new System.Media.SoundPlayer(Properties.Resources.Eating_Apple);
EatenApple.Play();
}*/
}
答案 0 :(得分:4)
mainBoard.draw(appleList[i], Properties.Resources.apple);
这是问题陈述。 VS中的资源设计师设计得不是很好,违反了微软自己的编码指南。根本不明显的是apple
属性每次使用它时都会创建一个新的Bitmap对象。由于它位于一个循环中,在一个本身将经常被调用的方法中,代码会生成一个 lot 的位图对象。
Bitmap是一个一次性类。不处理它通常很麻烦,它是一个非常小的包装类,可以使用大量的非托管内存。如果垃圾收集器没有经常运行以便终结器可以运行,程序的内存使用量可以非常快地运行。
解决方法是仅使用属性。将它存储在类的字段中(在方法之外):
Bitmap apple = Properties.Resources.apple;
修正声明:
mainBoard.draw(appleList[i], apple);
如果你穿过你的T并点缀你的话,那么当表格关闭时你就把它丢弃了:
private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
apple.Dispose();
}
这是一个很好的习惯,虽然这可能是不必要的,因为你的程序可能会在用户关闭窗口时结束。