“RUN” それは魔法の言葉

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

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