【プチコン4講座】スプライト変数とグリッド移動を覚えよう

プチコン4

プチコン4 パズルゲーム グリッド移動

こんにちは。なおキーヌです。

ブログ毎日更新は262日目になります。

今回からソウコバンライクを実際に作っていきましょう。

まずはミニゲーム作り恒例のスプライト表示からです。

スプライトの基礎を終えている前提で話を進めますので、
わからなくなったらスプライトの基礎で勉強しなおしてみてください。

それではプチコンミニゲーム講座第11回目を始めようと思います。

  1. ソウコバンライクに必要なスプライトを表示しよう
  2. スプライト変数をつかってスプライトに座標を管理させよう
  3. キー操作でプレイヤーを動かせるようにしよう
  4. 衝突判定の準備をしておこう

ソウコバンライクに必要なスプライトを表示しよう

ソウコバンライクに必要なスプライトはなんでしょうか。

ざっと考えてみると以下のリストになります。

  • プレイヤー
  • 木箱
  • 木箱を置く目印

これぐらいでしょうか。

マップは今回はスプライトを使わないので、
この3つがあればいいでしょう。

木箱を置く目印もマップにつけてしまえば
2種類のスプライトで事足りるのですが衝突判定が面倒になるんのでスプライトにしておきます。

それではスプライトの準備をしましょう。

' 画面クリア
ACLS

' チップサイズ定数
CONST #CS = 16

' ゴールと木箱の個数
VAR OBJ = 5


' ループ用変数
VAR G_I = 0

' プレイヤースプライトの準備
SPSET 0, 721
SPOFS 0, 0, 0

' つぼスプライトの準備
FOR G_I = 1 TO OBJ
  SPSET G_I, 265
  SEPOFS G_I, G_I * #CS, 0
NEXT

' つぼを置くための目印スプライト準備
FOR G_I = 11 TO OBJ+10
  SPSET G_I, 224
  SEPSET G_I, G_I * #CS, 0
NEXT

とりあえず表示させるために並べています。

スマイルツールをパッと見、画像に木箱やタルっぽいのがなかったのでつぼにしてみました。

つぼを置くための目印は分かりやすくトランプのダイヤマークにしています。

プレイヤーは勇者に飽きたので働き者のメイドさんにしました。

以下のように表示されたらOKです。

プチコン4 出力結果その1

スプライト変数をつかってスプライトに座標を管理させよう

スプライトの基本でなんどか話したと思うのですが、
スプライト毎に座標変数を用意するのはとても面倒なのでスプライト変数を使いましょう。

スプライト変数とは、スプライト毎に専用の変数を持つことが出来ます。

変数はVARで宣言してたと思うのですが、スプライトも同じでSPVARを使って宣言します。

もちろんSPSETをしてからじゃないとSPVARは出来ないので注意してください。

まずは例としてプレイヤーのスプライト変数を使って座標を持たせてみましょう。

' プレイヤースプライトの準備
SPSET 0, 721
' スプライト管理番号0番目に「X」という名前の変数を宣言し、0を代入する
SPVAR 0, "X", 0
' スプライト管理番号0番目に「Y」という名前の変数を宣言し、0を代入する
SPVAR 0, "Y", 0
' スプライト変数の呼び出しはカッコを使って呼び出したいスプライト管理番号と変数名を指定する
SPOFS 0, SPVAR(0,"X"), SPVAR(0,"Y")

SPVARはカッコありとなしで挙動が変わります。

宣言や代入するときはカッコ無しで「管理番号・変数名・代入する値」の順でカンマ区切りで入れましょう。

変数の中身を呼び出したいときはカッコ有りで呼び、「管理番号・変数名」だけを指定すれば、
その変数の中身を使うことが出来ます。

代入も呼び出しも毎回SPVARを書かなきゃいけないのが面倒ですが、後々便利さが身に沁みるので我慢しましょう。

余談ですがプチコンではカッコ無しを命令・カッコ有りを関数と読んでいます。

これでスプライト変数を使えるようになったので、ツボも目印も座標変数を与えてやりましょう。

' 画面クリア
ACLS

' チップサイズ定数
CONST #CS = 16

' ゴールと木箱の個数
VAR OBJ = 5


' ループ用変数
VAR G_I = 0

' プレイヤースプライトの準備
SPSET 0, 721
' スプライト管理番号0番目に「X」という名前の変数を宣言し、0を代入する
SPVAR 0, "X", 0
' スプライト管理番号0番目に「Y」という名前の変数を宣言し、0を代入する
SPVAR 0, "Y", 0
' スプライト変数の呼び出しはカッコを使って呼び出したいスプライト管理番号と変数名を指定する
SPOFS 0, SPVAR(0,"X"), SPVAR(0,"Y")

' つぼスプライトの準備
FOR G_I = 1 TO OBJ
  SPSET G_I, 265
  SPVAR G_I, "X", G_I * #CS
  SPVAR G_I, "Y", 0
  SPOFS 0, SPVAR(G_I,"X"), SPVAR(G_I,"Y")
NEXT

' つぼを置くための目印スプライト準備
FOR G_I = 11 TO OBJ+10
  SPSET G_I, 224
  SPVAR G_I, "X", G_I * #CS
  SPVAR G_I, "Y", 0
  SPOFS 0, SPVAR(G_I,"X"), SPVAR(G_I,"Y")
NEXT

出力結果は先ほどの画像と同じになっていればOKです。

キー操作でプレイヤーを動かせるようにしよう

スプライトを出すことが出来たので次はプレイヤーを操作できるようにしてみましょう。

コントローラー関数はいつものを使います。

スプライトの基礎の最後で使ったコントローラー関数は中身を改良してしまったので、
一旦シンプルな形に戻しているので注意してください。

' ボタンカウント用変数
VAR UP_BTN = 0, DOWN_BTN = 0, LEFT_BTN = 0, RIGHT_BTN = 0

' ループ開始
LOOP
  D_Controller
  VSYNC
ENDLOOP


' コントローラー関数
'───────────────────────────────
def D_Controller
  ' 0番目のコントローラー(つまり1コン)の押されているボタンを取得
  VAR B = BUTTON(0)

  ' 上ボタン処理
  if (B AND 1 << #B_LUP) != 0 then
    D_BtnPressCount #B_LUP
  else
    if UP_BTN >= 1 then
      UP_BTN = 0
    endif
  endif

  ' 下ボタン処理
  if (B AND 1 << #B_LDOWN) != 0 then
    D_BtnPressCount #B_LDOWN
  else
    if DOWN_BTN >= 1 then
      DOWN_BTN = 0
    endif
  endif

  ' 左ボタン処理
  if (B AND 1 << #B_LLEFT) != 0 then
    D_BtnPressCount #B_LLEFT
  else
    if LEFT_BTN >= 1 then
      LEFT_BTN = 0
    endif
  endif

  ' 右ボタン処理
  if (B AND 1 << #B_LRIGHT) != 0 then
    D_BtnPressCount #B_LRIGHT
  else
    if RIGHT_BTN >= 1 then
      RIGHT_BTN = 0
    endif
  endif

  ' ボタンカウントに応じて座標を変更
  IF UP_BTN == 1 THEN
    SPVAR 0, "Y" , SPVAR(0,"Y") - #CS
  ELSEIF DOWN_BTN == 1 THEN
    SPVAR 0, "Y" , SPVAR(0,"Y") + #CS
  ELSEIF LEFT_BTN == 1 THEN
    SPVAR 0, "X" , SPVAR(0,"X") - #CS
  ELSEIF RIGHT_BTN == 1 THEN
    SPVAR 0, "X" , SPVAR(0,"X") + #CS
  ENDIF

  ' プレイヤーを移動
  SPOFS 0, SPVAR(0,"X"), SPVAR(0,"Y")

end


' ボタンカウント関数
'───────────────────────────────
def D_BtnPressCount A_Button

  ' ボタンカウント分岐
  case A_Button
    ' 渡されたボタンが上だったら
    when #B_LUP
      ' ボタンカウント配列の数が256未満かどうか調べる
      if UP_BTN < 256 then 
        ' 条件に一致したら+1する
        INC UP_BTN
      endif

    ' 渡されたボタンが下だったら
    when #B_LDOWN
      ' ボタンカウント配列の数が256未満かどうか調べる
      if DOWN_BTN < 256 then 
        ' 条件に一致したら+1する
        INC DOWN_BTN
      endif

    ' 渡されたボタンが左だったら
    when #B_LLEFT
      ' ボタンカウント配列の数が256未満かどうか調べる
      if LEFT_BTN < 256 then 
        ' 条件に一致したら+1する
        INC LEFT_BTN
      endif

    ' 渡されたボタンが右だったら
    when #B_LRIGHT
      ' ボタンカウント配列の数が256未満かどうか調べる
      if RIGHT_BTN < 256 then 
        ' 条件に一致したら+1する
        INC RIGHT_BTN
      endif
  endcase
end

ボタンカウント用の変数を作っているのに注意してください。

今回はグリッド移動をしたいので16ドットずつ動かします。

なのでボタンカウント関数を利用して1回押したら1回動くように制御しないと
動きすぎるのでパズルゲームとして成り立たなくなってしまいます。

ボタンカウント関数は元々ABXYで作っていましたが、
今回はUP_DOWN_LEFT_RIGHTに変更していますので、そこも気を付けてください。

前回のコントローラー関数そのままコピーではないです。

ちょっと面倒かもしれませんが、打ち込んでください。

実行してみてプレイヤーがマス目移動出来ていればOKです。

プチコン4 出力結果その2

衝突判定の準備をしておこう

次回は壺にぶつかったら押せるようにしてみましょう。

そのためには衝突判定が必要ですね。

SPSETの後にSPCOLをして衝突判定の準備をしておきましょう。

今回のコードのまとめと一緒にSPCOLを記述してあるので、
各自どこに記述してるか確認して次回に備えてください。

それでは。

' 画面クリア
ACLS

' チップサイズ定数
CONST #CS = 16

' ゴールと木箱の個数
VAR OBJ = 5

' ループ用変数
VAR G_I = 0

' ボタンカウント用変数
VAR UP_BTN = 0, DOWN_BTN = 0, LEFT_BTN = 0, RIGHT_BTN = 0


' プレイヤースプライトの準備
SPSET 0, 721
' スプライト管理番号0番目に「X」という名前の変数を宣言し、0を代入する
SPVAR 0, "X", 0
' スプライト管理番号0番目に「Y」という名前の変数を宣言し、0を代入する
SPVAR 0, "Y", 0
' スプライト変数の呼び出しはカッコを使って呼び出したいスプライト管理番号と変数名を指定する
SPOFS 0, SPVAR(0,"X"), SPVAR(0,"Y")
' スプライト衝突判定の準備
SPCOL 0

' つぼスプライトの準備
FOR G_I = 1 TO OBJ
  SPSET G_I, 265
  SPVAR G_I, "X", G_I * #CS
  SPVAR G_I, "Y", 0
  SPCOL G_I
  SPOFS 0, SPVAR(G_I,"X"), SPVAR(G_I,"Y")
NEXT

' つぼを置くための目印スプライト準備
FOR G_I = 11 TO OBJ+10
  SPSET G_I, 224
  SPVAR G_I, "X", G_I * #CS
  SPVAR G_I, "Y", 0
  SPCOL G_I
  SPOFS 0, SPVAR(G_I,"X"), SPVAR(G_I,"Y")
NEXT

' ループ開始
LOOP
  D_Controller
  VSYNC
ENDLOOP


' コントローラー関数
'───────────────────────────────
def D_Controller
  ' 0番目のコントローラー(つまり1コン)の押されているボタンを取得
  VAR B = BUTTON(0)

  ' 上ボタン処理
  if (B AND 1 << #B_LUP) != 0 then
    D_BtnPressCount #B_LUP
  else
    if UP_BTN >= 1 then
      UP_BTN = 0
    endif
  endif

  ' 下ボタン処理
  if (B AND 1 << #B_LDOWN) != 0 then
    D_BtnPressCount #B_LDOWN
  else
    if DOWN_BTN >= 1 then
      DOWN_BTN = 0
    endif
  endif

  ' 左ボタン処理
  if (B AND 1 << #B_LLEFT) != 0 then
    D_BtnPressCount #B_LLEFT
  else
    if LEFT_BTN >= 1 then
      LEFT_BTN = 0
    endif
  endif

  ' 右ボタン処理
  if (B AND 1 << #B_LRIGHT) != 0 then
    D_BtnPressCount #B_LRIGHT
  else
    if RIGHT_BTN >= 1 then
      RIGHT_BTN = 0
    endif
  endif

  ' ボタンカウントに応じて座標を変更
  IF UP_BTN == 1 THEN
    SPVAR 0, "Y" , SPVAR(0,"Y") - #CS
  ELSEIF DOWN_BTN == 1 THEN
    SPVAR 0, "Y" , SPVAR(0,"Y") + #CS
  ELSEIF LEFT_BTN == 1 THEN
    SPVAR 0, "X" , SPVAR(0,"X") - #CS
  ELSEIF RIGHT_BTN == 1 THEN
    SPVAR 0, "X" , SPVAR(0,"X") + #CS
  ENDIF

  ' プレイヤーを移動
  SPOFS 0, SPVAR(0,"X"), SPVAR(0,"Y")

end


' ボタンカウント関数
'───────────────────────────────
def D_BtnPressCount A_Button

  ' ボタンカウント分岐
  case A_Button
    ' 渡されたボタンが上だったら
    when #B_LUP
      ' ボタンカウント配列の数が256未満かどうか調べる
      if UP_BTN < 256 then 
        ' 条件に一致したら+1する
        INC UP_BTN
      endif

    ' 渡されたボタンが下だったら
    when #B_LDOWN
      ' ボタンカウント配列の数が256未満かどうか調べる
      if DOWN_BTN < 256 then 
        ' 条件に一致したら+1する
        INC DOWN_BTN
      endif

    ' 渡されたボタンが左だったら
    when #B_LLEFT
      ' ボタンカウント配列の数が256未満かどうか調べる
      if LEFT_BTN < 256 then 
        ' 条件に一致したら+1する
        INC LEFT_BTN
      endif

    ' 渡されたボタンが右だったら
    when #B_LRIGHT
      ' ボタンカウント配列の数が256未満かどうか調べる
      if RIGHT_BTN < 256 then 
        ' 条件に一致したら+1する
        INC RIGHT_BTN
      endif
  endcase
end