pyxelで2Dアクションゲームを作る(お試し)
今回はpyxelで2Dアクションゲームっぽいものを作ってみます。ほんのお試しですが、横視点で「ジャンプ」・「落下」までを実現していきます。
▲宇宙飛行士っぽいやつがジャンプして落ちます。
ではコードに移ります。
まずはpyxelをインポートして画像ファイルを読み込みます。
def __init__(self):
self.player = Player()
pyxel.init(128, 128, caption="TEST", scale=5,)
pyxel.load('assets/assets.pyxres')
pyxel.mouse(False)
pyxel.run(self.update, self.draw)
▲後述するPlayerクラスのインスタンスplayerを作成しておきます。
class Player:
def __init__(self):
self.p_x = 8
self.p_y = 8
self.p_m = 0
self.p_m2 = 0
self.p_c = 0
self.p_j = False
self.p_jc = 0
def Jump(self, x):
if x == 1:
self.p_y -= 1.5
self.p_jc += 1
if self.p_jc == 10 :
self.p_j = False
self.p_jc = 0
def Dawn(self):
self.p_y += 1
▲Playerクラスです。変数として「p_x(プレイヤー座標x)、p_y(プレイヤー座標y)、p_m(プレイヤー移動方向)、p_m2(アニメーション制御用)、p_c(アニメーション制御用2)、p_j(ジャンプフラグ)、p_jc(ジャンプ時間カウント用)」があります。
関数としてはジャンプ制御のJumpと落下制御のDawnがあります。
続いてupdate関数です。ここではプレイヤーの動きを制御します。
def update(self):
#Jump
if self.player.p_j == True:
j = self.check_move(1)
self.player.Jump(j)
#Fall
else:
d = self.check_move(3)
if d == 3:
self.player.Dawn()
#Move UP
if pyxel.btn(pyxel.KEY_SPACE) and self.player.p_j == False:
self.player.p_m = 1
self.player.p_c += 1
self.player.p_j = True
#Move RIGHT
elif pyxel.btn(pyxel.KEY_RIGHT):
self.player.p_m = 2
self.player.p_c += 1
a = self.check_move(2)
if a == 2:
self.player.p_x += 1
#Move LEFT
elif pyxel.btn(pyxel.KEY_LEFT):
self.player.p_m = 4
self.player.p_c += 1
a = self.check_move(4)
if a == 4:
self.player.p_x -= 1
else:
self.player.p_m = 0
self.player.p_c = 0
self.player.p_m2 = 0
▲スペースキーでジャンプ、左右キーで左右制御です。動く際にはcheck_move関数を呼び出して移動判定をします。壁だったら進めなくします。
check_move関数の前に描画部分のdraw関数を記載しておきます。
def draw(self):
pyxel.cls(0)
#Draw tilemap
pyxel.bltm(0,0,0,0,0,16,16)
#Player draw//////////////////////////////
x = self.player.p_x
y = self.player.p_y
if self.player.p_j == True:
pyxel.blt(x,y,0,8,0,8,8,0)
elif self.player.p_m == 2:
if self.player.p_c % 15 == 0:
self.player.p_m2 += 1
if self.player.p_m2 % 2 == 0:
pyxel.blt(x,y,0,0,8,8,8,0)
else:
pyxel.blt(x,y,0,8,8,8,8,0)
elif self.player.p_m == 4:
if self.player.p_c % 15 == 0:
self.player.p_m2 += 1
if self.player.p_m2 % 2 == 0:
pyxel.blt(x,y,0,0,16,8,8,0)
else:
pyxel.blt(x,y,0,8,16,8,8,0)
elif self.player.p_m == 0:
pyxel.blt(x,y,0,0,0,8,8,0)
#/////////////////////////////////////////
▲描画部分です。プレイヤーの描画はp_j(ジャンプ中かどうか)・p_m(左右の判別)・p_m2(アニメーション制御)の値をもとに行います。
▲左右の動き
▲ジャンプ
さて、次はcheck_move関数です。ここでいわゆる「当たり判定」を実装します。
def check_move(self, x):
"""
Player coordinates
"""
px = int((self.player.p_x - 1) / 8)
py = int((self.player.p_y) / 8)
px2 = int((self.player.p_x + 8) / 8)
py2 = int((self.player.p_y + 8) / 8)
px3 = int((self.player.p_x + 6) / 8)
px4 = int((self.player.p_x) / 8)
py3 = int((self.player.p_y + 6) / 8)
py4 = int((self.player.p_y + 2) / 8)
pm = pyxel.tilemap(0).get(px3, py)
pm2 = pyxel.tilemap(0).get(px4, py)
pm3 = pyxel.tilemap(0).get(px3, py2)
pm4 = pyxel.tilemap(0).get(px4, py2)
pm5 = pyxel.tilemap(0).get(px, py3)
pm6 = pyxel.tilemap(0).get(px2, py3)
pm7 = pyxel.tilemap(0).get(px, py4)
pm8 = pyxel.tilemap(0).get(px2, py4)
#Move UP
if x == 1:
if pm > 50 and pm2 > 50:
return 1
#Move DOWN
elif x == 3:
if pm3 > 50 and pm4 > 50:
return 3
else:
return 0
#Move RIGHT
elif x == 2:
if pm6 > 50 and pm8 > 50:
return 2
#Move LEFT
elif x == 4:
if pm5 > 50 and pm7 > 50:
return 4
else:
return 0
▲ごちゃごちゃ書いていますが、プレイヤーの四隅の座標を取得して、移動先のタイルがブロックかどうかを判定しているだけです。
全てつなげたコードは以下の通りです。
# -*- coding: utf-8 -*-
#2D-action_game test
import pyxel
class APP:
def __init__(self):
self.player = Player()
pyxel.init(128, 128, caption="TEST", scale=5,)
pyxel.load('assets/assets.pyxres')
pyxel.mouse(False)
pyxel.run(self.update, self.draw)
def update(self):
#Jump
if self.player.p_j == True:
j = self.check_move(1)
self.player.Jump(j)
#Fall
else:
d = self.check_move(3)
if d == 3:
self.player.Dawn()
#Move UP
if pyxel.btn(pyxel.KEY_SPACE) and self.player.p_j == False:
self.player.p_m = 1
self.player.p_c += 1
self.player.p_j = True
#Move RIGHT
elif pyxel.btn(pyxel.KEY_RIGHT):
self.player.p_m = 2
self.player.p_c += 1
a = self.check_move(2)
if a == 2:
self.player.p_x += 1
#Move LEFT
elif pyxel.btn(pyxel.KEY_LEFT):
self.player.p_m = 4
self.player.p_c += 1
a = self.check_move(4)
if a == 4:
self.player.p_x -= 1
else:
self.player.p_m = 0
self.player.p_c = 0
self.player.p_m2 = 0
def draw(self):
pyxel.cls(0)
#Draw tilemap
pyxel.bltm(0,0,0,0,0,16,16)
#Player draw//////////////////////////////
x = self.player.p_x
y = self.player.p_y
if self.player.p_j == True:
pyxel.blt(x,y,0,8,0,8,8,0)
elif self.player.p_m == 2:
if self.player.p_c % 15 == 0:
self.player.p_m2 += 1
if self.player.p_m2 % 2 == 0:
pyxel.blt(x,y,0,0,8,8,8,0)
else:
pyxel.blt(x,y,0,8,8,8,8,0)
elif self.player.p_m == 4:
if self.player.p_c % 15 == 0:
self.player.p_m2 += 1
if self.player.p_m2 % 2 == 0:
pyxel.blt(x,y,0,0,16,8,8,0)
else:
pyxel.blt(x,y,0,8,16,8,8,0)
elif self.player.p_m == 0:
pyxel.blt(x,y,0,0,0,8,8,0)
#/////////////////////////////////////////
def check_move(self, x):
"""
Player coordinates
"""
px = int((self.player.p_x - 1) / 8)
py = int((self.player.p_y) / 8)
px2 = int((self.player.p_x + 8) / 8)
py2 = int((self.player.p_y + 8) / 8)
px3 = int((self.player.p_x + 6) / 8)
px4 = int((self.player.p_x) / 8)
py3 = int((self.player.p_y + 6) / 8)
py4 = int((self.player.p_y + 2) / 8)
pm = pyxel.tilemap(0).get(px3, py)
pm2 = pyxel.tilemap(0).get(px4, py)
pm3 = pyxel.tilemap(0).get(px3, py2)
pm4 = pyxel.tilemap(0).get(px4, py2)
pm5 = pyxel.tilemap(0).get(px, py3)
pm6 = pyxel.tilemap(0).get(px2, py3)
pm7 = pyxel.tilemap(0).get(px, py4)
pm8 = pyxel.tilemap(0).get(px2, py4)
#Move UP
if x == 1:
if pm > 50 and pm2 > 50:
return 1
#Move DOWN
elif x == 3:
if pm3 > 50 and pm4 > 50:
return 3
else:
return 0
#Move RIGHT
elif x == 2:
if pm6 > 50 and pm8 > 50:
return 2
#Move LEFT
elif x == 4:
if pm5 > 50 and pm7 > 50:
return 4
else:
return 0
class Player:
def __init__(self):
self.p_x = 8
self.p_y = 8
self.p_m = 0
self.p_m2 = 0
self.p_c = 0
self.p_j = False
self.p_jc = 0
def Jump(self, x):
if x == 1:
self.p_y -= 1.5
self.p_jc += 1
if self.p_jc == 10 :
self.p_j = False
self.p_jc = 0
def Dawn(self):
self.p_y += 1
APP()
▲左右の移動・ジャンプ・落下が実現できました。
今回はここまで。今後こいつが発展していくかは未定です。また、何か機能を追加したらnoteに書こうと思います。
ソースと画像ファイルはGitHubにあります。
ここまで読んでいただきありがとうございました。
ここまで読んでいただきありがとうございます!