見出し画像

pyxelでシミュレーションゲームを作る(3)

前回はコストとターン経過を実装しました。今回は主に見た目の部分を改善しつつ、以下の機能を実現していきます。
・兵糧の概念(ターン経過とともに兵士数に応じて米が減る)
・労力の増加方式を変える(具体的には領内が発展しているほど多くしたい)
・施設の改修ができるようにする(田んぼ、町、武家屋敷は3段階で強化できるようにする)

それでは始めていきます。

前回のnoteは以下になります。よろしければご参照ください。

まずは見た目の部分です。今までは暫定的に漢字で表現していましたが、さすがに味気ないのでイメージファイルを手直しします。

無題

▲田んぼ・町・武家屋敷です。町と武家屋敷がほぼ同じですが、屋根が青いのが町で、黄色いのが武家屋敷です。今回は施設の改修コマンドも作るので3種類の絵を用意しました。下に行くほど発展しています。

無題

▲その他、川やら平地やら城などなど。下段は街道のパーツです。

無題

▲見た目がにぎやかになりました。

続いて、機能面の改修です。
まずは、施設の改修ができるようにします。

             if ((self.txt_ctr < 3) or (32 <= self.txt_ctr <= 34)) :
                self.update_list.append(80)

▲画面描画のdraw関数内、建築ウィンドウの部分にこのようなif文を追加しました。各施設にはタイルマップに紐づいた数字が振られていて、「田んぼは0,町は1、武家屋敷は2」のようになっています。一段階改修が進むと「田んぼ:32、町:33、武家屋敷:34」になります。そのため、このif文は「1段階目の田んぼ・町・武家屋敷と2段階目の田んぼ・町・武家屋敷」の場合にTrueになります。Trueになったら、80番目の施設を建築可能リストに追加します。この80番目のものが「改修」になります。

無題

▲改修コマンドが選べるようになりました。

「かいしゅう」を選んだ際の動きは以下のコードになります。

    def update_pos(self, v, c):
       x = self.tgt_x
       y = self.tgt_y
       #Taget point check
       if v == 80:
           v2 = pyxel.tilemap(0).get(x, y)
           if v2 == 0:
               v = 32
           elif v2 == 32:
               v = 64
           elif v2 == 1:
               v = 33
           elif v2 == 33:
               v = 65
           elif v2 == 2:
               v = 34
           elif v2 == 34:
               v = 66
               
       tile = format(v, 'x')
       tile2 = str(format(tile, '0>3'))
       #Update tilemap
       pyxel.tilemap(0).set(x, y, [tile2]) 

▲Craftクラスのupdate_pos関数です。改修は80番が割り振られているので、if v == 80:以下の処理が走ります。選択したマス目に何があるかをpyxel.tilemap(0).get(x, y)で取得して、それに応じた建築物を改修先としてvに代入します。あとはvを16進数に直して(変数tile)、文字列にして3桁に0埋めした後(変数tile2)、pyxel.tilemap(0).set(x, y, [tile2])で更新です。

これで改修コマンドは実装できました。
次に、ターン経過時の動きを見直します。
Appクラス内Turn_change関数を修正します。

 def Turn_change(self):
    r = 0
    for i in range(16):
        for i2 in range(16):
            m = pyxel.tilemap(0).data[i][i2]
            if m == 0:
                self.kome = self.kome + 50
                r = r + 1
            elif m == 1:
                self.sikin = self.sikin + 50
                r = r + 1
            elif m == 2:
                self.heisi = self.heisi + 15
                r = r + 1
            elif m == 32:
                self.kome = self.kome + 100
                r = r + 1
            elif m == 33:
                self.sikin = self.sikin + 75
                r = r + 1
            elif m == 34:
                self.heisi = self.heisi + 25
                r = r + 1
            elif m == 64:
                self.kome = self.kome + 200
                r = r + 1
            elif m == 65:
                self.sikin = self.sikin + 100
                r = r + 1
            elif m == 66:
                self.heisi = self.heisi + 50
                r = r + 1
            
                
    #hyoro
    self.kome = self.kome - int(self.heisi*0.5)
    if self.kome < 0:
        self.heisi = self.heisi - abs(self.kome*3)
        self.heisi = self.heisi - 100
        if self.heisi < 0:
            self.heisi = 0
        self.kome = 0
        
    self.roryoku = self.roryoku + int(r*20)
    self.turn = self.turn + 1

まずはせっかく各施設の改修ができるようになったので、強化するほど資源も多く手に入るようにします。

    r = 0
    for i in range(16):
        for i2 in range(16):
            m = pyxel.tilemap(0).data[i][i2]
            if m == 0:
                self.kome = self.kome + 50
                r = r + 1
            elif m == 1:
                self.sikin = self.sikin + 50
                r = r + 1
            elif m == 2:
                self.heisi = self.heisi + 15
                r = r + 1
            elif m == 32:
                self.kome = self.kome + 100
                r = r + 1
            elif m == 33:
                self.sikin = self.sikin + 75
                r = r + 1
            elif m == 34:
                self.heisi = self.heisi + 25
                r = r + 1
            elif m == 64:
                self.kome = self.kome + 200
                r = r + 1
            elif m == 65:
                self.sikin = self.sikin + 100
                r = r + 1
            elif m == 66:
                self.heisi = self.heisi + 50
                r = r + 1
            

▲分岐が細かくなってしまいましたが、施設の番号を条件としてif文で振り分けています。上位の施設程もらえる資源が多くなります。変数rは後の労力計算で用いますが、領内の発展度合いを測るために建築された施設数を足しあげています。

次に兵糧の計算です。

    #hyoro
    self.kome = self.kome - int(self.heisi*0.5)
    if self.kome < 0:
        self.heisi = self.heisi - abs(self.kome*3)
        self.heisi = self.heisi - 100
        if self.heisi < 0:
            self.heisi = 0
        self.kome = 0

▲今回のルールはターンが経過するごとに「兵士数×0.5」の米が消費されることにしました。もしも米がマイナスになったら「マイナスになった米×3」「固定値で100」の合計分兵士が減ります。米にマイナスの概念はないので、兵士を減らした後は0にします。

無題

▲兵士数に対して兵糧が足りていないと...。

無題

▲兵士が減ってしまいます。

最後に労力の調整です。
領内が発展しているほど使える労力も大きくします。

    self.roryoku = self.roryoku + int(r*20)
    self.turn = self.turn + 1

▲先ほど領内の施設数を足しあげた変数rを使います。ターンが経過すると「r×20」の労力が手に入ります。施設1つにつき20ですね。

また、今回いろいろと動かしている中で、ロードに関するバグが見つかりました。

self.turn = data[16][0]

▲csvからロードした各種ステータスを変数に入れる際にこのような書き方をしていたのですが、これだと文字として代入されてしまうので、その後の条件分岐などに使えませんでした。

self.turn = int(data[16][0])

▲intで囲って整数にします。これで大丈夫そう。

メインファイルのソースは以下のようになりました。

#main.py

import pyxel
import csv
from module import Fontlist, Text_list, Game_status

class App:
def __init__(self):
    #Font set
    self.font_list = Fontlist.text_j()
    #Text list set
    self.text_list = Text_list.text_get()
    #Costs set
    self.costs = Game_status.costs_get()
    #System status
    self.craft = Craft()
    self.window_ctr = 999
    self.txt_ctr = 0
    self.inf_ctr = 999
    self.update_list = []
    self.update_tgt = 0
    self.turn = 1
    #Player status
    self.sikin = 0
    self.roryoku = 100
    self.heisi = 0
    self.kome = 0
    
    #Base window create
    pyxel.init(128,128, caption="sengoku", scale=5)
    
    #Mouse visivle
    pyxel.mouse(True)

    #Image read
    pyxel.load('assets/assets.pyxres')
    
    pyxel.run(self.update, self.draw)
    
def update(self):
            
    #Main window
    if self.window_ctr == 0:
        if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
            x = pyxel.mouse_x
            y = pyxel.mouse_y
            x2 = int(x/8)
            y2 = int(y/8)
            v = pyxel.tilemap(0).get(x2, y2)
            self.craft.get_pos(x2, y2, v)
            if v == 6:
                self.window_ctr = 99
            else:
                self.window_ctr = 1
            self.txt_ctr = v
    #Craft window
    elif self.window_ctr == 1:
        if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
            x = pyxel.mouse_x
            y = pyxel.mouse_y
            if ((0 < x < 64)  and (114 < y < 128)):
                if ((self.txt_ctr < 3) or (self.txt_ctr == 5) or
                 (32 <= self.txt_ctr <= 34)) :
                   self.update_tgt = 0
                   self.window_ctr = 2
                elif ((self.txt_ctr == 3) or (64 <= self.txt_ctr <= 66)) :
                    self.update_tgt = 5
                    self.window_ctr = 2
                else:
                    self.window_ctr = 3
            if ((64 < x < 128)  and (114 < y < 128)):
                self.window_ctr = 0
    #Craft window2
    elif self.window_ctr == 2:
        if pyxel.btnp(pyxel.MOUSE_LEFT_BUTTON):
            x = pyxel.mouse_x
            y = pyxel.mouse_y
            l = len(self.update_list)
            for i in range(l):
                if ((0 < x < 64)  and (55+i*10 < y < 65+i*10)):
                    self.update_tgt = self.update_list[i]
            if ((0 < x < 64)  and (100 < y < 114)):
                t = str(self.update_tgt)
                c = self.costs[t]
                if self.roryoku >= c:
                    self.craft.update_pos(self.update_tgt, c)
                    self.roryoku = self.roryoku - c
                    self.window_ctr = 0
                else:
                    self.window_ctr = 4
            if ((64 < x < 128)  and (100 < y < 114)):
                self.window_ctr = 0
    #Cannot craft1
    elif self.window_ctr == 3:
        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 = 0
    #Cannot craft2
    elif self.window_ctr == 4:
        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 = 0
    #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)):
                self.window_ctr = 0
    #Siro
    elif self.window_ctr == 99:
        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 = 0
            if ((0 < x < 64)  and (114 < y < 128)):
                self.Turn_change()
                self.window_ctr = 98
                #self.window_ctr = 0
            if ((0 < x < 64)  and (100 < y < 114)):
                self.Save_data()
                self.window_ctr = 100
            if ((64 < x < 128)  and (100 < y < 114)):
                self.Load_data()
                self.window_ctr = 100
    #Information window
    elif self.window_ctr == 100:
        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 = 0
                self.inf_ctr = 999
    #Title
    elif self.window_ctr == 999:
        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 = 0

def draw(self):
    #Draw tilemap
    pyxel.bltm(0,0,0,0,0,16,16)
    #Status window
    if  0 < self.window_ctr < 90 :
        pyxel.rect(25, 0, 103, 60, 0)
        pyxel.rectb(25, 0, 103, 60, 7)
        self.Draw_fonts(self.text_list["96"], 30, 5)
        pyxel.text(75, 5, str(self.sikin), 7)
        self.Draw_fonts(self.text_list["97"], 30, 15)
        pyxel.text(75, 15, str(self.kome), 7)
        self.Draw_fonts(self.text_list["95"], 30, 25)
        pyxel.text(75, 25, str(self.heisi), 7)
        self.Draw_fonts(self.text_list["98"], 30, 35)
        pyxel.text(75, 35, str(self.roryoku), 7)
        
    #Status window2
    if  self.window_ctr == 99 :
        pyxel.rect(25, 0, 103, 70, 0)
        pyxel.rectb(25, 0, 103, 70, 7)
        pyxel.text(30, 5, str(self.turn), 7)
        self.Draw_fonts(self.text_list["106"], 45, 5)
        self.Draw_fonts(self.text_list["96"], 30, 15)
        pyxel.text(75, 15, str(self.sikin), 7)
        self.Draw_fonts(self.text_list["97"], 30, 25)
        pyxel.text(75, 25, str(self.kome), 7)
        self.Draw_fonts(self.text_list["95"], 30, 35)
        pyxel.text(75, 35, str(self.heisi), 7)
        self.Draw_fonts(self.text_list["98"], 30, 45)
        pyxel.text(75, 45, str(self.roryoku), 7)
        
    #Craft window
    if self.window_ctr == 1:
        pyxel.rect(0, 100, 128, 26, 0)
        pyxel.rectb(0, 100, 128, 26, 7)
        key = str(self.txt_ctr)
        self.Draw_fonts(self.text_list[key], 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["100"], 5, 117)
        self.Draw_fonts(self.text_list["101"], 69, 117)

    #Craft window2  
    elif self.window_ctr == 2:
        
        pyxel.rect(0, 50, 128, 64, 0)
        pyxel.rectb(0, 50, 128, 64, 7)
        #Target = TANBO,MATI,BUKEYASIKI,HEITI
        if ((self.txt_ctr < 3) or (self.txt_ctr == 5) or
            (32 <= self.txt_ctr <= 34)) :
            self.update_list = [0,1,2]
            if ((self.txt_ctr < 3) or (32 <= self.txt_ctr <= 34)) :
                self.update_list.append(80)
            l = len(self.update_list)
            for i in range(l):
                self.Draw_fonts(self.text_list[str(self.update_list[i])],
                                12, 56+10*i)
        #Target = KI
        elif ((self.txt_ctr == 3) or (64 <= self.txt_ctr <= 66)) :
            self.update_list = [5]
            l = len(self.update_list)
            for i in range(l):
                self.Draw_fonts(self.text_list[str(self.update_list[i])],
                                12, 56+10*i)
        pyxel.rect(0, 100, 64, 14, 0)
        pyxel.rectb(0, 100, 64, 14, 7)
        pyxel.rect(64, 100, 64, 14, 0)
        pyxel.rectb(64, 100, 64, 14, 7)
        self.Draw_fonts(self.text_list["102"], 5, 103)
        self.Draw_fonts(self.text_list["101"], 69, 103)
        
        s = self.update_list.index(self.update_tgt)
        pyxel.circb(5, 59+10*s, 2, 7)
    #Cannot craft1
    elif self.window_ctr == 3:
        pyxel.rect(0, 100, 128, 26, 0)
        pyxel.rectb(0, 100, 128, 26, 7)
        self.Draw_fonts(self.text_list["99"], 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["101"], 69, 117)
    #Cannot craft2
    elif self.window_ctr == 4:
        pyxel.rect(0, 100, 128, 26, 0)
        pyxel.rectb(0, 100, 128, 26, 7)
        self.Draw_fonts(self.text_list["108"], 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)
    #Turn change
    elif self.window_ctr == 98:
        pyxel.rect(0, 100, 128, 26, 0)
        pyxel.rectb(0, 100, 128, 26, 7)
        pyxel.text(10, 105, str(self.turn), 7)
        self.Draw_fonts(self.text_list["106"], 25, 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)
    #Siro
    elif self.window_ctr == 99:
        pyxel.rect(0, 86, 128, 26, 0)
        pyxel.rectb(0, 86, 128, 26, 7)
        pyxel.rect(0, 100, 128, 26, 0)
        pyxel.rectb(0, 100, 128, 26, 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)
        pyxel.rect(0, 100, 64, 14, 0)
        pyxel.rectb(0, 100, 64, 14, 7)
        pyxel.rect(64, 100, 64, 14, 0)
        pyxel.rectb(64, 100, 64, 14, 7)
        key = str(self.txt_ctr)
        self.Draw_fonts(self.text_list[key], 5, 91)
        self.Draw_fonts(self.text_list["101"], 69, 117)
        self.Draw_fonts(self.text_list["103"], 5, 103)
        self.Draw_fonts(self.text_list["104"], 69, 103)
        self.Draw_fonts(self.text_list["105"], 5, 117)
    #Information window
    elif self.window_ctr == 100:
        pyxel.rect(0, 100, 128, 26, 0)
        pyxel.rectb(0, 100, 128, 26, 7)
        t = str(self.inf_ctr)
        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)
    #Title
    elif self.window_ctr == 999:
        pyxel.rect(0, 100, 128, 26, 0)
        pyxel.rectb(0, 100, 128, 26, 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["113"], 69, 117)
        
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)
        
def Turn_change(self):
    r = 0
    for i in range(16):
        for i2 in range(16):
            m = pyxel.tilemap(0).data[i][i2]
            if m == 0:
                self.kome = self.kome + 50
                r = r + 1
            elif m == 1:
                self.sikin = self.sikin + 50
                r = r + 1
            elif m == 2:
                self.heisi = self.heisi + 15
                r = r + 1
            elif m == 32:
                self.kome = self.kome + 100
                r = r + 1
            elif m == 33:
                self.sikin = self.sikin + 75
                r = r + 1
            elif m == 34:
                self.heisi = self.heisi + 25
                r = r + 1
            elif m == 64:
                self.kome = self.kome + 200
                r = r + 1
            elif m == 65:
                self.sikin = self.sikin + 100
                r = r + 1
            elif m == 66:
                self.heisi = self.heisi + 50
                r = r + 1
            
                
    #hyoro
    self.kome = self.kome - int(self.heisi*0.5)
    if self.kome < 0:
        self.heisi = self.heisi - abs(self.kome*3)
        self.heisi = self.heisi - 100
        if self.heisi < 0:
            self.heisi = 0
        self.kome = 0
        
    self.roryoku = self.roryoku + int(r*20)
    self.turn = self.turn + 1
    
def Save_data(self):
    #Save data
    data2 = []
    for i in range(16):
        data = []
        for i2 in range(16):
            data.append(pyxel.tilemap(0).data[i][i2])
        data2.append(data)
    try:
        with open('DATA/data.csv', 'w', newline="") as f:
                writer = csv.writer(f)
                for i3 in range(16):
                    writer.writerow(data2[i3])
                data3 = []
                data3.append(self.turn)
                data3.append(self.sikin)
                data3.append(self.roryoku)
                data3.append(self.heisi)
                data3.append(self.kome)
                writer.writerow(data3)
                self.inf_ctr = 109
    except:
        self.inf_ctr = 112
                
def Load_data(self):
    #Load data
    data = []
    data2 = []
    data3 = []
    try:
        with open('DATA/data.csv') as f:
            reader = csv.reader(f)
            for row in reader:
                data.append(row)
        for i in range(16):
            data2 = []
            for i2 in range(16):
                a = format(int(data[i][i2]), 'x')
                data2.append(str(format(a, '0>3')))
            data3.append(data2)
        for i2 in range(16):
            d = ""
            d = "".join(data3[i2])
            pyxel.tilemap(0).set(0, 0+i2, [d]) 
        self.turn = int(data[16][0])
        self.sikin = int(data[16][1])
        self.roryoku = int(data[16][2])
        self.heisi = int(data[16][3])
        self.kome = int(data[16][4])
        self.inf_ctr = 110
    except:
       self.inf_ctr = 111


        
class Craft:
   def __init__(self):
       self.tgt_x = 0
       self.tgt_y = 0
       self.tgt_v = 0
   def get_pos(self, x, y, v):
       self.tgt_x = x
       self.tgt_y = y
       self.tgt_v = v
   def update_pos(self, v, c):
       x = self.tgt_x
       y = self.tgt_y
       #Taget point check
       if v == 80:
           v2 = pyxel.tilemap(0).get(x, y)
           if v2 == 0:
               v = 32
           elif v2 == 32:
               v = 64
           elif v2 == 1:
               v = 33
           elif v2 == 33:
               v = 65
           elif v2 == 2:
               v = 34
           elif v2 == 34:
               v = 66
               
       tile = format(v, 'x')
       tile2 = str(format(tile, '0>3'))
       #Update tilemap
       pyxel.tilemap(0).set(x, y, [tile2]) 
       
App()

コードはGitHubにも載せていますが、ちょくちょく手を入れているので内容がnoteと異なっているかもしれません。その時はごめんなさい。
また、タイルマップ等が入っているpyxresファイルやモジュールファイルもGitHubに置いてあります。

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

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