Squashed commit of the following:
commit b6799a240bb2674f6b835b8402da609e22059030
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 20:03:55 2022 +0800
修改异常处理方式
commit dcf925ca526e66166c5b19b0b8442a32120a332d
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 19:51:06 2022 +0800
暂时放弃OpenGL
commit 2c0dc94c75d902aa356ee0b8350ea0aa02c84fdb
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 19:41:50 2022 +0800
更改非Nuitka程序图标设定
commit 1dd0894adffdafd61bd696807a6eb9d2735d4d25
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 19:16:21 2022 +0800
维护清理
commit b8a7fc0a66a22fae0ead9a9e4f88aa024276f078
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 14:43:51 2022 +0800
修复传送带模式中点击到达传送带底部的卡片没有透明度变化的bug
commit 9303304e94aabd4f955c3c186ff73525057bb133
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 14:21:47 2022 +0800
优化报纸僵尸设定
commit 0b9dbdc14513916dcb15dc717060faf380c1b681
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 14:17:26 2022 +0800
微调报纸僵尸速度
commit 44e6ce77e77fba19ebec22d08cdccf6d07246905
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 13:58:31 2022 +0800
清理
commit e00ed2f061ff148cbe0b38991a6ab585963ec9b3
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 13:58:05 2022 +0800
修复潜水僵尸只能攻击一次的bug
commit 790bc0bc5eeb206ebe769d91a4f339d050e86100
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri Jun 3 10:15:33 2022 +0800
更改构建命令
commit db86b3144ced0603c4db1e7220dbc47559b9dd87
Author: 星外之神 <wszqkzqk@qq.com>
Date: Thu Jun 2 19:03:13 2022 +0800
更改模块调用方式
commit 885f9902af79b2e23590956626e6eabe17e71931
Author: 星外之神 <wszqkzqk@qq.com>
Date: Wed Jun 1 14:15:50 2022 +0800
更新null值引用方式
commit d054ff498ba58356e9886064ae9c1a62fb0585a5
Author: 星外之神 <wszqkzqk@qq.com>
Date: Wed Jun 1 13:39:56 2022 +0800
进一步将常数性内容汇总到constants.py中
commit c4a756756b922cba8f8224b247bce7e7e7838808
Author: 星外之神 <wszqkzqk@qq.com>
Date: Fri May 27 15:23:52 2022 +0800
说明
This commit is contained in:
parent
cdf992095e
commit
783e0743ba
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -45,6 +45,7 @@ jobs:
|
||||
--distpath ./out `
|
||||
--noconsole `
|
||||
--add-data="resources;./resources" `
|
||||
--add-data="pypvz-exec-logo.png;./pypvz-exec-logo.png" `
|
||||
-i ./pypvz.ico
|
||||
|
||||
- name: Release the version built by pyinstaller
|
||||
@ -76,8 +77,8 @@ jobs:
|
||||
--include-data-file=c:\hostedtoolcache\windows\python\${{ matrix.python_version }}*\x64\lib\site-packages\pygame\libvorbisfile-3.dll=libvorbisfile-3.dll `
|
||||
--include-data-file=c:\hostedtoolcache\windows\python\${{ matrix.python_version }}*\x64\lib\site-packages\pygame\libvorbis-0.dll=libvorbis-0.dll `
|
||||
--windows-disable-console `
|
||||
-o ./out/pypvz-with-python${{ matrix.python_version }}-nuitka-msvc-x64.exe `
|
||||
main.py
|
||||
mv ./out/main.exe ./out/pypvz-with-python${{ matrix.python_version }}-nuitka-msvc-x64.exe
|
||||
|
||||
# artifact压缩包处上传包含exe和运行环境的文件夹
|
||||
- name: "Upload binaries"
|
||||
|
||||
BIN
pypvz-exec-logo.png
Normal file
BIN
pypvz-exec-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@ -44,7 +44,6 @@ class Map():
|
||||
# 判断位置是否可用
|
||||
# 暂时没有写紫卡植物的判断方法
|
||||
# 由于紫卡植物需要移除以前的植物,所以可用另外定义一个函数
|
||||
# 注意咖啡豆生效后需要同时将植物的睡眠状态和格子的睡眠记录改变
|
||||
def isAvailable(self, map_x, map_y, plantName):
|
||||
# 咖啡豆和墓碑吞噬者的判别最为特殊
|
||||
if plantName == c.COFFEEBEAN:
|
||||
@ -97,7 +96,7 @@ class Map():
|
||||
else: # 非水生植物,依赖睡莲
|
||||
if c.LILYPAD in self.map[map_y][map_x][c.MAP_PLANT]:
|
||||
if (all((i in {c.LILYPAD, '南瓜头(未实现)'}) for i in self.map[map_y][map_x][c.MAP_PLANT])
|
||||
and (plantName not in self.map[map_y][map_x][c.MAP_PLANT])): # 例外植物:集合中填花盆和南瓜头,只要这里没有这种植物就能种植;判断方法:并集
|
||||
and (plantName not in self.map[map_y][map_x][c.MAP_PLANT])):
|
||||
if plantName in {c.SPIKEWEED, c.POTATOMINE, '花盆(未实现)'}: # 不能在睡莲上种植的植物
|
||||
return False
|
||||
else:
|
||||
|
||||
@ -4,133 +4,6 @@ import pygame as pg
|
||||
from .. import tool
|
||||
from .. import constants as c
|
||||
|
||||
plantInfo = (# 元组 (植物名称, 卡片名称, 阳光, 冷却时间)
|
||||
(c.PEASHOOTER,
|
||||
c.CARD_PEASHOOTER,
|
||||
100,
|
||||
7500),
|
||||
(c.SUNFLOWER,
|
||||
c.CARD_SUNFLOWER,
|
||||
50,
|
||||
7500),
|
||||
(c.CHERRYBOMB,
|
||||
c.CARD_CHERRYBOMB,
|
||||
150,
|
||||
50000),
|
||||
(c.WALLNUT,
|
||||
c.CARD_WALLNUT,
|
||||
50,
|
||||
30000),
|
||||
(c.POTATOMINE,
|
||||
c.CARD_POTATOMINE,
|
||||
25,
|
||||
30000),
|
||||
(c.SNOWPEASHOOTER,
|
||||
c.CARD_SNOWPEASHOOTER,
|
||||
175,
|
||||
7500),
|
||||
(c.CHOMPER,
|
||||
c.CARD_CHOMPER,
|
||||
150,
|
||||
7500),
|
||||
(c.REPEATERPEA,
|
||||
c.CARD_REPEATERPEA,
|
||||
200,
|
||||
7500),
|
||||
(c.PUFFSHROOM,
|
||||
c.CARD_PUFFSHROOM,
|
||||
0,
|
||||
7500),
|
||||
(c.SUNSHROOM,
|
||||
c.CARD_SUNSHROOM,
|
||||
25,
|
||||
7500),
|
||||
(c.FUMESHROOM,
|
||||
c.CARD_FUMESHROOM,
|
||||
75,
|
||||
7500),
|
||||
(c.GRAVEBUSTER,
|
||||
c.CARD_GRAVEBUSTER,
|
||||
75,
|
||||
7500),
|
||||
(c.HYPNOSHROOM,
|
||||
c.CARD_HYPNOSHROOM,
|
||||
75,
|
||||
30000),
|
||||
(c.SCAREDYSHROOM,
|
||||
c.CARD_SCAREDYSHROOM,
|
||||
25,
|
||||
7500),
|
||||
(c.ICESHROOM,
|
||||
c.CARD_ICESHROOM,
|
||||
75,
|
||||
50000),
|
||||
(c.DOOMSHROOM,
|
||||
c.CARD_DOOMSHROOM,
|
||||
75,
|
||||
50000),
|
||||
(c.LILYPAD,
|
||||
c.CARD_LILYPAD,
|
||||
25,
|
||||
7500),
|
||||
(c.SQUASH,
|
||||
c.CARD_SQUASH,
|
||||
50,
|
||||
30000),
|
||||
(c.TANGLEKLEP,
|
||||
c.CARD_TANGLEKLEP,
|
||||
25,
|
||||
30000),
|
||||
(c.THREEPEASHOOTER,
|
||||
c.CARD_THREEPEASHOOTER,
|
||||
325,
|
||||
7500),
|
||||
(c.JALAPENO,
|
||||
c.CARD_JALAPENO,
|
||||
125,
|
||||
50000),
|
||||
(c.SPIKEWEED,
|
||||
c.CARD_SPIKEWEED,
|
||||
100,
|
||||
7500),
|
||||
(c.TORCHWOOD,
|
||||
c.CARD_TORCHWOOD,
|
||||
175,
|
||||
7500),
|
||||
(c.TALLNUT,
|
||||
c.CARD_TALLNUT,
|
||||
125,
|
||||
30000),
|
||||
(c.SEASHROOM,
|
||||
c.CARD_SEASHROOM,
|
||||
125,
|
||||
30000),
|
||||
(c.STARFRUIT,
|
||||
c.CARD_STARFRUIT,
|
||||
125,
|
||||
7500),
|
||||
(c.COFFEEBEAN,
|
||||
c.CARD_COFFEEBEAN,
|
||||
75,
|
||||
7500),
|
||||
(c.GARLIC,
|
||||
c.CARD_GARLIC,
|
||||
50,
|
||||
7500),
|
||||
# 应当保证这两个在一般模式下不可选的特殊植物恒在最后
|
||||
(c.WALLNUTBOWLING,
|
||||
c.CARD_WALLNUT,
|
||||
0,
|
||||
0),
|
||||
(c.REDWALLNUTBOWLING,
|
||||
c.CARD_REDWALLNUT,
|
||||
0,
|
||||
0),
|
||||
)
|
||||
|
||||
# 指定了哪些卡可选
|
||||
cards_to_choose = range(len(plantInfo) - 2)
|
||||
|
||||
|
||||
def getSunValueImage(sun_value):
|
||||
# for pack, must include ttf
|
||||
@ -152,7 +25,7 @@ def getSunValueImage(sun_value):
|
||||
def getCardPool(data):
|
||||
card_pool = []
|
||||
for card in data:
|
||||
for i,name in enumerate(plantInfo):
|
||||
for i,name in enumerate(c.PLANT_CARD_INFO):
|
||||
if name[c.PLANT_NAME_INDEX] == card:
|
||||
card_pool.append(i)
|
||||
break
|
||||
@ -160,14 +33,14 @@ def getCardPool(data):
|
||||
|
||||
class Card():
|
||||
def __init__(self, x, y, index, scale=0.5):
|
||||
self.loadFrame(plantInfo[index][c.CARD_INDEX], scale)
|
||||
self.loadFrame(c.PLANT_CARD_INFO[index][c.CARD_INDEX], scale)
|
||||
self.rect = self.orig_image.get_rect()
|
||||
self.rect.x = x
|
||||
self.rect.y = y
|
||||
|
||||
self.index = index
|
||||
self.sun_cost = plantInfo[index][c.SUN_INDEX]
|
||||
self.frozen_time = plantInfo[index][c.FROZEN_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_timer = -self.frozen_time
|
||||
self.refresh_timer = 0
|
||||
self.select = True
|
||||
@ -289,7 +162,7 @@ class MenuBar():
|
||||
for card in self.card_list:
|
||||
if card.checkMouseClick(mouse_pos):
|
||||
if card.canClick(self.sun_value, self.current_time):
|
||||
result = (plantInfo[card.index][c.PLANT_NAME_INDEX], card)
|
||||
result = (c.PLANT_CARD_INFO[card.index][c.PLANT_NAME_INDEX], card)
|
||||
break
|
||||
return result
|
||||
|
||||
@ -310,7 +183,7 @@ class MenuBar():
|
||||
|
||||
def setCardFrozenTime(self, plant_name):
|
||||
for card in self.card_list:
|
||||
if plantInfo[card.index][c.PLANT_NAME_INDEX] == plant_name:
|
||||
if c.PLANT_CARD_INFO[card.index][c.PLANT_NAME_INDEX] == plant_name:
|
||||
card.setFrozenTime(self.current_time)
|
||||
break
|
||||
|
||||
@ -440,7 +313,7 @@ class Panel():
|
||||
if self.selected_num >= c.CARD_LIST_NUM:
|
||||
surface.blit(self.button_image, self.button_rect)
|
||||
|
||||
# 传送带模式
|
||||
# 传送带模式的卡片
|
||||
class MoveCard():
|
||||
def __init__(self, x, y, card_name, plant_name, scale=0.5):
|
||||
self.loadFrame(card_name, scale)
|
||||
@ -526,8 +399,8 @@ class MoveBar():
|
||||
y = 6
|
||||
index = random.randint(0, len(self.card_pool) - 1)
|
||||
card_index = self.card_pool[index]
|
||||
card_name = plantInfo[card_index][c.CARD_INDEX] + '_move'
|
||||
plant_name = plantInfo[card_index][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
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from random import randint
|
||||
import random
|
||||
import pygame as pg
|
||||
import os
|
||||
from .. import tool
|
||||
@ -1143,7 +1143,7 @@ class WallNutBowling(Plant):
|
||||
self.animate_interval = 200
|
||||
self.move_timer = 0
|
||||
self.move_interval = 70
|
||||
self.vel_x = randint(12, 15)
|
||||
self.vel_x = random.randint(12, 15)
|
||||
self.vel_y = 0
|
||||
self.disable_hit_y = -1
|
||||
|
||||
@ -1192,7 +1192,7 @@ class WallNutBowling(Plant):
|
||||
elif self.map_y == (c.GRID_Y_LEN - 1): # 坚果保龄球显然没有泳池的6行情形
|
||||
self.vel_y = -self.vel_x
|
||||
else:
|
||||
if randint(0, 1):
|
||||
if random.randint(0, 1):
|
||||
self.vel_y = self.vel_x
|
||||
else:
|
||||
self.vel_y = -self.vel_x
|
||||
@ -1227,7 +1227,7 @@ class RedWallNutBowling(Plant):
|
||||
self.animate_interval = 200
|
||||
self.move_timer = 0
|
||||
self.move_interval = 70
|
||||
self.vel_x = randint(12, 15)
|
||||
self.vel_x = random.randint(12, 15)
|
||||
self.start_boom = False
|
||||
self.boomed = False
|
||||
|
||||
@ -1648,7 +1648,7 @@ class Hole(Plant):
|
||||
class Grave(Plant):
|
||||
def __init__(self, x, y):
|
||||
Plant.__init__(self, x, y, c.GRAVE, c.INF, None)
|
||||
self.frame_index = randint(0, self.frame_num - 1)
|
||||
self.frame_index = random.randint(0, self.frame_num - 1)
|
||||
self.image = self.frames[self.frame_index]
|
||||
self.mask = pg.mask.from_surface(self.image)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import pygame as pg
|
||||
import os
|
||||
from random import randint
|
||||
import random
|
||||
from .. import tool
|
||||
from .. import constants as c
|
||||
|
||||
@ -245,7 +245,8 @@ class Zombie(pg.sprite.Sprite):
|
||||
self.changeFrames(self.attack_frames)
|
||||
self.helmetType2 = False
|
||||
if self.name == c.NEWSPAPER_ZOMBIE:
|
||||
self.speed = 2.5
|
||||
self.speed = 2.65
|
||||
self.walk_animate_interval = 300
|
||||
if (((self.current_time - self.attack_timer) > (c.ATTACK_INTERVAL * self.getAttackTimeRatio()))
|
||||
and (not self.lostHead)):
|
||||
if self.prey.health > 0:
|
||||
@ -273,7 +274,7 @@ class Zombie(pg.sprite.Sprite):
|
||||
if self.checkToDie(self.losthead_attack_frames):
|
||||
return
|
||||
|
||||
if (self.current_time - self.freeze_timer) >= c.MIN_FREEZE_TIME + randint(0, 2000):
|
||||
if (self.current_time - self.freeze_timer) >= c.MIN_FREEZE_TIME + random.randint(0, 2000):
|
||||
self.setWalk()
|
||||
# 注意寒冰菇解冻后还有减速
|
||||
self.ice_slow_timer = self.freeze_timer + 10000 # 每次冰冻冻结 + 减速时间为20 s,而减速有10 s计时,故这里+10 s
|
||||
@ -737,6 +738,7 @@ class NewspaperZombie(Zombie):
|
||||
self.changeFrames(self.walk_frames)
|
||||
self.speedUp = True
|
||||
self.speed = 2.65
|
||||
self.walk_animate_interval = 300
|
||||
# 触发报纸僵尸暴走音效
|
||||
pg.mixer.Sound(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "sound", "newspaperZombieAngry.ogg")).play()
|
||||
return
|
||||
@ -1252,3 +1254,10 @@ class SnorkelZombie(Zombie):
|
||||
self.changeFrames(self.float_frames)
|
||||
self.canSetAttack = False
|
||||
|
||||
def setWalk(self):
|
||||
self.state = c.WALK
|
||||
self.animate_interval = self.walk_animate_interval
|
||||
|
||||
if self.rect.right <= c.MAP_POOL_FRONT_X:
|
||||
self.swimming = True
|
||||
self.changeFrames(self.sink_frames)
|
||||
|
||||
@ -8,6 +8,8 @@ GAME_RATE = 1
|
||||
|
||||
# 窗口标题
|
||||
ORIGINAL_CAPTION = 'pypvz'
|
||||
# 窗口图标
|
||||
ORIGINAL_LOGO = "pypvz-exec-logo.png"
|
||||
|
||||
# 游戏模式
|
||||
GAME_MODE = 'mode'
|
||||
@ -55,8 +57,6 @@ GREEN = ( 0, 255, 0)
|
||||
|
||||
# 退出游戏按钮
|
||||
EXIT = 'exit'
|
||||
# 当想要一个特殊值时用
|
||||
NULL = 'null'
|
||||
# 游戏界面可选的菜单
|
||||
LITTLE_MENU = 'littleMenu'
|
||||
BIG_MENU = 'bigMenu'
|
||||
@ -342,7 +342,7 @@ ICE_SLOW_TIME = 10000
|
||||
MIN_FREEZE_TIME = 4000
|
||||
ICETRAP = 'IceTrap'
|
||||
|
||||
# 植物卡片信息
|
||||
# 植物卡片名称
|
||||
CARD_SUNFLOWER = 'card_sunflower'
|
||||
CARD_PEASHOOTER = 'card_peashooter'
|
||||
CARD_SNOWPEASHOOTER = 'card_snowpea'
|
||||
@ -373,6 +373,136 @@ CARD_GRAVEBUSTER = 'card_gravebuster'
|
||||
CARD_FUMESHROOM = 'card_fumeshroom'
|
||||
CARD_GARLIC = 'card_garlic'
|
||||
|
||||
|
||||
# 植物卡片信息汇总(包括植物名称, 卡片名称, 阳光, 冷却时间)
|
||||
PLANT_CARD_INFO = (# 元组 (植物名称, 卡片名称, 阳光, 冷却时间)
|
||||
(PEASHOOTER,
|
||||
CARD_PEASHOOTER,
|
||||
100,
|
||||
7500),
|
||||
(SUNFLOWER,
|
||||
CARD_SUNFLOWER,
|
||||
50,
|
||||
7500),
|
||||
(CHERRYBOMB,
|
||||
CARD_CHERRYBOMB,
|
||||
150,
|
||||
50000),
|
||||
(WALLNUT,
|
||||
CARD_WALLNUT,
|
||||
50,
|
||||
30000),
|
||||
(POTATOMINE,
|
||||
CARD_POTATOMINE,
|
||||
25,
|
||||
30000),
|
||||
(SNOWPEASHOOTER,
|
||||
CARD_SNOWPEASHOOTER,
|
||||
175,
|
||||
7500),
|
||||
(CHOMPER,
|
||||
CARD_CHOMPER,
|
||||
150,
|
||||
7500),
|
||||
(REPEATERPEA,
|
||||
CARD_REPEATERPEA,
|
||||
200,
|
||||
7500),
|
||||
(PUFFSHROOM,
|
||||
CARD_PUFFSHROOM,
|
||||
0,
|
||||
7500),
|
||||
(SUNSHROOM,
|
||||
CARD_SUNSHROOM,
|
||||
25,
|
||||
7500),
|
||||
(FUMESHROOM,
|
||||
CARD_FUMESHROOM,
|
||||
75,
|
||||
7500),
|
||||
(GRAVEBUSTER,
|
||||
CARD_GRAVEBUSTER,
|
||||
75,
|
||||
7500),
|
||||
(HYPNOSHROOM,
|
||||
CARD_HYPNOSHROOM,
|
||||
75,
|
||||
30000),
|
||||
(SCAREDYSHROOM,
|
||||
CARD_SCAREDYSHROOM,
|
||||
25,
|
||||
7500),
|
||||
(ICESHROOM,
|
||||
CARD_ICESHROOM,
|
||||
75,
|
||||
50000),
|
||||
(DOOMSHROOM,
|
||||
CARD_DOOMSHROOM,
|
||||
75,
|
||||
50000),
|
||||
(LILYPAD,
|
||||
CARD_LILYPAD,
|
||||
25,
|
||||
7500),
|
||||
(SQUASH,
|
||||
CARD_SQUASH,
|
||||
50,
|
||||
30000),
|
||||
(TANGLEKLEP,
|
||||
CARD_TANGLEKLEP,
|
||||
25,
|
||||
30000),
|
||||
(THREEPEASHOOTER,
|
||||
CARD_THREEPEASHOOTER,
|
||||
325,
|
||||
7500),
|
||||
(JALAPENO,
|
||||
CARD_JALAPENO,
|
||||
125,
|
||||
50000),
|
||||
(SPIKEWEED,
|
||||
CARD_SPIKEWEED,
|
||||
100,
|
||||
7500),
|
||||
(TORCHWOOD,
|
||||
CARD_TORCHWOOD,
|
||||
175,
|
||||
7500),
|
||||
(TALLNUT,
|
||||
CARD_TALLNUT,
|
||||
125,
|
||||
30000),
|
||||
(SEASHROOM,
|
||||
CARD_SEASHROOM,
|
||||
125,
|
||||
30000),
|
||||
(STARFRUIT,
|
||||
CARD_STARFRUIT,
|
||||
125,
|
||||
7500),
|
||||
(COFFEEBEAN,
|
||||
CARD_COFFEEBEAN,
|
||||
75,
|
||||
7500),
|
||||
(c.GARLIC,
|
||||
c.CARD_GARLIC,
|
||||
50,
|
||||
7500),
|
||||
# 应当保证这两个在一般模式下不可选的特殊植物恒在最后
|
||||
(WALLNUTBOWLING,
|
||||
CARD_WALLNUT,
|
||||
0,
|
||||
0),
|
||||
(REDWALLNUTBOWLING,
|
||||
CARD_REDWALLNUT,
|
||||
0,
|
||||
0),
|
||||
)
|
||||
|
||||
# 指定了哪些卡可选(排除坚果保龄球特殊植物)
|
||||
CARDS_TO_CHOOSE = range(len(PLANT_CARD_INFO) - 2)
|
||||
|
||||
|
||||
# 子弹信息
|
||||
# 子弹类型
|
||||
BULLET_PEA = 'PeaNormal'
|
||||
|
||||
@ -2,7 +2,7 @@ import os
|
||||
import json
|
||||
import sys
|
||||
import pygame as pg
|
||||
from random import randint, uniform, choices
|
||||
import random
|
||||
from .. import tool
|
||||
from .. import constants as c
|
||||
from ..component import map, plant, zombie, menubar
|
||||
@ -41,7 +41,7 @@ class Level(tool.State):
|
||||
f = open(file_path)
|
||||
self.map_data = json.load(f)
|
||||
f.close()
|
||||
except Exception:
|
||||
except:
|
||||
print("成功通关!")
|
||||
if self.game_info[c.GAME_MODE] == c.MODE_LITTLEGAME:
|
||||
self.game_info[c.LEVEL_NUM] = c.START_LEVEL_NUM
|
||||
@ -147,7 +147,7 @@ class Level(tool.State):
|
||||
minCost = c.CREATE_ZOMBIE_DICT[min(useableZombies, key=lambda x:c.CREATE_ZOMBIE_DICT[x][0])][0]
|
||||
|
||||
while (volume >= minCost) and (len(zombieList) < 50):
|
||||
newZombie = choices(useableZombies, weights)[0]
|
||||
newZombie = random.choices(useableZombies, weights)[0]
|
||||
# 普通僵尸、路障僵尸、铁桶僵尸有概率生成水中变种
|
||||
if self.background_type in c.POOL_EQUIPPED_BACKGROUNDS:
|
||||
# 有泳池第一轮的第四波设定上生成水生僵尸
|
||||
@ -155,7 +155,7 @@ class Level(tool.State):
|
||||
if newZombie in c.CONVERT_ZOMBIE_IN_POOL:
|
||||
newZombie = c.CONVERT_ZOMBIE_IN_POOL[newZombie]
|
||||
elif survivalRounds > 0 or wave > 4:
|
||||
if randint(1, 3) == 1: # 1/3概率水上,暂时人为设定
|
||||
if random.randint(1, 3) == 1: # 1/3概率水上,暂时人为设定
|
||||
if newZombie in c.CONVERT_ZOMBIE_IN_POOL:
|
||||
newZombie = c.CONVERT_ZOMBIE_IN_POOL[newZombie]
|
||||
# 首先几轮不出水生僵尸
|
||||
@ -165,7 +165,7 @@ class Level(tool.State):
|
||||
zombieList.append(newZombie)
|
||||
volume -= c.CREATE_ZOMBIE_DICT[newZombie][0]
|
||||
waves.append(zombieList)
|
||||
#print(wave, zombieList, len(zombieList))
|
||||
# print(wave, zombieList, len(zombieList))
|
||||
|
||||
self.waves = waves
|
||||
|
||||
@ -201,20 +201,20 @@ class Level(tool.State):
|
||||
elif c.GRAVE not in self.map.map[mapY][mapX][c.MAP_PLANT]:
|
||||
occupied.append((mapX, mapY))
|
||||
if unoccupied:
|
||||
target = unoccupied[randint(0, len(unoccupied) - 1)]
|
||||
target = unoccupied[random.randint(0, len(unoccupied) - 1)]
|
||||
mapX, mapY = target
|
||||
posX, posY = self.map.getMapGridPos(mapX, mapY)
|
||||
self.plant_groups[mapY].add(plant.Grave(posX, posY))
|
||||
self.map.map[mapY][mapX][c.MAP_PLANT].add(c.GRAVE)
|
||||
self.graveSet.add((mapX, mapY))
|
||||
elif occupied:
|
||||
target = occupied[randint(0, len(occupied) - 1)]
|
||||
target = occupied[random.randint(0, len(occupied) - 1)]
|
||||
mapX, mapY = target
|
||||
posX, posY = self.map.getMapGridPos(mapX, mapY)
|
||||
for i in self.plant_groups[mapY]:
|
||||
checkMapX, _ = self.map.getMapIndex(i.rect.centerx, i.rect.bottom)
|
||||
if mapX == checkMapX:
|
||||
# 不能杀死毁灭菇坑和冰道
|
||||
# 不杀死毁灭菇坑和冰道
|
||||
if i.name not in exceptionObjects:
|
||||
i.health = 0
|
||||
self.plant_groups[mapY].add(plant.Grave(posX, posY))
|
||||
@ -227,7 +227,7 @@ class Level(tool.State):
|
||||
for item in self.graveSet:
|
||||
itemX, itemY = self.map.getMapGridPos(*item)
|
||||
# 目前设定:2/3概率普通僵尸,1/3概率路障僵尸
|
||||
if randint(0, 2):
|
||||
if random.randint(0, 2):
|
||||
self.zombie_groups[item[1]].add(zombie.NormalZombie(itemX, itemY, self.head_group))
|
||||
else:
|
||||
self.zombie_groups[item[1]].add(zombie.ConeHeadZombie(itemX, itemY, self.head_group))
|
||||
@ -237,11 +237,11 @@ class Level(tool.State):
|
||||
if current_time - self.waveTime > 1500:
|
||||
for i in range(3):
|
||||
# 水中倒数四列内可以在此时产生僵尸。共产生3个
|
||||
mapX, mapY = randint(5, 8), randint(2, 3)
|
||||
mapX, mapY = random.randint(5, 8), random.randint(2, 3)
|
||||
itemX, itemY = self.map.getMapGridPos(mapX, mapY)
|
||||
# 用随机数指定产生的僵尸类型
|
||||
# 带有权重
|
||||
zombieType = randint(1, 6)
|
||||
zombieType = random.randint(1, 6)
|
||||
if zombieType == 1:
|
||||
self.zombie_groups[mapY].add(zombie.BucketHeadDuckyTubeZombie(itemX, itemY, self.head_group))
|
||||
elif zombieType <= 3:
|
||||
@ -272,7 +272,7 @@ class Level(tool.State):
|
||||
pg.mixer.Sound(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))) ,"resources", "sound", "zombieComing.ogg")).play()
|
||||
return
|
||||
if (self.waveNum % 10 != 9):
|
||||
if ((current_time - self.waveTime >= 25000 + randint(0, 6000)) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.waveTime >= 12500 + randint(0, 3000))):
|
||||
if ((current_time - self.waveTime >= 25000 + random.randint(0, 6000)) or (self.bar_type != c.CHOOSEBAR_STATIC and current_time - self.waveTime >= 12500 + random.randint(0, 3000))):
|
||||
self.waveNum += 1
|
||||
self.waveTime = current_time
|
||||
self.waveZombies = self.waves[self.waveNum - 1]
|
||||
@ -293,7 +293,7 @@ class Level(tool.State):
|
||||
numZombies = 0
|
||||
for i in range(self.map_y_len):
|
||||
numZombies += len(self.zombie_groups[i])
|
||||
if (numZombies / self.numZombie < uniform(0.15, 0.25)) and (current_time - self.waveTime > 4000):
|
||||
if (numZombies / self.numZombie < random.uniform(0.15, 0.25)) and (current_time - self.waveTime > 4000):
|
||||
# 当僵尸所剩无几并且时间过了4000 ms以上时,改变时间记录,使得2000 ms后刷新僵尸(所以需要判断剩余时间是否大于2000 ms)
|
||||
if self.bar_type == c.CHOOSEBAR_STATIC:
|
||||
if current_time - 43000 < self.waveTime: # 判断剩余时间是否有2000 ms
|
||||
@ -364,7 +364,7 @@ class Level(tool.State):
|
||||
|
||||
def initChoose(self):
|
||||
self.state = c.CHOOSE
|
||||
self.panel = menubar.Panel(menubar.cards_to_choose, self.map_data[c.INIT_SUN_NAME])
|
||||
self.panel = menubar.Panel(c.CARDS_TO_CHOOSE, self.map_data[c.INIT_SUN_NAME])
|
||||
|
||||
# 播放选卡音乐
|
||||
pg.mixer.music.stop()
|
||||
@ -417,7 +417,7 @@ class Level(tool.State):
|
||||
|
||||
self.removeMouseImage()
|
||||
self.setupGroups()
|
||||
if (c.ZOMBIE_LIST in self.map_data) and self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST:
|
||||
if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST:
|
||||
self.setupZombies()
|
||||
else:
|
||||
# 僵尸波数数据及僵尸生成数据
|
||||
@ -468,8 +468,8 @@ class Level(tool.State):
|
||||
graveVolume = c.GRAVES_GRADE_INFO[gradeGraves]
|
||||
self.graveSet = set()
|
||||
while len(self.graveSet) < graveVolume:
|
||||
mapX = randint(4, 8) # 注意是从0开始编号
|
||||
mapY = randint(0, 4)
|
||||
mapX = random.randint(4, 8) # 注意是从0开始编号
|
||||
mapY = random.randint(0, 4)
|
||||
self.graveSet.add((mapX, mapY))
|
||||
if self.graveSet:
|
||||
for i in self.graveSet:
|
||||
@ -656,7 +656,7 @@ class Level(tool.State):
|
||||
self.pauseAndCheckLittleMenuOptions(mouse_pos, mouse_click)
|
||||
return
|
||||
|
||||
if (c.ZOMBIE_LIST in self.map_data) and self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST:
|
||||
if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST:
|
||||
# 旧僵尸生成方式
|
||||
if self.zombie_start_time == 0:
|
||||
self.zombie_start_time = self.current_time
|
||||
@ -694,7 +694,7 @@ class Level(tool.State):
|
||||
|
||||
if self.produce_sun:
|
||||
# 原版阳光掉落机制:(已掉落阳光数*100 ms + 4250 ms) 与 9500 ms的最小值,再加 0 ~ 2750 ms 之间的一个数
|
||||
if (self.current_time - self.sun_timer) > min(c.PRODUCE_SUN_INTERVAL + 100*self.fallenSun, 9500) + randint(0, 2750):
|
||||
if (self.current_time - self.sun_timer) > min(c.PRODUCE_SUN_INTERVAL + 100*self.fallenSun, 9500) + random.randint(0, 2750):
|
||||
self.sun_timer = self.current_time
|
||||
map_x, map_y = self.map.getRandomMapIndex()
|
||||
x, y = self.map.getMapGridPos(map_x, map_y)
|
||||
@ -728,8 +728,8 @@ class Level(tool.State):
|
||||
clickedCardsOrMap = True
|
||||
self.clickResult[1].clicked = False
|
||||
elif mouse_click[0]:
|
||||
self.clickResult[1].clicked = False
|
||||
if self.menubar.checkMenuBarClick(mouse_pos):
|
||||
self.clickResult[1].clicked = False
|
||||
self.removeMouseImage()
|
||||
else:
|
||||
self.addPlant()
|
||||
@ -778,22 +778,22 @@ class Level(tool.State):
|
||||
# 情况复杂:分水路和陆路,不能简单实现,需要另外加判断
|
||||
# 0, 1, 4, 5路为陆路,2, 3路为水路
|
||||
if self.map_data[c.BACKGROUND_TYPE] in c.POOL_EQUIPPED_BACKGROUNDS:
|
||||
if name in c.WATER_ZOMBIE: # 水生僵尸集合
|
||||
map_y = randint(2, 3)
|
||||
if name in c.WATER_ZOMBIE:
|
||||
map_y = random.randint(2, 3)
|
||||
elif name == '这里应该换成气球僵尸的名字(最好写调用的变量名,最好不要直接写,保持风格统一)':
|
||||
map_y = randint(0, 5)
|
||||
map_y = random.randint(0, 5)
|
||||
else: # 陆生僵尸
|
||||
map_y = randint(0, 3)
|
||||
map_y = random.randint(0, 3)
|
||||
if map_y >= 2: # 后两路的map_y应当+2
|
||||
map_y += 2
|
||||
elif self.map_data[c.BACKGROUND_TYPE] == c.BACKGROUND_SINGLE:
|
||||
map_y = 2
|
||||
elif self.map_data[c.BACKGROUND_TYPE] == c.BACKGROUND_TRIPLE:
|
||||
map_y = randint(1, 3)
|
||||
map_y = random.randint(1, 3)
|
||||
else:
|
||||
map_y = randint(0, 4)
|
||||
map_y = random.randint(0, 4)
|
||||
|
||||
if not ((c.ZOMBIE_LIST in self.map_data) and self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST):
|
||||
if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_AUTO:
|
||||
# 旗帜波出生点右移
|
||||
if self.waveNum % 10:
|
||||
hugeWaveMove = 0
|
||||
@ -802,35 +802,37 @@ class Level(tool.State):
|
||||
else:
|
||||
hugeWaveMove = 0
|
||||
x, y = self.map.getMapGridPos(0, map_y)
|
||||
|
||||
# 新增的僵尸也需要在这里声明
|
||||
if name == c.NORMAL_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.NormalZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.NormalZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.CONEHEAD_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.ConeHeadZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.ConeHeadZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.BUCKETHEAD_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.BucketHeadZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.BucketHeadZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.FLAG_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.FlagZombie(c.ZOMBIE_START_X, y, self.head_group))
|
||||
elif name == c.NEWSPAPER_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.NewspaperZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.NewspaperZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.FOOTBALL_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.FootballZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.FootballZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.DUCKY_TUBE_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.DuckyTubeZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.DuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.CONEHEAD_DUCKY_TUBE_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.ConeHeadDuckyTubeZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.ConeHeadDuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.BUCKETHEAD_DUCKY_TUBE_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.BucketHeadDuckyTubeZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.BucketHeadDuckyTubeZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.SCREEN_DOOR_ZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.ScreenDoorZombie(c.ZOMBIE_START_X + randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.ScreenDoorZombie(c.ZOMBIE_START_X + random.randint(-20, 20) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.POLE_VAULTING_ZOMBIE:
|
||||
# 本来撑杆跳生成位置不同,对齐左端可认为修正了一部分(看作移动了70),只需要相对修改即可
|
||||
self.zombie_groups[map_y].add(zombie.PoleVaultingZombie(c.ZOMBIE_START_X + randint(0, 10) + hugeWaveMove, y, self.head_group))
|
||||
self.zombie_groups[map_y].add(zombie.PoleVaultingZombie(c.ZOMBIE_START_X + random.randint(0, 10) + hugeWaveMove, y, self.head_group))
|
||||
elif name == c.ZOMBONI:
|
||||
# 冰车僵尸生成位置不同
|
||||
self.zombie_groups[map_y].add(zombie.Zomboni(c.ZOMBIE_START_X + randint(0, 10) + hugeWaveMove, y, self.plant_groups[map_y], self.map, plant.IceFrozenPlot))
|
||||
self.zombie_groups[map_y].add(zombie.Zomboni(c.ZOMBIE_START_X + random.randint(0, 10) + hugeWaveMove, y, self.plant_groups[map_y], self.map, plant.IceFrozenPlot))
|
||||
elif name == c.SNORKELZOMBIE:
|
||||
self.zombie_groups[map_y].add(zombie.SnorkelZombie(c.ZOMBIE_START_X + randint(0, 10) + hugeWaveMove, y, self.head_group))
|
||||
# 潜水僵尸生成位置不同
|
||||
self.zombie_groups[map_y].add(zombie.SnorkelZombie(c.ZOMBIE_START_X + random.randint(0, 10) + hugeWaveMove, y, self.head_group))
|
||||
|
||||
# 能否种植物的判断:
|
||||
# 先判断位置是否合法 isValid(map_x, map_y)
|
||||
@ -845,6 +847,9 @@ class Level(tool.State):
|
||||
if pos is None:
|
||||
return
|
||||
|
||||
# 恢复植物卡片样式
|
||||
self.clickResult[1].clicked = False
|
||||
|
||||
if self.hint_image is None:
|
||||
self.setupHintImage()
|
||||
x, y = self.hint_rect.centerx, self.hint_rect.bottom
|
||||
@ -924,7 +929,7 @@ class Level(tool.State):
|
||||
mushroomSleep = False
|
||||
self.plant_groups[map_y].add(new_plant)
|
||||
# 种植植物后应当刷新僵尸的攻击对象
|
||||
# 这里用植物名称代替布尔值,保存更多信息
|
||||
# 用元组表示植物的名称和格子坐标
|
||||
self.newPlantAndPositon = (new_plant.name, (map_x, map_y))
|
||||
if self.bar_type == c.CHOOSEBAR_STATIC:
|
||||
self.menubar.decreaseSunValue(self.select_plant.sun_cost)
|
||||
@ -932,7 +937,7 @@ class Level(tool.State):
|
||||
else:
|
||||
self.menubar.deleateCard(self.select_plant)
|
||||
|
||||
if self.bar_type != c.CHOSSEBAR_BOWLING:
|
||||
if self.bar_type != c.CHOSSEBAR_BOWLING: # 坚果保龄球关卡无需考虑格子被占用的情况
|
||||
self.map.addMapPlant(map_x, map_y, self.plant_name, sleep=mushroomSleep)
|
||||
self.removeMouseImage()
|
||||
|
||||
@ -1149,8 +1154,8 @@ class Level(tool.State):
|
||||
for hypno_zombie in self.hypno_zombie_groups[i]:
|
||||
if hypno_zombie.health <= 0:
|
||||
continue
|
||||
zombie_list = pg.sprite.spritecollide(hypno_zombie,
|
||||
self.zombie_groups[i], False,collided_func)
|
||||
zombie_list = pg.sprite.spritecollide( hypno_zombie, self.zombie_groups[i],
|
||||
False, collided_func)
|
||||
for zombie in zombie_list:
|
||||
if zombie.state == c.DIE:
|
||||
continue
|
||||
@ -1372,7 +1377,7 @@ class Level(tool.State):
|
||||
self.killPlant(plant)
|
||||
|
||||
def checkVictory(self):
|
||||
if (c.ZOMBIE_LIST in self.map_data) and self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST:
|
||||
if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST:
|
||||
if len(self.zombie_list) > 0:
|
||||
return False
|
||||
for i in range(self.map_y_len):
|
||||
@ -1522,7 +1527,7 @@ class Level(tool.State):
|
||||
surface.blit(self.restart_button, self.restart_button_rect)
|
||||
surface.blit(self.mainMenu_button, self.mainMenu_button_rect)
|
||||
|
||||
if not ((c.ZOMBIE_LIST in self.map_data) and self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_LIST):
|
||||
if self.map_data[c.SPAWN_ZOMBIES] == c.SPAWN_ZOMBIES_AUTO:
|
||||
self.showLevelProgress(surface)
|
||||
if self.current_time - self.showHugeWaveApprochingTime <= 2000:
|
||||
surface.blit(self.huge_wave_approching_image, self.huge_wave_approching_image_rect)
|
||||
|
||||
@ -97,7 +97,7 @@ class Control():
|
||||
while not self.done:
|
||||
self.event_loop()
|
||||
self.update()
|
||||
pg.display.flip()
|
||||
pg.display.update()
|
||||
self.clock.tick(self.fps)
|
||||
print('game over')
|
||||
|
||||
@ -106,7 +106,7 @@ def get_image(sheet, x, y, width, height, colorkey=c.BLACK, scale=1):
|
||||
rect = image.get_rect()
|
||||
|
||||
image.blit(sheet, (0, 0), (x, y, width, height))
|
||||
if colorkey != c.NULL:
|
||||
if colorkey:
|
||||
image.set_colorkey(colorkey)
|
||||
image = pg.transform.scale(image,
|
||||
(int(rect.width*scale),
|
||||
@ -203,6 +203,10 @@ def loadPlantImageRect():
|
||||
pg.init()
|
||||
pg.display.set_caption(c.ORIGINAL_CAPTION) # 设置标题
|
||||
SCREEN = pg.display.set_mode(c.SCREEN_SIZE) # 设置初始屏幕
|
||||
try: # 设置窗口图标,仅对非Nuitka时生效,Nuitka不需要包括额外的图标文件,自动跳过这一过程即可
|
||||
pg.display.set_icon(pg.image.load(os.path.join(os.path.dirname(os.path.dirname(__file__)), c.ORIGINAL_LOGO)))
|
||||
except:
|
||||
pass
|
||||
|
||||
GFX = load_all_gfx(os.path.join(os.path.dirname(os.path.dirname(__file__)) ,os.path.join("resources","graphics")))
|
||||
ZOMBIE_RECT = loadZombieImageRect()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user