Processing筆記05—貪吃蛇小遊戲

貪吃蛇是非常經典的小遊戲,大家肯定接觸過,它在當年只能打電話發短信的諾基亞手機中是唯一的娛樂項目了。它的操作非常簡單,很多編程語言都可以來實現它。我們已經學習了Processing中基本圖形的繪製以及鼠標鍵盤的識別響應,本篇我們使用Processing來編程實現貪吃蛇小遊戲。

1. 蛇身的繪製

這應該是貪吃蛇遊戲中最主要的部分了,在程序中使用數組來保存組成蛇身的每個方塊的座標值。

// 保存組成蛇身的每個方格位置
int[] x = new int[snake_length_max];
int[] y = new int[snake_length_max];

當蛇頭位置改變以後,我們從尾部開始遍歷數組,將每個方塊座標位置向後移動,然後將新的蛇頭位置賦值到數組第一元素,然後重新繪製所有方塊。

void draw_snake()
{
  //從尾部開始更新蛇身方塊座標
  for (int i=snake_length-1; i>0; i--) {
    x[i] = x[i-1];
    y[i] = y[i-1];
  }

  // 設置蛇頭新的座標
  x[0] = snake_head_x;
  y[0] = snake_head_y;

  // 設置蛇身填充顏色
  fill(#3874F6);

  // 開始畫蛇
  for (int i=0; i<snake_length; i++) {
    rect(x[i], y[i], grid, grid);
  }
}

2. 食物的產生

當食物被吃掉以後,我們需要在指定長寬的區域內隨機生成食物的座標數據,這裏使用了**random()**函數,用來生成座標值,這個座標值需要是方塊邊長的整數倍。

void draw_food(int max_width, int max_high)
{
  //食物填充顏色
  fill(#F71E1E); 

  //如果食物被吃掉,則隨機生成一個
  if (food_eaten)
  {
    food_x = int(random(0, max_width) / grid) * grid;
    food_y = int(random(0, max_high) / grid) * grid;
  }

  rect(food_x, food_y, grid, grid);
  food_eaten = false;
}

3. 方向控制

這裏使用前篇介紹的按鍵識別操作。對方向按鍵進行判斷,然後對應改變蛇的運動方向。

 if (snake_direction != 'P'&& keyPressed && key == CODED)
  {
    switch(keyCode) {
    case LEFT:
      if (snake_direction != 'R') {
        snake_direction = 'L';
      }
      break;
    case RIGHT:
      if (snake_direction != 'L') {
        snake_direction = 'R';
      }
      break;
    case DOWN:
      if (snake_direction != 'U') {
        snake_direction = 'D';
      }
      break;
    case UP:
      if (snake_direction != 'D') {
        snake_direction = 'U';
      }
      break;
    }

在刷新顯示的時候,會根據移動方向的不同,對蛇頭的座標進行改變,當重新對蛇身進行繪製的時候,整個蛇就進行了一次移動。

//移動方向選擇
switch(snake_direction) {
    case 'L':
        snake_head_x -= grid;
        break;
    case 'R':
        snake_head_x += grid;
        break;
    case 'D':
        snake_head_y += grid;
        break;
    case 'U':
        snake_head_y -= grid;
        break;
}

此外,增加了暫停鍵“P”或“p”,以及運行鍵“R”或“r”的判斷。

if (key == 'p' || key == 'P')
  {
    game_pause++;
    if (game_pause%2 == 1)
    {
      snake_direction_temp = snake_direction;
      snake_direction = 'P';
    } else {
      snake_direction = snake_direction_temp;
    }
  }
....
if (keyPressed && (key == 'r' || key == 'R'))
  {
   ...
  }

值得注意的是,這些對於按鍵的監聽,沒有放在draw() 函數中,而是使用了鍵盤事件函數 keyPressed(),每當按下一個鍵,其中的代碼就會運行一次,使用這種方式監聽按鍵更加方便靈活。

4. 判斷遊戲結束

當蛇頭座標超過顯示區域,即蛇撞牆,或蛇頭位置座標與蛇身其他方塊座標相同,即自己吃了自己,都會導致遊戲結束。

boolean check_snake_die()
{
  // 撞牆了
  if ( snake_head_x < 0 || snake_head_x >= width || snake_head_y < 0 || snake_head_y >= height) {
    show_game_over();
    return true;
  }

  // 自己吃自己
  if ( snake_length > 2 ) {
    for ( int i=1; i<snake_length; i++ ) {
      if ( snake_head_x == x[i] && snake_head_y == y[i] ) {
        show_game_over();
        return true;
      }
    }
  }
  return false;
}

5. 移動速度

程序中使用millis() 函數來獲取自程序開始到當前的時間。每當draw() 中代碼運行一次,我們都重新獲取一次當前時間,然後減掉之前的時間來計算出經過的時間,然後與移動間隔時間進行比較,當大於間隔時間時,說明需要刷新移動蛇身一次,然後重新獲取一次時間,爲後續比較做準備。

 time_passed = millis() - time_start; //計算出經過的時間
 time_interval = 1000 / speed; //計算移動間隔時間

 if (time_passed > time_interval && snake_direction != 'P' && game_start)//遊戲刷新條件
  {
     ...
    time_start = millis(); //重新獲取時間
  }

6. 吃到食物

當蛇頭座標移動到與食物座標相同時,就代表食物被吃到,這時蛇身長度要加1,重新生成食物。程序中每吃掉5個食物,移動速度就會增加1。

//蛇吃到食物
if (snake_head_x == food_x && snake_head_y == food_y)
{
	food_eaten = true; //可重新生成食物
	snake_length++;

	if ( snake_length%5 == 1) {
	speed++;
	}
	speed = min(20, speed);//控制最大速度
}

7. 實現效果

snake

貪吃蛇的實現還是非常簡單的,當然代碼還有很多需要優化的地方,比如說我們在隨機生成食物座標的時候,需要排除蛇身中方塊的座標,即食物不能直接出現在蛇身中,你可以試着來優化下。

我們還可以直接將代碼導出成exe可執行文件,你也來試一試吧。

關注公衆號「TonyCode」,後臺回覆“snake”,獲取貪吃蛇完整程序。
回覆「1024」獲取1000G學習資料。
個人博客
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章