pyxelでRPG風のものを作る(1)
pythonのゲームエンジンpyxelでRPG風の何かをつくってみます。見下ろし型のアクションゲームの要領で、ミニマップ間を行き来できるようにするところまでをいったんの目標とします。
今回からpyxelのバージョンを1.3にしたので、色合いが少し変わりました。
class App:
def __init__(self):
#Player status
self.Player = Player(8, 56)
self.player_move = 0
#Map status
self.stage_flug = 1
self.map_count_x = 1
self.map_count_y = 1
self.game_start = False
self.map_x = 0
self.map_y = 0
self.map_move = 0
pyxel.init(128,128)
#Image read
pyxel.load('C:/pyxel/image/pknights.pyxres')
pyxel.run(self.update, self.draw)
まずは変数を宣言します。プレイヤーに関するものとマップに関するものです。その後、イメージリソースを読み込んで、pyxel.runで動作を開始させます。
def update(self):
if pyxel.btnp(pyxel.KEY_S):
self.game_start = True
if pyxel.btnp(pyxel.KEY_Q):
pyxel.quit()
#Player controll
self.Player_ctr()
update関数です。ここで変数の更新などを行い、draw関数で描画させます。
Sを押すとゲームがスタートし、Qを押すと終了します。プレイヤーに関する更新作業はPlayer_ctr関数を後で作り、そこで行わせます。
def draw(self):
pyxel.cls(0)
#Draw tilemap
pyxel.bltm(0,0,0,0 + self.map_x,0 + self.map_y,16,16)
#Draw player
if self.Player.player_m == 0: #Player situation is right
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,0,0+self.Player.player_m2*8,8,8,14)
elif self.Player.player_m == 1: #Player situation is left
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,8,0+self.Player.player_m2*8,8,8,14)
elif self.Player.player_m == 2: #Player situation is up
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,16,0+self.Player.player_m2*8,8,8,14)
elif self.Player.player_m == 3: #Player situation is down
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,24,0+self.Player.player_m2*8,8,8,14)
#Draw title text
if self.game_start == False:
pyxel.cls(0)
pyxel.text(35, 40, "PYXEL KNIGHTS", 7)
pyxel.text(45, 70, "S = START ", 7)
pyxel.text(45, 80, "Q = QUIT ", 7)
draw関数です。タイルマップとプレイヤーの描画、ゲームがスタートしていない場合はタイトル画面の描画を行います。描画順は上からなので、タイトルマップの描画が行われる場合は、最終的に上書きされる形です。
プレイヤーはplayer_mとplayer_m2の値を使って、簡単なアニメーションのようにしています。player_mが上下左右の方向、player_m2が移動動作を表現するための値です。
def Player_ctr(self):
#Get map coordinate
map_x = 16*(self.map_count_x-1)
map_y = 16*(self.map_count_y-1)
#Get player coordinate
move_map_x = int(self.Player.player_x / 8 + map_x)
move_map_y = int(self.Player.player_y / 8 + map_y)
#Plyer move
self.player_move = self.player_move + 1
if self.player_move > 6:
if pyxel.tilemap(0).get(move_map_x, move_map_y-1) < 32:
#Up
if pyxel.btnp(pyxel.KEY_UP):
self.Player.player_y = self.Player.player_y - 8
self.player_move = 0
self.Player.player_m = 2
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
if (self.Player.player_y - 8) < 0: #When map change
self.map_y = self.map_y - 16
self.Player.update(56, 120)
self.map_count_y = self.map_count_y - 1
self.map_move = 1
if pyxel.tilemap(0).get(move_map_x, move_map_y+1) < 32:
#Down
if pyxel.btnp(pyxel.KEY_DOWN):
self.Player.player_y = self.Player.player_y + 8
self.player_move = 0
self.Player.player_m = 3
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
if (self.Player.player_y + 8) > 128: #When map change
self.map_y = self.map_y + 16
self.Player.update(56, 8)
self.map_count_y = self.map_count_y + 1
self.map_move = 1
if pyxel.tilemap(0).get(move_map_x+1, move_map_y) < 32:
#Right
if pyxel.btnp(pyxel.KEY_RIGHT):
self.Player.player_x = self.Player.player_x + 8
self.player_move = 0
self.Player.player_m = 0
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
if (self.Player.player_x + 8) > 128: #When map change
self.map_x = self.map_x + 16
self.Player.update(8, 56)
self.map_count_x = self.map_count_x + 1
self.map_move = 1
if pyxel.tilemap(0).get(move_map_x-1, move_map_y) < 32:
#Left
if pyxel.btnp(pyxel.KEY_LEFT):
self.Player.player_x = self.Player.player_x - 8
self.player_move = 0
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
self.Player.player_m = 1
if (self.Player.player_x - 8) < 0: #When map change
self.map_x = self.map_x - 16
self.Player.update(120, 56)
self.map_count_x = self.map_count_x - 1
self.map_move = 1
Player_ctr関数です。細かくばらしながら書いていきます。
#Get map coordinate
x = 16*(self.map_count_x-1)
y = 16*(self.map_count_y-1)
#Get player coordinate
move_map_x = int(self.Player.player_x / 8 + x)
move_map_y = int(self.Player.player_y / 8 + y)
まず、マップとプレイヤーの座標を取得します。
マップは開始地点を左端としてx、yで何枚目のミニマップかを考えます。今回は、右にマップを移動するとx+1、下にマップを移動するとy+1としています(左と上は逆に-1です)。そのため例えばスタートのミニマップから右に2、下に1移動したミニマップは(2.1)の座標になります。この値がそれぞれmap_count_xとmap_count_yに入っています。スタートを(0.0)にしたいので-1
して、タイルマップの一辺が16なので*16したものがxとyの値です。
プレイヤーの座標はタイルマップの1マスが8*8なので、自身の座標を8で割ったものが基本的には自分がいるマス目になります。これに自分がどのマップにいるのかを加えることでプレイヤーの座標を取得しています。
例えばプレイヤーの初期値である(8.56)はマス目にすると(1.8)となります。右に一枚マップが進むと(24.56)となり、そこから下に1枚進むと(24.72)になります。
#Plyer move
self.player_move = self.player_move + 1
if self.player_move > 6:
プレイヤーが際限なく動けてもつまらないので、硬直を設けます。player_moveを硬直用の変数として6フレームの硬直を持たせます。
if pyxel.tilemap(0).get(move_map_x, move_map_y-1) < 32:
#Up
if pyxel.btnp(pyxel.KEY_UP):
self.Player.player_y = self.Player.player_y - 8
self.player_move = 0
self.Player.player_m = 2
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
if (self.Player.player_y - 8) < 0: #When map change
self.map_y = self.map_y - 16
self.Player.update(56, 120)
self.map_count_y = self.map_count_y - 1
self.map_move = 1
各キーき合わせた動きは基本的に同じなので上の場合で書いていきます。
pyxel.tilemap(0).get(move_map_x, move_map_y-1) < 32: で移動先が移動可能なマス目かを判定していきます。各タイルにはどのドット絵があるかが情報としてもたれています。イメージバンクの1行目が0から、2行目が32から始まっているので、getで情報を取得して1行目だったら移動可能と判定します。その後に各方向に8移動し、player_mの値を変更します。player_m2の値はいちます動くごとに0と1との交互にして、歩くアニメを作ってみます。
最後に移動先の座標がマップ外かを判定して、マップ外の場合はマップ移動の動作に移行します。
class Player:
def __init__(self, x, y):
self.player_x = x
self.player_y = y
self.player_h = 100
self.player_d = 0
self.player_m = 0
self.player_m2 = 0
def update(self, x, y):
self.player_x = x
self.player_y = y
App()
Playerのクラスを書いて、App()で動作させれば終了です。つなげたソースが以下のものです。
# -*- coding: utf-8 -*-
import pyxel
class App:
def __init__(self):
#Player status
self.Player = Player(8, 56)
self.player_move = 0
self.atc_flug = False
self.atc_count = 0
self.p_atc_x = 0
self.p_atc_y = 0
#Map status
self.stage_flug = 1
self.map_count_x = 1
self.map_count_y = 1
self.game_start = False
self.map_x = 0
self.map_y = 0
self.map_move = 0
pyxel.init(128,128)
#Image read
pyxel.load('C:/pyxel/image/pknights.pyxres')
pyxel.run(self.update, self.draw)
def update(self):
if pyxel.btnp(pyxel.KEY_S):
self.game_start = True
if pyxel.btnp(pyxel.KEY_Q):
pyxel.quit()
#Player controll
self.Player_ctr()
def draw(self):
pyxel.cls(0)
#Draw tilemap
pyxel.bltm(0,0,0,0 + self.map_x,0 + self.map_y,16,16)
#Draw player
if self.Player.player_m == 0: #Player situation is right
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,0,0+self.Player.player_m2*8,8,8,14)
elif self.Player.player_m == 1: #Player situation is left
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,8,0+self.Player.player_m2*8,8,8,14)
elif self.Player.player_m == 2: #Player situation is up
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,16,0+self.Player.player_m2*8,8,8,14)
elif self.Player.player_m == 3: #Player situation is down
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,24,0+self.Player.player_m2*8,8,8,14)
#Draw title text
if self.game_start == False:
pyxel.cls(0)
pyxel.text(35, 40, "PYXEL KNIGHTS", 7)
pyxel.text(45, 70, "S = START ", 7)
pyxel.text(45, 80, "Q = QUIT ", 7)
def Player_ctr(self):
#Get map coordinate
x = 16*(self.map_count_x-1)
y = 16*(self.map_count_y-1)
#Get player coordinate
move_map_x = int(self.Player.player_x / 8 + x)
move_map_y = int(self.Player.player_y / 8 + y)
#Plyer move
self.player_move = self.player_move + 1
if self.player_move > 6:
if pyxel.tilemap(0).get(move_map_x, move_map_y-1) < 32:
#Up
if pyxel.btnp(pyxel.KEY_UP):
self.Player.player_y = self.Player.player_y - 8
self.player_move = 0
self.Player.player_m = 2
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
if (self.Player.player_y - 8) < 0: #When map change
self.map_y = self.map_y - 16
self.Player.update(56, 120)
self.map_count_y = self.map_count_y - 1
self.map_move = 1
if pyxel.tilemap(0).get(move_map_x, move_map_y+1) < 32:
#Down
if pyxel.btnp(pyxel.KEY_DOWN):
self.Player.player_y = self.Player.player_y + 8
self.player_move = 0
self.Player.player_m = 3
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
if (self.Player.player_y + 8) > 128: #When map change
self.map_y = self.map_y + 16
self.Player.update(56, 8)
self.map_count_y = self.map_count_y + 1
self.map_move = 1
if pyxel.tilemap(0).get(move_map_x+1, move_map_y) < 32:
#Right
if pyxel.btnp(pyxel.KEY_RIGHT):
self.Player.player_x = self.Player.player_x + 8
self.player_move = 0
self.Player.player_m = 0
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
if (self.Player.player_x + 8) > 128: #When map change
self.map_x = self.map_x + 16
self.Player.update(8, 56)
self.map_count_x = self.map_count_x + 1
self.map_move = 1
if pyxel.tilemap(0).get(move_map_x-1, move_map_y) < 32:
#Left
if pyxel.btnp(pyxel.KEY_LEFT):
self.Player.player_x = self.Player.player_x - 8
self.player_move = 0
if self.Player.player_m2 == 0: #Move animation
self.Player.player_m2 = 1
else:
self.Player.player_m2 = 0
self.Player.player_m = 1
if (self.Player.player_x - 8) < 0: #When map change
self.map_x = self.map_x - 16
self.Player.update(120, 56)
self.map_count_x = self.map_count_x - 1
self.map_move = 1
class Player:
def __init__(self, x, y):
self.player_x = x
self.player_y = y
self.player_h = 100
self.player_d = 0
self.player_m = 0
self.player_m2 = 0
def update(self, x, y):
self.player_x = x
self.player_y = y
App()
とりあえずマップの移動は出来たので、次は敵の追加や攻撃処理を足していこうと思います。
今回使ったイメージソースファイルです。色々汚いですがよろしければご利用ください。↓
ここまで読んでいただきありがとうございます!