Merge branch 'master' into opengl

This commit is contained in:
星外之神 2022-07-23 15:06:38 +08:00
commit f7575aa33f
45 changed files with 133 additions and 59 deletions

View File

@ -18,6 +18,7 @@
* 支持“关卡进程”进度条显示 * 支持“关卡进程”进度条显示
* 夜晚模式支持墓碑以及从墓碑生成僵尸 * 夜晚模式支持墓碑以及从墓碑生成僵尸
* 含有泳池的模式也支持在最后一波时从泳池中自动冒出僵尸 * 含有泳池的模式也支持在最后一波时从泳池中自动冒出僵尸
* 支持保存进度
## 环境要求 ## 环境要求
@ -79,7 +80,7 @@ python main.py
### 使用Nuitka进行构建 ### 使用Nuitka进行构建
编译依赖: 编译依赖:
- `Python` >= 3.7,最好使用最新版 - `Python` >= 3.10,最好使用最新版
- `Python-Pygame` >= 1.9,最好使用最新版 - `Python-Pygame` >= 1.9,最好使用最新版
- `Nuitka` - `Nuitka`
- `MinGW-w64`或其他C编译器 - `MinGW-w64`或其他C编译器
@ -95,14 +96,14 @@ python main.py
- 对于`opus`编码,需要添加`libogg-0.dll``libopus-0.dll``libopusfile-0.dll` - 对于`opus`编码,需要添加`libogg-0.dll``libopus-0.dll``libopusfile-0.dll`
- 以添加`opus``vorbis`编码的背景音乐支持为例,编译需执行以下命令: - 以添加`opus``vorbis`编码的背景音乐支持为例,编译需执行以下命令:
``` powershell ``` cmd
git clone https://github.com/wszqkzqk/pypvz.git git clone https://github.com/wszqkzqk/pypvz.git
cd pypvz cd pypvz
nuitka --mingw64 --standalone ` nuitka --mingw64 --standalone `
--onefile ` --onefile `
--show-progress ` --show-progress `
--show-memory ` --show-memory `
--output-dir=out ` --output-dir=release `
--windows-icon-from-ico=pypvz.ico ` --windows-icon-from-ico=pypvz.ico `
--include-data-dir=resources=resources ` --include-data-dir=resources=resources `
--include-data-file=C:\Users\17265\AppData\Local\Programs\Python\Python310\Lib\site-packages\pygame\libogg-0.dll=libogg-0.dll ` --include-data-file=C:\Users\17265\AppData\Local\Programs\Python\Python310\Lib\site-packages\pygame\libogg-0.dll=libogg-0.dll `
@ -119,12 +120,30 @@ nuitka --mingw64 --standalone `
main.py main.py
``` ```
* 其中`C:\Users\17265\AppData\Local\Programs\Python\Python310\Lib\site-packages\pygame\xxx.dll`应当替换为`xxx.dll`实际所在路径 * 其中`C:\Users\17265\AppData\Local\Programs\Python\Python310\Lib\site-packages\pygame\xxx.dll`应当替换为`xxx.dll`实际所在路径`--output-dir=`后应当跟实际需要输出的路径,绝对路径或者相对路径均可
* 由于仅复制了`opus``vorbis`的解码器故要求所有背景音乐都要以opus或vorbis编码 * 由于仅复制了`opus``vorbis`的解码器故要求所有背景音乐都要以opus或vorbis编码
* `--windows-product-version=`表示版本号信息,所跟内容格式必须为`x.x.x.x` * `--windows-product-version=`表示版本号信息,所跟内容格式必须为`x.x.x.x`
* 建议开启`--lto=yes`选项优化链接,如果编译失败可以关闭此选项 * 建议开启`--lto=yes`选项优化链接,如果编译失败可以关闭此选项
可执行文件生成路径为`./out/main.exe` 可执行文件生成路径为`./release/main.exe`
如果只需要在本地生成编译文件测试,则只需要执行:
``` cmd
nuitka --mingw64 `
--follow-imports `
--show-progress `
--output-dir=test-build `
--windows-icon-from-ico=pypvz.ico `
--windows-product-name=pypvz `
--windows-company-name=null `
--windows-file-description=pypvz `
--windows-disable-console `
--windows-product-version=0.7.33.0 `
main.py
```
这样生成的程序只能在有python环境的机器上运行
### 使用pyinstaller进行构建 ### 使用pyinstaller进行构建
@ -145,6 +164,7 @@ nuitka --mingw64 --standalone `
* 增加关卡进程进度条 * 增加关卡进程进度条
* 该功能自0.5.4已实现 * 该功能自0.5.4已实现
* 增加保存数据文件以存储用户进度的功能 * 增加保存数据文件以存储用户进度的功能
* 该功能自0.8.0.0已实现
* 增加调整音量的功能 * 增加调整音量的功能
* `pg.mixer.music.set_volume()` * `pg.mixer.music.set_volume()`
* 可以用`音量+``音量-`按钮实现 * 可以用`音量+``音量-`按钮实现

View File

@ -6,7 +6,7 @@
"included_zombies":["Zombie", "ConeheadZombie", "BucketheadZombie", "NewspaperZombie", "PoleVaultingZombie"], "included_zombies":["Zombie", "ConeheadZombie", "BucketheadZombie", "NewspaperZombie", "PoleVaultingZombie"],
"num_flags":4, "num_flags":4,
"inevitable_zombie_list":{"20":["BucketheadZombie"]}, "inevitable_zombie_list":{"20":["BucketheadZombie"]},
"card_pool":[ "WallNutBowling", "card_pool":{ "WallNutBowling":300,
"RedWallNutBowling" "RedWallNutBowling":100
] }
} }

View File

@ -6,12 +6,12 @@
"num_flags":3, "num_flags":3,
"included_zombies":["Zombie", "ConeheadZombie", "BucketheadZombie", "PoleVaultingZombie"], "included_zombies":["Zombie", "ConeheadZombie", "BucketheadZombie", "PoleVaultingZombie"],
"inevitable_zombie_list":{"20":["BucketheadZombie"]}, "inevitable_zombie_list":{"20":["BucketheadZombie"]},
"card_pool":[ "Peashooter", "card_pool":{ "Peashooter":200,
"SnowPea", "SnowPea":200,
"WallNut", "WallNut":100,
"CherryBomb", "CherryBomb":100,
"RepeaterPea", "RepeaterPea":200,
"Chomper", "Chomper":100,
"PotatoMine" "PotatoMine":100
] }
} }

View File

@ -8,12 +8,12 @@
"BucketheadZombie", "NewspaperZombie", "BucketheadZombie", "NewspaperZombie",
"FootballZombie", "ScreenDoorZombie"], "FootballZombie", "ScreenDoorZombie"],
"inevitable_zombie_list":{"30":["FootballZombie"]}, "inevitable_zombie_list":{"30":["FootballZombie"]},
"card_pool":[ "PuffShroom", "card_pool":{ "PuffShroom":200,
"ScaredyShroom", "ScaredyShroom":100,
"IceShroom", "IceShroom":100,
"HypnoShroom", "HypnoShroom":100,
"DoomShroom", "DoomShroom":100,
"GraveBuster", "GraveBuster":100,
"FumeShroom" "FumeShroom":200
] }
} }

View File

@ -8,13 +8,13 @@
"BucketheadZombie", "SnorkelZombie", "BucketheadZombie", "SnorkelZombie",
"Zomboni"], "Zomboni"],
"inevitable_zombie_list":{"30":["BucketheadZombie"]}, "inevitable_zombie_list":{"30":["BucketheadZombie"]},
"card_pool":[ "Lilypad", "Lilypad", "card_pool":{ "Lilypad":200,
"TorchWood", "TorchWood":100,
"TallNut", "TallNut":100,
"TangleKlep", "TangleKlep":100,
"Spikeweed", "Spikeweed":100,
"Squash", "Squash":100,
"Jalapeno", "Jalapeno":100,
"Threepeater", "Threepeater", "Threepeater", "Threepeater", "Threepeater" "Threepeater":400
] }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -1,5 +1,6 @@
import os import os
import random import random
from select import select
import pygame as pg import pygame as pg
from .. import tool from .. import tool
from .. import constants as c from .. import constants as c
@ -23,12 +24,9 @@ def getSunValueImage(sun_value):
return image return image
def getCardPool(data): def getCardPool(data):
card_pool = [] card_pool = {}
for card in data: for cardName in data:
for i,name in enumerate(c.PLANT_CARD_INFO): card_pool[c.PLANT_CARD_INFO[c.PLANT_CARD_INDEX[cardName]]] = data[cardName]
if name[c.PLANT_NAME_INDEX] == card:
card_pool.append(i)
break
return card_pool return card_pool
class Card(): class Card():
@ -40,7 +38,7 @@ class Card():
self.index = index self.index = index
self.sun_cost = c.PLANT_CARD_INFO[index][c.SUN_INDEX] self.sun_cost = c.PLANT_CARD_INFO[index][c.SUN_INDEX]
self.frozen_time = c.PLANT_CARD_INFO[index][c.FROZEN_INDEX] self.frozen_time = c.PLANT_CARD_INFO[index][c.FROZEN_TIME_INDEX]
self.frozen_timer = -self.frozen_time self.frozen_timer = -self.frozen_time
self.refresh_timer = 0 self.refresh_timer = 0
self.select = True self.select = True
@ -382,6 +380,8 @@ class MoveBar():
self.card_start_x = self.rect.x + 8 self.card_start_x = self.rect.x + 8
self.card_end_x = self.rect.right - 5 self.card_end_x = self.rect.right - 5
self.card_pool = card_pool self.card_pool = card_pool
self.card_pool_name = tuple(self.card_pool.keys())
self.card_pool_weight = tuple(self.card_pool.values())
self.card_list = [] self.card_list = []
self.create_timer = -c.MOVEBAR_CARD_FRESH_TIME self.create_timer = -c.MOVEBAR_CARD_FRESH_TIME
@ -397,11 +397,8 @@ class MoveBar():
return False return False
x = self.card_end_x x = self.card_end_x
y = 6 y = 6
index = random.randint(0, len(self.card_pool) - 1) selected_card = random.choices(self.card_pool_name, self.card_pool_weight)[0]
card_index = self.card_pool[index] self.card_list.append(MoveCard(x, y, selected_card[c.CARD_INDEX] + "_move", selected_card[c.PLANT_NAME_INDEX]))
card_name = c.PLANT_CARD_INFO[card_index][c.CARD_INDEX] + '_move'
plant_name = c.PLANT_CARD_INFO[card_index][c.PLANT_NAME_INDEX]
self.card_list.append(MoveCard(x, y, card_name, plant_name))
return True return True
def update(self, current_time): def update(self, current_time):

View File

@ -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_LEVEL_NUM = 1
# 小游戏模式起始关卡
START_LITTLE_GAME_NUM = 1 START_LITTLE_GAME_NUM = 1
# 游戏模式完成次数
START_LEVEL_COMPLETIONS = 0
START_LITTLEGAME_COMPLETIONS = 0
# 游戏速度倍率(调试用) # 游戏速度倍率(调试用)
GAME_RATE = 1 GAME_RATE = 1
@ -79,6 +88,8 @@ LEVEL_PROGRESS_FLAG = 'LevelProgressFlag'
CURRENT_TIME = 'current time' CURRENT_TIME = 'current time'
LEVEL_NUM = 'level num' LEVEL_NUM = 'level num'
LITTLEGAME_NUM = 'littleGame num' LITTLEGAME_NUM = 'littleGame num'
LEVEL_COMPLETIONS = 'level completions'
LITTLEGAME_COMPLETIONS = 'littleGame completions'
# 整个游戏的状态 # 整个游戏的状态
MAIN_MENU = 'main menu' MAIN_MENU = 'main menu'
@ -198,7 +209,7 @@ BAR_CARD_X_INTERNAL = 51
PLANT_NAME_INDEX = 0 PLANT_NAME_INDEX = 0
CARD_INDEX = 1 CARD_INDEX = 1
SUN_INDEX = 2 SUN_INDEX = 2
FROZEN_INDEX = 3 FROZEN_TIME_INDEX = 3
# 传送带模式中的刷新间隔和移动速率 # 传送带模式中的刷新间隔和移动速率
MOVEBAR_CARD_FRESH_TIME = 6000 MOVEBAR_CARD_FRESH_TIME = 6000
@ -503,6 +514,11 @@ PLANT_CARD_INFO = (# 元组 (植物名称, 卡片名称, 阳光, 冷却时间)
0), 0),
) )
# 卡片中的植物名称与索引序号的对应关系,指定名称以得到索引值
PLANT_CARD_INDEX={}
for i, item in enumerate(PLANT_CARD_INFO):
PLANT_CARD_INDEX[item[PLANT_NAME_INDEX]] = i
# 指定了哪些卡可选(排除坚果保龄球特殊植物) # 指定了哪些卡可选(排除坚果保龄球特殊植物)
CARDS_TO_CHOOSE = range(len(PLANT_CARD_INFO) - 2) CARDS_TO_CHOOSE = range(len(PLANT_CARD_INFO) - 2)
@ -638,5 +654,11 @@ SLEEP = 'sleep'
CHOOSE = 'choose' CHOOSE = 'choose'
PLAY = 'play' PLAY = 'play'
# 记录本地存储文件需要记录哪些内容
USERDATA_KEYS = { LEVEL_NUM, LITTLEGAME_NUM,
LEVEL_COMPLETIONS,
LITTLEGAME_COMPLETIONS,
}
# 无穷大常量 # 无穷大常量
INF = float("inf") # python传递字符串性能较低故在这里对inf声明一次以后仅需调用即可 INF = float("inf") # python传递字符串性能较低故在这里对inf声明一次以后仅需调用即可

View File

@ -45,20 +45,28 @@ class Level(tool.State):
file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))),'resources' , 'data', 'map', map_file) file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))),'resources' , 'data', 'map', map_file)
# 最后一关之后应该结束了 # 最后一关之后应该结束了
try: try:
f = open(file_path) with open(file_path) as f:
self.map_data = json.load(f) self.map_data = json.load(f)
f.close() except FileNotFoundError:
except:
print("成功通关!") print("成功通关!")
if self.game_info[c.GAME_MODE] == c.MODE_LITTLEGAME: 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_NUM] = c.START_LEVEL_NUM
self.game_info[c.LEVEL_COMPLETIONS] += 1
elif self.game_info[c.GAME_MODE] == c.MODE_LITTLEGAME: 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_NUM] = c.START_LITTLE_GAME_NUM
self.game_info[c.LITTLEGAME_COMPLETIONS] += 1
self.done = True self.done = True
self.next = c.MAIN_MENU self.next = c.MAIN_MENU
pg.mixer.music.stop() 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.load(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "music", "intro.opus"))
pg.mixer.music.play(-1, 0) 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 return
# 是否有铲子的信息无铲子时为0有铲子时为1故直接赋值即可 # 是否有铲子的信息无铲子时为0有铲子时为1故直接赋值即可
self.hasShovel = self.map_data[c.SHOVEL] self.hasShovel = self.map_data[c.SHOVEL]
@ -542,7 +550,6 @@ class Level(tool.State):
elif self.checkMainMenuClick(mouse_pos): elif self.checkMainMenuClick(mouse_pos):
self.done = True self.done = True
self.next = c.MAIN_MENU 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]} 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.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.load(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "music", "intro.opus"))
@ -917,9 +924,9 @@ class Level(tool.State):
new_plant = plant.TangleKlep(x, y) new_plant = plant.TangleKlep(x, y)
case c.DOOMSHROOM: case c.DOOMSHROOM:
if self.map.gridHeightSize == c.GRID_Y_SIZE: if self.map.gridHeightSize == c.GRID_Y_SIZE:
new_plant = plant.DoomShroom(x, y, self.map.map[map_y][map_x][c.MAP_PLANT], explode_y_range=3)
else:
new_plant = plant.DoomShroom(x, y, self.map.map[map_y][map_x][c.MAP_PLANT], explode_y_range=2) new_plant = plant.DoomShroom(x, y, self.map.map[map_y][map_x][c.MAP_PLANT], explode_y_range=2)
else:
new_plant = plant.DoomShroom(x, y, self.map.map[map_y][map_x][c.MAP_PLANT], explode_y_range=3)
case c.GRAVEBUSTER: case c.GRAVEBUSTER:
new_plant = plant.GraveBuster(x, y, self.plant_groups[map_y], self.map, map_x) new_plant = plant.GraveBuster(x, y, self.plant_groups[map_y], self.map, map_x)
case c.FUMESHROOM: case c.FUMESHROOM:
@ -928,6 +935,7 @@ class Level(tool.State):
new_plant = plant.Garlic(x, y) new_plant = plant.Garlic(x, y)
if new_plant.can_sleep and self.background_type in c.DAYTIME_BACKGROUNDS: if new_plant.can_sleep and self.background_type in c.DAYTIME_BACKGROUNDS:
new_plant.setSleep() new_plant.setSleep()
mushroomSleep = True mushroomSleep = True
@ -1418,6 +1426,13 @@ class Level(tool.State):
self.done = True self.done = True
# 播放胜利音效 # 播放胜利音效
pg.mixer.Sound(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "sound", "win.ogg")).play() 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(): elif self.checkLose():
self.next = c.GAME_LOSE self.next = c.GAME_LOSE
self.done = True self.done = True

View File

@ -42,9 +42,28 @@ class Control():
self.state_dict = {} self.state_dict = {}
self.state_name = None self.state_name = None
self.state = None self.state = None
self.game_info = {c.CURRENT_TIME:0, try:
c.LEVEL_NUM:c.START_LEVEL_NUM, # 存在存档即导入
c.LITTLEGAME_NUM:c.START_LITTLE_GAME_NUM} 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): def setup_states(self, state_dict, start_state):
self.state_dict = state_dict self.state_dict = state_dict
@ -69,7 +88,8 @@ class Control():
if self.state.next == c.EXIT: if self.state.next == c.EXIT:
pg.quit() pg.quit()
os._exit(0) os._exit(0)
previous, self.state_name = self.state_name, self.state.next # previous, self.state_name = self.state_name, self.state.next
self.state_name = self.state.next
persist = self.state.cleanup() persist = self.state.cleanup()
self.state = self.state_dict[self.state_name] self.state = self.state_dict[self.state_name]
self.state.startup(self.current_time, persist) self.state.startup(self.current_time, persist)