ゲーム開発ラボ

視覚的に楽しいアプリやゲーム開発をしながら,Javaやjavascriptを楽しく学んでいきます

ヘビゲームを作る-1

ヘビゲーム(snake game)とは,伸長するヘビをうまく操作しながら,エサをたべて高得点を狙うゲームのことです
今回はこのヘビゲームを作成してみましょう
下図が今回作成するアプリの様子です
f:id:filopodia:20201120120147g:plain


今回はエサは出現せず,ただヘビを操作するだけのアプリです
コードは以下のようになります

int col_num = 21; // 列の数
int row_num = 21; // 行の数
int snake_size = 5; // 蛇の長さの初期値
ArrayList<PVector> snake = new ArrayList<PVector>();
PVector velocity = new PVector(0, -1); // 蛇の進行速度の初期値

void setup(){
  frameRate(10);
  size(400, 400);
  stroke(150);
  for(int i=0; i<snake_size; i++){
    snake.add(new PVector(10, 10+i)); // 蛇の初期状態
  }
}

void draw(){
  background(255);
  updateSnake();
  displayCells();
}

void displayCells(){
  float c_x = width/col_num; // セルサイズ
  float c_y = height/row_num;
  
  // 全てのセルの描画
  fill(255);
  for(int i=0; i<col_num; i+=1){
    for(int j=0; j<row_num; j++){
      rect(i*c_x, j*c_y, c_x, c_y);
    }
  }  
  // snakeの描画
  fill(0, 0, 255);
  for(int i=0; i<snake.size(); i++){
    rect(snake.get(i).x * c_x, snake.get(i).y * c_y, c_x, c_y);
  }  
}

void updateSnake(){
  for(int i=snake_size-1; i>0; i--){
    snake.get(i).x = snake.get(i-1).x;
    snake.get(i).y = snake.get(i-1).y;
  }
  snake.get(0).add(velocity);
  snake.get(0).x = constrain(snake.get(0).x, 0, col_num-1);
  snake.get(0).y = constrain(snake.get(0).y, 0, row_num-1);    
}

void keyPressed(){
  switch(keyCode){
    case UP:
          velocity.set(0, -1);
          break;
    case DOWN:
          velocity.set(0, 1);
          break;
    case LEFT:
          velocity.set(-1, 0);
          break;
    case RIGHT:
          velocity.set(1, 0);
          break;
  }
}

上のコードを詳しくみていきます

今回のアプリではヘビの長さは不変ですが,今後はエサを食べるにつれて長さが変わるため,ArrayListを用いてヘビを表現しています

int snake_size = 5; // 蛇の長さの初期値
ArrayList<PVector> snake = new ArrayList<PVector>();

void setup(){
  for(int i=0; i<snake_size; i++){
    snake.add(new PVector(10, 10+i)); // 蛇の長さの分だけArrayListの要素を生成
  }
}

ArrayListは配列と似ていますが,要素の数を自由に増減させることができる,という点で配列と異なります
コード中のArrayList<PVector> snakeの部分では,PVector型の要素をもつArrayListを生成しています
下に続くコードでは,PVectorにヘビの体のx座標とy座標のデータを格納しています
座標の初期値は,ヘビの頭の方からみて(x, y) = (10, 10), (10, 11), (10, 12), (10, 13), (10, 14) となっています

次に,ヘビの移動についてみてみましょう
アプリが開始すると,ヘビは静止することなく移動し続けます
ヘビの速度をvelocityとして定義し,各frameごとにヘビの頭の座標にvelocityを足していくことでヘビの移動を実現しています
頭以降,尾にかけての座標については,ArrayListの一つ前の座標をそれぞれ順番に代入していくことで,這う動作を実現しています

PVector velocity = new PVector(0, -1); // 蛇の進行速度の初期値

void updateSnake(){

  // ArrayList(snake)のそれぞれの要素について,一つ前の要素の座標を順番に代入する 
  for(int i=snake_size-1; i>0; i--){
    snake.get(i).x = snake.get(i-1).x;
    snake.get(i).y = snake.get(i-1).y;
  }
  snake.get(0).add(velocity); // ヘビの頭の座標に速度を加算
  snake.get(0).x = constrain(snake.get(0).x, 0, col_num-1);
  snake.get(0).y = constrain(snake.get(0).y, 0, row_num-1);    
}

上のコード中のconstrain()という記述は,変数の上限と下限を規定するものです
ヘビx軸,y軸それぞれ0~20番まである座標の中だけで移動してほしいので,上限と下限を設けています
この記述がないと,ヘビが盤目の外へと逃げ出てしまうので注意です


次に方向転換についてですが,PCの矢印キーを入力するとvelocityの向きが変化するようにしています

void keyPressed(){
  switch(keyCode){
    case UP:
          velocity.set(0, -1);
          break;
    case DOWN:
          velocity.set(0, 1);
          break;
    case LEFT:
          velocity.set(-1, 0);
          break;
    case RIGHT:
          velocity.set(1, 0);
          break;
  }
}


以上でヘビの基本的な動作を実装することができました
次回以降はエサやゲームオーバーの概念を作り込んでいきます