pyxelでシミュレーションゲームを作る(5-1)
今回は合戦の仕組みと城郭施設でできることを作ってみます。これでぐっと戦国時代っぽくなるはず。調子に乗って作ってたらごちゃごちゃになってしまいましたが、お付き合いいただけますと幸いです。
まずは前半部分として合戦について書いていきたいと思います。
前回のnoteは以下になります。よろしければご参照ください。
今回は合戦といっても大名相手のものではなく、「ある程度ターンが経過すると山賊が攻めてくる」というものにします。
#Kassen
k1 = int(self.turn * 0.5)
if k1 > 5:
k1 = randint(2, 5)
self.k_cnt = self.k_cnt + k1
k2 = int(self.turn * 50) + randint(5, 30) * randint(2, 10 * self.turn)
if k2 > 50000:
k2 = 50000
self.k_hei = k2
self.k_hei2 = k2
▲ターン経過時のロジックにこのようなものを追加してみました。
まず変数k1は合戦イベントの発生に関係します。基本的にはターン数*0.5となり、k_cntに足しあげられます。このk_cntが一定値を超えた場合に合戦イベントを発生させます。
k2は山賊の兵力に関係します。ここはターン数やランダム値などで計算したものをk_heiに代入します。これが敵の兵力です。
実際に合戦イベントが起きた場合の動きを見ていきます。
#Turn change
elif self.window_ctr == 98:
if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
x = pyxel.mouse_x
y = pyxel.mouse_y
if ((64 < x < 128) and (114 < y < 128)):
if ((self.daimyo1.event_flug == True) and
(self.daimyo2.event_flug == True)):
self.daimyo_flug = randint(1, 2)
self.window_ctr = 101
self.msg_num = randint(1, 3)
elif self.daimyo1.event_flug == True:
self.daimyo_flug = 1
self.window_ctr = 101
self.msg_num = randint(1, 3)
elif self.daimyo2.event_flug == True:
self.daimyo_flug = 2
self.window_ctr = 101
self.msg_num = randint(1, 3)
elif self.k_cnt >= 35:
self.window_ctr = 201
#self.k_cnt = 0
self.enemy_tgt = 9
else:
self.window_ctr = 0
▲ターン経過ロジックの一部です。「elif self.k_cnt >= 35:」から始まる条件文を追加しました。Trueになったらwindow_ctrを201にして合戦ウィンドウに進みます。enemy_tgtは敵の種類です。山賊は9にしてみました(とりあえず)。
#Kassen1
elif self.window_ctr == 201:
if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
x = pyxel.mouse_x
y = pyxel.mouse_y
if ((64 < x < 128) and (114 < y < 128)):
self.window_ctr = 202
▲合戦ウィンドウその1です。ここは誰が攻めてきたかを表示するだけなので単純です。
#Kassen1
elif self.window_ctr == 201:
pyxel.rect(0, 80, 128, 46, 0)
pyxel.rectb(0, 80, 128, 46, 7)
if self.k_cnt < 100:
if self.enemy_tgt == 9:
self.Draw_fonts(self.text_list["120"], 5, 85)
self.Draw_fonts(self.text_list["114"], 85, 85)
self.Draw_fonts(self.text_list["119"], 5, 95)
else:
if self.enemy_tgt == 9:
self.Draw_fonts(self.text_list["120"], 5, 85)
self.Draw_fonts(self.text_list["131"], 85, 85)
self.Draw_fonts(self.text_list["132"], 5, 95)
pyxel.rect(0, 114, 64, 14, 0)
pyxel.rectb(0, 114, 64, 14, 7)
pyxel.rect(64, 114, 64, 14, 0)
pyxel.rectb(64, 114, 64, 14, 7)
self.Draw_fonts(self.text_list["107"], 69, 117)
▲描画部分はこんな感じ。
▲合戦イベントが始まると誰が攻めてきたかを表示するウィンドウが出てきます。
#Kassen2
elif self.window_ctr == 202:
if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
x = pyxel.mouse_x
y = pyxel.mouse_y
if ((64 < x < 128) and (114 < y < 128)):
self.Kassen(self.heisi, self.k_hei)
if self.k_end == True:
self.window_ctr = 203
else:
self.window_ctr = 202
▲実際の戦闘が行われる合戦ウィンドウその2です。といっても「つぎへ」をクリックしてオートで戦うだけですが。合戦終了フラグであるk_endがFalseの場合は再度このウィンドウに戻り、Trueだったら結果画面へと進みます。実際の戦闘部分はKassen関数に投げています。Kassen関数は引数としてプレイヤーと敵の兵力を与えています。
#Kassen2
elif self.window_ctr == 202:
pyxel.bltm(0,0,0,240,16,16,16)
h1 = self.heisi // 100
if h1 < 1 and self.heisi > 0:
h1 = 1
for h2 in range(h1):
h3 = h2 // 7
if h3 < 7:
h4 = ((h2 * 8) - (h3 * 56 ))
if self.rend >= 40:
pyxel.blt(8 + (h3 * 8),8 + h4,2,24,248,8,8,9)
else:
pyxel.blt(8 + (h3 * 8),8 + h4,2,24,240,8,8,9)
h5 = self.k_hei // 100
if h5 < 1 and self.k_hei > 0:
h5 = 1
for h6 in range(h5):
h7 = h6 // 7
if h7 < 7:
h8 = ((h6 * 8) - (h7 * 56))
pyxel.blt(113 - (h7 * 8), 8 + h8,2,32,240,8,8,9)
pyxel.rect(0, 114, 64, 14, 0)
pyxel.rectb(0, 114, 64, 14, 7)
pyxel.rect(64, 114, 64, 14, 0)
pyxel.rectb(64, 114, 64, 14, 7)
self.Draw_fonts(self.text_list["125"], 10, 75)
self.Draw_fonts(self.text_list["95"], 10, 85)
pyxel.text(37,86,str(self.heisi),7)
if self.enemy_tgt == 9:
self.Draw_fonts(self.text_list["120"], 68, 75)
self.Draw_fonts(self.text_list["95"], 68, 85)
pyxel.text(95,86,str(self.k_hei),7)
self.Draw_fonts(self.text_list["124"], 69, 117)
▲合戦ウィンドウその2の描画部分です。ちょっと複雑なのは兵数に応じて足軽を表示する部分ですかね。足軽1人につき兵力100としてfor文を使って表示しています。
▲画面はこんな感じです。兵力に応じて足軽が表示されます。中央まで来たら上限なので止まります。
def Kassen(self, p, e):
pr = int(1 + (self.rend * 0.1))
pl = self.un
if self.enemy_tgt == 9:
es = int(self.turn * 0.5) + 1
if es > 100:
es = 100
er = randint(1, es)
el = 1
p_atk = int(p * (randint(pl, pr) * 0.1))
if p_atk < 1:
p_atk = 1
e_atk = int(e * (randint(el, er) * 0.1))
if e_atk < 1:
e_atk = 1
self.heisi = self.heisi - e_atk
self.k_hei = self.k_hei - p_atk
if self.heisi <= 0 and self.k_hei <= 0:
self.heisi = 0
self.k_hei = 0
self.k_end = True
self.k_end_msg = 123
self.k_kome = 0
self.k_sikin = 0
elif self.heisi < 0:
self.heisi = 0
self.k_end = True
self.k_end_msg = 122
self.k_kome = randint(100, self.k_hei) * -1
self.k_sikin = randint(100, self.k_hei) * -1
self.k_cnt = -25
elif self.k_hei < 0:
self.k_end = True
self.k_end_msg = 121
self.k_kome = randint(100, self.k_hei2)
self.k_sikin = randint(100, self.k_hei2)
▲戦闘ロジックが入ったKassen関数を新設しました。いろいろ書いてますが、ある程度のランダム性を持たせるように、そしてターンが経過するほど敵が強い可能性を高くしてみました。
また、プレイヤー側の成長要素として練度と運というものを用意してみました。詳しい仕組みはこれからですが、基本的には兵力差が勝敗に直結する計算式になっているので、アクセントになればいいなと思っています。
どちらか(あるいは両方)の兵数が0以下になるとk_endがTrueになります。これで合戦が終わります。勝った場合は米と資金がもらえ、負けたら取られます。どちらかが全滅するまで終わらない非情仕様となっております。
#Kassen3
elif self.window_ctr == 203:
if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
x = pyxel.mouse_x
y = pyxel.mouse_y
if ((64 < x < 128) and (114 < y < 128)):
self.window_ctr = 204
▲合戦ウィンドウその3です。ここは結果表示だけです。
#Kassen3
elif self.window_ctr == 203:
pyxel.rect(0, 100, 128, 26, 0)
pyxel.rectb(0, 100, 128, 26, 7)
t = str(self.k_end_msg)
self.Draw_fonts(self.text_list[t], 5, 105)
pyxel.rect(0, 114, 64, 14, 0)
pyxel.rectb(0, 114, 64, 14, 7)
pyxel.rect(64, 114, 64, 14, 0)
pyxel.rectb(64, 114, 64, 14, 7)
self.Draw_fonts(self.text_list["107"], 69, 117)
▲描画部分はこんな感じ。
▲「かちました」
#Kassen4
elif self.window_ctr == 204:
if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
x = pyxel.mouse_x
y = pyxel.mouse_y
if ((64 < x < 128) and (114 < y < 128)):
self.kome = self.kome + self.k_kome
self.sikin = self.sikin + self.k_sikin
if self.kome < 0:
self.kome = 0
if self.sikin < 0:
self.sikin = 0
#if self.k_cnt > 0:
self.k_cnt = 0
self.k_end = False
self.k_end_msg = 0
self.k_kome = 0
self.k_sikin = 0
self.k_hei = 0
self.k_hei2 = 0
self.enemy_tgt = 0
self.window_ctr = 0
▲合戦ウィンドウその4、結果報告ウィンドウです。米・資金をどれだけ取ったか・取られたかを表示します。
#Kassen4
elif self.window_ctr == 204:
pyxel.rect(0, 50, 128, 65, 0)
pyxel.rectb(0, 50, 128, 65, 7)
self.Draw_fonts(self.text_list["126"], 5, 53)
self.Draw_fonts(self.text_list["97"], 5, 64)
self.Draw_fonts(self.text_list["96"], 5, 74)
if self.k_kome < 0:
pyxel.text(35,65,str(self.k_kome),7)
pyxel.text(35,75,str(self.k_sikin),7)
else:
pyxel.text(35,65,"+" + str(self.k_kome),7)
pyxel.text(35,75,"+" + str(self.k_sikin),7)
pyxel.rect(0, 114, 64, 14, 0)
pyxel.rectb(0, 114, 64, 14, 7)
pyxel.rect(64, 114, 64, 14, 0)
pyxel.rectb(64, 114, 64, 14, 7)
self.Draw_fonts(self.text_list["107"], 69, 117)
▲描画部分はこんな感じ。
▲勝ったので資源を奪いました。ちなみに負けた場合は兵数が0になって資源も取られます。
▲実際に動かすとこんな感じです。山賊の最後の300人弱が根性見せましたね。
今回はここまでです。次回は城郭施設についてです。上のGifでもちょっと映っていますが、場内にいろいろな人材を配置してそれぞれからコマンドを実行できるようにしています。今回作ったのは「侍大将」の「訓練」コマンドです。これで練度を上げることができます。詳しくは次回のnoteで書いていこうと思います。
ここまで読んでいただきありがとうございました。
ここまで読んでいただきありがとうございます!