弾幕ゲームは、キャラクターに対して発射される弾を避けまくるゲーム。弾の早さやタイミングを変えることで、ギリギリで避ける爽快感やクリアの達成感を楽しむゲーム。古くはインベーダーゲームとかのファミコン系のゲームもあり、作りやすさやオリジナリティの出しやすさもあって、よくインディーズ(メジャーじゃない、個人開発などの)ゲームで今でも多数のものが作られているジャンル。
今回はpyxelを使って、弾幕ゲームの基本を作っていくよ
何も考えずにいきなりpythonを書き始めるのは、あんまり良くないとされている。みんなも英作文の宿題とかで、いきなり英語で文章を考えるより、まず日本語で何を言いたいかを整理して、どんな単語や文法を使うかを考えてから英文を作ったほうが効率が良かったりするので、どんな感じでコードを描いていくのか、どんな機能を使って作っていくのかを先に考えておこう。
### アプリに必要なものを考えてみよう プログラミングの勉強として、なにかアプリを作り始めるときに、「自分の実力でできるか」を考えないで、「こんなアプリができたらいいな」を考えるのがコツ。なんでかっていうと、それが一番楽しいから!アプリを作る順番として
①「こんなことできたらいいな!」をふんだん詰め込んだ「ぼくがかんがえたさいきょうのアプリ」を考える。 ②アプリに必要なものを考える ③その中から、「最低限」のものを考える ④まずは最低限のものを作ってみる ⑤うまくいったら、機能を付け加えていく
ここまでは、利用者=プレイヤー視点で必要なこと。では、開発する側として考えなくちゃいけないことはなんだろう?
他にも開発していくうえでいろいろ必要になってくるかもしれないけど、とりあえずこんな感じにしよう💦
データを考えたあとで必要なのは、そのデータを使って、どんな機能を作っていくか、つまり機能を考えなくちゃいけない。
pyxelの準備をしよう。 今回はパソコンにpyxelがインストール済みだから、インストール作業は必要なし。
作業をしたいフォルダに移動したら、まずはpythonファイルを作成しよう。今回はdanmaku.pyという名前にするよ。
ここに、pyxelの初期コードをコピペしよう。
import pyxel
pyxel.init(120, 120)
pyxel.load("danmaku.pyxres")
def update():
pass
def draw():
pass
pyxel.run(update, draw)
これを実行して、黒い四角が出てきたらOK
次に、キャラクターデザインとかをするためのpyxresファイルを用意するよ。
今回はこちらで用意したデザイン用のファイル(pyxresファイル)を共有フォルダから自分のプロジェクトにコピーして使います。
ターミナルに次のコマンドを打ってみよう
pyxel edit danmaku.pyxres
実行すると、pyxel editorというお絵かき+作曲ツールが出てくるので。 一度保存してから 画面を閉じよう。一度保存することで、danmaku.pyxres.pyxresというファイルができて、このファイルがゲームのデザインとか音楽を担当するファイルになる。
まず、ターミナルでこのコマンドを打って、どんな画像がデザインファイルに入っているかを確認しよう。
pyxel edit danmaku.pyxres
表示したいメインキャラクター派、イメージバンク0番の、(0, 0)から(16, 16)のところにある。
pyxelでイメージバンクの絵を表示させたい場合は、blt という関数を使えばOK。取り合えすこのコードを、表示を担当するdraw()関数の中に書いてみよう
draw():
pyxel.blt(0, 0, 0, 0, 0, 16, 16, 0)
できた
ただ、ゲーム開始時にこんな左端にいたら、ちょっと妙だよね。
<img class=”” src=”img/draw_character1.png” alt=”” width=50%>
今回は上から敵が弾幕を撃ってくるようにしたいので、キャラクターは下の方の真ん中に配置して、左右に動いて弾を避けるようにしよう
表示位置を変更するためには。さっき書いたblt()関数の引数を変更する必要がある。引数は、今回のコードでいうとこの部分。めっちゃある。
この関数の場合、引数にはこんな感じで順番と役割が決まっている。
今回のばあい、表示位置のXを担当するのが1番目 Yを担当するのが2番目の引数で、xが0,yが0のところに表示してね、となってるから、そこに画像の左上を合わせた形で表示されたわけ。
じゃあ、それぞれの引数を合わせて位置を調整してみよう。
下の方に合わせたいので、Y方向に90のところに合わせよう
def draw():
pyxel.blt(0, 90, 0, 0, 0, 16, 16, 0)
pyxel.run(update, draw)
できた。 さて、あとは横方向に真ん中に合わせるだけ。余裕だぜ!
今回のアプリの縦幅、横幅は、コードのここで書いてあるとおり、120ピクセル
pyxle.init(120, 120)
てことは、真ん中に置きたいんだから、120の半分のところに置けばいい=割り算すればいいわけじゃんww俺天才wwww
def draw():
pyxel.blt(120 / 2, 90, 0, 0, 0, 16, 16, 0)
pyxel.run(update, draw)
ん〜。。。

。。。なんかズレてね??
やってみよう
さっき書いたblt関数の1つ目、2つ目の引数を、アニメーションのフレームごとに変えていければ、キャラクターを動かすことができそうな気がする。
となると、blt関数を使うときに常に「キャラクターのx座標・y座標」にアクセスできるようにしておくのが便利。
いろんな方法があるけど、今回は辞書型のデータを作って、変数としていつでも呼び出せるようにする方法を使っていくよ
辞書型の復習をしておこう。リッキーの情報を辞書型にしてみるとこんな感じ
ricky_information = {
"age": 37,
"gender": "男",
"hobby": "プログラミング"
}
# 呼び出すとき
print(ricky["age"])
こんな感じで、キャラクターの情報をまとめておこう。そういやキャラの名前を決めてなかったので。操作キャラをcharacter, 敵キャラをenemyとしよう
character = {
"x": 120 / 2 - 16 / 2,
"y": 90
}
enemy = {
"x": 120 / 2 - 16 / 2,
"y": 20
}
せっかく辞書型にまとまったので、draw関数で表示する部分で、この変数を使うように変更しよう。 現時点での全体のコードはこんな感じ
import pyxel
pyxel.init(120, 120)
pyxel.load("danmaku.pyxres")
character = {
"x": 120 / 2 - 16 / 2,
"y": 90
}
enemy = {
"x": 120 / 2 - 16 / 2,
"y": 20
}
def update():
pass
def draw():
pyxel.blt(character["x"], character["y"], 0, 0, 0, 16, 16, 0)
pyxel.blt(enemy["x"], enemy["y"], 0, 16, 0, 16, 16, 0)
pyxel.run(update, draw)
さっき宣言した辞書型の「x」の数字を増やしたり減らしたりすれば、ゲーム内で動かすことができそう。
pyxelで、情報の更新を担当する関数は update関数だったね。
敵キャラを動かすから、enemyのXを変えていこう
xの数字を1増やすコードを、update 関数の中に勝てみよう
import pyxel
pyxel.init(120, 120)
pyxel.load("danmaku.pyxres")
character = {
"x": 120 / 2 - 16 / 2,
"y": 90
}
enemy = {
"x": 120 / 2 - 16 / 2,
"y": 20
}
def update():
enemy["x"] = enemy["x"] + 1
def draw():
pyxel.blt(character["x"], character["y"], 0, 0, 0, 16, 16, 0)
pyxel.blt(enemy["x"], enemy["y"], 0, 16, 0, 16, 16, 0)
pyxel.run(update, draw)

なんかのびたんだがwwww
ここでちょっとpyxleの描画=イラストなどを表示する仕組みについて説明するよ
draw関数というのを使ってキャラクターを表示しているけど、実はこの関数、すでにある絵に絵を書き足しているだけだから、キャラクターの位置を変えて絵を書き足していくと、さっきみたいなことになる。

そこで、draw関数で絵を書き足す前に。一度画面をリセットして、キャラクターを描き直すと、キャラクターが移動しているように見える。
pyxle.cls(0)という一文を加えることで、こんな感じで移動するアニメーションができるよ。ちなみに、0は0番目のカラーコード、つまり黒のこと。
イメージ的には、絵を書いて、そこにインクをぶちまけて、その上に新た敷く絵を書いて、って感じ。
import pyxel
pyxel.init(120, 120)
pyxel.load("danmaku.pyxres")
character = {
"x": 120 / 2 - 16 / 2,
"y": 90
}
enemy = {
"x": 120 / 2 - 16 / 2,
"y": 20
}
def update():
enemy["x"] = enemy["x"] + 1
def draw():
pyxel.cls(0)
pyxel.blt(character["x"], character["y"], 0, 0, 0, 16, 16, 0)
pyxel.blt(enemy["x"], enemy["y"], 0, 16, 0, 16, 16, 0)
pyxel.run(update, draw)
さてどうする?
画面外に行くってことはどういうことか考えてみると
敵キャラのx座標が大きくなりすぎ!
って言えるから、それをなんとかすればよさげ。
もっというと
敵キャラのx軸が〇〇より小さいときは移動する そうじゃないときは移動しない
ってすれば、行けそうな気がする!
もっともっというと、
<もし>敵キャラのx軸が〇〇より小さいときは移動する <そうじゃないとき>は移動しない
もうひとこえ!
if 敵キャラのx座標が120より小さいとき:
character["x"] = character["x"] + 1
else:
移動しない
行ったれ!!!
def update()
if enemy["x"] < 120 - 16:
enemy["x"] = enemy["x"] + 1
print(enemy["x"])
else:
pass
これ、どうするよ ちょっと設計を変えて、こんな感じ、左右に敵キャラが動くようにしよう。
これを実現する耐えには、進行方向を示す変数を設定する必要があるんだけど、どういうデータにしようか。
右のときは+1にして、左のときは−1にして、右のときは+1にして、左のときは−1にして
このとき、右から左、左から右のときにやってる共通したことってなんだろう?
そう、-1をかければいい!
コードに起こしてみると、こうなる!
def update():
enemy["x"] = enemy["x"] + enemy["direction"]
if enemy["x"] >= 120 - 16 or enemy["x"] <= 16:
enemy["direction"] = enemy["direction"] * -1
敵キャラを動かすのは自動操作でできたけど、操作キャラクターを勝手に操作されるのは困るので、キーボード入力がされているときに、そのキーに応じた方向に移動するようにしたい。 具体的には
| キー | 移動方向 |
| 右矢印(→) | x軸方向に+ |
| 左矢印(←) | x軸方向にー |
移動の部分は敵キャラの移動の応用をすればいけそう。
問題はキー入力の部分。pyxelでは、キーごとに変数名が決まっていて、キーが押されているときはその変数にTrueが入る(=そうじゃないときはFalse)が入る。それを利用して
if キーが押されたかどうか== True:
押されたときにやりたいこと
って感じにすればOK。 今回はキーボードの矢印キーを検知したいので、使うのはこの4つだけ
| pyxel.KEY_RIGHT | 右矢印 |
| pyxel.KEY_LEFT | 左矢印 |
| pyxel.KEY_UP | 上矢印 |
| pyxel.KEY_DOWN | 下矢印 |
じゃあ、右矢印が 押されたときに、キャラクターを右(x方向)に1移動するコードを書いてみよう
if pyxel.btn(pyxel.KEY_RIGHT) == True:
character["x"] = character["x"] + 1
elif pyxel.btn(pyxel.KEY_LEFT) == True:
character["x"] = character["x"] - 1