2017-02-02 15 views
0

Я написал и изменил исходный код классической игры-змеи. По мере увеличения уровня увеличивается количество яблок (например, уровень 1 будет генерировать 1 яблоко, уровень 2 будет генерировать 2 яблока и т. Д.). Когда я добираюсь до уровня 5, 5 яблок генерируются вместе с огромным увеличением моего процессорную память, от 400 МБ до 2 ГБ. Именно там появляется ошибка «ArgumentException», и игра разбилась. Извините за мое плохое кодирование, поскольку я все еще участвую.ArgumentException & память процесса продолжает увеличиваться в C#

Ошибка, показывающая мой метод draw(), где я вызывал каждые 500 мс для обновления доски.

Ошибка происходит при розыгрыше() в Board.cs

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

Я не думаю, что вы показываете соответствующий раздел своего кода. Проблема может быть внутри apples.draw(). Общим шаблоном проектирования является то, что называется репозиторий, может помочь вам. Вы можете создать экземпляр одного изображения для всех яблок и повторно использовать его. Не могли бы вы показать нам код внутри класса apple? Спасибо – AxelWass

+0

Да, конечно ... я отредактирую свой вопрос – Jatiz

+1

'Properties.Resources.apple' - Это десериализует изображение при каждом вызове, постарайтесь избежать этого. – Caramiriel

ответ

4
mainBoard.draw(appleList[i], Properties.Resources.apple); 

Это заявление о проблеме. Разработчик ресурсов в VS не был разработан очень хорошо и нарушает собственные правила Microsoft по кодированию. Что совсем не очевидно, так это то, что свойство apple создает новый объект Bitmap каждый раз, когда вы его используете. Поскольку он находится внутри цикла, в методе, который сам будет вызываться очень часто, код генерирует лот растровых объектов.

Bitmap - одноразовый класс. Не утилизировать его вообще довольно сложно, это очень маленький класс-оболочка, который может использовать много неуправляемой памяти. Если сборщик мусора работает недостаточно часто, так что финализатор может работать, использование вашей программы в памяти может начаться очень быстро.

Обходным путем является использование только . Храните его в поле вашего класса (за пределами методы):

Bitmap apple = Properties.Resources.apple; 

И исправить заявление:

mainBoard.draw(appleList[i], apple); 

И если вы скрестите T, и точка ваш я, то вы выбрасывайте его, когда форма закрывается:

private void Form1_FormClosed(object sender, FormClosedEventArgs e) { 
     apple.Dispose(); 
    } 

который является хорошей привычкой попасть, хотя это, вероятно, нет необходимости, поскольку ваша программа, вероятно, заканчивается, когда пользователь закрывает окно.

+0

Вы правы: _ «Внутренне свойство get использует класс ResourceManager для создания нового экземпляра объекта« _ ». Из [документации] (https://msdn.microsoft.com/en-us/library/7k989cfy (v = vs.90) .aspx) – AxelWass

 Смежные вопросы

  • Нет связанных вопросов^_^