迷路を右手法で攻略する(4) 右手法でキャラクターを動かす

それでは右手法を使ってキャラクターが自動でゴールまでたどり着けるようにしましょう。
と、その前に。ゴールがないと分かりにくいのでゴールの絵を用意してみたよ。

ゴールにしたい場所のmapの値を2にしておきます。そして、main関数内の記述を以下のように修正します。

for(int i = 0; i < 20; i ++){
    for(int j = 0; j < 20; j ++){
      if (map[j][i] == 1)  image(E[1], i*20, j*20);
    }
  }
 ↓ 修正 
for(int i = 0; i < 20; i ++){
    for(int j = 0; j < 20; j ++){
      if (map[j][i] == 1)  image(E[1], i*20, j*20);
      else if (map[j][i] == 2)  image(E[2], i*20, j*20);
    }
  }

 

さて、右手法。以下の優先順位で進みます。
(1) 右側の壁伝いにすすむ
(2) 右が開いていれば右に進む(右に90度回転)
(3) (2)以外で正面が開いていれば直進する(向きはそのまま)
(4) (2)(3)以外で左が開いていれば左に進む(左に90度回転)
(5) 上記以外の場合、来たところに戻る(180度回転)

今回の地図上では、以下のように進めればいいわけです。

では、「向き」をどのように表せばいいでしょうか。向きを表現するために、新しく dir という変数を用意してみました。現在位置から見て上に移動する場合は dir を0とし、時計回りに右、下、左に移動する場合はそれぞれ1,2,3と値を設定することとします。上では「回転」と書いていますが、図形を回転させたりは特にしていません。dirの初期値を2としているのは、はじめは下向きにしておきたいからです。

それぞれの向きの絵も新しく用意してみたよ(それぞれ、chara0.jpg ~chara3.jpg として dataフォルダに保存しておいてね)。
   

変数dirの番号順に、0 (上向き)の場合から考えてみます。
手順は上記の(1)~(5)を参考にします。現在地(map[Y][X])から見て右側はmap[Y][X-1]です。これが0であればそちらに移動します。この時、向きが上から右に変わるので向きも右側に変えておきます(dir = 1)。向きが変わるのでキャラクターの画像も変えます(E[0] = loadImage(“chara(番号).jpg”);)。

if (dir == 0){
    if (map[Y][X+1] == 0){
      X++;
      dir = 1;
      E[0] = loadImage("chara1.jpg");
    } 
    else if (map[Y-1][X] == 0)  Y--;
    else if (map[Y][X-1] == 0){
      X--;
      dir = 3;
      E[0] = loadImage("chara3.jpg");
    }
    else {
      dir = 2;
      E[0] = loadImage("chara2.jpg");
    }
  }

dir が 1 から 3 の場合も同じように設定します。どの方向が「右側」かそれぞれの場合で変わるので注意です。ここまでの全体のコードです。

 

int map[][] = {{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},
               {1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,2,1},
               {1,0,1,1,0,1,1,0,1,0,1,0,0,1,1,1,0,1,0,1},
               {1,0,1,0,0,0,1,0,1,0,1,1,0,1,0,0,0,0,0,1},
               {1,0,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1},
               {1,0,1,0,1,0,1,0,0,0,1,1,1,1,0,1,1,1,0,1},
               {1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,1,0,1,0,1},
               {1,1,1,0,1,1,0,1,0,0,0,1,0,1,0,1,0,0,0,1},
               {1,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,1,1,1,1},
               {1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1},
               {1,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1},
               {1,0,0,1,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1},
               {1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,1},
               {1,0,0,0,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1},
               {1,0,1,0,1,0,1,0,0,0,1,1,1,1,0,1,1,1,0,1},
               {1,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,1,0,1},
               {1,1,1,0,1,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1},
               {1,0,0,0,0,1,0,1,0,1,0,1,0,1,0,1,1,1,0,1},
               {1,0,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1},
               {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
PImage[] E;
int X, Y;
int dir;

void setup(){
  size(400,400);
  background(255);
  frameRate(8);
  X = 1;
  Y = 1;
  dir = 2;
  E = new PImage[10];
  E[0] = loadImage("chara2.jpg");
  E[1] = loadImage("block.jpg");
  E[2] = loadImage("goal.jpg");
}

void draw(){
  background(255);
  for(int i = 0; i < 20; i ++){
    for(int j = 0; j < 20; j ++){
      if (map[j][i] == 1)  image(E[1], i*20, j*20);
      else if (map[j][i] == 2)  image(E[2], i*20, j*20);
    }
  }

  if (dir == 0){
    if (map[Y][X+1] == 0){
      X++;
      dir = 1;
      E[0] = loadImage("chara1.jpg");
    } 
    else if (map[Y-1][X] == 0)  Y--;
    else if (map[Y][X-1] == 0){
      X--;
      dir = 3;
      E[0] = loadImage("chara3.jpg");
    }
    else {
      dir = 2;
      E[0] = loadImage("chara2.jpg");
    }
  }
  
  else if (dir == 1){
    if (map[Y+1][X] == 0){
      Y++;
      dir = 2;
      E[0] = loadImage("chara2.jpg");
    } 
    else if (map[Y][X+1] == 0)  X++;
    else if (map[Y-1][X] == 0){
      Y--;
      dir = 0;
      E[0] = loadImage("chara0.jpg");
    }
    else {
      dir = 3;
      E[0] = loadImage("chara3.jpg");
    }
  }
  
  else if (dir == 2){
    if (map[Y][X-1] == 0){
      X--;
      dir = 3;
      E[0] = loadImage("chara3.jpg");
    } 
    else if (map[Y+1][X] == 0)  Y++;
    else if (map[Y][X+1] == 0){
      X++;
      dir = 1;
      E[0] = loadImage("chara1.jpg");
    }
    else {
      dir = 0;
      E[0] = loadImage("chara0.jpg");
    }
  }
  
  else {
    if (map[Y-1][X] == 0){
      Y--;
      dir = 0;
      E[0] = loadImage("chara0.jpg");
    } 
    else if (map[Y][X-1] == 0)  X--;
    else if (map[Y+1][X] == 0){
      Y++;
      dir = 2;
      E[0] = loadImage("chara2.jpg");
    }
    else {
      dir = 1;
      E[0] = loadImage("chara1.jpg");
    }
  }
  image(E[0], X*20, Y*20); 
  
  if((map[Y-1][X]==2) || (map[Y][X+1]==2) || 
     (map[Y+1][X]==2) || (map[Y][X-1]==2)){
    textAlign(CENTER, CENTER);
    textSize(100);
    fill(0);
    text("GOAL!", width/2, height/2);
    noLoop(); 
  }
}

 

ゴールしたら Goal! と表示され、止まるようにしました。noLoop(); は、それ以上描画をしないようにする命令です。

現状の問題は、右側に壁がないような広い空間に置かれた場合にくるくると回ってしまって進めなくなってしまうことです。これを回避するには、壁があるところまでとりあえず直進する処理を加えるなどの対策が必要です。

 

Leave a Reply

Your email address will not be published. Required fields are marked *