トップ


大ボスをつける

middleBoss後の諸処理

大ボスをつける前に、middleBoss後の諸処理を行ってあげましょう。このままではUFOも動かずゲームが終わってしまっている状態です。

ところで、middleBossが破壊されたときに黄色い玉が残っていた場合にはどうなるのでしょうか?
黄色い玉はmiddleBossからx,y座標を参照できなくなり、エラーかと思われますが、幸いエラーではなく黄色い玉が残された状態になります。しかしながら、いずれにしても黄色い玉はmiddleBossが破壊されたときに一緒に破壊されたほうがよさそうです。
また、もう一度敵を出現してもらわなければならないので、stopが2の状態から回避しなければなりません。

Round.tonyu
extends Enemy;

constructor round(x,y,p,ang) {                //コンストラクター
  super(x,y,p);
  this.ang=ang;
}
life=100;
mark=50;
while(1){
  for( t in $Chars ){
    if( t is middleBoss ){
      x=t.x+80*cos(ang);
      y=t.y+80*sin(ang);
    }
    if( t is middleBoss && t.isDead() ) die();
  }
  ang++;
  atariHantei();
  update();
}
UFO.tonyu
extends SpriteChar;

function appearEnemy() {
   if (rnd( 400 )==0) appear(new Item(rnd(530)+15,y,22));
   if (rnd( 1600 )==0) appear(new Item(rnd(530)+15,y,17));
   if (rnd( 50 )==0) appear(new skyBlue(x,y,$pat_Sample+2));
   if (rnd( 100 )==0 && $score>100) appear(new Yellow(x,y,$pat_Sample+8));
   if (rnd( 200 )==0 && $score>200) appear(new Red(x,y,$pat_Sample+11));
   if (rnd( 800 )==0 && $score>300) appear(new Green(x,y+20,$pat_Sample+19));
   if (rnd( 1600 )==0 && $score>400) appear(new Blue(x,y+20,$pat_Sample+22));
   if ($score>1000 && stop==0) stop=1;
}
$score=0;
vx=2;
stop=0;
while(1) {
  if(! $myChar.isDead()) {
    if(!( (stop==1 || stop==2) && x>$screenWidth - 42)) x=x+vx;
    else {
      if(stop==1){
        appear(new middleBoss(x,y,$pat_Sample+26));
        stop=2;
      }
    }
    if( stop!=1 && stop!=2 ) {
      appearEnemy();
    }
    if( x<40 || x>$screenWidth - 40 ) vx=-vx;
  }
  update();
}
Enemy.tonyu
extends SpriteChar;

function onDie() {
  appear(new Bomb(x , y ,$pat_Sample+4,3));
}
function atariHantei() {
  for (t in $chars) {
   if ( t is Tama && crashTo(t) )  {
     life=life-1;
     if(life<=0) {
       die();
       if(mark==200) $UFO.stop=3;
       $score=$score+mark;
       $mplayer.play($se_bomb,0,60);
     }
     t.die();
   }
  }
  if (crashTo($myChar)) $myChar.die();
}

まず、UFOの「stop==0」を「stop!=1 && stop!=2」に変えました。これで、「stopが0の時だけ」をいう命令が「stopが1ではなくかつstopが2でもない時」という命令に変わりました。stop==3の時にも動き始めると思います。
次に、Roundの方ですが、middleBossが死んでいる時に、自分も死ぬように設定しました。
Enemyの方も変えました。markが200点なのは現在ではmiddleBossしかいません。動き出したときにさらに右側に行くと思いますが、x>$screenWidth - 40の条件によりvxはすぐに-2となってくれるはずです。UFOを右端のx>$screenWidth - 40ではなくx>$screenWidth - 42で止めておいたのは、x>$screenWidth - 40で止めておいた場合、動き出したときにさらに右に行ったのでは$screenWidth - 38>x>$screenWidth - 40の間でぶるぶると震えて止まってしまうかもしれないからです。

ラウンドを破壊する方法はこれ以外の方法でも、Roundクラスには変更を加えずに、UFOクラスは先と同じように変更して、Enemyクラスには

Enemy.tonyu
extends SpriteChar;

function onDie() {
  appear(new Bomb(x , y ,$pat_Sample+4,3));
}
function atariHantei() {
  for (t in $chars) {
   if ( t is Tama && crashTo(t) )  {
     life=life-1;
     if(life<=0) {
       die();
        if(mark==200) {
          $UFO.stop=3;
          for( tt in $chars ) if( tt is Round ) tt.die();
        }
       $score=$score+mark;
       $mplayer.play($se_bomb,0,60);
     }
     t.die();
   }
  }
  if (crashTo($myChar)) $myChar.die();
}

とする方法も考えられます。このように、どこの部分を変更するのかは作成するものの自由です。しかし、関連する物同士は近くに置いたほうが後で見やすくなります。

また、Roundクラスに「$UFO.stop=3」と書くことはできません。Roundが死んで最後にmiddleBossが残ったときに、middleBossを破壊はしたもののUFOは再び動き出してはくれないからです。

大ボスを作る

大ボスを作成してみましょう。


Sample8.lzh

やはり、最後のボスも関連性をもたせてskyBlueたちと同じようにしてみました。最後のボスとわかりやすいように王冠を戴冠して頂いております。

では、早速作ってみましょう。オブジェクトを作成して、以下のコードを打ち込んでみてください。

Boss.tonyu
extends Enemy;

function appearShoot() {
   if (rnd( 100 )==0) for(i=-2;i<=2;i++) appear(new Sting(x,y,$pat_Sample+28,i));
   if (rnd( 100 )==0) appear(new Ball(x,y,$pat_Sample+25));
}
function involute(sx,sy,ang,rate) {
  x=sx+cos(ang)+ang/rate*3.14156*sin(ang);
  y=sy+sin(ang)-ang/rate*3.14156*cos(ang);
}
function lemniscate(sx,sy,ang,rate) {
  if(1+sin(ang)==0) ang++;
  x=sx+rate*(cos(ang)/(1 +(sin(ang))*(sin(ang))));
  y=sy+rate*(sin(ang)*cos(ang)/(1 +sin(ang))*(1 +sin(ang)));
}
ang=5000;
while(ang>0){
  involute($screenWidth/2-15,100,ang,60);
  ang-=10;
  update();
}
vx=2;
life=500;
mark=1000;
sx=x;
sy=y;
ang=90;
while(1){
  ang++;
  lemniscate(sx,sy,ang,150);
  if(x<80 || x>$screenWidth-80) vx=-vx;
  appearShoot();
  atariHantei();
  update();
}

Bossは画面をくるくると回りながら登場してきました。インボリュート(伸開線)という三角関数を使用した特別な構文(曲線)を使用しています。
involute(sx,sy,ang,rate)・・・sx,sy:最終到達地点(出発地点)の座標、ang:角度、rate:振幅
動きもレムニスケート(連珠形)という特別な形を使用しています。
lemniscate(sx,sy,ang,rate)・・・sx,sy:直行点の座標、ang:角度、rate:振幅

これらの曲線がなぜこのような不思議な移動方法を取るのかは、大学でも数学を専攻しなければなりません。高校でも、理系で進学校であれば、インボリュートあたりまで勉強するかもしれませんが、レムニスケート(厳密にはベルヌーイのレムにスケートと呼びます)まで勉強するかどうかはわかりません。「なぜ?」よりも「結果」を優先して、「これでBossが効率良く無限大のような移動方法を取ってくれた」と解釈してください。レムニスケートを使用せずに同じような動きを再現することはできますが、プログラムは見難くなります。曲線の中身は知らなくてもプログラムを組み込むことはできるのです。
曲線に興味があれば数学の参考書(平面代数曲線、有理曲線に関する参考書)を買うか、インターネットでも結果だけならば見ることはできます。

次は、多重継承と継承の継承についてやってみましょう。

  トップ