diff --git a/pypvz.py b/pypvz.py index 89e0b5a..dffe61c 100755 --- a/pypvz.py +++ b/pypvz.py @@ -11,13 +11,14 @@ from source import tool from source import constants as c from source.state import mainmenu, screen, level -if __name__=="__main__": +if __name__ == "__main__": # 日志设置 if not os.path.exists(os.path.dirname(c.USERLOG_PATH)): os.makedirs(os.path.dirname(c.USERLOG_PATH)) logger = logging.getLogger("main") formatter = logging.Formatter("%(asctime)s - %(levelname)s: %(message)s") - fileHandler = RotatingFileHandler(c.USERLOG_PATH, "a", 1024*1024, 0, "utf-8") + fileHandler = RotatingFileHandler(c.USERLOG_PATH, "a", 1_000_000, 0, "utf-8") + os.chmod(c.USERLOG_PATH, 420) # 设置日志文件权限,Unix为644,Windows为可读、可写 fileHandler.setFormatter(formatter) streamHandler = logging.StreamHandler() streamHandler.setFormatter(formatter) diff --git a/resources/music/intro.opus b/resources/music/intro.opus index 19c4028..ddfd16b 100644 Binary files a/resources/music/intro.opus and b/resources/music/intro.opus differ diff --git a/source/component/map.py b/source/component/map.py index ce01487..87b6d40 100755 --- a/source/component/map.py +++ b/source/component/map.py @@ -10,27 +10,50 @@ class Map(): self.width = c.GRID_POOL_X_LEN self.height = c.GRID_POOL_Y_LEN self.grid_height_size = c.GRID_POOL_Y_SIZE - self.map = [[(self.initMapGrid(c.MAP_GRASS), self.initMapGrid(c.MAP_WATER))[y in {2, 3}] for x in range(self.width)] for y in range(self.height)] + self.map = [ [self.initMapGrid(c.MAP_WATER) if 2 <= y <= 3 + else self.initMapGrid(c.MAP_GRASS) + for x in range(self.width) + ] + for y in range(self.height) + ] elif self.background_type in c.ON_ROOF_BACKGROUNDS: self.width = c.GRID_ROOF_X_LEN self.height = c.GRID_ROOF_Y_LEN self.grid_height_size = c.GRID_ROOF_Y_SIZE - self.map = [[self.initMapGrid(c.MAP_TILE) for x in range(self.width)] for y in range(self.height)] + self.map = [ [self.initMapGrid(c.MAP_TILE) + for x in range(self.width) + ] + for y in range(self.height) + ] elif self.background_type == c.BACKGROUND_SINGLE: self.width = c.GRID_X_LEN self.height = c.GRID_Y_LEN self.grid_height_size = c.GRID_Y_SIZE - self.map = [[(self.initMapGrid(c.MAP_UNAVAILABLE), self.initMapGrid(c.MAP_GRASS))[y == 2] for x in range(self.width)] for y in range(self.height)] + self.map = [ [self.initMapGrid(c.MAP_GRASS) if y ==2 + else self.initMapGrid(c.MAP_UNAVAILABLE) + for x in range(self.width) + ] + for y in range(self.height) + ] elif self.background_type == c.BACKGROUND_TRIPLE: self.width = c.GRID_X_LEN self.height = c.GRID_Y_LEN self.grid_height_size = c.GRID_Y_SIZE - self.map = [[(self.initMapGrid(c.MAP_UNAVAILABLE), self.initMapGrid(c.MAP_GRASS))[y in {1, 2, 3}] for x in range(self.width)] for y in range(self.height)] + self.map = [ [self.initMapGrid(c.MAP_GRASS) if 1 <= y <= 3 + else self.initMapGrid(c.MAP_UNAVAILABLE) + for x in range(self.width) + ] + for y in range(self.height) + ] else: self.width = c.GRID_X_LEN self.height = c.GRID_Y_LEN self.grid_height_size = c.GRID_Y_SIZE - self.map = [[self.initMapGrid(c.MAP_GRASS) for x in range(self.width)] for y in range(self.height)] + self.map = [ [self.initMapGrid(c.MAP_GRASS) + for x in range(self.width) + ] + for y in range(self.height) + ] def isValid(self, map_x, map_y): if (map_x < 0 or map_x >= self.width or @@ -50,12 +73,14 @@ class Map(): def isAvailable(self, map_x, map_y, plant_name): # 咖啡豆和墓碑吞噬者的判别最为特殊 if plant_name == c.COFFEEBEAN: - if self.map[map_y][map_x][c.MAP_SLEEP] and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT]): + if (self.map[map_y][map_x][c.MAP_SLEEP] + and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT])): return True else: return False if plant_name == c.GRAVEBUSTER: - if (c.GRAVE in self.map[map_y][map_x][c.MAP_PLANT]): + if (c.GRAVE in self.map[map_y][map_x][c.MAP_PLANT] + and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT])): return True else: return False @@ -70,7 +95,8 @@ class Map(): elif (all((i in {"花盆(未实现)", c.PUMPKINHEAD}) for i in self.map[map_y][map_x][c.MAP_PLANT]) and (plant_name not in self.map[map_y][map_x][c.MAP_PLANT])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植 return True - elif (plant_name == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 没有南瓜头就能种南瓜头 + elif ((plant_name == c.PUMPKINHEAD) + and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT])): # 没有南瓜头就能种南瓜头 return True else: return False @@ -86,7 +112,8 @@ class Map(): return False else: return True - elif (plant_name == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 有花盆且没有南瓜头就能种南瓜头 + elif ((plant_name == c.PUMPKINHEAD) + and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT])): # 有花盆且没有南瓜头就能种南瓜头 return True else: return False @@ -110,7 +137,8 @@ class Map(): return False else: return True - elif (plant_name == c.PUMPKINHEAD) and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT]): # 在睡莲上且没有南瓜头就能种南瓜头 + elif ((plant_name == c.PUMPKINHEAD) + and (c.PUMPKINHEAD not in self.map[map_y][map_x][c.MAP_PLANT])): # 在睡莲上且没有南瓜头就能种南瓜头 return True else: return False @@ -248,7 +276,8 @@ LEVEL_MAP_DATA = ( c.INIT_SUN_NAME: 50, c.SHOVEL: 1, c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO, - c.INCLUDED_ZOMBIES: (c.NORMAL_ZOMBIE, c.CONEHEAD_ZOMBIE, c.POLE_VAULTING_ZOMBIE, c.BUCKETHEAD_ZOMBIE), + c.INCLUDED_ZOMBIES: ( c.NORMAL_ZOMBIE, c.CONEHEAD_ZOMBIE, + c.POLE_VAULTING_ZOMBIE, c.BUCKETHEAD_ZOMBIE), c.NUM_FLAGS:3 }, # 第6关 目前夜晚第一关 @@ -360,16 +389,21 @@ LEVEL_MAP_DATA = ( LITTLE_GAME_MAP_DATA = ( # 第0关 测试 { - c.BACKGROUND_TYPE: 6, + c.BACKGROUND_TYPE: 3, c.GAME_TITLE: "隐藏测试关卡", - c.CHOOSEBAR_TYPE: c.CHOOSEBAR_BOWLING, - c.SHOVEL: 0, + c.CHOOSEBAR_TYPE: c.CHOOSEBAR_MOVE, + c.SHOVEL: 1, c.SPAWN_ZOMBIES:c.SPAWN_ZOMBIES_AUTO, - c.INCLUDED_ZOMBIES: ( c.POLE_VAULTING_ZOMBIE,), - c.NUM_FLAGS:1, - c.CARD_POOL: { c.WALLNUTBOWLING: 0, - c.REDWALLNUTBOWLING: 0, - c.GIANTWALLNUT:100,} + c.INCLUDED_ZOMBIES: ( c.NORMAL_ZOMBIE, c.NEWSPAPER_ZOMBIE, + c.ZOMBONI, c.FOOTBALL_ZOMBIE, + c.CONEHEAD_ZOMBIE, c.BUCKETHEAD_ZOMBIE), + c.NUM_FLAGS:4, + c.CARD_POOL: { c.LILYPAD: 300, + c.STARFRUIT: 400, + c.PUMPKINHEAD: 100, + c.SEASHROOM: 100, + c.SPIKEWEED: 100, + } }, # 第1关 坚果保龄球 { @@ -415,9 +449,9 @@ LITTLE_GAME_MAP_DATA = ( c.NUM_FLAGS:3, c.CARD_POOL: { c.PUFFSHROOM: 100, c.SCAREDYSHROOM: 100, - c.ICESHROOM: 100, + c.ICESHROOM: 70, c.HYPNOSHROOM: 100, - c.DOOMSHROOM: 100, + c.DOOMSHROOM: 50, c.GRAVEBUSTER: 100, c.FUMESHROOM: 200}, c.GRADE_GRAVES:3 @@ -440,7 +474,7 @@ LITTLE_GAME_MAP_DATA = ( c.SPIKEWEED: 100, c.SQUASH: 100, c.JALAPENO: 50, - c.THREEPEASHOOTER: 300,} + c.THREEPEASHOOTER: 400,} }, # 第5关 坚果保龄球2 { diff --git a/source/component/menubar.py b/source/component/menubar.py index 19acedd..52bd69b 100755 --- a/source/component/menubar.py +++ b/source/component/menubar.py @@ -22,9 +22,7 @@ def getSunValueImage(sun_value): return image def getCardPool(data): - card_pool = {} - for cardName in data: - card_pool[c.PLANT_CARD_INFO[c.PLANT_CARD_INDEX[cardName]]] = data[cardName] + card_pool = {c.PLANT_CARD_INFO[c.PLANT_CARD_INDEX[card_name]]: data[card_name] for card_name in data} return card_pool class Card(): @@ -58,8 +56,8 @@ class Card(): def checkMouseClick(self, mouse_pos): x, y = mouse_pos - if(x >= self.rect.x and x <= self.rect.right and - y >= self.rect.y and y <= self.rect.bottom): + if (self.rect.x <= x <= self.rect.right and + self.rect.y <= y <= self.rect.bottom): return True return False @@ -85,25 +83,28 @@ class Card(): # 有关是否满足冷却与阳光条件的图片形式 time = current_time - self.frozen_timer if time < self.frozen_time: #cool down status - image = pg.Surface([self.rect.w, self.rect.h]) - # 在冷却时间不足且阳光也不足时,叠加两者效果显示,即同时改变透明度与图像覆盖 - if self.sun_cost > sun_value: - image.set_alpha(192) - frozen_image = self.orig_image.copy() + image = pg.Surface((self.rect.w, self.rect.h)) # 黑底 + frozen_image = self.orig_image frozen_image.set_alpha(128) frozen_height = (self.frozen_time - time)/self.frozen_time * self.rect.h image.blit(frozen_image, (0,0), (0, 0, self.rect.w, frozen_height)) + self.orig_image.set_alpha(192) image.blit(self.orig_image, (0,frozen_height), (0, frozen_height, self.rect.w, self.rect.h - frozen_height)) elif self.sun_cost > sun_value: #disable status - image = self.orig_image.copy() - image.set_alpha(192) + image = pg.Surface((self.rect.w, self.rect.h)) # 黑底 + self.orig_image.set_alpha(192) + image.blit(self.orig_image, (0,0), (0, 0, self.rect.w, self.rect.h)) elif self.clicked: - image = self.orig_image.copy() - image.set_alpha(128) + image = pg.Surface((self.rect.w, self.rect.h)) # 黑底 + chosen_image = self.orig_image + chosen_image.set_alpha(128) + + image.blit(chosen_image, (0,0), (0, 0, self.rect.w, self.rect.h)) else: image = self.orig_image + image.set_alpha(255) return image def update(self, sun_value, current_time): @@ -357,14 +358,21 @@ class MoveCard(): # 新增卡片时显示图片 if self.rect.w < self.orig_rect.w: #create a part card image image = pg.Surface([self.rect.w, self.rect.h]) + if self.clicked: + self.orig_image.set_alpha(128) + else: + self.orig_image.set_alpha(255) image.blit(self.orig_image, (0, 0), (0, 0, self.rect.w, self.rect.h)) self.rect.w += 1 else: - image = self.orig_image - if self.clicked: - image.set_alpha(192) - else: - image.set_alpha(255) + if self.clicked: + image = pg.Surface([self.rect.w, self.rect.h]) # 黑底 + self.orig_image.set_alpha(128) + + image.blit(self.orig_image, (0,0), (0, 0, self.rect.w, self.rect.h)) + else: + self.orig_image.set_alpha(255) + image = self.orig_image return image def update(self, left_x, current_time): diff --git a/source/component/plant.py b/source/component/plant.py index db01a8f..a4e4a59 100755 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -195,8 +195,7 @@ class StarBullet(Bullet): self.rect.x += 7 self.rect.y += 7 elif self.direction == c.STAR_UPWARD: - # 实际上不知道为什么向上飞的看起来要快一些,所以拟合的时候把速度调小了一点 - self.rect.y -= 9 + self.rect.y -= 10 elif self.direction == c.STAR_DOWNWARD: self.rect.y += 10 else: @@ -1280,18 +1279,20 @@ class TorchWood(Plant): def idling(self): for i in self.bullet_group: - if i.name == c.BULLET_PEA: - if i.passed_torchwood_x != self.rect.centerx: - if abs(i.rect.centerx - self.rect.centerx) <= 20: - self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.dest_y, - c.BULLET_FIREBALL, c.BULLET_DAMAGE_FIREBALL_BODY, effect=c.BULLET_EFFECT_UNICE, passed_torchwood_x=self.rect.centerx)) - i.kill() - elif i.name == c.BULLET_PEA_ICE: - if i.passed_torchwood_x != self.rect.centerx: - if abs(i.rect.centerx - self.rect.centerx) <= 20: - self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.dest_y, - c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, effect=None, passed_torchwood_x=self.rect.centerx)) - i.kill() + if (i.name == c.BULLET_PEA + and i.passed_torchwood_x != self.rect.centerx + and abs(i.rect.centerx - self.rect.centerx) <= 20): + self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.dest_y, + c.BULLET_FIREBALL, c.BULLET_DAMAGE_FIREBALL_BODY, + effect=c.BULLET_EFFECT_UNICE, passed_torchwood_x=self.rect.centerx)) + i.kill() + elif (i.name == c.BULLET_PEA_ICE + and i.passed_torchwood_x != self.rect.centerx + and abs(i.rect.centerx - self.rect.centerx)): + self.bullet_group.add(Bullet(i.rect.x, i.rect.y, i.dest_y, + c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, + effect=None, passed_torchwood_x=self.rect.centerx)) + i.kill() class StarFruit(Plant): def __init__(self, x, y, bullet_group, level): @@ -1475,7 +1476,7 @@ class TangleKlep(Plant): def canAttack(self, zombie): if zombie.state != c.DIE and (not zombie.losthead): # 这里碰撞应当比碰撞一般更容易,就设置成圆形或矩形模式,不宜采用mask - if pg.sprite.collide_circle_ratio(0.7)(zombie, self): + if pg.sprite.collide_rect_ratio(1)(zombie, self): return True return False diff --git a/source/constants.py b/source/constants.py index 987710d..ceae9c5 100755 --- a/source/constants.py +++ b/source/constants.py @@ -9,12 +9,14 @@ else: # 非Windows系统存储路径 USERDATA_PATH = os.path.expanduser(os.path.join("~", ".config", "wszqkzqk.dev", "pypvz", "userdata.json")) USERLOG_PATH = os.path.expanduser(os.path.join("~", ".config", "wszqkzqk.dev", "pypvz", "run.log")) -# 窗口图标 -ORIGINAL_LOGO = os.path.join(os.path.dirname(os.path.dirname(__file__)), "pypvz-exec-logo.png") # 游戏图片资源路径 PATH_IMG_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources", "graphics") # 游戏音乐文件夹路径 PATH_MUSIC_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources","music") +# 窗口图标 +ORIGINAL_LOGO = os.path.join(os.path.dirname(os.path.dirname(__file__)), "pypvz-exec-logo.png") +# 字体路径 +FONT_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources", "DroidSansFallback.ttf") # 窗口标题 ORIGINAL_CAPTION = "pypvz" @@ -29,8 +31,6 @@ SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 SCREEN_SIZE = (SCREEN_WIDTH, SCREEN_HEIGHT) -# 字体路径 -FONT_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources", "DroidSansFallback.ttf") # 选卡数量 # 最大数量 @@ -231,7 +231,7 @@ CARD_MOVE_TIME = 60 CAR = "car" SUN = "Sun" -# plant子类非植物对象 +# plant子类非植物对象(这里的是不包括阳光、子弹的拟植物对象) NON_PLANT_OBJECTS = { HOLE := "Hole", ICEFROZENPLOT := "IceFrozenPlot", @@ -376,9 +376,7 @@ PLANT_CARD_INFO = (# 元组 (植物名称, 卡片名称, 阳光, 冷却时间) ) # 卡片中的植物名称与索引序号的对应关系,指定名称以得到索引值 -PLANT_CARD_INDEX={} -for i, item in enumerate(PLANT_CARD_INFO): - PLANT_CARD_INDEX[item[PLANT_NAME_INDEX]] = i +PLANT_CARD_INDEX={item[PLANT_NAME_INDEX]: index for (index, item) in enumerate(PLANT_CARD_INFO)} # 指定了哪些卡可选(排除坚果保龄球特殊植物) CARDS_TO_CHOOSE = range(len(PLANT_CARD_INFO) - 3) @@ -482,7 +480,7 @@ FUME = "Fume" # 子弹伤害 BULLET_DAMAGE_NORMAL = 20 BULLET_DAMAGE_FIREBALL_BODY = 27 # 这是火球本体的伤害,注意不是40,本体(27) + 溅射(13)才是40 -BULLET_DAMAGE_FIREBALL_RANGE = 13 +BULLET_DAMAGE_FIREBALL_RANGE = 13 # 原版溅射伤害会随着僵尸数量增多而减少,这里相当于做了一个增强 # 子弹效果 BULLET_EFFECT_ICE = "ice" BULLET_EFFECT_UNICE = "unice" diff --git a/source/state/level.py b/source/state/level.py index 6091cf6..9a41d24 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -126,7 +126,7 @@ class Level(tool.State): zombie_list.append(c.FLAG_ZOMBIE) zombie_volume -= c.CREATE_ZOMBIE_DICT[c.FLAG_ZOMBIE][0] - # 传送带模式应当增大僵尸容量 + # 保龄球模式应当增大僵尸容量 if (self.bar_type != c.CHOOSEBAR_STATIC): zombie_volume += 2 @@ -265,7 +265,7 @@ class Level(tool.State): c.SOUND_ZOMBIE_COMING.play() return if (self.wave_num % 10 != 9): - if ((current_time - self.wave_time >= 25000 + random.randint(0, 6000)) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.wave_time >= 12500 + random.randint(0, 3000))): + if ((current_time - self.wave_time >= 25000 + random.randint(0, 6000)) or (self.bar_type == c.CHOOSEBAR_BOWLING and current_time - self.wave_time >= 12500 + random.randint(0, 3000))): self.wave_num += 1 self.wave_time = current_time self.wave_zombies = self.waves[self.wave_num - 1] @@ -1547,6 +1547,14 @@ class Level(tool.State): self.showAllContentOfMenu(surface) # 以后可能需要插入一个预备的状态(预览显示僵尸、返回战场) elif self.state == c.PLAY: + if self.has_shovel: + # 画铲子 + surface.blit(self.shovel_box, self.shovel_box_rect) + surface.blit(self.shovel, self.shovel_rect) + # 画小菜单 + surface.blit(self.little_menu, self.little_menu_rect) + + self.menubar.draw(surface) for i in range(self.map_y_len): self.plant_groups[i].draw(surface) self.zombie_groups[i].draw(surface) @@ -1556,19 +1564,6 @@ class Level(tool.State): if self.cars[i]: self.cars[i].draw(surface) self.head_group.draw(surface) - - # 浓雾模式的雾 - #if self.background_type == c.BACKGROUND_FOG: - # pg.draw.rect(surface, c.LIGHTGRAY, (400, 0, 400, 600)) - - if self.has_shovel: - # 画铲子 - surface.blit(self.shovel_box, self.shovel_box_rect) - surface.blit(self.shovel, self.shovel_rect) - # 画小菜单 - surface.blit(self.little_menu, self.little_menu_rect) - - self.menubar.draw(surface) self.sun_group.draw(surface) if self.drag_plant: diff --git a/source/state/mainmenu.py b/source/state/mainmenu.py index 5fc70ef..1da7f3b 100644 --- a/source/state/mainmenu.py +++ b/source/state/mainmenu.py @@ -124,6 +124,7 @@ class Menu(tool.State): self.adventure_timer = self.adventure_start = self.current_time self.persist[c.GAME_MODE] = c.MODE_ADVENTURE # 播放进入音效 + pg.mixer.music.stop() c.SOUND_EVILLAUGH.play() c.SOUND_LOSE.play() diff --git a/source/tool.py b/source/tool.py index 9f5e2a3..8e7af76 100755 --- a/source/tool.py +++ b/source/tool.py @@ -1,9 +1,11 @@ +import logging import os import json from abc import abstractmethod import pygame as pg from pygame.locals import * from . import constants as c +logger = logging.getLogger("main") # 状态机 抽象基类 class State(): @@ -31,15 +33,15 @@ class State(): # 工具:范围判断函数,用于判断点击 def inArea(self, rect, x, y): - if (x >= rect.x and x <= rect.right and - y >= rect.y and y <= rect.bottom): + if (rect.x <= x <= rect.right and + rect.y <= y <= rect.bottom): return True else: return False # 工具:用户数据保存函数 def saveUserData(self): - with open(c.USERDATA_PATH, "w") as f: + with open(c.USERDATA_PATH, "w", encoding="utf-8") as f: userdata = {} for i in self.game_info: if i in c.INIT_USERDATA: @@ -60,12 +62,18 @@ class Control(): self.state_dict = {} self.state_name = None self.state = None - # 这里需要考虑多种情况,如文件不存在、文件不可读、文件不符合JSON语法要求,这些情况目前暂定统一进行新建文件操作 - # 因此仍然采用try-except实现而非if-else实现 try: # 存在存档即导入 - with open(c.USERDATA_PATH) as f: + # 先自动修复读写权限(Python权限规则和Unix不一样,420表示unix的644,Windows自动忽略不支持项) + os.chmod(c.USERDATA_PATH, 420) + with open(c.USERDATA_PATH, encoding="utf-8") as f: userdata = json.load(f) + except FileNotFoundError: + self.setupUserData() + except json.JSONDecodeError: + logger.warning("用户存档解码错误!程序将新建初始存档!\n") + self.setupUserData() + else: # 没有引发异常才执行 self.game_info = {} # 导入数据,保证了可运行性,但是放弃了数据向后兼容性,即假如某些变量在以后改名,在导入时可能会被重置 need_to_rewrite = False @@ -76,23 +84,23 @@ class Control(): self.game_info[key] = c.INIT_USERDATA[key] need_to_rewrite = True if need_to_rewrite: - with open(c.USERDATA_PATH, "w") as f: + with open(c.USERDATA_PATH, "w", encoding="utf-8") as f: savedata = json.dumps(self.game_info, sort_keys=True, indent=4) f.write(savedata) - except: - if not os.path.exists(os.path.dirname(c.USERDATA_PATH)): - os.makedirs(os.path.dirname(c.USERDATA_PATH)) - with open(c.USERDATA_PATH, "w") as f: - savedata = json.dumps(c.INIT_USERDATA, sort_keys=True, indent=4) - f.write(savedata) - self.game_info = c.INIT_USERDATA.copy() # 内部全是不可变对象,浅拷贝即可 # 存档内不包含即时游戏时间信息,需要新建 self.game_info[c.CURRENT_TIME] = 0 # 50为目前的基础帧率,乘以倍率即是游戏帧率 self.fps = 50 * self.game_info[c.GAME_RATE] - + def setupUserData(self): + if not os.path.exists(os.path.dirname(c.USERDATA_PATH)): + os.makedirs(os.path.dirname(c.USERDATA_PATH)) + with open(c.USERDATA_PATH, "w", encoding="utf-8") as f: + savedata = json.dumps(c.INIT_USERDATA, sort_keys=True, indent=4) + f.write(savedata) + self.game_info = c.INIT_USERDATA.copy() # 内部全是不可变对象,浅拷贝即可 + def setup_states(self, state_dict, start_state): self.state_dict = state_dict self.state_name = start_state @@ -137,8 +145,7 @@ class Control(): self.mouse_pos = pg.mouse.get_pos() self.mouse_click[0], _, self.mouse_click[1] = pg.mouse.get_pressed() # self.mouse_click[0]表示左键,self.mouse_click[1]表示右键 - print( f"点击位置: ({self.mouse_pos[0]:3}, {self.mouse_pos[1]:3})", - f"左右键点击情况: {self.mouse_click}") + print(f"点击位置: ({self.mouse_pos[0]:3}, {self.mouse_pos[1]:3}) 左右键点击情况: {self.mouse_click}") def run(self):