Merge branch 'master' into opengl
30
README.md
@ -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()`
|
||||||
* 可以用`音量+`、`音量-`按钮实现
|
* 可以用`音量+`、`音量-`按钮实现
|
||||||
|
|||||||
@ -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
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.8 KiB |
@ -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):
|
||||||
|
|||||||
@ -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声明一次,以后仅需调用即可
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||