pyxelでRPG風のものを作る(6)
今回は新要素が盛りだくさんなので、前置きは短めにさっさとコードを書いていこうと思います。実現する要素としては「敵をエリアごとに配置」、「NPC(町の住人)の配置」、「ひらがなを描画」の3点です。加えて細かな調整もしていきます。前回までの進行具合は以下の記事をご参照ください。
# -*- coding: utf-8 -*-
import pyxel
class App:
def __init__(self):
#Font set
self.font_list = {
"a":[0,0],
"A":[8,0],
"i":[16,0],
"I":[24,0],
"u":[32,0],
"U":[40,0],
"e":[48,0],
"E":[56,0],
"o":[64,0],
"O":[72,0],
"KA":[80,0],
"GA":[88,0],
"KI":[96,0],
"GI":[104,0],
"KU":[112,0],
"GU":[120,0],
"KE":[128,0],
"GE":[136,0],
"KO":[144,0],
"GO":[152,0],
"SA":[160,0],
"ZA":[168,0],
"SI":[176,0],
"JI":[184,0],
"SU":[192,0],
"ZU":[200,0],
"SE":[208,0],
"ZE":[216,0],
"SO":[224,0],
"ZO":[232,0],
"TA":[240,0],
"DA":[248,0],
"TI":[0,8],
"DI":[8,8],
"tu":[16,8],
"TU":[24,8],
"DU":[32,8],
"TE":[40,8],
"DE":[48,8],
"TO":[56,8],
"DO":[64,8],
"NA":[72,8],
"NI":[80,8],
"NU":[88,8],
"NE":[96,8],
"NO":[104,8],
"HA":[112,8],
"BA":[120,8],
"PA":[128,8],
"HI":[136,8],
"BI":[144,8],
"PI":[152,8],
"HU":[160,8],
"BU":[168,8],
"PU":[176,8],
"HE":[184,8],
"BE":[192,8],
"PE":[200,8],
"HO":[208,8],
"BO":[216,8],
"PO":[224,8],
"MA":[232,8],
"MI":[240,8],
"MU":[248,8],
"ME":[0,16],
"MO":[8,16],
"ya":[16,16],
"YA":[24,16],
"yu":[32,16],
"YU":[40,16],
"yo":[48,16],
"YO":[56,16],
"RA":[64,16],
"RI":[72,16],
"RU":[80,16],
"RE":[88,16],
"RO":[96,16],
"wa":[104,16],
"WA":[112,16],
"WI":[120,16],
"WE":[128,16],
"WO":[136,16],
"NN":[144,16],
}
#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.map_x = 0
self.map_y = 0
self.map_move = 0
#NPC status
self.npcs = []
self.npc_move = 0
self.npc_pos_x = {
"0-0":[],
"1-0":[],
"2-0":[],
"3-0":[],
"4-0":[],
"5-0":[13],
"6-0":[12,12],
"7-0":[107,208],
"8-0":[],
"9-0":[],
"10-0":[],
"0-1":[],
"1-1":[],
"2-1":[],
"3-1":[],
"4-1":[],
"5-1":[],
"6-1":[],
"7-1":[],
"8-1":[7],
"9-1":[],
"10-1":[],
"0-2":[],
"1-2":[],
"2-2":[],
"3-2":[],
"4-2":[],
"5-2":[],
"6-2":[],
"7-2":[],
"8-2":[13],
"9-2":[],
"10-2":[],
}
self.npc_pos_y = {
"0-0":[],
"1-0":[],
"2-0":[],
"3-0":[],
"4-0":[],
"5-0":[9],
"6-0":[4,10],
"7-0":[107,212],
"8-0":[],
"9-0":[],
"10-0":[],
"0-1":[],
"1-1":[],
"2-1":[],
"3-1":[],
"4-1":[],
"5-1":[],
"6-1":[],
"7-1":[],
"8-1":[5],
"9-1":[],
"10-1":[],
"0-2":[],
"1-2":[],
"2-2":[],
"3-2":[],
"4-2":[],
"5-2":[],
"6-2":[],
"7-2":[],
"8-2":[7],
"9-2":[],
"10-2":[],
}
#Enemy status
self.enemys = []
self.enemy_move = 0
self.enemy_pos_x = {
"0-0":[],
"1-0":[5,13],
"2-0":[9,12,13],
"3-0":[10,12,8],
"4-0":[6,8,9,12],
"5-0":[],
"6-0":[],
"7-0":[],
"8-0":[],
"9-0":[],
"10-0":[],
"0-1":[5,6,8],
"1-1":[5,5,11,11,7,8],
"2-1":[2,3,2,3,4],
"3-1":[],
"4-1":[],
"5-1":[],
"6-1":[],
"7-1":[],
"8-1":[],
"9-1":[],
"10-1":[],
"0-2":[6,8,9,12],
"1-2":[7,8,7,8,4,5,11,12],
"2-2":[],
"3-2":[7,8,9,10,11,11,12],
"4-2":[],
"5-2":[],
"6-2":[],
"7-2":[],
"8-2":[],
"9-2":[],
"10-2":[],
}
self.enemy_pos_y = {
"0-0":[],
"1-0":[5,7],
"2-0":[7,8,2],
"3-0":[7,8,11],
"4-0":[7,8,7,8],
"5-0":[],
"6-0":[],
"7-0":[],
"8-0":[],
"9-0":[],
"10-0":[],
"0-1":[5,10,10],
"1-1":[5,10,5,10,8,7],
"2-1":[7,8,9,10,11],
"3-1":[],
"4-1":[],
"5-1":[],
"6-1":[],
"7-1":[],
"8-1":[],
"9-1":[],
"10-1":[],
"0-2":[7,11,7,8],
"1-2":[6,6,9,9,7,8,7,8],
"2-2":[],
"3-2":[10,10,10,10,10,5,5,],
"4-2":[],
"5-2":[],
"6-2":[],
"7-2":[],
"8-2":[],
"9-2":[],
"10-2":[],
}
#System status
self.game_start = False
self.game_over = False
pyxel.init(128,128)
#Image read
pyxel.load('assets/pknights.pyxres')
pyxel.run(self.update, self.draw)
init部分にごちゃごちゃと追加していますが、ここの部分の変数を使って敵の配置とひらがな文字の出力を実装していきます。
self.font_listはひらがな文字用の辞書型変数で、各keyに対してイメージバンク上のxy座標が対応付けられています。そして各keyはひらがな文字を表しています。例えば「か」はkeyとしては"KA"で座標は[80,0]です。力技ではありますが、このように五十音すべてにkeyと座標を作っていきます。
self.npc_pos_xとself.npc_pos_yはNPC用の辞書型変数で、敵の座標を表すself.enemy_pos_xとself.enemy_pos_yも同様の仕組みになっています。keyにミニマップの座標を持ち、各keyごとにNPC(敵)の配置が対応しています。例えばself.enemy_pos_xのkey"2-0"の内容は[9,12,13]です。これはスタート地点から右に2枚、下に0枚の位置のミニマップには敵が3体いて、x座標は[9,12,13]であることを示しています。同様にself.enemy_pos_yのkey"2-0"は[7,8,2]です。合わせるとミニマップ"2-0"には[9,7]、[12,8]、[13,2]の座標に敵がいることとなります。
あとは細かな修正になりますが.pyxresファイルを読み込む際のパスを絶対パスから相対パスに変更しました。実行する.pyファイルと同じ階層にassetsフォルダを作り、その中に.pyxresファイルを入れることにします。
def update(self):
if pyxel.btnp(pyxel.KEY_S):
self.game_start = True
if pyxel.btnp(pyxel.KEY_R):
self.Retry()
if pyxel.btnp(pyxel.KEY_Q):
pyxel.quit()
#Player attack
if pyxel.btnp(pyxel.KEY_SPACE):
self.atc_flug = True
#Player controll
self.Player_ctr()
#NPC controll
self.NPC_ctr()
#Enemy controll
self.Enemy_ctr()
#Enemy Hit-check
self.Hit_chk()
#Player Damage-check
self.Dmg_chk()
#Enemy & NPC creation
if self.map_move == 1:
self.npcs.clear()
self.enemys.clear()
tgt_map_x = int(self.map_x / 16)
tgt_map_y = int(self.map_y / 16)
xy_key = str(tgt_map_x) + "-" + str(tgt_map_y)
#Enemy creation
enemy_x_1 = self.enemy_pos_x[xy_key]
enemy_y_1 = self.enemy_pos_y[xy_key]
enemy_kazu = len(enemy_x_1)
for i in range(enemy_kazu):
new_enemy = Enemy1(enemy_x_1[i]*8, enemy_y_1[i]*8)
self.enemys.append(new_enemy)
#NPC creation
npc_x_1 = self.npc_pos_x[xy_key]
npc_y_1 = self.npc_pos_y[xy_key]
npc_kazu = len(npc_x_1)
for i in range(npc_kazu):
if npc_x_1[i] < 101:
new_npc_b = 16
new_npc_x = npc_x_1[i]
elif npc_x_1[i] < 201:
new_npc_b = 8
new_npc_x = npc_x_1[i] - 100
else:
new_npc_b = 8
new_npc_x = npc_x_1[i] - 200
if npc_y_1[i] < 101:
new_npc_v = 0
new_npc_y = npc_y_1[i]
elif npc_y_1[i] < 201:
new_npc_v = 16
new_npc_y = npc_y_1[i] - 100
else:
new_npc_v = 32
new_npc_y = npc_y_1[i] - 200
new_npc = NPC(new_npc_x*8, new_npc_y*8, new_npc_b, new_npc_v)
self.npcs.append(new_npc)
self.map_move = 0
update関数にNPCと敵を作成する処理を追加します。
if self.map_move == 1:でマップ移動を判定し、マップ移動の際にはself.npcs.clear()、self.enemys.clear()でNPCと敵をリセットします。
その後、tgt_map_x = int(self.map_x / 16)とenemy_y_1 = self.enemy_pos_y[xy_key]でミニマップの座標を取得します。これを str(tgt_map_x) + "-" + str(tgt_map_y)で成型することで、”x-y”の形にしてxy_keyに代入します。
xy_keyの取得出来たら実際にNPCと敵を作成する処理に入ります。まずは敵から作っていきます。self.enemy_pos_x[xy_key]とself.enemy_pos_yからxy_keyを使って敵のx座標とy座標の配列を取り出し、enemy_x_1、enemy_y_1に代入します。len(enemy_x_1)で取得した配列の個数だけforで処理を回して敵を作成します。
NPCの場合も基本的には同じですが、NPCは見た目の種類を変えたいので座標の指定に追加の条件を加えています。npc_x_1[i]の値によってnew_npc_bを、npc_y_1[i]の値によってnew_npc_vを変化させます。new_npc_bは該当のNPCの大きさ(8*8や16*16)を表し、new_npc_vはイメージバンクの座標を示すことでNPCの種類を変えています。
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.atc_flug == True:
if self.Player.player_m == 0:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,0,16,8,8,14)
pyxel.blt(self.Player.player_x+8,self.Player.player_y,
0,0,24,8,8,14)
elif self.Player.player_m == 1:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,8,16,8,8,14)
pyxel.blt(self.Player.player_x-8,self.Player.player_y,
0,8,24,8,8,14)
elif self.Player.player_m == 2:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,16,16,8,8,14)
pyxel.blt(self.Player.player_x,self.Player.player_y-8,
0,16,24,8,8,14)
elif self.Player.player_m == 3:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,24,16,8,8,14)
pyxel.blt(self.Player.player_x,self.Player.player_y+8,
0,24,24,8,8,14)
else:
if self.Player.player_m == 0:
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:
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:
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:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,24,0+self.Player.player_m2*8,8,8,14)
#Draw NPCs
npc_count = len(self.npcs)
for e in range(npc_count):
if self.npc_move < 50:
pyxel.blt(self.npcs[e].npc_x,self.npcs[e].npc_y,
0,
0 + self.npcs[e].npc_v, 224,
self.npcs[e].npc_b,self.npcs[e].npc_b,14)
else:
pyxel.blt(self.npcs[e].npc_x,self.npcs[e].npc_y,
0,
0 + self.npcs[e].npc_v,240,
self.npcs[e].npc_b,self.npcs[e].npc_b,14)
#Draw Enemys
enemy_count = len(self.enemys)
for e in range(enemy_count):
if self.enemys[e].enemy_m == 0:
pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
1,
8,32,
8,8,14)
else:
pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
1,
8,40,
8,8,14)
if self.enemys[e].enemy_d == 1:
pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
0,40,16,8,8,14)
#Draw damage
if self.Player.player_d == 1:
pyxel.blt(self.Player.player_x,self.Player.player_y,0,32,16,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 = ", 7)
self.Draw_fonts(["HA","JI","ME","RU"], 60, 70)
pyxel.text(45, 85, "Q = ", 7)
self.Draw_fonts(["YA","ME","RU"], 60, 85)
else: #Draw player hp
pyxel.text(2, 122, "HP="+ str(self.Player.player_h),7)
#Draw gameover text
if self.game_over == True:
pyxel.cls(0)
pyxel.text(20, 30, "GAME OVER!", 7)
pyxel.text(80, 70, "R = RETRY ", 7)
pyxel.text(80, 80, "Q = QUIT ", 7)
Draw部分では新規にNPCの描画が追加されていますが、特に特殊なことはしていません。self.npc_moveの値によって描画を変えて待機アニメーションっぽくしてみます。self.npc_moveは後で作成するNPC_ctr関数で制御します。
また、タイトル画面にひらがなを表示するようにしてみました。新規作成したDraw_fonts関数を呼び出して描画します。
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)
#Tilemap action
#HP recovery
if pyxel.tilemap(0).get(move_map_x, move_map_y) == 31:
self.Player.player_h = 100
#Plyer move
self.player_move = self.player_move + 1
if (self.player_move > 6) and (self.atc_flug == False):
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) < -8: #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, 0)
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(0, 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) < -8: #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
#Attack action
if self.atc_flug == True:
self.atc_count = self.atc_count + 1
if self.atc_count > 8:
self.atc_count = 0
self.p_atc_x = 0
self.p_atc_y = 0
self.atc_flug = False
else:
if self.Player.player_m == 0:
self.p_atc_x = self.Player.player_x + 8
self.p_atc_y = self.Player.player_y
elif self.Player.player_m == 1:
self.p_atc_x = self.Player.player_x - 8
self.p_atc_y = self.Player.player_y
elif self.Player.player_m == 2:
self.p_atc_x = self.Player.player_x
self.p_atc_y = self.Player.player_y - 8
elif self.Player.player_m == 3:
self.p_atc_x = self.Player.player_x
self.p_atc_y = self.Player.player_y + 8
Player_ctr関数には少し手を加えて、攻撃中にプレイヤーが移動できないようにしました。プレイヤーの移動可否の条件文にself.atc_flug == Falseの条件を追加しています。
def NPC_ctr(self):
self.npc_move = self.npc_move + 1
if self.npc_move > 100:
self.npc_move = 0
新規作成したNPC_ctr関数です。といってもself.npc_moveをカウントアップしているだけです。self.npc_move > 100にはself.npc_moveを0に戻します。
def Draw_fonts(self,txt,x,y):
txt_count = len(txt)
for i in range(txt_count):
#Key check
font_xy = self.font_list[txt[i]]
fontx = font_xy[0]
fonty = font_xy[1]
pyxel.blt(x + 8 * i,y,1,fontx,fonty,8,8,14)
新規作成したDraw_fonts関数です。引数として、描画文字列が入るtxtと描画位置を示すx、yがあります。len(txt)で何文字描画するかを取得し、txt_countに入れます。その後forで処理を回して文字を描画していきます。font_xy = self.font_list[txt[i]]で文字判別用のkeyをfont_xyに代入し、font_xy[0]で文字のx座標、font_xy[1]で文字のy座標を取得します。その後pyxel.blt(x + 8 * i,y,1,fontx,fonty,8,8,14)で描画しますが、文字は8*8なので描画位置をx + 8 * iの形にして重なりを防ぎます。関数の呼び出し方はself.Draw_fonts(["HA","JI","ME","RU"], 60, 70)のようにします。この例では[60,70]の位置に"はじめる"と描画されます。
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
class NPC:
def __init__(self, x, y, b, v):
self.npc_x = x
self.npc_y = y
self.npc_b = b
self.npc_v = v
self.npc_m = 0
def update(self, x, y):
self.npc_x = x
self.npc_y = y
class Enemy1:
def __init__(self, x, y):
self.enemy_x = x
self.enemy_y = y
self.enemy_h = 15
self.enemy_d = 0
self.enemy_m = 0
def update(self, x, y):
self.enemy_x = x
self.enemy_y = y
App()
最後にクラス部分です。新規に作成したのはclass NPCです。NPC部分はあまりまだ有効活用できていない感があるので、今後いろいろと追加していこうと思います。
全てつなげたソースは以下の通りです。
# -*- coding: utf-8 -*-
import pyxel
class App:
def __init__(self):
#Font set
self.font_list = {
"a":[0,0],
"A":[8,0],
"i":[16,0],
"I":[24,0],
"u":[32,0],
"U":[40,0],
"e":[48,0],
"E":[56,0],
"o":[64,0],
"O":[72,0],
"KA":[80,0],
"GA":[88,0],
"KI":[96,0],
"GI":[104,0],
"KU":[112,0],
"GU":[120,0],
"KE":[128,0],
"GE":[136,0],
"KO":[144,0],
"GO":[152,0],
"SA":[160,0],
"ZA":[168,0],
"SI":[176,0],
"JI":[184,0],
"SU":[192,0],
"ZU":[200,0],
"SE":[208,0],
"ZE":[216,0],
"SO":[224,0],
"ZO":[232,0],
"TA":[240,0],
"DA":[248,0],
"TI":[0,8],
"DI":[8,8],
"tu":[16,8],
"TU":[24,8],
"DU":[32,8],
"TE":[40,8],
"DE":[48,8],
"TO":[56,8],
"DO":[64,8],
"NA":[72,8],
"NI":[80,8],
"NU":[88,8],
"NE":[96,8],
"NO":[104,8],
"HA":[112,8],
"BA":[120,8],
"PA":[128,8],
"HI":[136,8],
"BI":[144,8],
"PI":[152,8],
"HU":[160,8],
"BU":[168,8],
"PU":[176,8],
"HE":[184,8],
"BE":[192,8],
"PE":[200,8],
"HO":[208,8],
"BO":[216,8],
"PO":[224,8],
"MA":[232,8],
"MI":[240,8],
"MU":[248,8],
"ME":[0,16],
"MO":[8,16],
"ya":[16,16],
"YA":[24,16],
"yu":[32,16],
"YU":[40,16],
"yo":[48,16],
"YO":[56,16],
"RA":[64,16],
"RI":[72,16],
"RU":[80,16],
"RE":[88,16],
"RO":[96,16],
"wa":[104,16],
"WA":[112,16],
"WI":[120,16],
"WE":[128,16],
"WO":[136,16],
"NN":[144,16],
}
#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.map_x = 0
self.map_y = 0
self.map_move = 0
#NPC status
self.npcs = []
self.npc_move = 0
self.npc_pos_x = {
"0-0":[],
"1-0":[],
"2-0":[],
"3-0":[],
"4-0":[],
"5-0":[13],
"6-0":[12,12],
"7-0":[107,208],
"8-0":[],
"9-0":[],
"10-0":[],
"0-1":[],
"1-1":[],
"2-1":[],
"3-1":[],
"4-1":[],
"5-1":[],
"6-1":[],
"7-1":[],
"8-1":[7],
"9-1":[],
"10-1":[],
"0-2":[],
"1-2":[],
"2-2":[],
"3-2":[],
"4-2":[],
"5-2":[],
"6-2":[],
"7-2":[],
"8-2":[13],
"9-2":[],
"10-2":[],
}
self.npc_pos_y = {
"0-0":[],
"1-0":[],
"2-0":[],
"3-0":[],
"4-0":[],
"5-0":[9],
"6-0":[4,10],
"7-0":[107,212],
"8-0":[],
"9-0":[],
"10-0":[],
"0-1":[],
"1-1":[],
"2-1":[],
"3-1":[],
"4-1":[],
"5-1":[],
"6-1":[],
"7-1":[],
"8-1":[5],
"9-1":[],
"10-1":[],
"0-2":[],
"1-2":[],
"2-2":[],
"3-2":[],
"4-2":[],
"5-2":[],
"6-2":[],
"7-2":[],
"8-2":[7],
"9-2":[],
"10-2":[],
}
#Enemy status
self.enemys = []
self.enemy_move = 0
self.enemy_pos_x = {
"0-0":[],
"1-0":[5,13],
"2-0":[9,12,13],
"3-0":[10,12,8],
"4-0":[6,8,9,12],
"5-0":[],
"6-0":[],
"7-0":[],
"8-0":[],
"9-0":[],
"10-0":[],
"0-1":[5,6,8],
"1-1":[5,5,11,11,7,8],
"2-1":[2,3,2,3,4],
"3-1":[],
"4-1":[],
"5-1":[],
"6-1":[],
"7-1":[],
"8-1":[],
"9-1":[],
"10-1":[],
"0-2":[6,8,9,12],
"1-2":[7,8,7,8,4,5,11,12],
"2-2":[],
"3-2":[7,8,9,10,11,11,12],
"4-2":[],
"5-2":[],
"6-2":[],
"7-2":[],
"8-2":[],
"9-2":[],
"10-2":[],
}
self.enemy_pos_y = {
"0-0":[],
"1-0":[5,7],
"2-0":[7,8,2],
"3-0":[7,8,11],
"4-0":[7,8,7,8],
"5-0":[],
"6-0":[],
"7-0":[],
"8-0":[],
"9-0":[],
"10-0":[],
"0-1":[5,10,10],
"1-1":[5,10,5,10,8,7],
"2-1":[7,8,9,10,11],
"3-1":[],
"4-1":[],
"5-1":[],
"6-1":[],
"7-1":[],
"8-1":[],
"9-1":[],
"10-1":[],
"0-2":[7,11,7,8],
"1-2":[6,6,9,9,7,8,7,8],
"2-2":[],
"3-2":[10,10,10,10,10,5,5,],
"4-2":[],
"5-2":[],
"6-2":[],
"7-2":[],
"8-2":[],
"9-2":[],
"10-2":[],
}
#System status
self.game_start = False
self.game_over = False
pyxel.init(128,128)
#Image read
pyxel.load('assets/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_R):
self.Retry()
if pyxel.btnp(pyxel.KEY_Q):
pyxel.quit()
#Player attack
if pyxel.btnp(pyxel.KEY_SPACE):
self.atc_flug = True
#Player controll
self.Player_ctr()
#NPC controll
self.NPC_ctr()
#Enemy controll
self.Enemy_ctr()
#Enemy Hit-check
self.Hit_chk()
#Player Damage-check
self.Dmg_chk()
#Enemy & NPC creation
if self.map_move == 1:
self.npcs.clear()
self.enemys.clear()
tgt_map_x = int(self.map_x / 16)
tgt_map_y = int(self.map_y / 16)
xy_key = str(tgt_map_x) + "-" + str(tgt_map_y)
#Enemy creation
enemy_x_1 = self.enemy_pos_x[xy_key]
enemy_y_1 = self.enemy_pos_y[xy_key]
enemy_kazu = len(enemy_x_1)
for i in range(enemy_kazu):
new_enemy = Enemy1(enemy_x_1[i]*8, enemy_y_1[i]*8)
self.enemys.append(new_enemy)
#NPC creation
npc_x_1 = self.npc_pos_x[xy_key]
npc_y_1 = self.npc_pos_y[xy_key]
npc_kazu = len(npc_x_1)
for i in range(npc_kazu):
if npc_x_1[i] < 101:
new_npc_b = 16
new_npc_x = npc_x_1[i]
elif npc_x_1[i] < 201:
new_npc_b = 8
new_npc_x = npc_x_1[i] - 100
else:
new_npc_b = 8
new_npc_x = npc_x_1[i] - 200
if npc_y_1[i] < 101:
new_npc_v = 0
new_npc_y = npc_y_1[i]
elif npc_y_1[i] < 201:
new_npc_v = 16
new_npc_y = npc_y_1[i] - 100
else:
new_npc_v = 32
new_npc_y = npc_y_1[i] - 200
new_npc = NPC(new_npc_x*8, new_npc_y*8, new_npc_b, new_npc_v)
self.npcs.append(new_npc)
self.map_move = 0
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.atc_flug == True:
if self.Player.player_m == 0:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,0,16,8,8,14)
pyxel.blt(self.Player.player_x+8,self.Player.player_y,
0,0,24,8,8,14)
elif self.Player.player_m == 1:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,8,16,8,8,14)
pyxel.blt(self.Player.player_x-8,self.Player.player_y,
0,8,24,8,8,14)
elif self.Player.player_m == 2:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,16,16,8,8,14)
pyxel.blt(self.Player.player_x,self.Player.player_y-8,
0,16,24,8,8,14)
elif self.Player.player_m == 3:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,24,16,8,8,14)
pyxel.blt(self.Player.player_x,self.Player.player_y+8,
0,24,24,8,8,14)
else:
if self.Player.player_m == 0:
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:
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:
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:
pyxel.blt(self.Player.player_x,self.Player.player_y,
0,24,0+self.Player.player_m2*8,8,8,14)
#Draw NPCs
npc_count = len(self.npcs)
for e in range(npc_count):
if self.npc_move < 50:
pyxel.blt(self.npcs[e].npc_x,self.npcs[e].npc_y,
0,
0 + self.npcs[e].npc_v, 224,
self.npcs[e].npc_b,self.npcs[e].npc_b,14)
else:
pyxel.blt(self.npcs[e].npc_x,self.npcs[e].npc_y,
0,
0 + self.npcs[e].npc_v,240,
self.npcs[e].npc_b,self.npcs[e].npc_b,14)
#Draw Enemys
enemy_count = len(self.enemys)
for e in range(enemy_count):
if self.enemys[e].enemy_m == 0:
pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
1,
8,32,
8,8,14)
else:
pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
1,
8,40,
8,8,14)
if self.enemys[e].enemy_d == 1:
pyxel.blt(self.enemys[e].enemy_x,self.enemys[e].enemy_y,
0,40,16,8,8,14)
#Draw damage
if self.Player.player_d == 1:
pyxel.blt(self.Player.player_x,self.Player.player_y,0,32,16,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 = ", 7)
self.Draw_fonts(["HA","JI","ME","RU"], 60, 70)
pyxel.text(45, 85, "Q = ", 7)
self.Draw_fonts(["YA","ME","RU"], 60, 85)
else: #Draw player hp
pyxel.text(2, 122, "HP="+ str(self.Player.player_h),7)
#Draw gameover text
if self.game_over == True:
pyxel.cls(0)
pyxel.text(20, 30, "GAME OVER!", 7)
pyxel.text(80, 70, "R = RETRY ", 7)
pyxel.text(80, 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)
#Tilemap action
#HP recovery
if pyxel.tilemap(0).get(move_map_x, move_map_y) == 31:
self.Player.player_h = 100
#Plyer move
self.player_move = self.player_move + 1
if (self.player_move > 6) and (self.atc_flug == False):
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) < -8: #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, 0)
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(0, 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) < -8: #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
#Attack action
if self.atc_flug == True:
self.atc_count = self.atc_count + 1
if self.atc_count > 8:
self.atc_count = 0
self.p_atc_x = 0
self.p_atc_y = 0
self.atc_flug = False
else:
if self.Player.player_m == 0:
self.p_atc_x = self.Player.player_x + 8
self.p_atc_y = self.Player.player_y
elif self.Player.player_m == 1:
self.p_atc_x = self.Player.player_x - 8
self.p_atc_y = self.Player.player_y
elif self.Player.player_m == 2:
self.p_atc_x = self.Player.player_x
self.p_atc_y = self.Player.player_y - 8
elif self.Player.player_m == 3:
self.p_atc_x = self.Player.player_x
self.p_atc_y = self.Player.player_y + 8
def Retry(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.map_x = 0
self.map_y = 0
self.map_move = 0
#Enemy status
self.enemys = []
self.enemy_move = 0
#System status
self.game_start = False
self.game_over = False
def Hit_chk(self):
enemy_count = len(self.enemys)
for e in range(enemy_count):
self.enemys[e].enemy_d = 0
enemy_pos_x = self.enemys[e].enemy_x
enemy_pos_y = self.enemys[e].enemy_y
if ((enemy_pos_x <= self.p_atc_x < enemy_pos_x + 8) and
(enemy_pos_y <= self.p_atc_y < enemy_pos_y + 8)):
self.enemys[e].enemy_d = 1
self.enemys[e].enemy_h = self.enemys[e].enemy_h -1
#Enemy delete
if self.enemys[e].enemy_h < 0:
del self.enemys[e]
break
def Dmg_chk(self):
self.Player.player_d = 0
enemy_count = len(self.enemys)
player_pos_x = self.Player.player_x
player_pos_y = self.Player.player_y
for e in range(enemy_count):
enemy_pos_x = self.enemys[e].enemy_x
enemy_pos_y = self.enemys[e].enemy_y
if ((enemy_pos_x <= player_pos_x < enemy_pos_x + 8) and
(enemy_pos_y <= player_pos_y < enemy_pos_y + 8)):
self.Player.player_h = self.Player.player_h - 1
self.Player.player_d = 1
if self.Player.player_h <= 0:
self.game_over = True
def Enemy_ctr(self):
self.enemy_move = self.enemy_move + 1
enemy_count = len(self.enemys)
if self.enemy_move > 40:
for e in range(enemy_count):
enemy_pos_x = int(self.enemys[e].enemy_x / 8 + self.map_x)
enemy_pos_y = int(self.enemys[e].enemy_y / 8 + self.map_y)
enemy_pos_x2 = self.Player.player_x - self.enemys[e].enemy_x
enemy_pos_y2 = self.Player.player_y - self.enemys[e].enemy_y
#Check tilemap
if (abs(enemy_pos_x2) < 35 and abs(enemy_pos_y2) < 35):
if abs(enemy_pos_x2) > abs(enemy_pos_y2):
#Move right
if enemy_pos_x2 > 0:
if (40> (pyxel.tilemap(0).get(enemy_pos_x+1,
enemy_pos_y)) < 32):
self.enemys[e].enemy_x=self.enemys[e].enemy_x+8
self.enemys[e].enemy_m = 1
#Move left
else:
if (40> (pyxel.tilemap(0).get(enemy_pos_x-1,
enemy_pos_y)) < 32):
self.enemys[e].enemy_x=self.enemys[e].enemy_x-8
self.enemys[e].enemy_m = 0
else:
#Move down
if enemy_pos_y2 > 0:
if (40> (pyxel.tilemap(0).get(enemy_pos_x,
enemy_pos_y+1)) < 32):
self.enemys[e].enemy_y=self.enemys[e].enemy_y+8
#Move up
else:
if (40> (pyxel.tilemap(0).get(enemy_pos_x,
enemy_pos_y-1)) < 32):
self.enemys[e].enemy_y=self.enemys[e].enemy_y-8
self.enemy_move = 0
def NPC_ctr(self):
self.npc_move = self.npc_move + 1
if self.npc_move > 100:
self.npc_move = 0
def Draw_fonts(self,txt,x,y):
txt_count = len(txt)
for i in range(txt_count):
#Key check
font_xy = self.font_list[txt[i]]
fontx = font_xy[0]
fonty = font_xy[1]
pyxel.blt(x + 8 * i,y,1,fontx,fonty,8,8,14)
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
class NPC:
def __init__(self, x, y, b, v):
self.npc_x = x
self.npc_y = y
self.npc_b = b
self.npc_v = v
self.npc_m = 0
def update(self, x, y):
self.npc_x = x
self.npc_y = y
class Enemy1:
def __init__(self, x, y):
self.enemy_x = x
self.enemy_y = y
self.enemy_h = 15
self.enemy_d = 0
self.enemy_m = 0
def update(self, x, y):
self.enemy_x = x
self.enemy_y = y
App()
今回使用したイメージソースは以下のものです。
ここまで読んでいただき、ありがとうございました。
各ミニマップごとに敵の配置を変更できるようになりました。
NPCも配置できるようになりました。(特に会話するわけでもなくその場にいるだけですが・・・。)
ここまで読んでいただきありがとうございます!