Merge branch 'master' into opengl
This commit is contained in:
commit
3d84d34cc0
5
pypvz.py
5
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)
|
||||
|
||||
Binary file not shown.
@ -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
|
||||
{
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
@ -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):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user