【プチコン4講座】木を切り倒す処理を実装
こんにちは。なおキーヌです。
ブログ毎日更新は294日目になります。
斧で切るための木を実装の続きの記事になります。
前回は木を切るための準備を行いました。
今回は斧を当てた時に木のHPが減るようにして、
HPが0になったら気を倒すようにしてみましょう。
それぞれ描写するテキストスクリーンのIDを変えたので、
HPが0になったら倒れる関数を実行するといったイメージです。
それでは木こりゲーム作り第9回目、始めていきましょう。
木のHPを減らす処理を作る
前回にSPVARでHPを設定したので、今回は木を切ったときに減らすようにしてみましょう。
まずはPRINTでHPの減少を確認します。
CASEで振り分けてましたが、2つしかないので別に要らない処理でしたね(笑)
なのでソースをスッキリさせました。
' 斧と木の衝突判定処理
'──────────────────────────
DEF SLASH_WOOD
VAR SP = SPHITSP(100,200,201)
IF SP != -1 THEN
IF SPVAR(SP,"HITTING") == #FALSE
SPVAR SP, "HITTING" = #TRUE
SPVAR SP, "HP", SPVAR(SP,"HP")-1
PRINT SPVAR(SP,"HP")
ENDIF
ENDIF
END
これで木を切ってみるとHPが減っていくのが分かると思います。
木のHPが0になったら回転処理を加える
HPの減る処理が出来たので、HPが0になったら木の倒れるモーションが欲しいですね。
カセットビジョンリスペクトでパッと消してもいいですが、せっかくなので見た目を豪華にしてみましょう。
テキストスクリーンを回転させるにはTROTを使っていきます。
' 回転用変数
SPVAR 200, "ROT", "0"
SPVAR 201, "ROT", "0"
LOOP
WOOD_ROTATE
LOOPEND
DEF WOOD_ROTATE
FOR G_I = 0 TO 1
VAR SP = G_I+200
IF SPVAR(SP,"HP") <= 0 THEN
IF TROT(G_I+1) <=> 70 THEN
SPVAR SP,"ROT", SPVAR(SP,"ROT")+1
TROT G_I+1, SPVAR(SP,"ROT")
ENDIF
ENDIF
NEXT
END
TROTは関数でスクリーンIDを与えると現在の回転角度を取得できます。
命令で使うと角度を設定できます。
ここで現在の角度を記憶してくれて入るのですが、一応スプライト側にも角度を記録しておきましょう。
それでは実行してみます。
#petitcom #プチコン4 #NintendoSwitch
どこいくねーん pic.twitter.com/AGPjIRr9XR
— なおキーヌ@ゲームクリエイターLv5 (@naokeyzmt) October 20, 2019
気付いてた人はいるかもしれませんが、回転するためのホームポジションをきめなければいけません。
スクリーンは画面全体の矩形なので、単純に真ん中の下とすると画面真ん中下がホームになってしまうので、
うまく木の根元を中心にできるようにしてみましょう。
ホームポジションを変更させるには「THOME」を使用します。
テキストスクリーンは1=16で指定されていましたが、
ホーム座標に関してはスプライトと同じで1ドット単位なので注意しましょう。
判定用スプライトの座標のX+8すれば真ん中に座標がいくはずです。
下座標はそのまま計算式を当てはめてなぜかうまくいかなかったのでスクリーンサイズから無理矢理合わせています。
THOME 1, 6*16-16+8, 240-32
THOME 2, 400-(16*7)+8, 240-32
実行してみると……
ううーん?思ってたのとは違いますね。
Pivotがズレるだけかと思ったらそのものが全部ずれちゃうので
SPOFSで同じだけ移動させなきゃだめでした。
THOME 1, 6*16-16+8, 240-32
THOME 2, 400-(16*7)+8, 240-32
TOFS 1, 6*16-16+8, 240-32
TOFS 2, 400-(16*7)+8, 240-32
これでいいでしょう。
#petitcom #プチコン4 #NintendoSwitch
イイカンジ pic.twitter.com/STJEnCrLkT
— なおキーヌ@ゲームクリエイターLv5 (@naokeyzmt) October 20, 2019
そういえばこの時点で思い出しましたが、TVARというテキストスクリーン用の変数もありましたね。
まぁそこまで大きなゲームじゃないので衝突判定用のSPVARでも動けばOKです。
完全に倒れたら木を消滅させる
現状、木が倒れたらその場に残り続けます。
回転の最高角度を90度にして画面から消してしまう手もありですが、
折角なので回転が終わったらフェードアウトするようにしてみましょう。
透明度を徐々に下げていくのでALPHA用の変数を作ってループで少しずつ下げていきます。
テキストスクリーンの透明度の変更はTCOLORです。
' 回転用変数
SPVAR 200, "ALPHA", "255"
SPVAR 201, "ALPHA", "255"
DEF WOOD_ROTATE
FOR G_I = 0 TO 1
VAR SP = G_I+200
IF SPVAR(SP,"HP") <= 0 THEN
IF TROT(G_I+1) <=> 70 THEN
SPVAR SP,"ROT", SPVAR(SP,"ROT")+1
TROT G_I+1, SPVAR(SP,"ROT")
ENDIF
ENDIF
IF SPVAR(SP,"ROT") >= 70 && SPVAR(SP, "ALPHA") > 0 THEN
SPVAR SP, "ALPHA", SPVAR(SP, "ALPHA")-1
TCOLOR G_I+1, RGB(SPVAR(SP, "ALPHA"),255,255,255)
ENDIF
NEXT
END
良い感じに両方とも倒れてくれてますね!
イチゴの表示はもういらないので、非表示にしてしまいましょう。
次回はステージクリアを実装したいと思います。
ネタバレしておくと、木が両方とも倒れて完全に見えなくなったらステージクリアにします。
消えてる最中に攻撃を喰らうとミスになる仕様にして最後まで油断させないゲームにしたいですね。
最後に今回までのソースコードを記載しておきます。
それでは。
ACLS
' 地面と判定するための座標定数
CONST #GND = 160
' 神崎最大Y座標
CONST #KANZAKI_MAXUP = 176
' 出現までのフレーム数
CONST #WANPAKU_POP = 480
' ループ用変数
VAR G_I = 0
' 衝突判定用変数
VAR HITSP = -1
' ジャンプ配列アクセス用変数
VAR JPPC = 0
' ジャンプ配列
DIM JUMP_PROCESS[] = [-14,-10,-8,-6,-4,-2,2,4,6,8,10,14]
' スプライト定義
SPSET 0, 1432
SPCOL 0
SPVAR 0, "X", 35
SPVAR 0, "Y", #GND
SPVAR 0, "DIRECT" , #FALSE
SPVAR 0, "SWING" , #FALSE
SPOFS 0, SPVAR(0,"X"), SPVAR(0,"Y")
SPVAR 0, "JUMP" , #FALSE
' 斧スプライト定義(非表示にしておく)
SPSET 100, 161, 0
SPCOL 100
SPVAR 100, "ROTATE", 0
' アトリビュートの基準点を変更
SPHOME 100, 8, 16
' ワンパクくんの初期を非表示に設定
SPSET 1, 1436, 0
SPCOL 1
' 開始時にカウント開始するために1を入れておく
SPVAR 1, "HIDE", 1
' ワンパク君の座標変数
SPVAR 1, "X", -16
SPVAR 1, "Y", 160
' ワンパク君の向き変数
SPVAR 1, "DIRECT", #FALSE
' ワンパク君のスピード(後で使う)
SPVAR 1, "SPEED", 0
' ワンパク君が斧に当たったかどうか
SPVAR 1, "DAMAGE", #FALSE
' ワンパク君の座標設定
SPOFS 1, SPVAR(1,"X"),SPVAR(1,"Y")
' 神崎スプライト設定
SPSET 2, 1438, 0
SPCOL 2
SPVAR 2, "HIDE", 1
SPVAR 2, "X", 0
SPVAR 2, "Y", 240
SPVAR 2, "SPEED", 0
SPVAR 2, "DIRECT" , #FALSE
SPVAR 2, "DAMAGE", #FALSE
SPOFS 2, SPVAR(2,"X"),SPVAR(2,"Y")
' インテリスプライト設定
SPSET 3, 1442, 0
SPCOL 3
SPVAR 3, "HIDE", 1
SPVAR 3, "X", 0
SPVAR 3, "Y", 50
SPVAR 3, "SPEED", 0
SPVAR 3, "DIRECT" , #FALSE
SPOFS 3, SPVAR(3,"X"),SPVAR(3,"Y")
' 青空ぽい背景描写
FOR G_I=0 TO 240
GLINE 0,I,400,I,RGB(I/2, 125+ROUND(I/2), 255)
NEXT
' 地面を描写
FOR G_I = 0 TO 24
TPUT 0, G_I, 14, &HECC2
TPUT 0, G_I, 14, &HED02
TPUT 0, G_I, 14, &HED02
NEXT
' 木の描写
TREE_DRAW 4,6,1
TREE_DRAW 17,6,1
LOOP
D_CONTROLLER
' 斧とハカセ以外のスプライトの判定を取る
HITSP = SPHITSP(100,1,3)
' 敵の衝突制御
ENEMY_COL_PROCESS
' 非表示敵の出現までのカウント
HIDE_COUNT
' ワンパクくん移動処理
WANPAKU_DASH
' 神崎移動処理
KANZAKI_UPDOWN
' インテリ移動処理
INTELI_FLOAT
' 斧と木の衝突判定
SLASH_WOOD
' 木の回転処理
WOOD_ROTATE
ENDLOOP
' コントローラー関数
'───────────────────────────────
DEF D_CONTROLLER
' 0番目のコントローラー(つまり1コン)の押されているボタンを取得
VAR B = BUTTON(0)
' 斧を振っていなかったら
IF SPVAR(0,"SWING") == #FALSE THEN
' 左ボタン処理
IF (B AND 1 << #B_LLEFT) != 0 THEN
SPVAR 0, "X", SPVAR(0,"X")-1
SPVAR 0, "DIRECT", #TRUE
ENDIF
' 右ボタン処理
IF (B AND 1 << #B_LRIGHT) != 0 THEN
SPVAR 0, "X", SPVAR(0,"X")+1
SPVAR 0, "DIRECT", #FALSE
ENDIF
' 向き変更
IF SPVAR(0, "DIRECT") == #TRUE THEN
SPCHR 0,,,32,32,#A_REVH
SPCHR 100,,,,,#A_REVH
' 向きに合わせて斧の位置を変える
SPOFS 100, SPVAR(0,"X"), SPVAR(0,"Y")+24
ELSE
SPCHR 0,,,32,32,0
SPCHR 100,,,,,0
' 向きに合わせて斧の位置を変える
SPOFS 100, SPVAR(0,"X")-32, SPVAR(0,"Y")+24
ENDIF
' 移動処理
IF SPVAR(0,"X") < -16 THEN
SPVAR 0,"X", -16
ELSEIF SPVAR(0,"X") > 400-16 THEN
SPVAR 0,"X", 400-16
ENDIF
SPOFS 0, SPVAR(0,"X"), SPVAR(0,"Y")
' Yボタン処理
IF (B AND 1 << #B_LRIGHT) != 0 THEN
' 振った音を鳴らす
BEEP 100
' ハカセのグラを変更
IF SPVAR(0, "DIRECT") == #TRUE && SPVAR(0,"JUMP") != #TRUE THEN
SPCHR 0,1433,,32,32,#A_REVH
ELSE
SPCHR 0,1433,,32,32,0
ENDIF
' 斧振りフラグON
SPVAR 0,"SWING", #TRUE
ENDIF
' ジャンプ中か調べる
IF SPVAR(0,"JUMP") != #TRUE THEN
' ジャンプ中じゃなければAボタン処理が効く
IF (B AND 1 << #B_RRIGHT) != 0 THEN
' ジャンプフラグをONにする
SPVAR 0,"JUMP", #TRUE
' 上昇中フラグに切り替える
SPVAR 0,"UPDOWN", #TRUE
ENDIF
ELSE
' 現在座標にジャンプ配列の該当する値を取り出して足す
SPVAR 0, "Y", SPVAR(0,"Y") + JUMP_PROCESS[JPPC]
' 次のジャンプ配列にアクセスするためにインクリメント
INC JPPC
' もしアクセス変数と配列の長さが同じになったら
IF JPPC == LEN(JUMP_PROCESS)-1 THEN
' プレイヤーのY座標補正
SPVAR 0, "Y", #GND
' ジャンプフラグを解除
SPVAR 0,"JUMP", #FALSE
' 次のジャンプのためにアクセス変数を初期化しておく
JPPC = 0
ENDIF
ENDIF
ENDIF
END
' 斧振り関数
'───────────────────────────────
DEF D_SWING_AXE
IF SPVAR(0,"SWING") == #TRUE THEN
' 斧を出現させる
SPSHOW 100
' 向きによって振る方向を変更
IF SPVAR(0, "DIRECT") == #TRUE THEN
' 斧を指定位置まで回転させる
IF SPVAR(100, "ROTATE") > -90 THEN
SPVAR 100, "ROTATE", SPVAR(100, "ROTATE")-5
SPROT 100, SPVAR(100, "ROTATE")
ELSE
SPHIDE 100
SPVAR 100, "ROTATE", 0
SPROT 100, SPVAR(100, "ROTATE")
SPVAR 0,"SWING", #FALSE
ENDIF
ELSE
' 斧を指定位置まで回転させる
IF SPVAR(100, "ROTATE") < 90 THEN
SPVAR 100, "ROTATE", SPVAR(100, "ROTATE")+5
SPROT 100, SPVAR(100, "ROTATE")
ELSE
SPHIDE 100
SPVAR 100, "ROTATE", 0
SPROT 100, SPVAR(100, "ROTATE")
SPVAR 0,"SWING", #FALSE
' 斧を振り終わったら木の衝突判定をリセット
SPVAR 200, "HITTING", #FALSE
SPVAR 201, "HITTING", #FALSE
ENDIF
ENDIF
ENDIF
END
' 消滅時のカウント
'───────────────────────────────
DEF HIDE_COUNT
VAR SP_WANPAKU = 1
VAR SP_KANZAKI = 2
VAR SP_INTELI = 3
IF SPVAR(SP_WANPAKU,"HIDE") >= 1 THEN
SPVAR SP_WANPAKU, "HIDE", SPVAR(SP_WANPAKU, "HIDE")+1
IF SPVAR(SP_WANPAKU, "HIDE") > #WANPAKU_POP THEN
IF SPVAR(0,"X") < (400/2-1) THEN
SPVAR SP_WANPAKU, "X", 400-16
SPVAR SP_WANPAKU, "DIRECT", #TRUE
SPCHR SP_WANPAKU, 128,352,32,32,#A_REVH
ELSE
SPVAR SP_WANPAKU, "X", -16
SPVAR SP_WANPAKU, "DIRECT", #FALSE
SPCHR SP_WANPAKU, 128,352,32,32,0
ENDIF
SPSHOW SP_WANPAKU
SPVAR SP_WANPAKU, "DAMAGE", #FALSE
SPVAR SP_WANPAKU, "Y", 160
SPOFS SP_WANPAKU, SPVAR(SP_WANPAKU,"X"),SPVAR(SP_WANPAKU,"Y")
SPVAR SP_WANPAKU, "SPEED", SPVAR(SP_WANPAKU,"SPEED") + 5
SPVAR SP_WANPAKU, "HIDE", 0
ENDIF
ENDIF
IF SPVAR(SP_KANZAKI,"HIDE") >= 1 THEN
SPVAR SP_KANZAKI, "HIDE", SPVAR(SP_KANZAKI, "HIDE")+1
IF SPVAR(1, "HIDE") > #WANPAKU_POP THEN
SPVAR SP_KANZAKI, "X", SPVAR(0,"X")+16
SPVAR SP_KANZAKI, "DIRECT", #FALSE
SPVAR SP_KANZAKI, "DAMAGE", #FALSE
SPVAR SP_KANZAKI, "Y", 240+32
SPOFS SP_KANZAKI, SPVAR(SP_KANZAKI,"X"),SPVAR(SP_KANZAKI,"Y")
SPVAR SP_KANZAKI, "SPEED", SPVAR(SP_KANZAKI,"SPEED") + 5
SPVAR SP_KANZAKI, "HIDE", 0
SPSHOW SP_KANZAKI
ENDIF
ENDIF
IF SPVAR(SP_INTELI,"HIDE") >= 1 THEN
SPVAR SP_INTELI, "HIDE", SPVAR(SP_INTELI, "HIDE")+1
IF SPVAR(SP_INTELI, "HIDE") > #WANPAKU_POP THEN
IF SPVAR(0,"X") < (400/2-1) THEN
SPVAR SP_INTELI, "X", 400-16
SPVAR SP_INTELI, "DIRECT", #TRUE
SPCHR SP_INTELI, 288,352,32,32,#A_REVH
ELSE
SPVAR SP_INTELI, "X", -16
SPVAR SP_INTELI, "DIRECT", #FALSE
SPCHR SP_INTELI, 288,352,32,32,0
ENDIF
SPSHOW SP_INTELI
SPVAR SP_INTELI, "Y", 50
SPOFS SP_INTELI, SPVAR(SP_INTELI,"X"),SPVAR(SP_INTELI,"Y")
SPVAR SP_INTELI, "SPEED", 0
SPVAR SP_INTELI, "HIDE", 0
ENDIF
ENDIF
END
' ワンパク君移動関数
'───────────────────────────────
DEF WANPAKU_DASH
SPID = 1
IF SPSHOW(SPID) == 1 THEN
IF SPVAR (SPID, "DIRECT") == #FALSE THEN
IF SPVAR (SPID, "DAMAGE") == #FALSE THEN
SPVAR SPID, "X", SPVAR(SPID, "X") + SPVAR(SPID, "SPEED")
ELSE
SPVAR SPID, "X", SPVAR(SPID, "X") -10
SPVAR SPID, "Y", SPVAR(SPID, "Y") -10
ENDIF
ELSE
IF SPVAR (SPID, "DAMAGE") == #FALSE THEN
SPVAR SPID, "X", SPVAR(SPID, "X") - SPVAR(SPID, "SPEED")
ELSE
SPVAR SPID, "X", SPVAR(SPID, "X") +10
SPVAR SPID, "Y", SPVAR(SPID, "Y") -10
ENDIF
ENDIF
ENDIF
SPOFS SPID, SPVAR(SPID, "X"), SPVAR(SPID, "Y")
IF SPVAR(SPID, "X") > 400+32 || SPVAR(SPID, "X") < -32 THEN
SPVAR SPID, "HIDE", 1
SPHIDE SPID
ENDIF
END
' 神崎移動関数
'───────────────────────────────
DEF KANZAKI_UPDOWN
VAR SPID = 2
IF SPSHOW(SPID) == 1 THEN
IF SPVAR (SPID, "DAMAGE") == #FALSE THEN
IF SPVAR (SPID, "DIRECT") == #FALSE THEN
SPVAR SPID, "Y", SPVAR(SPID, "Y") - SPVAR(SPID, "SPEED")
ELSE
SPVAR SPID, "Y", SPVAR(SPID, "Y") + 10
ENDIF
ELSE
SPVAR SPID, "Y", SPVAR(SPID, "Y") +10
ENDIF
ENDIF
SPOFS SPID, SPVAR(SPID, "X"), SPVAR(SPID, "Y")
IF SPVAR(SPID, "Y") < #KANZAKI_MAXUP THEN
SPVAR SPID, "DIRECT", #TRUE
ENIDF
IF SPVAR(SPID, "Y") > 240+32 THEN
SPVAR SPID, "HIDE", 1
SPHIDE SPID
ENDIF
END
' インテリ移動関数
'───────────────────────────────
DEF INTELI_FLOAT
SPID = 3
IF SPSHOW(SPID) == 1 THEN
IF SPVAR (SPID, "DIRECT") == #FALSE THEN
SPVAR SPID, "X", SPVAR(SPID, "X") + 1
ELSE
SPVAR SPID, "X", SPVAR(SPID, "X") - 1
ENDIF
SPVAR SPID, "SPEED", SPVAR(SPID,"SPEED")+0.05
SPOFS SPID, SPVAR(SPID,"X"),SPVAR(SPID,"Y")+SIN(SPVAR(SPID,"SPEED")) * 30
IF SPVAR(SPID, "X") > 400+32 || SPVAR(SPID, "X") < -32 THEN
SPVAR SPID, "HIDE", 1
SPHIDE SPID
ENDIF
ENDIF
END
' エネミー判定処理
'───────────────────────────────
DEF ENEMY_COL_PROCESS
FOR G_I = 0 TO 1
IF HITSP == G_I && SPSHOW(G_I) == 1 THEN
SPVAR G_I, "DAMAGE", #TRUE
BEEP 120
ENDIF
NEXT
END
' 木描写
'──────────────────────────
DEF TREE_DRAW A_X,A_Y,A_Screen
TPUT A_Screen,A_X+1,A_Y+0,&HEC93
TPUT A_Screen,A_X+2,A_Y+0,&HEC94
TPUT A_Screen,A_X+0,A_Y+1,&HECD3
TPUT A_Screen,A_X+1,A_Y+1,&HECD4
TPUT A_Screen,A_X+2,A_Y+1,&HECD5
TPUT A_Screen,A_X+0,A_Y+2,&HED13
TPUT A_Screen,A_X+1,A_Y+2,&HED14
TPUT A_Screen,A_X+2,A_Y+2,&HED15
TPUT A_Screen,A_X+0,A_Y+3,&HED53
TPUT A_Screen,A_X+1,A_Y+3,&HED54
TPUT A_Screen,A_X+2,A_Y+3,&HED55
TPUT A_Screen,A_X+0,A_Y+4,&HED93
TPUT A_Screen,A_X+1,A_Y+4,&HED94
TPUT A_Screen,A_X+2,A_Y+4,&HED95
TPUT A_Screen,A_X+0,A_Y+5,&HEDD3
TPUT A_Screen,A_X+1,A_Y+5,&HEDD4
TPUT A_Screen,A_X+2,A_Y+5,&HEDD5
THOME 1, 6*16-16+8, 240-32
THOME 2, 400-(16*7)+8, 240-32
TOFS 1, 6*16-16+8, 240-32
TOFS 2, 400-(16*7)+8, 240-32
SPSET 200, 0,1
SPSET 201, 0,1
SPCOL 200
SPCOL 201
SPVAR 200, "HP", 10
SPVAR 201, "HP", 10
SPVAR 200, "HITTING", #FALSE
SPVAR 201, "HITTING", #FALSE
SPVAR 200, "ROT", "0"
SPVAR 201, "ROT", "0"
SPVAR 200, "ALPHA", "255"
SPVAR 201, "ALPHA", "255"
SPOFS 200, 6*16-16, (6-5)*16
SPOFS 201, 17*16-16, (6-5)*16
END
' 斧と木の衝突判定処理
'──────────────────────────
DEF SLASH_WOOD
VAR SP = SPHITSP(100,200,201)
IF SP != -1 THEN
IF SPVAR(SP,"HITTING") == #FALSE
SPVAR SP, "HITTING" = #TRUE
SPVAR SP, "HP", SPVAR(SP,"HP")-1
ENDIF
ENDIF
END
' 木の回転処理
'──────────────────────────
DEF WOOD_ROTATE
FOR G_I = 0 TO 1
VAR SP = G_I+200
IF SPVAR(SP,"HP") <= 0 THEN
IF TROT(G_I+1) <=> 70 THEN
SPVAR SP,"ROT", SPVAR(SP,"ROT")+1
TROT G_I+1, SPVAR(SP,"ROT")
ENDIF
ENDIF
IF SPVAR(SP,"ROT") >= 70 && SPVAR(SP, "ALPHA") > 0 THEN
SPVAR SP, "ALPHA", SPVAR(SP, "ALPHA")-1
TCOLOR G_I+1, RGB(SPVAR(SP, "ALPHA"),255,255,255)
ENDIF
NEXT
END