見出し画像

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で書いていこうと思います。

ここまで読んでいただきありがとうございました。

ここまで読んでいただきありがとうございます!