“RUN” それは魔法の言葉

私とコンピュータの思い出を、だらだらと綴ります。最近はHSP3でのゲーム作り日記です

124.HSPでゲームを作ろう:シューティングゲームっぽい何か その1

標準スプライトの学習を兼ねて作ったのが、あれっぽいあれwだったのは、「シューティングゲームっぽい何か」を作るアイデアが浮かんだからだった。
イデアの大筋から、細かな仕様を固めて作る前に、シューティングゲームの基礎である、自機の移動と自弾の発射処理を作ることにした。

移動処理自体はすでに作っているので、自弾の発射処理を作っていく。
オーソドックスな作りなら、スペースキーをショットキーにするのだが、3つ以上のキー同時押しに対応できないことが多いので、Zキーをショットキーにした。

で、JStickであれば、ボタン1が同時に検出できて好都合。

だけど、動作確認に使っているメガドラミニの6BPADは、ちょっと変態さんな並びのようで、Yボタンがボタン1になる。

「PAD設定さん」では、そのあたりをコンフィグできるのだが、まだあとで対応する。
とりあえず、Aボタンがボタン3なので、ボタン1と3をショットキーになるようにした。この副産物として、Cキーもショットキーになった。

弾は画面外に出たら勝手に消えてくれるように、便利な命令es_areaで、画面サイズの座標値を指定した。

ショットキーを押したら、自弾を処理するサブルーチンに飛ばす。es_exnewでスプライトの空きを調べて、空いてたらスプライトのセット、タイプ番号の設定、そして、es_adirで、自動的に移動するようにした。

#include "hsp3dish.as"
#include "m_joystick.hsp"

  screen 0,800,600,0
  title "シューティングっぽい何か(仮称)"

  es_ini ;スプライト初期化

  buffer 2
  picload "bg.png" ;仮背景画像

  buffer 3 ;バッファを作成
  picload "player.png" ;自機画像を読み込み
  es_size 64,64,1 ;パターンサイズ、ヒット領域1%で
  es_pat 0,0,0 ;パターンを読み込み

  buffer 4 ;バッファを作成
  picload "shot.png" ;ショット画像を読み込み
  es_size 64,64,20
  es_pat 1,0,0

  gsel 0 ;操作バッファを0に戻す

  px=300:py=200 ;自機のXY座標
  es_set 0,px,py,0,0,1 ;自機のスプライトをセット
  gamecnt=0

  es_area 0,0,800,600 ;スプライトの領域設定
  moveangle=2 ;自機の弾の方向

*main
  redraw 0
  sht=0 ;ショットボタンフラグ
  JStick key,1+2+4+8
  if key&1 : px=px-5 : ix=0 ;カーソル左
  if key&4 : px=px+5 : ix=2 ;カーソル右
  if key&2 : py=py-5 : iy=0 ;カーソル上
  if key&8 : py=py+5 : iy=2;カーソル下
  if (key&2048) or (key&8192) : sht=1 ;ボタンZ、Cとボタン1、ボタン3(6BパッドのA)

  px=limit(px,0,800-64)
  py=limit(py,0,600-64)
  
  if key&128 : end ;ESCでゲーム終了(暫定)

  pos 0,0
  gcopy 2,0,0,800,600 ;背景画像のコピー
  color 255,0,0:gmode 2
  gamecnt++
  es_pos 0,px,py ;自機スプライトの位置変更

  gosub *shoot ;自弾の発射
  es_draw 

  redraw 1
  await 1000/60
  goto *main

*shoot
  if sht=1 {
    es_exnew snum,100,101,1 ;ショットは画面内に最大2発
    if snum>0 { ;ショットの空きがあれば
      es_set snum,px,py,1
      es_type snum,2 ;弾はタイプ2
      es_adir snum,2*8,1000 ;方向はとりあえず前方。
    }
  }

return

そして、これを動かしてみたのがこれ。うん。雰囲気は出てくるね。
youtu.be

自機のグラフィックがダサいのは、ご愛敬ということでw
これからもう少しマシに見えるように頑張って描いて行くつもり。

123.HSPでゲームを作ろう:技術研究 MUCOM88でMMLを演奏しよう

BASICなら、たいてい音楽を演奏するPLAY命令があり、その音楽を記述する言語がMMLMusic Macro Language)だった。
ドレミファソラシを、C D E F G A B で表し、オクターブや音量、長さなどは、記号+数字で記述する。

HSPには、MMLを演奏する命令はなく、別に用意したmp3などのメディアファイルを再生することで、BGMを鳴らすようになっていた。
でもHSP3.6から、知る人ぞ知るゲームミュージック界の神、古代祐三氏が作ったPC-8801FM音源用ドライバー「MUCOM88」のWindows版が、拡張プラグインで使用できるようになった!
MUCOM88を使って、単純にMMLで音楽を鳴らすだけでなく、ゲームのBGMに使えないかなと思ってサンプルを見始めた。

イメージは単純にMMLをそのまま書いて、PLAY命令のように鳴らせると思っていたのだが、どうやら事前に専用のバイナリファイル,*.mubを作っておいて、読み込みんで鳴らすのがメインの使い方のようだ。
16ファイルまでバンク指定で読み込めるようなので、BGMにできるかな?

ファイルを使わずに、直接HSP3上でMMLを鳴らそうと思ったが、そうすると固定でバンク0になってしまうので、複数の音楽を切り替えて再生することは出来なさそう。
とりあえず、MUCOM88 for Windowsをダウンロードして、MMLからmubファイルを作るか、他の方法でBGM用のMP3ファイルを作ることにしよう。

122.HSPでゲームを作ろう:技術研究 ジョイスティックに対応しよう「PAD設定さん」

ゲームウォッチぐらいなら、キーボードだけで操作しても問題ないけど、シューティングゲームやアクションゲームを作るときは、ジョイスティックにも対応させたい。
HSP3では、標準モジュールでジョイスティックに対応するものがあるのだが、いかんせん使い方に関するよい資料を見つけられなかった。

そんな中で一番情報が揃っていたのが、GENKIさん作のPAD設定さんだった。
mclab.uunyan.com

PAD設定さんの「m_joystick.hsp」をincludeした後、標準のstick命令を、JStrick命令に書き換えるだけ。これだけ。
あっさりとカーソルキーとジョイスティックのどちらでも自機を移動できるようになった!

単純にこれだけでなく、接続したジョイスティックのIDの取得や、ボタンのコンフィグに対応できるような便利な命令群が拡張されている。
少なくとも、シューティングゲームを作るなら、ショットのボタンを自分で好きなボタンに割り当てられるようにしたいので、ありがたく使わせていただきたいと思います。

<余談>
試したのは、メガドラミニのUSBパッドが最初。十字キーは普通に読み込めたが、その他のボタンは一般的な配置で取得できるものとはちょっと違っていたので、今回使ったPAD設定さんのようなモジュールを使って、キーコンフィグができるようにしないといけないかな。
また、むかーし買ったHORIのアナログスティック付きのPSライクなコントローラも引っ張り出して繋いでみたら、こっちも問題なし。
しかも左のアナログスティックでも動く!ソース書き換えたの一か所だけですけど。すげー。
アナログスティックを使うゲームは、今のところ作る予定もアイデアもないけど、覚えておこう。

121.HSPでゲームを作ろう:技術研究 2Dスプライト機能 その3

初めは、プログラミングガイドを読んでいたが、PCの画面で読んでもイマイチ頭に入ってこない。なので、サンプルシューティングゲーム「マジカル タマホーキ」のソースをプリントアウトして、何の処理をしているかメモを取りながら勉強した。

f:id:CORO3:20220226175455j:plain

年齢的なものもあるが、この方法が一番しっくりくる。今の子供は紙の教科書だけでなく、タブレットや、オンラインで授業を受けなくてはならないが、理解できるのだろうか。
と、余計な話は置いておいて。

HSPの標準スプライト機能は、単純に座標を指定して表示するだけではなく、便利な機能が満載だった。

まずはアニメーション。パターンを登録するときに、es_patanim命令を使うと、連続するパターンを一括で登録できて、さらに、指定したフレーム数で画像を切り替えてくれる。

スプライトの移動を自動でやってくれる命令がある。
es_apos命令は、X座標の移動量、Y座標の移動量、移動スピードを指定すると、勝手に動いてくれる。
シューティングゲームなどで、直線的に動くモノに使えば、移動処理をいちいち書かなくていい。
例えば、自機の弾なんかもこれが使える。

も一つ移動系で便利なのは、es_aim命令。
これは、X座標、Y座標、移動スピードを指定すると、その座標に向かって勝手に動いてくれる。
これもシューティングゲームでよくある、自機を狙ってくる敵弾や、ホーミングする敵に使える。
sin、cosを使って、移動方向を決めなくてもいいのが便利。

あとは、弾幕で使えそうな、移動方向を指定して移動し続けてくれるes_adir命令がある。

es_aimes_aposes_adirの3つだけで、シューティングゲームの基本の動きを作れるのがすばらしい。

そして、スプライト同士の衝突判定も簡単。es_check命令が用意されている。
指定したスプライトと衝突しているスプライトNoを知ることができる。

es_checkと合わせて使うと便利なのが、es_type命令と、es_find命令。

es_typeは、任意のタイプ番号をスプライトに設定できる命令。
ビットで処理するため、数字は1,2,4,8…と、2のn乗の値を設定する。

これだけだと何のことやらとなるんだけど、es_findes_checkでは、このタイプ番号を持つスプライトだけを検索、チェック対象にできる。

使い方の一つに、自機のショットと敵の当たり判定がある。
例えば、ショットはタイプ番号2、敵はタイプ番号4と設定したとする。

es_findで、タイプ番号2のスプライトを探して、es_checkで、そのスプライト番号と、タイプ番号が4のスプライトが衝突しているかを判定できる。

普通に考えると、ショット1発、敵1体ごとの座標を配列などに格納しておいて、判定するとかを考えるのだけど、配列を使わなくて単純なループだけで衝突判定ができる。

これをもとに、それっぽい何かwを作ったのがこちら。
youtu.be

BASIC!で、初めて作ったキューブ避けゲームの画像を使って、キューブが張り付く処理も加えてみた。これも上で説明した命令群で簡単に作れた。

これから作ろうとしているアイデアの大半を、実現できそうということが分かったことが、大きな収穫だった。

#include "hsp3dish.as"

screen 0,800,600,0
es_ini ;スプライト初期化

buffer 2
picload "bg.png"

buffer 3 ;バッファを作成
picload "meta.png" ;画像を読み込み
es_size 42,23 ;パターンサイズ
es_pat 0,0,0 ;パターンを読み込み
buffer 4 
picload "cube.png"
es_size 53,58,60
es_patanim 1,3,0,0,10
es_patanim 11,3,0,0,0
gsel 0 ;操作バッファを0に戻す
  px=300:py=200
  es_set 0,px,py,0,0,1

  gamecnt=0
  cubenum=99
  showcube=0

  randomize

*main
  redraw 0
  stick key,1+2+4+8
  if key&1 : px=px-5 ;カーソル左
  if key&4 : px=px+5 ;カーソル右
  if key&2 : py=py-5 ;カーソル上
  if key&8 : py=py+5 ;カーソル下
  px=limit(px,0,800-42)
  py=limit(py,0,600-23)
  
  if key&128 : end ;ESCでゲーム終了(暫定)

  pos 0,0
  gcopy 2,0,0,800,600
  color 255,0,0:gmode 2
  pos 0,0:mes "残りCUBE="+str(cubenum)
  gamecnt++
  es_pos 0,px,py
  gosub *addenemy
  es_draw ,,0,1,100

  ;自機の当たり判定はいったんコメントアウト
  ;es_check hitf,0
  ;if hitf>0 : assert

  redraw 1
  await 1000/60
  goto *main
  
*addenemy
  ;キューブの追加処理
  if showcube<3 and cubenum>0 {
    es_exnew snum,100,200,1
    es_set snum,800,rnd(600),1,,100
    es_type snum,2
    es_apos snum,-(rnd(10)+1),0
    showcube++
    cubenum--
  }

  ;キューブを自機に向かって飛ばすか?
  if gamecnt\50=0 {
    es_find n,2,100
    if n>0 {
      ;向きを変えるキューブの属性を取得
      es_get nocurve,n,ESI_OPTION
      es_getpos n,cubex,cubey
      ;もし、一度も向きを変えていなくて、X座標が300未満なら向きを変える
      if nocurve=0 and cubex>300 {
        es_aim n,px,py,1000
        es_setp n,ESI_OPTION,1 ;向きを変えたことをOPTIONに持たせる
      }
    }
  }

  ;キューブの当たり判定処理
  n=100
  repeat
  es_find n,2,n
  if n=-1 : break
  es_check cubeco,n,4
  es_getpos n,cx,cy,0
  if cx<=0 or cy<=0 or cy>=600-58 or cubeco>0 {
    es_get pt,n,ESI_CHRNO
    es_type n,4
    es_apos n,0,0
    es_chr n,pt+10
    showcube--
  }
  n+
  loop
    
  return