【Pyxel】作りながら学ぶゲームプログラム (クリックゲームを改造する)
今回は以前に作成したクリックゲームを改造してたくさんのニャンコが出現するようにします。
元のコードと画像データはこちらからダウンロードできます。
http://syun777.sakura.ne.jp/tmp/pyxel/click.zip
このようにニャンコが4体出るようにします。
■ニャンコをクラス化する
前回のコードでは、ニャンコを制御するためのデータを全て App クラスの中に定義していました。この書き方ではより機能を拡張したい場合に Appクラスがどんどん肥大化してしまいます。
そこで、ニャンコをクラス化してコードをスッキリさせます。
Appクラスに定義した、ニャンコの情報を Catクラスに抜き出します。
import pyxel
class Cat:
def __init__(self):
# 変数初期化
self.x = 0
self.y = 0
self.vx = 1
self.vy = 1
self.exists = True # ニャンコ様存在フラグ
def update(self):
# 移動する
self.x += self.vx
self.y += self.vy
# 画面外に出ないようにする
if self.x < 0:
self.x = 0
self.vx *= -1 # 移動方向を反転する
if self.y < 0:
self.y = 0
self.vy *= -1 # 移動方向を反転する
if self.x > pyxel.width - 16:
self.x = pyxel.width - 16
self.vx *= -1 # 移動方向を反転する
if self.y > pyxel.height - 16:
self.y = pyxel.height - 16
self.vy *= -1 # 移動方向を反転する
def checkHit(self, x, y):
# 当たり判定
left = self.x
top = self.y
right = self.x + 16
bottom = self.y + 16
if left <= x <= right:
if top <= y <= bottom:
return True # 当たり
return False # 外れ
def draw(self):
# ニャンコ様を描画する
pyxel.blt(self.x, self.y, 0, 0, 0, 16, 16, 5)
class App:
def __init__(self):
pyxel.init(160, 120, fps=30)
pyxel.image(0).load(0, 0, "cat.png") # 画像読み込み
self.cat = Cat() # ニャンコオブジェクト生成
pyxel.mouse(True) # マウスカーソルを表示する
pyxel.run(self.update, self.draw)
def update(self):
if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
if self.cat.checkHit(pyxel.mouse_x, pyxel.mouse_y):
# 命中したので、ニャンコを消す
self.cat.exists = False
if self.cat.exists:
# 生存している場合のみ更新
self.cat.update()
def draw(self):
pyxel.cls(0)
if self.cat.exists:
# 生存している場合のみ描画
self.cat.draw()
else:
pyxel.text(60, 50, "GAME CLEAR", 7)
App()
修正後のコードは上記のようになりますが、前回と変わりすぎてしまったので、順を追って説明します。
まず、App.__init__() の「self.x から self.exists」までを Cat.__init__() に移動します。
次に、App.update() の「移動する」から「画面外に出ないようにする」の部分を Cat.update() に移動します。
そして App.update() のクリックによる当たり判定の部分を 新たに定義した Cat.checkHit() に移動します。
Cat.checkHit() はクリックした座標を引数として渡すようにしているので、pyxel.mouse_x を 引数の x 、pyxel.mouse_y を 引数の y に変更します。
if left <= x <= right:
if top <= y <= bottom:
return True # 当たり
最後に、App.draw() のニャンコ描画処理を Cat.draw() に移動します。
App 側は、抜き出した部分を Cat クラスに置き換える修正をします。
まずは、App.__init__() から……
self.cat に Cat クラスのインスタンス (実体) を生成して代入します。
続けて、App.update() の変更点です。こちらはクリックの部分と Catクラスの更新の 2つの修正があります。
まずは、クリックの部分 (pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON)) です。
self.cat.checkHit() にマウスの座標を渡し、Trueを返したら当たりなので、self.cat.exsits を False にしてニャンコを消滅させます。
そしてすぐ下の部分です。
self.cat.exists が Trueの時のみ、ニャンコを移動させる (self.cat.update() を呼び出す)ようにしています。
最後に、App.draw() の修正です。
ニャンコが存在している時は、self.cat.draw() を呼び出して描画するようにします。そうでなければ、"GAME CLEAR" のテキストを表示しています。
では実行して、前回と同じ動作することを確認してください。
■余談:リファクタリングについて
ここで行なった作業は、前回と同じ動作を保ちながら、コードを修正しました。このように「同じ動作結果を維持しながら、コードを読みやすいように修正する」ことをリファクタリングと呼びます。
「同じ動作をしているのに、なぜコードを変更する必要があるのか?」
と疑問に思うかもしれませんが、この修正は、これから実装する「ニャンコをたくさん出現させる」という機能を実装しやすくためのものです。
リファクタリングの機能として、「今後の機能拡張をやりやすくする」という効果があります。
もしリファクタリングについて、もっと理解したい場合は
「新装版 リファクタリング―既存のコードを安全に改善する― 」
「リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック」
といった書籍で勉強することをオススメします。
■ニャンコを配列で管理する
ニャンコをたくさん表示するために、配列を使ってニャンコを管理します。まずはコード先頭に import random という定義を追加してください。
import pyxel
import random # これを追加する!
class Cat:
def __init__(self):
これは乱数を使用するための定義となります。
次に、 App.__init__() の修正です。
class App:
def __init__(self):
pyxel.init(160, 120, fps=30)
pyxel.image(0).load(0, 0, "cat.png") # 画像読み込み
# ここから修正
self.cat_list = []
for i in range(4):
cat = Cat() # ニャンコオブジェクト生成
cat.x = random.randint(32, pyxel.width-32)
cat.y = random.randint(32, pyxel.height-32)
self.cat_list.append(cat)
# ここまで修正
pyxel.mouse(True) # マウスカーソルを表示する
pyxel.run(self.update, self.draw)
self.cat_list という変数にCatクラスの配列 (リスト) を格納するようにしました。そして、初期位置を random.randint() でランダムな座標に出現させるようにしています。random.randint() は渡された 2つの引数の値の間でランダムな値を返す関数です。
続いて、App.update() の修正です。
def update(self):
for cat in self.cat_list:
if cat.exists:
if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
if cat.checkHit(pyxel.mouse_x, pyxel.mouse_y):
# 命中したので、ニャンコを消す
cat.exists = False
if cat.exists:
# 生存している場合のみ更新
cat.update()
for文で cat_list のイテレーターを回し、その中で self.cat で処理していた部分を cat 変数に置き換えます。
最後に App.draw() です。
def draw(self):
pyxel.cls(0)
for cat in self.cat_list:
if cat.exists:
# 生存している場合のみ描画
cat.draw()
is_wiped = True # 全滅したかどうか
for cat in self.cat_list:
if cat.exists:
is_wiped = False # 全滅していない
if is_wiped:
# 全滅させたのでクリア表示
pyxel.text(60, 50, "GAME CLEAR", 7)
こちらも cat_list をイテレーターで回して、self.cat を cat変数に置き換えます。
後半は、全滅チェックした上で、全滅していた場合のみ (is_wipedが Trueの時のみ) クリア表示を行います。
なお全滅チェックですが、filter() を使うと一行で書くことができます
# 全滅チェック
is_wiped = len(list(filter(lambda cat:cat.exists, self.cat_list))) == 0
ただ……、これはプログラム初心者には難しい書き方ですので、ひとまず for文で問題ないです。
では、実行してニャンコが4体表示され、クリックして絶滅させると "GAME CLEAR" が表示されることを確認します。
ひとまずこれで終了。
今回作成したプログラムとデータは以下の場所にアップしていますので、うまく動作しない場合はこちらを参考にしてみてください。
http://syun777.sakura.ne.jp/tmp/pyxel/click2.zip
この記事が気に入ったらサポートをしてみませんか?