![見出し画像](https://assets.st-note.com/production/uploads/images/45030376/rectangle_large_type_2_f0a36b640bf454643591f5fe5af0429e.png?width=1200)
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に置いてあります。
ここまで読んでいただきありがとうございました。
ここまで読んでいただきありがとうございます!