diff --git a/README.md b/README.md index 18ff8e8..94d4374 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ * 支持“关卡进程”进度条显示 * 夜晚模式支持墓碑以及从墓碑生成僵尸 * 含有泳池的模式也支持在最后一波时从泳池中自动冒出僵尸 +* 支持保存进度 ## 环境要求 @@ -163,6 +164,7 @@ nuitka --mingw64 ` * 增加关卡进程进度条 * 该功能自0.5.4已实现 * 增加保存数据文件以存储用户进度的功能 + * 该功能自0.8.0.0已实现 * 增加调整音量的功能 * `pg.mixer.music.set_volume()` * 可以用`音量+`、`音量-`按钮实现 diff --git a/source/constants.py b/source/constants.py index 6f8b044..fba31bf 100755 --- a/source/constants.py +++ b/source/constants.py @@ -1,7 +1,16 @@ -# 冒险模式起始关卡 +import os +# 用户数据存储路径 +if os.name == 'nt': # Windows系统存储路径 + USERDATA_PATH = os.path.expandvars(os.path.join("%APPDATA%", "wszqkzqk.dev", "pypvz", "userdata.json")) +else: # 非Windows系统存储路径 + USERDATA_PATH = os.path.expanduser(os.path.join("~", ".config", "wszqkzqk.dev", "pypvz", "userdata.json")) + +# 游戏起始关卡 START_LEVEL_NUM = 1 -# 小游戏模式起始关卡 START_LITTLE_GAME_NUM = 1 +# 游戏模式完成次数 +START_LEVEL_COMPLETIONS = 0 +START_LITTLEGAME_COMPLETIONS = 0 # 游戏速度倍率(调试用) GAME_RATE = 1 @@ -79,6 +88,8 @@ LEVEL_PROGRESS_FLAG = 'LevelProgressFlag' CURRENT_TIME = 'current time' LEVEL_NUM = 'level num' LITTLEGAME_NUM = 'littleGame num' +LEVEL_COMPLETIONS = 'level completions' +LITTLEGAME_COMPLETIONS = 'littleGame completions' # 整个游戏的状态 MAIN_MENU = 'main menu' @@ -643,5 +654,11 @@ SLEEP = 'sleep' CHOOSE = 'choose' PLAY = 'play' +# 记录本地存储文件需要记录哪些内容 +USERDATA_KEYS = { LEVEL_NUM, LITTLEGAME_NUM, + LEVEL_COMPLETIONS, + LITTLEGAME_COMPLETIONS, + } + # 无穷大常量 INF = float("inf") # python传递字符串性能较低,故在这里对inf声明一次,以后仅需调用即可 diff --git a/source/state/level.py b/source/state/level.py index 93de690..bc0e406 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -47,17 +47,26 @@ class Level(tool.State): try: with open(file_path) as f: self.map_data = json.load(f) - except: + except FileNotFoundError: print("成功通关!") if self.game_info[c.GAME_MODE] == c.MODE_LITTLEGAME: self.game_info[c.LEVEL_NUM] = c.START_LEVEL_NUM + self.game_info[c.LEVEL_COMPLETIONS] += 1 elif self.game_info[c.GAME_MODE] == c.MODE_LITTLEGAME: self.game_info[c.LITTLEGAME_NUM] = c.START_LITTLE_GAME_NUM + self.game_info[c.LITTLEGAME_COMPLETIONS] += 1 self.done = True self.next = c.MAIN_MENU pg.mixer.music.stop() pg.mixer.music.load(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "music", "intro.opus")) pg.mixer.music.play(-1, 0) + with open(c.USERDATA_PATH, "w") as f: + userdata = {} + for i in self.game_info: + if i in c.USERDATA_KEYS: + userdata[i] = self.game_info[i] + savedata = json.dumps(userdata, sort_keys=True, indent=4) + f.write(savedata) return # 是否有铲子的信息:无铲子时为0,有铲子时为1,故直接赋值即可 self.hasShovel = self.map_data[c.SHOVEL] @@ -541,7 +550,6 @@ class Level(tool.State): elif self.checkMainMenuClick(mouse_pos): self.done = True self.next = c.MAIN_MENU - #self.persist = {c.CURRENT_TIME:0, c.LEVEL_NUM:c.START_LEVEL_NUM} # 应该不能用c.LEVEL_NUM:c.START_LEVEL_NUM self.persist = {c.CURRENT_TIME:0, c.LEVEL_NUM:self.persist[c.LEVEL_NUM], c.LITTLEGAME_NUM:self.persist[c.LITTLEGAME_NUM]} pg.mixer.music.stop() pg.mixer.music.load(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "music", "intro.opus")) @@ -1418,6 +1426,13 @@ class Level(tool.State): self.done = True # 播放胜利音效 pg.mixer.Sound(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "sound", "win.ogg")).play() + with open(c.USERDATA_PATH, "w") as f: + userdata = {} + for i in self.game_info: + if i in c.USERDATA_KEYS: + userdata[i] = self.game_info[i] + savedata = json.dumps(userdata, sort_keys=True, indent=4) + f.write(savedata) elif self.checkLose(): self.next = c.GAME_LOSE self.done = True diff --git a/source/tool.py b/source/tool.py index ee4f277..d1f4b2c 100755 --- a/source/tool.py +++ b/source/tool.py @@ -42,9 +42,28 @@ class Control(): self.state_dict = {} self.state_name = None self.state = None - self.game_info = {c.CURRENT_TIME:0, - c.LEVEL_NUM:c.START_LEVEL_NUM, - c.LITTLEGAME_NUM:c.START_LITTLE_GAME_NUM} + try: + # 存在存档即导入 + with open(c.USERDATA_PATH) as f: + userdata = json.load(f) + # 导入数据 + self.game_info = {c.CURRENT_TIME:0} # 时间信息需要新建 + self.game_info.update(userdata) + except FileNotFoundError: + # 不存在存档即新建 + userdata = {c.LEVEL_NUM:c.START_LEVEL_NUM, + c.LITTLEGAME_NUM:c.START_LITTLE_GAME_NUM, + c.LEVEL_COMPLETIONS:c.START_LEVEL_COMPLETIONS, + c.LITTLEGAME_COMPLETIONS:c.START_LITTLEGAME_COMPLETIONS + } + 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(userdata, sort_keys=True, indent=4) + f.write(savedata) + self.game_info = userdata + self.game_info[c.CURRENT_TIME] = 0 # 时间信息需要新建 + def setup_states(self, state_dict, start_state): self.state_dict = state_dict