
ゲームが進行していくにつれて、いろんなイベントが起きるよ。それをコードで制御するのが、プログラマーの腕のみせどころ。今回はgeometry dashの続きを作りながら、イベント処理について勉強してくよ!
よくインターネットでも、「恋愛フラグ」とか、「◯亡フラグ立ったw」みたいな言い方するよね。めちゃくちゃ古い話でいうと、遅刻しそうな女の子が食パンをくわえながら全力ダッシュ→交差点でその子とぶつかる→恋愛フラグ、みたいなのがあったりする。
「〇〇フラグ」というと、このあと起こるイベントにつながる可能性がある伏線、みたいな意味で使われることがあるよね。
プログラミングでは、ある条件を満たすために必要な状態や変数 のことをいうよ。
例えば、最強の隠し武器を手に入れるのに、ただ単に宝箱を開けたらもらえる、みたいな感じだったら面白くないよね。〇〇というボスを倒しているかどうか、〇〇時間以上プレイしているかどうかなど、いろんな「かどうか」をクリアしてこその隠し武器だよね。ここでいう「かどうか」の条件が、隠し武器取得のための フラグ になるよ。
フラグの条件を満たしたときに起こることを「イベント」というよ。
例えば、、、
| フラグ | イベント |
|
・ジャイアンの機嫌がわるい ・ジャイアンがマイクを持っている |
ジャイアンリサイタル |
| のび太が泣きながら帰って来る | 「ドラえも~ん!なんか道具出して!」 |
| どこでもドアでしずかちゃんの家に行く | 「キャー、のび太さんの〇〇〇!!」 |
フラグを管理するのに便利なpythonのデータ型、bool型 を紹介するよ。この形には True:トゥルー と False:フォルス という2つのデータしか入らない!
TrueとFalseの使い分け方はだいたいこんなかんじ
| True | 正しい、存在する、(スイッチなどが)オンの状態 |
| False | 間違い、存在しない、(スイッチなどが)オフの状態 |

まず、bool型のフラグを2つ用意するよ。(説明のためにへんな変数名になっているけど、ほんとはもっといい変数名にするべき!)
# フラグ
# ジャイアンの機嫌が悪いかどうか → True:機嫌がわるい
jyaian_kigen_bad = True
# ジャイアンがマイクを持っているかどうか → True:マイクを持っている
jyaiann_has_mic = True
このフラグを使って、イベント処理をしていこう。
やりたいこととしては
もしjyaian_kigen_badがTrueで、jyaiann_has_micがTrueのなら
"ジャイアンリサイタル開催!ボェェェェ♫"と表示
それ以外の場合は
"ジャイアンリサイタル中止。。。"と表示
「あー、pythonのあれをつかえばいいのね!」って思った人、正解!そう、もし~なら、つまりifとフラグを組み合わせてイベントにすればいいわけだ!
これをコード化してみると
# フラグ
# ジャイアンの機嫌が悪いかどうか → True:機嫌がわるい
jyaian_kigen_bad = True
# ジャイアンがマイクを持っているかどうか → True:マイクを持っている
jyaiann_has_mic = True
# イベント処理
if jyaian_kigen_bad == True and jyaian_has_mic == True:
print("ジャイアンリサイタル開催!ボェェェェ♫")
else:
print("ジャイアンリサイタル中止。。。")
こんな感じで、今回はbool型のフラグとif文をつかって、geometry dashのイベント処理を実装していくよ
前回実装したのは、
import pyxel
screen = {
"yoko": 160,
"tate": 120
}
jump_box = {
"x":20,
"y":100,
"speed_x":0,
"speed_y":13
}
enemy_box = {
"x":160,
"y":100,
"speed_x":-1,
"speed_y":0
}
def update():
if jump_box["y"] == 100:
jump_box["speed_y"] = 13
jump_box["y"] -= jump_box["speed_y"]
jump_box["speed_y"] -= 1
if enemy_box["x"] == -10:
enemy_box["x"] = 160
enemy_box["x"] += enemy_box["speed_x"]
def draw():
pyxel.cls(0)
pyxel.rect(jump_box["x"], jump_box["y"], 10, 10, 7)
pyxel.rect(enemy_box["x"], enemy_box["y"], 10, 10, 8)
pyxel.init(screen["yoko"], screen["tate"])
pyxel.run(update, draw)
まず、日本語でやりたいことを整理してみよう。今回やりたいことは
の2本立て。
「フラグ」の考え方を使って、↑のやりたいことリストを言い換えてみよう。、もしスペースキーを押したときに、「ジャンプ中かどうか」を判定してるから、それをフラグとして設定しよう。jump_boxがジャンプしているかどうかのフラグだから、jump_box辞書の中で定義しよう。最初はジャンプしていない状態だから、Falseでスタートしよう
jump_box = {
"x":20,
"y":100,
"speed_x":0,
"speed_y":13,
# ジャンプの状態 ジャンプ中→True ジャンプしてないとき→False
"jump_status": False
}
フラグが用意できたから、さっきの日本語をコード化していこう。
# ジャンプしていない状態でスペースが押されたとき または ジャンプ中のとき
if (not jump_box["jump_status"] and ボタンが押された) or jump_box["jump_status"]:
jump_box["jump_status"] = True
jump_box["y"] -= jump_box["speed_y"]
jump_box["speed_y"] -= 1
# ジャンプ中の状態でy座標が100になったとき=着地したとき
if jump_box["y"] == 100 and jump_box["jump_status"]:
jump_box["speed_y"] = 13
jump_box["jump_status"] = False
and or などの論理演算子を覚えてるかな?
あとは、「ボタンが押された」というところの,
pyxelの機能をあてはめれば、できそうな感じ!
pyxelでスペースキーが押されたのを検知する関数は
pyxel.btnp(pyxel.KEY_SPACE)python
だから、この部分をあてて、update関数のjump_boxの部分を書き換えれば、完成!
import pyxel
screen = {
"yoko": 160,
"tate": 120
}
jump_box = {
"x":20,
"y":100,
"speed_x":0,
"speed_y":13,
"jump_status": False # ジャンプの状態 ジャンプ中→True ジャンプしてないとき→False
}
enemy_box = {
"x":160,
"y":100,
"speed_x":-1,
"speed_y":0
}
def update():
# ジャンプしていない状態でスペースが押されたとき または ジャンプ中のとき
if (not jump_box["jump_status"] and pyxel.btnp(pyxel.KEY_SPACE)) or jump_box["jump_status"]:
jump_box["jump_status"] = True
jump_box["y"] -= jump_box["speed_y"]
jump_box["speed_y"] -= 1
# ジャンプ中の状態でy座標が100になったとき=着地したとき
if jump_box["y"] == 100 and jump_box["jump_status"]:
jump_box["speed_y"] = 13
jump_box["jump_status"] = False
# 障害物の動き
if enemy_box["x"] == -10:
enemy_box["x"] = 160
enemy_box["x"] += enemy_box["speed_x"]
def draw():
pyxel.cls(0)
pyxel.rect(jump_box["x"], jump_box["y"], 10, 10, 7)
pyxel.rect(enemy_box["x"], enemy_box["y"], 10, 10, 8)
pyxel.init(screen["yoko"], screen["tate"])
pyxel.run(update, draw)
スペースキーを押したらちゃんとジャンプしたね!
デバッグ=debug は、プログラムのバグを取り除くこと、あるいはそのために調査をすること。例えば、さっきのプログラムで、update関数の
jump_box["jump_status"] = True
というところをコメントアウトしてみよう。明らかに動かなくなるのはわかるけど、このミスに気付いていなかったとして、原因をどうやって調べて修正する?コード全体を見てエラーを探さなくちゃいけないから、メチャクチャ大変だよね。
そこで大活躍するのが、みんながいつも使っているprint文。ターミナルに文字を出すだけの関数だけど、これを使ってプログラムの状態の管理やチェックをすることができる!
今回の場合は、何をprintしたらいいと思う?jumpしているかどうかの状態は、さっき作ったフラグ の
jump_box["jump_status"]
でわかるんだったよね。じゃあ、update関数の中で、1フレームごとにprint(jump_box["jump_status"]) でチェックしてみよう。そうすると、スペースキーを押しても、jump_status がFalseのままになってるのがわかるね。これで、「やべ、スペースキー押したときにjump_box["jump_status"]をTrueにするのわすれてた💦」って気が付くわけ。
みんなが高校生・大学生になったときには、アルバイトをするかもしれない。ゲームすることが仕事のバイトがあったら最高じゃない?
発売前のゲームのバグを発見するために、ゲームを遊びまくる、という、「ゲームデバッガー」という仕事があります。守秘義務があるからどのゲームとは言えないけど、リッキー先生もやったことがあるよ。「装備を一つ一つ変えて同じ道を100回くらい歩いて!」みたいな指示があったりして結構きついけど、新作ゲームを誰よりも早く遊べたりするから、好きな人はやってみるといいかも!
今回はスペースキーを押したときの処理だったから、
pyxel.btnp(pyxel.KEY_SPACE)
だったけど、ここの KEY_SPACEのところを変えると、いろんなキーに対応できるよ!VSCodeの補完で出てくるから、いろいろ試してみよう。
今回はキーが押されたときの処理だったけど、例えばクリック・右クリックされたときとかのいろいろな入力方法があるよね、pyxelにはそれらに対応する関数が用意されているから、いろいろ試してみよう。
| 関数名 | 機能 | 引数の解説 |
|---|---|---|
| pyxel.btn | 指定したキーが押されているかどうかを判定。 長押しの場合は反応し続ける |
key - 判定するキーのコード(例:pyxel.KEY_LEFT) |
| pyxel.btnp | 指定したキーが押された瞬間を判定。 長押ししても、最初の一回だけ反応する |
key - 判定するキーのコード hold - 連続入力を許可するフレーム数 |
| pyxel.btnr | 指定したキーが離された瞬間を判定。 | key - 判定するキーのコード |
| pyxel.mouse_x | マウスカーソルの現在のX座標を取得。 | なし |
| pyxel.mouse_y | マウスカーソルの現在のY座標を取得。 | なし |
| pyxel.btnv | 指定したキーが押されているかどうかを判定し、押されている場合はTrueをかえす。 | key - 判定するキーのコード(例:pyxel.KEY_LEFT) |