* 初心者向けプログラミング体験ワークショップ#6
-(by [[K]], 2021.12.06)

** (0)
-今回紹介するのは、「ロケット操縦ゲーム」です。34行で書けます。

-このページは[[「初心者向けプログラミング体験ワークショップ」>a21_edu01]]の教材のうちの一つです。

** (1) ストーリー & ルール
-(これは未来のお話です。)
-ぼくはとても運転がうまい宇宙船のパイロットです。宇宙には大きな星のまわりに小さな星(というか大きないんせき?)が集まって回っているところがあります。そしてそんな場所に小さな宇宙基地がある場合もあります。
-もちろんそんなところはとても危険な場所です。そんなところに基地を作らずにほかのところに作ればいいのにとぼくも思うけど、まあきっと何か理由があるんだろうな。
-さてさて、そんな宇宙基地に食べ物やにもつを配達しなければいけないときがある。でもそんなところを進むのはもちろんあぶない。ということで運転がうまいぼくに「やってください」ってたのみにくる。しょうがないのでひきうける。
-さあ、きみもぼくの宇宙船の操縦を手伝ってね!
----
| http://k.osask.jp/files/pic20211207a.png |
-ゲームスタート時には画面右の中央あたりに小さなロケットが表示されます。放っておくと徐々に落っこちてゲームオーバーになりますので、スペースキーを押してロケットを落ちないようにしてください。ただし上へ飛ぶためのメインエンジンは出力が大きいので一回押すだけでもかなり上に勢いがつきます。だから押しすぎに注意してください。
-落ちないし上にもぶつからないようにできるようになったら、カーソルキーの左を2~3回くらい押してみてください。ゆっくりと左に進むようになるはずです。
-左に進んでいるものをどうやって止めるかですが、それはカーソルキーの右を2~3回くらい押せばいいのです。
-この左右キーも押しすぎると逆噴射してもなかなか止まれなくなりますので、用心深く押しましょう。
-さてこのゲームの目的は、ロケットを画面中央の白の四角まで他の星にぶつからないように運ぶことです。

-と、ここまで書いて、私はこのストーリーに重大な間違いを見つけました。もしロケットが重力で下にひかれるのなら、いんせきや宇宙基地も同じように引かれて落ちるはずなのです。でも実際は落ちるのはロケットだけです。おかしいですね!(いんせきや基地が星の周りをまわる軌道にあるのなら、ロケットも落ちていかないのが正しい。)
-まあ今からゲームを直すと大変そうなので、その部分については今は見逃してください!!(このストーリーはゲームを作った後に書いています)。

-なお、HLXでは現在開いているゲームウィンドウよりも大きなウィンドウを開くことができません。ですから、たとえばもし「坂道を走ってきれいな石を拾い集めるゲーム」を遊んだ後にこれを実行しようとするとエラーになるはずです。その場合は、お手数ですがHLXを一度終了させて、もう一度HLXを起動して、それからrocket.txtやrocket.cをrunしてください。

** (2-1) HLX-BASICでのプログラム(34行)
-プログラム中に日本語で説明を書き込んでいますが、その部分は入力しないでください。矢印も入力しないでください。
 
 CANVAS 40,30,"ROCKET";                               ← ゲーム画面を作ります。よこ40マス、たて30マスの大きさです。
 HI=1;                                                ← ハイスコアを1に設定します。
 FOR;                                                 ← ここから繰り返します(ゲームオーバーの再ゲームの時にここに戻ってきます)。
   FOR ST=1,9999;                                     ← ここから繰り返します(ステージクリアの後の次ステージ開始時にここに戻ってきます)。
     HI=MAX(HI,ST);                                   ← HIとSTの大きいほうをHIとします。
     CLS@ 0;                                          ← 画面を黒(色番号0)で消します。
     PRINT@ 0,0,15,0,"STAGE:%2d    HIGH:%2d",ST,HI;    ← 画面の上のほう(場所(0,0))に白色(色番号(7,0))で現在のステージとハイスコアを書きます。
     LOOP 21;                                         ← 以下を21回の繰り返しますです。
       R=ST*3;                                        ← 半径はステージ数の3倍。
       X=RND(620-R);                                  ← 円が620ピクセルよりも右に行かないように、中心を決定(乱数を使っています)。
       Y=RND(460-R)+20+R;                             ← 円が20ピクセルよりも下になるように、中心を決定(乱数を使っています)。
       FILLOVALCENTER@@ RF,X,Y,R,R,RND(6)+1;          ← 場所(X,Y)を中心に半径Rの円を描きます。色は1~6のどれかです。
     NEXT;
     FILLRECT@@ RF,80,40,280,228,7;                   ← 横80ピクセル縦40ピクセルの長方形を、場所(280,228)に描きます。
     X=630; Y=470; VX=0; VY= -20;                     ← ロケットの初期位置と、初期速度を設定します。
     FOR;                                             ← ゲームのメインループです。
       C=GETPIX@@(RF,X,Y);                            ← ロケットの場所のピクセルの色を調べます。
       CHARSAVE@@ RF,X-8,Y-8,7,15,-1;                 ← ロケットをかきます。場所は(X-8,Y-8)で、キャラクター番号は7番、色は(15,-1)です。
       IF C==0XFFFFFF BREAK;                          ← もしCが白色なら、メインループを抜けます(ステージクリア)。
       IF Y<0 OR 479<Y OR C!=0 GOTO CRASH;           ← ロケットが上に行きすぎたか、もしくは下に行きすぎたか、もしくはCが黒以外なら、ゲームオーバー処理(CRASH)へ。
       I=INKEY@WRC(200);                              ← 200ミリ秒(つまり0.2秒)待って、キー入力を確認して、先ほどかいたロケットを消します。
       IF I==32 THEN VY-=9; FI;                       ← もしスペースキーを押していたら、VYから9を引きます。
       VX+=XMOVE(I); VY++;                            ← VXの値を、キー入力に応じて増やしたり減らしたりします。
       X=(X+VX+640)%640; Y+=VY;                       ← XにVXを足します。そして右はしにいったら左はしに、左はしにいったら右はしに移動させます。YにVYを足します。
     NEXT;
     PRINT@ 18,15,0,7," CLEAR!";                      ← (ステージクリアなので)「CLEAR!」と表示します。
     WAIT 3000;                                       ← 3000ミリ秒(つまり3秒)待ちます。
   NEXT;                                              ← STに1を足して、次のステージへ。
 CRASH:
   Y=MINMAX(Y,0,479);                                ← Yが画面外なら画面内に収まるように修正します。
   FOR I=0,3; R=I*5+10; DRAWOVALCENTER@@ RF,X,Y,R,R,4; NEXT;    ← 赤い丸を半径を広げながら3つかいています。
   PRINT@ 18,15,4,7," CRASH!";                        ← 「CRASH!」と表示します。
   WAITKEY@ 10;                                       ← Enterキー が押されるまで待ちます。
 NEXT;
 
-ほそく説明:
--PRINT@の中の%以降には、数字のゼロや小文字のc、dがあります。英語のオーではないので注意してくださいね。
--色番号の表
|0:黒|1:青|2:みどり|3:水色|4:赤|5:むらさき|6:黄色|7:白|
--色を2つの数字で表すときは、1つ目の数がキャラクターの色で、2つ目の数が背景の色です。
--キャラクターの表示位置は、2つの数字で表します。1つ目が左から数えて何番目のマスか(0番から数えます)、2つ目が上から数えて何番目のマスか(0番から数えます)。
---このゲームでは32x24マスを用意しているので、0,0~31,23までが使えます。
--キャラクター番号の表
|0:空白|1:四角|2:丸|3:バツ|4:よこぼう|5:たてぼう|6:顔マーク|7:ひしがた|8:ななめせん|9:ななめせん|
--RND(6)について: RNDは乱数(らんすう)の命令で、RND(6)は0~5までのどれかの数を適当に決める命令です。

** (2-2) HLX-BASICのプログラムを実行するための方法(大人の方へ)
-もしWindowsでHLX-BASICを使うなら、話は簡単です!
-[[a21_hlx003]]のページへ行って、 hlx003b.zip をダウンロードして、中にある hlx_x86_win.exe を入手してください。それだけあれば十分で他のファイルは捨ててしまってもかまいません。
-[[a21_hlx003]]のページへ行って、 hlx003c.zip をダウンロードして、中にある hlx_x86_win.exe を入手してください。それだけあれば十分で他のファイルは捨ててしまってもかまいません。
-このhlx_x86_win.exeを適当なフィルだ内において、同じフォルダの中にrocket.txtというテキストファイルを作ります。このテキストファイルをお子さんに入力させてあげてください。
--入力の際にはまずテキストエディタを開き(メモ帳でもいいですが、私はTeraPadが好きです)、キーボードのCapsLockをオンにした状態で、大人がテキストを一文字ずつ読んであげて、お子さんがキーを探して入力する、というスタイルがおすすめです。大人は1とI、0とOの入力間違いが起こりやすいので、特にそこを注意してみてあげます。
--キーを見つけられないときは、ほらここにあるよと教えてあげますが、それでもキーボードのキーを指さすだけにして、実際の入力はお子さんにやらせてあげてください。入力ミスがあった時の訂正も、「矢印キーを使ってカーソルをここに動かして、そこでDelキーを押して。」みたいに操作の指示はしても、実際の操作はお子さんにやらせてみてください。
--そうすると、「これは全部自分がやった。」という満足感が得られるはずです。
--(何回もやって慣れてきたら、自分でプログラムを読んで入力できるようになると思います。)
-入力が終わったら、先ほどのhlx_x86_win.exeを起動して、そこで
 hlx>run rocket.txt
-と入力してください。入力ミスがなければゲームが始まるはずです。
-ミスがあった場合は、エラーメッセージを見ながら間違いを探して直してください(エラーメッセージはかなり不親切なので、大人の方の手伝いが不可欠です。よろしくお願いします。お手数をおかけしてすみません)。
-なおゲーム中のキー操作は、ゲーム画面が入力アクティブになっていないと有効ではありませんので、あれ?操作が効かないなと思ったら、ゲーム画面が一番上のウィンドウになっているかどうかをまず確認してください。

-Windows以外のOSの方は、[[a21_hlx003]]のページを見て、ソースコードからhlxをビルドしなければいけません。そこがクリアできれば、あとは同じようにできるはずです。

** (2-3) 改造のポイント
-このゲームは自分で入力したのですから、自分で改造することだってできます。ただ遊ぶだけじゃなくて改造も楽しんでほしいです。

-もしゲームが簡単すぎるなら、いんせきの数を増やすといいかもしれません。今は21個ですが、30個くらいにしたらいいかもしれません。もしくはステージ1からのスタートにしないで、ステージ10くらいから始まるようにしたらいいかもしれません。
-ゲームが難しすぎたら、いんせきの数を減らすといいでしょう。もしくは、「OR C!=0」の部分を消して、いんせきに当たっても死なないようにするという「無敵化」もできそうです。「VY++;」をなくせば重力もなくせますが、そうすると上に行かせたときに止まれなくなるので(=画面上部にいって死んでしまう)、この改造だけではうまくいきません。

-このゲームのストーリーは先ほど書いたように問題があります。では、重力をなくして、ロケットの上下も左右と同じようにカーソルキーで動かせるようにしてみます。
--「VY= -20;」→「VY=0;」
--「VY++;」→「VY+=YMOVE(I);」
-やってみると、まあ、これはこれで一応ゲームにはなりますね。興味があったら試してみてください。

** (3-1) C言語でのプログラム(aclライブラリ利用)(39行)
-内容的に、(2-1)とほぼ一対一で対応しているので、細かい説明は省略します。
 
 #include <acl.c>
 
 void aMain()
 {
   int hi = 1, st, x, y, vx, vy, r, i, c;
   AWindow *w = aOpenWinEx(40, 30, "ROCKET", 0);
   for (;;) {
     for (st = 1;; st++) {
       hi = aMaxInt(hi, st);
       aCls(w, 0);
       aGrPrintf(w, 0, 0, 15, 0, "STAGE:%2d    HIGH:%2d", st, hi);
       for (i = 0; i < 21; i++) {
         r = st * 3;
         x = aRnd(620 - r);
         y = aRnd(460 - r) + 20 + r;
         aFillOvalCentOpt(w, AOPT_Rf, x, y, r, r, aRnd(6) + 1);
       }
       aFillRectOpt(w, AOPT_Rf, 80, 40, 280, 228, 7);
       x = 630; y = 470; vx = 0; vy = -20;
       for (;;) {
         c = aGetPixOpt(w, AOPT_Rf, x, y);
         aEchSavOpt(w, AOPT_Rf, x - 8, y - 8, 7, 15, -1);
         if (c == 0xffffff) break;
         if (y < 0 || 479 < y || c != 0x000000) goto crash;
         i = aInkey_waitRC(w, 200);
         if (i == 32) { vy -= 9; }
         vx += aMoveDx(i); vy++;
         x = (x + vx + 640) % 640; y += vy;
       }
       aGrPrintf(w, 18, 15, 0, 7, " CLEAR!");
       aWait(3000);
     }
 crash:
     y = aSaturateInt(y, 0, 479);
     for (i = 0; i < 3; i++) { r = i * 5 + 10; aDrawOvalCentOpt(w, AOPT_Rf, x, y, r, r, 4); }
     aGrPrintf(w, 18, 15, 4, 7, " CRASH!");
     aWaitKey(w, AKEY_ENTER);
   }
 }
 
** (3-2) C言語のプログラムを実行するための方法(大人の方へ)
-このプログラムは、C言語でありながらHLXのサポート範囲内の機能だけで書かれているので、HLXで実行することができます。この場合、C言語やaclライブラリのインストールは不要です(もしWindows以外で、まずhlx自身のビルドからやらなければいけない場合は、Cコンパイラやaclライブラリのインストールが必要です)。
-使い方もほとんど同じで、rocket.cを作って、
 hlx>run rocket.c
-とするだけでOKです。

-もし、HLXを使わずに普通のCコンパイラとaclライブラリの組み合わせでやる場合は、[[a21_acl01]]のページを見てaclライブラリを使えるようにしたうえで、上記のrocket.cをビルドしてください。

-そのほかの操作方法や改造方法などは、(2-2)、(2-3)と同等なのでここでは省略します。

** (4) バグ修正
-スペースキーを連打して画面上部に飛び出すと、HLXごと落ちてしまうというバグがありました。aclライブラリのバグなので、ライブラリとHLXの両方をバージョンアップします(acl01bとhlx003bへ)。

* こめんと欄
#comment

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS