モラこじ! ブログモードでGo!

レトロゲーム界隈にずぶずぶハマりつつある40代おっさんの生き様です!

イースはいいっすねぇ…と思っていたものの3

Ys1, 2に続き、PC98版 Ys3 (プロジェクトEGG 版) をクリアしました! (о´∀`о)

f:id:nyagbon:20190223230915p:plain

なんと言っても Ys3 の魅力はあの奥行き感のある横スクロールですね! オリジナルの PC88 のスペックでよくあんな神業が実現できたものだなぁと思います。当時、自分は PC88 でアセンブリプログラミングするのが趣味でしたから、あのスクロールを自分で実現するんだ!と頑張って見たものの、ノロノロしたスピードでしか実現できませんでした。やっぱりファルコムは神だなぁと思ったのも、そんなエピソードがあったからでした。

 

さて今回、ニコ生で配信しながらのプレイでしたが、Ys1は7回、Ys2は10回もかかったのに、Ys3は 3回でクリアしてしまいました(1回1時間半程度)。一旦終わってしまうと、あれ、こんなに短かったんだっけ?と拍子抜けしてしまいました。

live2.nicovideo.jp

それでも、Ys3 はアクション要素が強くて、なかなか倒せないボスも何体かいて、散々死にまくりましたし、その度にリスナーさんたちに叱咤激励をもらいつつ、ヒーコラヒーコラ泣きながら、何度も挑んで、なんとかようやく倒していきました。( ;∀;)

ただ、最後のガルバラン戦では、2~3 度やり直しただけで、「あれ?」と、自分でもあっけなく倒せてしまったのです。当時 PC88 でやったときには大層苦労した思い出がありました。30年経って、ちょっとはスキルアップしたということでしょうか?

それと Ys1, 2 と比べてマップに迷い要素がほぼない所が、いいのか悪いのか、スムーズに進める反面、一本道 JRPG 感を強く思わせてしまうところでもありますね。Ys3 は画面構成も違いますし、ストーリーとアクションを楽しむゲームという位置づけですね。

あと、Ys3 の最大の謎といえば、エレナ! どんなにアドルが苦労して進んできたところにも、いつも平気な姿で現れるエレナ! 彼女は一体どんな装備でどんなスキルを持っているのでしょうか!?  エレナにガルバランを倒して欲しいと何度も祈りました…。

f:id:nyagbon:20190224152035g:plain

 

そんなこんなで YS1~3 の3部作を30年ぶりにプレイし終えました! 紆余曲折あり、自分の迷いスキルが発覚したり、色々ありましたが、楽しくプレイさせていただきました。ストーリーも、ゲームシステムも、よくできており、感心してしまいます。いろんなプラットフォームに移植・リメイクされて、30年たった今でも愛されている理由がわかります。Ys1,2を毎年プレイするという生主さんもいらっしゃるほどですから。^^;

さて、次は何のゲームしようかな。色んなゲームを楽しみたいぜぃ! それでは~。

趣味のプログラミング(3)~ゲームバランス篇

先日の記事:

nyagbon.hatenablog.com

で公開したゲームのソースコードを、2/19 にリハビリ中さんニコニコ生放送で実機の MSX に一生懸命入力して、プレイしてくださいました! ありがとうございます!

live2.nicovideo.jp

ニコニコのプレミアム会員の方なら、配信を放送終了後から7日間は見られるはずなので、是非とも御覧になってください。お早めに!

ゲームバランス

さて、先日の記事でMSXのゲームプログラミングは一旦終了したはずでした。ところが、自分で何度かプレイしてみたところ、

 

    敵の動きがゆるくて、コツさえつかめば永遠に死なない、つーか死ねないw

 

ということが発覚したのでした…! しかもリハビリ中さんも、さすがゲーマーだけあって、放送中にすぐにコツを掴んでしまったのです!

 

    これはマズいぞ…。ゲームとして成り立たないじゃないか! (; ・`д・´)

 

ゲームプログラマー(?)としての闘争心がめらめらと燃えてきたのでありました… 。

…いやいや、こうやってプレイしつつゲームバランスを整えていくのがゲームプログラミングの醍醐味の一つなのですよ、ネ。(*´ω`*)

ゲームバランスの調整

さて、どうしよう? 敵に弾を打たせる? 敵の動くアルゴリズムを変える?  でも、BASIC だからこれ以上処理を増やすと重くなるし、それに、コードをまたイチから入力するのは大変だよなぁ。

コードの変更が少なく、動作も重くならないようにしたいので、以下の方法をとることにしました。

  • 敵もライフ制にする。3発当てるとやっつけられる
  • 敵のライフが減るたびに、自分に近づく速度を速くする
  • 敵を倒した後に新しい敵が出てくる場所をランダムにする
  • 自分のミサイルの速度を少し遅くする

そして、これはキツくする方向じゃないですが、放送中にリスナーの方が出されたアイデア:

も実装することにしました。5000点ごとにしてみました。

これで、よりゲームらしくなり、以前よりも攻防が楽しめるようになったのではないかと思います。(*^^)v

では、コードの変更点を説明していきます。

敵をライフ制に

まず、ライフに応じて色を変えるようにします。緑→黄→赤と信号の様に変わり、赤の状態で打つと敵をやっつけられるようにします。このために、配列 EC を DIM で宣言し、EC(0)~EC(2) にライフに応じた色番号を代入しています。(60行目)

敵のスプライトの表示色は 630 行目で EL に応じて決まるようにしています。 

次に、敵のライフを表す変数 EL を新しく導入します。初期値を3として、弾が当たるごとに1減らし、0になったら見事やっつけたことになるようにします。(220, 742~744行目)

なお、敵のライフを減らした時、敵が弾に打たれてバウンドして動くような感じにしました。(742行目のEHの値)

また、このタイミングで20点入るようにしました。(746行目)

そして、敵のライフが減るたびに速く動くようにするため、EL が減ると敵の速度 EH と EV が大きな値に振れやすくなるようにしました。(520~530行目)

敵をやっつけた

まず、やっつけたパターンの表示とBEEP音の出し方を少しだけ変えました。(750行目)

そして、やっつけたときには60点入るようにしました。ライフを2つ減らしたときに 2×20=40点入るから、合わせて一匹ごとに100点入ることになります。(760行目)

やっつけた後、新しい敵の出現位置をランダムな場所にしますが、あまりに自分に近いとすぐやられてしまうので、ある程度離れた場所になるまでランダムな値を計算し続けるようにしました。(770~780行目)

その他の修正

自分のミサイルの移動速度を 12 ドットずつから 10 ドットずつにしました。(430行目)

エクステンドの処理は、30行目と 901~902行目です。変数 XT がエクステンドになる点数、XS がエクステンドになった時に、XT に加えて次のエクステンドを決める点数です。点数 SC が XT 以上になったら、変数 RIHA を増やして、自機スプライトを BEEP を鳴らしつつ光らせて、残機表示を更新します。(902~905行目)

さらに細かい修正

いままでの背景は MSX が立ち上がった時の水色と青のままでしたが、真っ黒に変更しました。そして、ゲームオーバーになったら元の色に戻るようにしました。(10行目、1010行目)

自機の色を、白から薄い黄色に変更しました。(610行目)

ちなみに

MSX BASICの変数名は、2文字までしか認識しないらしく、RIHA という変数と RI という変数は同一とみなされることが分かりました。RIBBON でも RIRIRI でも同じものを指します。勉強不足でした。

また、前のコードからの変更を最小にするために、新しく追加したコードの行番号が細かい刻みになっています。ご了承ください。

実行!

ソースコードを打ち込んで run コマンドで実行します。

あるいは、WebMSX のサイトに飛び、Alt+B で Input Text のウィンドウを出してソースコードをコピペして OK を押します。MSX の画面に全部ソースコードが入力されたら、run コマンドで実行しましょう。

画面イメージ

こんな感じです。黒背景になりました。また、敵が黄色なのは、敵のライフが1減ったからですね。

f:id:nyagbon:20190221172101p:plain

ゲームバランスはどうなったか?

自分でやってみたところ、前よりは難しくなりました! 特に赤く怒った敵との攻防が難しくなりましたね! でも慣れるとやっぱりカンタンかな? もっと追求したい方は、いろいろとコード内の数値をいじって試してみてください。

また、このブログやツイッターなどで感想やアイデアをコメントいただければなお一層嬉しいです! (*´ω`*)

ソースコード

赤い部分が前回のコードから変更、追加した部分です。既にコードを入力されている方は、赤い部分だけ入力し直していただければ新しいバージョンになります。

それでは、お楽しみください! ではまた~。

 

10 SCREEN 1,2,0:KEY OFF:COLOR 15,1,1
20 ' INITIALIZE
30 SC=0:RIHA=3:XT=5000:XS=5000
40 GOSUB 980
50 ' :ENEMY COLORS
60 DIM EC(2):EC(0)=6:EC(1)=10:EC(2)=3
100 ' READ SPRITE 110 FOR S=1 TO 4:L$="":R$="" 120 FOR I=1 TO 16:READ I$ 130 L$=L$+CHR$(VAL("&B"+LEFT$(I$,8))) 140 R$=R$+CHR$(VAL("&B"+RIGHT$(I$,8))) 150 NEXT 160 SPRITE$(S)=L$+R$ 170 NEXT 200 ' INITIALIZE POSITIONS 210 X=180:Y=80:BB=0 220 EX=0:EY=INT(RND(1)*180):EH=0:EV=0:EL=3 300 ' MOVE BY CURSOR KEY OR JOY STICK 310 ST=STICK(0) OR STICK(1) 320 SG=STRIG(0) OR STRIG(1) 330 IF ST=0 THEN 400 340 IF ST>=1 AND ST<=2 AND Y>0 THEN Y=Y-8 350 IF ST>=3 AND ST<=4 AND X<240 THEN X=X+8 360 IF ST>=5 AND ST<=6 AND Y<180 THEN Y=Y+8 370 IF ST>=7 AND ST<=8 AND X>0 THEN X=X-8 400 ' BULLET 410 IF BB=1 THEN 430 420 IF SG<>0 THEN BB=1:BX=X:BY=Y 430 BX=BX-10 440 IF BX<0 THEN BB=0 500 ' ENEMY 510 EX=EX+EH:EY=EY+EV 520 EH=EH+SGN(X-EX)*INT(RND(1)*(9-EL*2)+1) 530 EV=EV+SGN(Y-EY)*INT(RND(1)*(9-EL*2)+1) 540 IF EH>10 THEN EH=10 550 IF EH<-10 THEN EH=-10 560 IF EV>10 THEN EV=10 570 IF EV<-10 THEN EV=-10 600 ' PUT SPRITES 610 PUTSPRITE 1,(X,Y),11,1 620 IF BB=1 THEN PUTSPRITE 2,(BX,BY),8,2 ELSE PUTSPRITE 2,,,0 630 PUTSPRITE 3,(EX,EY),EC(EL-1),3 700 ' COLLISION CHECK 710 ' :BULLET VS EMENY 720 IF BB=0 THEN 800 730 IF NOT(BX+2<=EX+13 AND EX+2<=BX+13 AND BY+2<=EY+13 AND EY+2<=BY+13) THEN 800 740 PUTSPRITE 3,(EX,EY),15,3:BEEP 742 EH=-10:EL=EL-1 744 IF EL=0 THEN 750 746 SC=SC+20:GOSUB 980 748 BB=0:GOTO 800 750 PUTSPRITE 3,(EX,EY),5,4:BEEP:PUTSPRITE 3,,,4:BEEP 760 SC=SC+60:BB=0:EH=0:EV=0:EL=3 770 EX=INT(RND(1)*240):EY=INT(RND(1)*180) 780 IF X-48<=EX+64 AND EX-48<=X+64 AND Y-48<=EY+64 AND EY-48<=Y+64 THEN 770 790 GOSUB 980 800 ' :ENEMY AND ME 810 IF NOT(X+2<=EX+13 AND EX+2<=X+13 AND Y+2<=EY+13 AND EY+2<=Y+13) THEN 900 820 ' :DEAD! 830 FOR I=0 TO 5 840 PUTSPRITE 1,(X,Y),8,4:BEEP:PUTSPRITE 1,,,0:BEEP 850 NEXT 860 RIHA=RIHA-1 870 GOSUB 980 880 IF RIHA=0 THEN 1010
890 GOTO 210 900 ' FINISHED A CYCLE
901 IF SC<XT THEN 910
902 XT=XT+XS:RIHA=RIHA+1:GOSUB 980
903 FOR I=0 TO 2
904 PUTSPRITE 1,(X,Y),15,1:BEEP:PUTSPRITE 1,(X,Y),4,1:BEEP
905 NEXT
909 ' END THIS GAME?
910 K$=INKEY$ 920 IF K$="q" THEN 1010 930 GOTO 300 970 ' SUBROUTINE TO SHOW SCORE AND LEFT RIHA 980 LOCATE 0,0:PRINT USING "SCORE:##### RIHA: #";SC;RIHA 990 RETURN 1000 ' GAME OVER 1010 SCREEN 1,1,1:KEY ON:COLOR 15,4,7 1020 GOSUB 980 1030 PRINT "GAME OVER!" 1040 END 2000 ' MINI RIHABILLY 2010 DATA 0000000000000000 2020 DATA 0000000110000000 2030 DATA 0000001111000000 2040 DATA 0000011111100000 2050 DATA 0000011001100000 2060 DATA 0000111111100000 2070 DATA 0000111111100000 2080 DATA 0011000000000000 2090 DATA 0111111011100000 2100 DATA 0001011101100000 2110 DATA 0000011111100000 2120 DATA 0000010011100000 2130 DATA 0000001111000000 2140 DATA 0000010000100000 2150 DATA 0000100000010000 2160 DATA 0000000000000000 2200 ' BULLET 2210 DATA 0000000000000000 2220 DATA 0000000000000000 2230 DATA 0000000000000000 2240 DATA 0000000000000000 2250 DATA 0000000000000000 2260 DATA 0000000000000000 2270 DATA 0000011111100000 2280 DATA 0001110000111000 2290 DATA 0000011111100000 2300 DATA 0000000000000000 2310 DATA 0000000000000000 2320 DATA 0000000000000000 2330 DATA 0000000000000000 2340 DATA 0000000000000000 2350 DATA 0000000000000000 2360 DATA 0000000000000000 2400 ' ENEMY 2410 DATA 0000000000000000 2420 DATA 0000000000000000 2430 DATA 0011000001100000 2440 DATA 0100100010010000 2450 DATA 0000011100000000 2460 DATA 0000011110000000 2470 DATA 0000111111000000 2480 DATA 0000111111100000 2490 DATA 0000110101100000 2500 DATA 0000110101110000 2510 DATA 0000111111110000 2520 DATA 0001111111110000 2530 DATA 0001111111111000 2540 DATA 0011111111111100 2550 DATA 0000000000000000 2560 DATA 0000000000000000 2600 ' KILLED 2610 DATA 0000000000000000 2620 DATA 0000000100000000 2630 DATA 0010000100001000 2640 DATA 0001000100010000 2650 DATA 0000100000100000 2660 DATA 0000000000000000 2670 DATA 0000000000000000 2680 DATA 0111000000011100 2690 DATA 0000000000000000 2700 DATA 0000000000000000 2710 DATA 0000100000100000 2720 DATA 0001000100010000 2730 DATA 0010000100001000 2740 DATA 0000000100000000 2750 DATA 0000000000000000 2760 DATA 0000000000000000

PS4のHDDをSSDに換装したョ!

なぜでしょう? そう、今更ながらモンハンにどっぷり浸かっているからなのです…!

f:id:nyagbon:20190216194115j:plain

ストーリーモードをクリアしても、さてここからが本番と言うゲーム構成。イベントクエストも豊富で、狩りを楽しんでおります。

しかーし! 何が不満かと言うと、誰もが思うあのロード時間! クエスト受けてマップに移動する時、拠点に戻る時、etc...。画面右下の薄暗くて見えにくい灰色のバーを食い入るようにジーっと眺めています。うーん、まだかー、と…。

f:id:nyagbon:20190217160753j:plain

SSD 500GB

安くなりましたねえ。アマゾンで 8510円で購入しました。もっと安いものもあったんですが、レビューをみてこれに決めました。

f:id:nyagbon:20190214223141j:plain

換装は、このサイトの通りにやりました。

ハードの換装自体は簡単。PS4本体のHDDが入ってる蓋をスライドして、ネジ外して、HDDを抜き出して、ネジ外して、SSDに置き換えてネジ締め直して、入れ直して、ネジ締め直す。以上! 10分足らずで完了です。

そして、これが元々入っていたHDD。

f:id:nyagbon:20190214223232j:plain

 

だからといってすぐにゲームができるわけではなく、面倒というか時間がかかるのは、

  • 換装の前に、セーブファイルを保存しておく

必要があります! USB メモリ、あるいは PSPlus 会員だとオンラインストレージに保存できます。だけど、1ゲーム1ゲーム保存して回らないといけない UI になっており、それが面倒でした。(;´д`)トホホ…

あとは、換装後に、

  • システムファイルのインストールと、ゲームやアプリの再インストール

ももちろん必要です。

自分はあまり PS4 のゲームを DL していなかったので、これらの作業もまぁちょっと面倒だな、ぐらいだったのですが、大量にゲームを持っている人だったら、心中お察しします…ってなっちゃいます。(-.-;)

さらに、モンハンのアプデがあったので、40分待たされましたw

f:id:nyagbon:20190214223355j:plain

まぁでも、一旦この作業さえ終えれば…、結果…、

 

     おおお、はええええええええええええええええええええええええええええ!!!

 

今までのロード時間は何だったんだ…!?!?!?! というほどの違い!!!!!!!

どれぐらい違うかは、こっちの動画を見たりしてください。

 

youtu.be

 

ともかく、今まで「じ~っ」と待たされていたのが、「す~、パッ」って感じで次のシーンに移ってくれるのだ!

いやぁ、これはSSDに変える価値ありましたわ。(≧∀≦)

 

これでモンハン生活をさらに満喫していこうと思います。では〜。

趣味のプログラミング(2)~MSXゲーム完成篇

前回の記事:
nyagbon.hatenablog.com

に引き続き、MSX でプログラミングを楽しみましょう! 前回は、自機を動かして、ミサイルが打てるところまで作りました。

今回はいよいよ敵が現れて、やっつけると点数が入り、やられると残機が減って、残機がなくなるとゲームオーバーになります。つまり、ちゃんとゲームとして遊べるシロモノにアップグレードです!

ソースコードは前回のものをベースとしていますが、いろいろな要素を追加しました。それぞれ説明していきます。

画面表示

まず、KEY OFF コマンドを使って、画面下のファンクションキー表示を消しました。これで画面がすっきりします。(10行目)

次に、スコア表示と残機表示を付けました。いろいろな場面で表示内容を変える必要があるので、サブルーチンにしました。また、PRINT USING コマンドを使って桁ずれが起きないようにしています。(980~990行目)

このサブルーチンは、スコアと残機を初期化した後の40行目、敵をやっつけてスコアが入った後の780行目、敵に体当たりされてやられた後の870行目、ゲームオーバーになった時の1020行目から GOSUB コマンドで呼び出しています。

また、SCREEN コマンドの引数で、キークリック音を消しています。(10行目)

スコアと残機とゲームオーバー

変数 SC がスコア、変数 RIHA が残機を表しています。30行目で初期化しています。

敵をやっつけたときにスコアを10点プラス(770行目)、自機に敵が体当たりした時に残機を1マイナス(860行目)しています。

上にも書きましたが、スコアか残機が変更されたら表示を更新するために980行目のサブルーチンを呼び出しています。

残機が 0 になったらゲームオーバーになります。その判定を880行目で行っています。1010行目からがゲームオーバーの処理で、画面をクリアしたあとにスコア表示をし、”GAME OVER!"と表示して END コマンドでプログラムを終了します。

敵は、ゆらゆらと自分を襲って来るようにしました。

仕組みはよくある方法にランダム要素を加えたもので、敵の移動速度を自分に向かうように増加・減少させています。また、速くなり過ぎないようにもしています。(510〜570行目)

敵の初期位置は、画面左端、縦の座標はランダムにしています。(220行目)

敵のスプライトを新しく定義し(2410〜2560行目)、630行目で表示しています。ちなみにこのデザインはリハビリ中さんのツイッターのページから拝借しました。(カワイイw

当たり判定(ミサイルと敵)

さて、「当たり判定」という言葉が出てきました。キャラクタ同士が衝突したかどうかを判定することを、ゲームプログラミング用語で「当たり判定」と言います。

730行目がミサイルと敵の当たり判定をしています。なんでこんな長い IF 文になるのかの詳細は省きますが、気になる方は

などのページを見ると良いと思います。

ミサイルと敵が当たったら、敵をやっつけたスプライトを表示して、ビープ音を鳴らして、新たな敵を出現させて(=敵の場所を初期化して)、スコアを足して、スコア表示を更新することになります。ミサイル発射フラグも 0 にします。それが740~780行目です。

やっつけたスプライトパターンは、2610~2760行目で定義しています。自機がやられたときにも使いまわしています。

ちなみに、MSX だと ON SPRITE GOSUB コマンドで当たり判定を行えるらしいのですが、以下のページ

を読んで、キャラクタが多いときには思うように使えないと知り、自前で当たり判定を実装しました。

当たり判定(敵と自機)

敵と自機が衝突したら、やられないといけません。これも上と同じように当たり判定をしています。(810行目)

自機がやられたら、ちょっとだけ派手な演出をすることにしました。やっつけられたパターンを赤で表示して、ビープ音を鳴らして、パターンを消して、ビープ音を鳴らして、という処理を6回繰り返すことにしました。つまり、音が鳴りながらやられたパターンが点滅するわけです。(830~850行目)

そして残機数 RIHA を1マイナスし、もし残機数が 0 ならば、ゲームオーバーの処理に向かいます。そうでなければ、自機や敵やミサイルを初期化して再スタートします。(210行目に飛ぶ)

くりかえし

さて、ここまでで敵が動いて、当たり判定がなされて、やっつけたりやっつけられたりすることができるようになりました!

また、おまけで ”Q" キーを押したら好きなときにゲームオーバーで終了するようにしました。飽きてきたときとか改造したい時にどうぞ。(910~920行目)

ここまでの処理が一連の流れになるので、これを繰り返すとゲームになります。というわけで、930行目で300行目に戻り、ループします。

画面イメージ

こんな感じです。画面に自機、敵、ミサイル、スコア、残機が表示されています。

f:id:nyagbon:20190215205545p:plain

というわけで

2回に渡ってお届けした「MSXでゲームプログラミングをやってやろうぜ!(リハビリ中篇)」は今回で終了となります。

久々に BASIC を触って、なかなかいい言語じゃん! もっと書きやすい言語あるけどな! とツンデレな自分に会えました。

また、初めての MSX プログラミングでしたが、特にスプライト機能はお手軽で、さすがゲームがあれだけ出たプラットフォームだなぁ、と感心しましたよ。

またネタを思いついたらプログラミング記事も書いていければと思います。それでは以下のコードでお楽しみください。ではまた~。

ソースコード

10 SCREEN 1,2,0:KEY OFF
20 ' INITIALIZE
30 SC=0:RIHA=3
40 GOSUB 980
100 ' READ SPRITE
110 FOR S=1 TO 4:L$="":R$=""
120 FOR I=1 TO 16:READ I$
130 L$=L$+CHR$(VAL("&B"+LEFT$(I$,8)))
140 R$=R$+CHR$(VAL("&B"+RIGHT$(I$,8)))
150 NEXT
160 SPRITE$(S)=L$+R$
170 NEXT
200 ' INITIALIZE POSITIONS
210 X=180:Y=80:BB=0
220 EX=0:EY=INT(RND(1)*180):EH=0:EV=0
300 ' MOVE BY CURSOR KEY OR JOY STICK
310 ST=STICK(0) OR STICK(1)
320 SG=STRIG(0) OR STRIG(1)
330 IF ST=0 THEN 400
340 IF ST>=1 AND ST<=2 AND Y>0 THEN Y=Y-8
350 IF ST>=3 AND ST<=4 AND X<240 THEN X=X+8
360 IF ST>=5 AND ST<=6 AND Y<180 THEN Y=Y+8
370 IF ST>=7 AND ST<=8 AND X>0 THEN X=X-8
400 ' BULLET
410 IF BB=1 THEN 430
420 IF SG<>0 THEN BB=1:BX=X:BY=Y
430 BX=BX-12
440 IF BX<0 THEN BB=0
500 ' ENEMY
510 EX=EX+EH:EY=EY+EV
520 EH=EH+SGN(X-EX)*INT(RND(1)*3+1)
530 EV=EV+SGN(Y-EY)*INT(RND(1)*3+1)
540 IF EH>10 THEN EH=10
550 IF EH<-10 THEN EH=-10
560 IF EV>10 THEN EV=10
570 IF EV<-10 THEN EV=-10
600 ' PUT SPRITES
610 PUTSPRITE 1,(X,Y),15,1
620 IF BB=1 THEN PUTSPRITE 2,(BX,BY),8,2 ELSE PUTSPRITE 2,,,0
630 PUTSPRITE 3,(EX,EY),3,3
700 ' COLLISION CHECK
710 ' :BULLET VS EMENY
720 IF BB=0 THEN 800
730 IF NOT(BX+2<=EX+13 AND EX+2<=BX+13 AND BY+2<=EY+13 AND EY+2<=BY+13) THEN 800
740 PUTSPRITE 3,(EX,EY),5,4
750 BEEP
760 BB=0:EX=0:EY=INT(RND(1)*180):EH=0:EV=0
770 SC=SC+10
780 GOSUB 980
800 ' :ENEMY AND ME
810 IF NOT(X+2<=EX+13 AND EX+2<=X+13 AND Y+2<=EY+13 AND EY+2<=Y+13) THEN 900
820 ' :DEAD!
830 FOR I=0 TO 5
840 PUTSPRITE 1,(X,Y),8,4:BEEP:PUTSPRITE 1,,,0:BEEP
850 NEXT
860 RIHA=RIHA-1
870 GOSUB 980
880 IF RIHA=0 THEN 1010
890 GOTO 210
900 ' FINISHED A CYCLE
910 K$=INKEY$
920 IF K$="q" THEN 1010 
930 GOTO 300
970 ' SUBROUTINE TO SHOW SCORE AND LEFT RIHA
980 LOCATE 0,0:PRINT USING "SCORE:##### RIHA: #";SC;RIHA
990 RETURN
1000 ' GAME OVER
1010 SCREEN1,1,1:KEY ON
1020 GOSUB 980
1030 PRINT "GAME OVER!"
1040 END
2000 ' MINI RIHABILLY
2010 DATA 0000000000000000
2020 DATA 0000000110000000
2030 DATA 0000001111000000
2040 DATA 0000011111100000
2050 DATA 0000011001100000
2060 DATA 0000111111100000
2070 DATA 0000111111100000
2080 DATA 0011000000000000
2090 DATA 0111111011100000
2100 DATA 0001011101100000
2110 DATA 0000011111100000
2120 DATA 0000010011100000
2130 DATA 0000001111000000
2140 DATA 0000010000100000
2150 DATA 0000100000010000
2160 DATA 0000000000000000
2200 ' BULLET
2210 DATA 0000000000000000
2220 DATA 0000000000000000
2230 DATA 0000000000000000
2240 DATA 0000000000000000
2250 DATA 0000000000000000
2260 DATA 0000000000000000
2270 DATA 0000011111100000
2280 DATA 0001110000111000
2290 DATA 0000011111100000
2300 DATA 0000000000000000
2310 DATA 0000000000000000
2320 DATA 0000000000000000
2330 DATA 0000000000000000
2340 DATA 0000000000000000
2350 DATA 0000000000000000
2360 DATA 0000000000000000
2400 ' ENEMY
2410 DATA 0000000000000000
2420 DATA 0000000000000000
2430 DATA 0011000001100000
2440 DATA 0100100010010000
2450 DATA 0000011100000000
2460 DATA 0000011110000000
2470 DATA 0000111111000000
2480 DATA 0000111111100000
2490 DATA 0000110101100000
2500 DATA 0000110101110000
2510 DATA 0000111111110000
2520 DATA 0001111111110000
2530 DATA 0001111111111000
2540 DATA 0011111111111100
2550 DATA 0000000000000000
2560 DATA 0000000000000000
2600 ' KILLED
2610 DATA 0000000000000000
2620 DATA 0000000100000000
2630 DATA 0010000100001000
2640 DATA 0001000100010000
2650 DATA 0000100000100000
2660 DATA 0000000000000000
2670 DATA 0000000000000000
2680 DATA 0111000000011100
2690 DATA 0000000000000000
2700 DATA 0000000000000000
2710 DATA 0000100000100000
2720 DATA 0001000100010000
2730 DATA 0010000100001000
2740 DATA 0000000100000000
2750 DATA 0000000000000000
2760 DATA 0000000000000000

趣味のプログラミング(1)~MSX篇

ニコ生でいつも楽しい配信をされているリハビリ中さんが、MSX でオリジナルキャラを動かしてゲームを作りたい、と仰ってるのを聞いて、「MSX でプログラミングしたことなかったけどやってみようかしらん」と思い、三十数年ぶりの BASIC に挑むことにしました。

…と言っても MSX を所持していないのですが、なんと WebMSX というサイトがあって、ブラウザ上でヴァーチャルな MSX が操作できるのです!

というわけで、早速、自機をカーソルキーかジョイスティックで動かして、ボタンかスペースキーでミサイル発射するプログラムを作ります。

2連射以上可能にすると処理がめんどくさくなるから、今回は1連射(画面内に1発しかミサイルが存在できない)とします。

スプライトの処理は初めてだったので、こちらのサイト

を参考にしました。また、カーソルキー、ジョイスティックの処理は、こちらのサイト

を参考にしました。

ちなみに、起動は run コマンドです。(当たり前ですね)

終了は、プログラムが無限ループなので無理矢理とめます。 WebMSX だと Ctrl+Pause/Break キー(Windowsの場合)です。実機の MSX だと STOP キーでしょうか? 持ってないのでわかりませんが、そのあたりです。

スプライトの定義

10行目、SCREEN1,2 で 16x16 スプライトモードにします。

100~170行目で、1010~1360行目の DATA 文にあるデータを引っ張ってきて、スプライトを定義します。2個で、1個目は自キャラ、2個目はミサイルです。

初期化

210行目。自キャラの初期座標を X, Y に設定します。変数 BB はボタンが押されてミサイルが飛んでいる状態かどうかを表すフラグです。0 がミサイルが飛んでない状態を表すものとします。

自機の移動

310~370行目がキーボードとジョイスティックの状態取得と、自機の移動です。

上下左右で8ドットずつ動くようにしています。

ミサイル発射

410~440行目がミサイルの処理です。BB が 1 だったらミサイルが打たれているとみなして、ミサイルの座標を水平方向に動かします。

420行目は、BB が 0 だったら、かつ、ボタンが押されていたら、BB を 1 にして、ミサイルを打ちます。このとき、ミサイルの座標 BX, BY を自機の座標と同じにします。

440行目では、ミサイルが画面外に出ていったなら、BB を 0 にして、ミサイルが打たれていない状態に戻します。

スプライト表示

510~520行目は、上記の処理をした結果の自機とミサイルの座標をもとに、スプライトを表示します。

520行目では、BB が 1 のときだけミサイルのスプライトを表示して、そうじゃないときは表示しないようにしています。

くりかえす

530行目は、すべての処理が終わったので、300行目に戻って、また自機の移動、ミサイルの処理…というように繰り返すようにします。

画面イメージ

こんな感じです。

f:id:nyagbon:20190214234405p:plain

WebMSX で動かす場合

起動後、画面をクリックし、ALT+B で Input Text というウィンドウが出現します。そこに、ソースコードをすべてコピーして OK ボタンを押します。その後 run コマンドを MSX 内で実行すると、ゲーム(?)が遊べます。

今後の展開

敵がいませんね! 敵をやっつけないとゲームになりません! 敵は自分を攻撃してこないとゲームになりません! 次回はそのあたりを攻めていきたいと思います。それでは、以下のコードでお楽しみください。では~。

ソースコード

10 SCREEN 1,2
100 ' READ SPRITE
110 FOR S=1 TO 2:L$="":R$=""
120 FOR I=1 TO 16:READ I$
130 L$=L$+CHR$(VAL("&B"+LEFT$(I$,8)))
140 R$=R$+CHR$(VAL("&B"+RIGHT$(I$,8)))
150 NEXT
160 SPRITE$(S)=L$+R$
170 NEXT
200 ' INITIALIZE
210 X=180:Y=80:BB=0
300 ' MOVE BY CURSOR KEY OR JOY STICK
310 ST=STICK(0) OR STICK(1)
320 SG=STRIG(0) OR STRIG(1)
330 IF ST=0 THEN 400
340 IF ST>=1 AND ST<=2 AND Y>0 THEN Y=Y-8
350 IF ST>=3 AND ST<=4 AND X<240 THEN X=X+8
360 IF ST>=5 AND ST<=6 AND Y<180 THEN Y=Y+8
370 IF ST>=7 AND ST<=8 AND X>0 THEN X=X-8
400 ' BULLET
410 IF BB=1 THEN 430
420 IF SG<>0 THEN BB=1:BX=X:BY=Y
430 BX=BX-16
440 IF BX<0 THEN BB=0
500 ' PUT SPRITES
510 PUTSPRITE 1,(X,Y),15,1
520 IF BB=1 THEN PUTSPRITE 2,(BX,BY),8,2 ELSE PUTSPRITE 2,,,0
530 GOTO 300
1000 ' MINI RIHA
1010 DATA 0000000000000000
1020 DATA 0000000110000000
1030 DATA 0000001111000000
1040 DATA 0000011111100000
1050 DATA 0000011001100000
1060 DATA 0000111111100000
1070 DATA 0000111111100000
1080 DATA 0011000000000000
1090 DATA 0111111011100000
1100 DATA 0001011101100000
1110 DATA 0000011111100000
1120 DATA 0000010011100000
1130 DATA 0000001111000000
1140 DATA 0000010000100000
1150 DATA 0000100000010000
1160 DATA 0000000000000000
1200 ' BULLET
1210 DATA 0000000000000000
1220 DATA 0000000000000000
1230 DATA 0000000000000000
1240 DATA 0000000000000000
1250 DATA 0000000000000000
1260 DATA 0000000000000000
1270 DATA 0000001111000000
1280 DATA 0000011001100000
1290 DATA 0000001111000000
1300 DATA 0000000000000000
1310 DATA 0000000000000000
1320 DATA 0000000000000000
1330 DATA 0000000000000000
1340 DATA 0000000000000000
1350 DATA 0000000000000000
1360 DATA 0000000000000000

イースはいいっすねぇ…と思っていたものの2

イース2のPC98版(プロジェクトEGG版)を配信でプレイしていたのですが、10回目の昨日、ようやくクリアすることが出来ました! \(ToT)/

f:id:nyagbon:20190211171518p:plain

 

イース2を最後にプレイしたのは、やはり20年前ほどで、それでもイース1よりは印象深く、当時は「感動的だなぁ」と子供心に思ったステキな作品でした。なので、今回は「よし、楽しくプレイできるだろう!」と思って意気揚々とプレイを始めました。

序盤は洞窟などのマップで少々迷うことはありましたが、トントン拍子でした。イース1とは違ってイース2はNPCのヒントも多く、ストーリーがそこに存在することを改めて分からせてくれるからです。

しかし、サルモンの神殿!  イース2を何度もプレイしているリスナーさん・生主さんでもやっぱり迷うことがあるという激ムズマップの神殿なのです!

f:id:nyagbon:20190211172218p:plain

でも自分となると、マッピングは面倒だからしない、せっかくのNPCの話をイイカゲンに聞いて忘れてしまう、それよりなにより今回わかったのは自分に重大な

 

      迷いスキル

 

があるということでした…。(´;ω;`)

リスナーさんから見れば、

 

  「ここもう何回も通ってるよ…。(-.-;)ハァ」

 

という場所でも、

 

  「え?え?そうだっけ?」

 

となってしまうのです…。_| ̄|○

それに、アドルの操作に夢中になって画面上にちらっと見えた宝箱すらスルーしてしまうという有様。もうホント、リスナーの皆さんは呆れていた事でしょう…。

ともあれ、そんな自分を見かねた、心優しいリスナーの皆さんの助言のおかげで、アドルくんはイースを救う事ができました。一人じゃ投げ出してたと思うし、よくこれを当時はマッピングもせずにクリアできたなあとも思います。本当に皆さんのおかげです。ありがとうございました!

f:id:nyagbon:20190211173042p:plain

さて、次は何のゲームしようかな。また迷子スキルが発動したら生暖かく見守ってご助言くださいませ! 

ポリスノーツ、めでたくクリア!

f:id:nyagbon:20190113000738j:plain

感動のエンディング

昨晩の配信で、PlayStation 版の「ポリスノーツ」をクリアしました! 

自分のヘタレっぷりで何度もコロニーを爆破したり、何度も主人公のジョナサンとエドを死なせつつでしたが、リスナーの皆さんに楽しいコメントや助けをもらい、何とかエンディングに到達することができました。みなさんに感謝です! (^人^)

 

ストーリーは宇宙モノのSFで細かい設定まで練られており、ハラハラドキドキのストーリー展開も飽きさせることがなく、さすがあの小島監督、感動巨編映画を見たかのような余韻がプレイ後に残りました。

 

25年前の作品ですが、全く色褪せた感じがない所がスゴいです。

小島監督にはまたこんなアドベンチャーゲームを作って欲しいなぁ、と思わせる一本です。作ってくれないかなぁ。

 

未プレイの方は、是非ともプレイされることをオススメします! (╹◡╹)