diff --git a/.gitignore b/.gitignore index 38fc5da..fd0b526 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,9 @@ -# Cache after running the app -__pycache__/ +<<<<<<< HEAD +# ignore debug out/ -build/ \ No newline at end of file +build/ +.vscode/ +__pycache__/ +*/__pycache__/ +# ignore test +test.py diff --git a/main.py b/main.py index 2964ddc..e8b9b85 100755 --- a/main.py +++ b/main.py @@ -1,7 +1,15 @@ #!/usr/bin/env python import pygame as pg -from source.main import main +from source import tool +from source import constants as c +from source.state import mainmenu, screen, level if __name__=='__main__': - main() - pg.quit() + # 控制状态机运行 + game = tool.Control() + state_dict = {c.MAIN_MENU: mainmenu.Menu(), + c.GAME_VICTORY: screen.GameVictoryScreen(), + c.GAME_LOSE: screen.GameLoseScreen(), + c.LEVEL: level.Level()} + game.setup_states(state_dict, c.MAIN_MENU) + game.run() diff --git a/resources/about.drawio b/resources/about.drawio new file mode 100644 index 0000000..73212b2 --- /dev/null +++ b/resources/about.drawio @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/data/entity/plant.json b/resources/data/entity/plant.json similarity index 100% rename from source/data/entity/plant.json rename to resources/data/entity/plant.json diff --git a/source/data/entity/zombie.json b/resources/data/entity/zombie.json similarity index 100% rename from source/data/entity/zombie.json rename to resources/data/entity/zombie.json diff --git a/source/data/map/level_0.json b/resources/data/map/level_0.json similarity index 88% rename from source/data/map/level_0.json rename to resources/data/map/level_0.json index c22fd75..c9c9ef0 100644 --- a/source/data/map/level_0.json +++ b/resources/data/map/level_0.json @@ -1,6 +1,7 @@ { "background_type":0, "init_sun_value":500, + "shovel":1, "zombie_list":[ {"time":1000, "map_y":2, "name":"Zombie"} ] diff --git a/resources/data/map/level_1.json b/resources/data/map/level_1.json new file mode 100644 index 0000000..575c4e2 --- /dev/null +++ b/resources/data/map/level_1.json @@ -0,0 +1,20 @@ +{ + "background_type": 0, + "init_sun_value": 50, + "shovel": 1, + "zombie_list": [ + { "time": 20000, "map_y": 0, "name": "Zombie" }, + { "time": 40000, "map_y": 2, "name": "FlagZombie" }, + { "time": 50000, "map_y": 4, "name": "Zombie" }, + { "time": 70000, "map_y": 3, "name": "Zombie" }, + { "time": 72000, "map_y": 1, "name": "FlagZombie" }, + { "time": 74000, "map_y": 2, "name": "Zombie" }, + { "time": 90000, "map_y": 0, "name": "Zombie" }, + { "time": 91000, "map_y": 1, "name": "FlagZombie" }, + { "time": 92000, "map_y": 2, "name": "Zombie" }, + { "time": 93000, "map_y": 3, "name": "FlagZombie" }, + { "time": 94000, "map_y": 0, "name": "Zombie" }, + { "time": 95000, "map_y": 4, "name": "FlagZombie" }, + { "time": 96000, "map_y": 1, "name": "Zombie" } + ] +} \ No newline at end of file diff --git a/source/data/map/level_2.json b/resources/data/map/level_2.json similarity index 97% rename from source/data/map/level_2.json rename to resources/data/map/level_2.json index b3d9170..f3c452d 100644 --- a/source/data/map/level_2.json +++ b/resources/data/map/level_2.json @@ -1,6 +1,7 @@ { "background_type":0, "init_sun_value":50, + "shovel":1, "zombie_list":[ {"time":20000, "map_y":0, "name":"Zombie"}, {"time":40000, "map_y":2, "name":"FlagZombie"}, diff --git a/source/data/map/level_3.json b/resources/data/map/level_3.json similarity index 98% rename from source/data/map/level_3.json rename to resources/data/map/level_3.json index 04ad595..4fd8d99 100644 --- a/source/data/map/level_3.json +++ b/resources/data/map/level_3.json @@ -1,6 +1,7 @@ { "background_type":1, "init_sun_value":50, + "shovel":1, "zombie_list":[ {"time":20000, "map_y":0, "name":"Zombie"}, {"time":40000, "map_y":2, "name":"ConeheadZombie"}, diff --git a/source/data/map/level_4.json b/resources/data/map/littleGame_1.json similarity index 99% rename from source/data/map/level_4.json rename to resources/data/map/littleGame_1.json index aaa525b..d03ece5 100644 --- a/source/data/map/level_4.json +++ b/resources/data/map/littleGame_1.json @@ -1,6 +1,7 @@ { "background_type":0, "choosebar_type":1, + "shovel":1, "card_pool":[ {"name":"Peashooter"}, {"name":"SnowPea"}, diff --git a/source/data/map/level_5.json b/resources/data/map/littleGame_2.json similarity index 98% rename from source/data/map/level_5.json rename to resources/data/map/littleGame_2.json index 343c68b..ac4bbf8 100644 --- a/source/data/map/level_5.json +++ b/resources/data/map/littleGame_2.json @@ -1,6 +1,7 @@ { "background_type":4, "choosebar_type":2, + "shovel":0, "card_pool":[ {"name":"WallNutBowling"}, {"name":"RedWallNutBowling"} diff --git a/resources/graphics/Screen/bigMenu.png b/resources/graphics/Screen/bigMenu.png new file mode 100644 index 0000000..450528a Binary files /dev/null and b/resources/graphics/Screen/bigMenu.png differ diff --git a/resources/graphics/Screen/exit.png b/resources/graphics/Screen/exit.png new file mode 100644 index 0000000..2a9e218 Binary files /dev/null and b/resources/graphics/Screen/exit.png differ diff --git a/resources/graphics/Screen/littleGameButton.png b/resources/graphics/Screen/littleGameButton.png new file mode 100644 index 0000000..affaec1 Binary files /dev/null and b/resources/graphics/Screen/littleGameButton.png differ diff --git a/resources/graphics/Screen/littleMenu.png b/resources/graphics/Screen/littleMenu.png new file mode 100644 index 0000000..17b8abf Binary files /dev/null and b/resources/graphics/Screen/littleMenu.png differ diff --git a/resources/graphics/Screen/mainMenuButton.png b/resources/graphics/Screen/mainMenuButton.png new file mode 100644 index 0000000..4aec146 Binary files /dev/null and b/resources/graphics/Screen/mainMenuButton.png differ diff --git a/resources/graphics/Screen/restartButton.png b/resources/graphics/Screen/restartButton.png new file mode 100644 index 0000000..2006ce5 Binary files /dev/null and b/resources/graphics/Screen/restartButton.png differ diff --git a/resources/graphics/Screen/returnButton.png b/resources/graphics/Screen/returnButton.png new file mode 100644 index 0000000..3bcf241 Binary files /dev/null and b/resources/graphics/Screen/returnButton.png differ diff --git a/resources/graphics/Screen/shovel.png b/resources/graphics/Screen/shovel.png new file mode 100644 index 0000000..d4da67f Binary files /dev/null and b/resources/graphics/Screen/shovel.png differ diff --git a/resources/graphics/Screen/shovelBox.png b/resources/graphics/Screen/shovelBox.png new file mode 100644 index 0000000..e33cb74 Binary files /dev/null and b/resources/graphics/Screen/shovelBox.png differ diff --git a/resources/huawen.TTF b/resources/huawen.TTF new file mode 100644 index 0000000..94dc60a Binary files /dev/null and b/resources/huawen.TTF differ diff --git a/source/component/map.py b/source/component/map.py index 0113947..158b18d 100755 --- a/source/component/map.py +++ b/source/component/map.py @@ -1,5 +1,4 @@ __author__ = 'wszqkzqk' - import random import pygame as pg from .. import tool diff --git a/source/component/menubar.py b/source/component/menubar.py index 2a9fa97..c154503 100755 --- a/source/component/menubar.py +++ b/source/component/menubar.py @@ -1,5 +1,5 @@ __author__ = 'wszqkzqk' - +import os import random import pygame as pg from .. import tool @@ -28,7 +28,9 @@ plant_frozen_time_list = [7500, 7500, 7500, 30000, 50000, 7500, 7500, 7500, 7500 all_card_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] def getSunValueImage(sun_value): - font = pg.font.SysFont(None, 22) + # for pack, must use other ttf + fontPath = os.path.join('resources', 'huawen.TTF') + font = pg.font.Font(fontPath, 14) width = 32 msg_image = font.render(str(sun_value), True, c.NAVYBLUE, c.LIGHTYELLOW) msg_rect = msg_image.get_rect() @@ -216,6 +218,7 @@ class MenuBar(): for card in self.card_list: card.draw(surface) +# 关卡模式选植物的界面 class Panel(): def __init__(self, card_list, sun_value): self.loadImages(sun_value) @@ -379,7 +382,7 @@ class MoveBar(): def __init__(self, card_pool): self.loadFrame(c.MOVEBAR_BACKGROUND) self.rect = self.image.get_rect() - self.rect.x = 90 + self.rect.x = 20 self.rect.y = 0 self.card_start_x = self.rect.x + 8 diff --git a/source/component/plant.py b/source/component/plant.py index dfaf947..c93800c 100755 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -1,5 +1,4 @@ __author__ = 'wszqkzqk' - import random import pygame as pg from .. import tool @@ -213,7 +212,7 @@ class Plant(pg.sprite.Sprite): self.changeFrames(self.sleep_frames) def setDamage(self, damage, zombie): - if not zombie.losHead: + if not zombie.lostHead: self.health -= damage self.hit_timer = self.current_time if self.health == 0: diff --git a/source/component/zombie.py b/source/component/zombie.py index 2e8db33..46499a2 100755 --- a/source/component/zombie.py +++ b/source/component/zombie.py @@ -1,5 +1,4 @@ __author__ = 'wszqkzqk' - import pygame as pg from .. import tool from .. import constants as c @@ -23,7 +22,7 @@ class Zombie(pg.sprite.Sprite): self.health = health self.damage = damage self.dead = False - self.losHead = False + self.lostHead = False self.helmet = False self.head_group = head_group @@ -67,9 +66,9 @@ class Zombie(pg.sprite.Sprite): self.freezing() def walking(self): - if (self.losHead and (self.current_time - self.losthead_timer) > self.dead_timer): + if (self.lostHead and (self.current_time - self.losthead_timer) > self.dead_timer): self.setDie() - elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: + elif self.health <= c.LOSTHEAD_HEALTH and not self.lostHead: self.changeFrames(self.losthead_walk_frames) self.setLostHead() elif self.health <= c.NORMAL_HEALTH and self.helmet: @@ -86,9 +85,9 @@ class Zombie(pg.sprite.Sprite): self.rect.x -= self.speed def attacking(self): - if (self.losHead and (self.current_time - self.losthead_timer) > self.dead_timer): + if (self.lostHead and (self.current_time - self.losthead_timer) > self.dead_timer): self.setDie() - elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: + elif self.health <= c.LOSTHEAD_HEALTH and not self.lostHead: self.changeFrames(self.losthead_attack_frames) self.setLostHead() elif self.health <= c.NORMAL_HEALTH and self.helmet: @@ -110,9 +109,9 @@ class Zombie(pg.sprite.Sprite): pass def freezing(self): - if (self.losHead and (self.current_time - self.losthead_timer) > self.dead_timer): + if (self.lostHead and (self.current_time - self.losthead_timer) > self.dead_timer): self.setDie() - elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: + elif self.health <= c.LOSTHEAD_HEALTH and not self.lostHead: if self.old_state == c.WALK: self.changeFrames(self.losthead_walk_frames) else: @@ -123,7 +122,7 @@ class Zombie(pg.sprite.Sprite): def setLostHead(self): self.losthead_timer = self.current_time - self.losHead = True + self.lostHead = True if self.head_group is not None: self.head_group.add(ZombieHead(self.rect.centerx, self.rect.bottom)) @@ -187,7 +186,7 @@ class Zombie(pg.sprite.Sprite): if self.helmet: self.changeFrames(self.helmet_walk_frames) - elif self.losHead: + elif self.lostHead: self.changeFrames(self.losthead_walk_frames) else: self.changeFrames(self.walk_frames) @@ -201,7 +200,7 @@ class Zombie(pg.sprite.Sprite): if self.helmet: self.changeFrames(self.helmet_attack_frames) - elif self.losHead: + elif self.lostHead: self.changeFrames(self.losthead_attack_frames) else: self.changeFrames(self.attack_frames) @@ -278,7 +277,7 @@ class NormalZombie(Zombie): self.frames = self.walk_frames - +# 路障僵尸 class ConeHeadZombie(Zombie): def __init__(self, x, y, head_group): Zombie.__init__(self, x, y, c.CONEHEAD_ZOMBIE, c.CONEHEAD_HEALTH, head_group) diff --git a/source/constants.py b/source/constants.py index 7cb404d..3d3d51c 100755 --- a/source/constants.py +++ b/source/constants.py @@ -1,5 +1,4 @@ __author__ = 'wszqkzqk' - START_LEVEL_NUM = 1 ORIGINAL_CAPTION = 'pypvz' @@ -26,6 +25,22 @@ GREEN = ( 0, 255, 0) SIZE_MULTIPLIER = 1.3 +# 退出游戏按钮 +EXIT = 'exit' +# 当想要一个特殊值时用 +NULL = 'null' +# 游戏界面可选的菜单 +LITTLE_MENU = 'littleMenu' +BIG_MENU = 'bigMenu' +RETURN_BUTTON = 'returnButton' +RESTART_BUTTON = 'restartButton' +MAINMENU_BUTTON = 'mainMenuButton' +LITTLEGAME_BUTTON = 'littleGameButton' +# 小铲子 +SHOVEL = 'shovel' +SHOVEL_BOX = 'shovelBox' + + #GAME INFO DICTIONARY KEYS CURRENT_TIME = 'current time' LEVEL_NUM = 'level num' diff --git a/source/data/map/level_1.json b/source/data/map/level_1.json deleted file mode 100644 index 59801a4..0000000 --- a/source/data/map/level_1.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "background_type":0, - "init_sun_value":50, - "zombie_list":[ - {"time":20000, "map_y":0, "name":"Zombie"}, - {"time":40000, "map_y":2, "name":"FlagZombie"}, - {"time":50000, "map_y":4, "name":"Zombie"}, - {"time":70000, "map_y":3, "name":"Zombie"}, - {"time":72000, "map_y":1, "name":"FlagZombie"}, - {"time":74000, "map_y":2, "name":"Zombie"}, - {"time":90000, "map_y":0, "name":"Zombie"}, - {"time":91000, "map_y":1, "name":"FlagZombie"}, - {"time":92000, "map_y":2, "name":"Zombie"}, - {"time":93000, "map_y":3, "name":"FlagZombie"}, - {"time":94000, "map_y":0, "name":"Zombie"}, - {"time":95000, "map_y":4, "name":"FlagZombie"}, - {"time":96000, "map_y":1, "name":"Zombie"} - ] -} \ No newline at end of file diff --git a/source/main.py b/source/main.py deleted file mode 100755 index e0dddcb..0000000 --- a/source/main.py +++ /dev/null @@ -1,14 +0,0 @@ -__author__ = 'wszqkzqk' - -from . import tool -from . import constants as c -from .state import mainmenu, screen, level - -def main(): - game = tool.Control() - state_dict = {c.MAIN_MENU: mainmenu.Menu(), - c.GAME_VICTORY: screen.GameVictoryScreen(), - c.GAME_LOSE: screen.GameLoseScreen(), - c.LEVEL: level.Level()} - game.setup_states(state_dict, c.MAIN_MENU) - game.main() \ No newline at end of file diff --git a/source/state/level.py b/source/state/level.py index 48471a5..6015d3b 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -1,5 +1,4 @@ __author__ = 'wszqkzqk' - import os import json import sys @@ -18,18 +17,37 @@ class Level(tool.State): self.game_info[c.CURRENT_TIME] = current_time self.map_y_len = c.GRID_Y_LEN self.map = map.Map(c.GRID_X_LEN, self.map_y_len) + + # 默认显然不用显示菜单 + self.showLittleMenu = False self.loadMap() self.setupBackground() self.initState() def loadMap(self): - map_file = 'level_' + str(self.game_info[c.LEVEL_NUM]) + '.json' - file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'source', 'data', 'map', map_file) - f = open(file_path) - self.map_data = json.load(f) - f.close() - + if c.LITTLEGAME_BUTTON in self.game_info: + map_file = 'littleGame_' + str(self.game_info[c.LEVEL_NUM]) + '.json' + else: + map_file = 'level_' + str(self.game_info[c.LEVEL_NUM]) + '.json' + file_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))),'resources' , 'data', 'map', map_file) + # 最后一关之后应该结束了 + try: + f = open(file_path) + self.map_data = json.load(f) + f.close() + except Exception as e: + print("游戏结束") + f = open(file_path) + self.map_data = json.load(f) + self.done = True + self.next = c.MAIN_MENU + return + if self.map_data[c.SHOVEL] == 0: + self.hasShovel = False + else: + self.hasShovel = True + def setupBackground(self): img_index = self.map_data[c.BACKGROUND_TYPE] self.background_type = img_index @@ -39,6 +57,7 @@ class Level(tool.State): self.level = pg.Surface((self.bg_rect.w, self.bg_rect.h)).convert() self.viewport = tool.SCREEN.get_rect(bottom=self.bg_rect.bottom) self.viewport.x += c.BACKGROUND_OFFSET_X + def setupGroups(self): self.sun_group = pg.sprite.Group() @@ -69,7 +88,8 @@ class Level(tool.State): for i in range(self.map_y_len): _, y = self.map.getMapGridPos(0, i) self.cars.append(plant.Car(-25, y+20, i)) - + + # 更新函数每帧被调用,将鼠标事件传入给状态处理函数 def update(self, surface, current_time, mouse_pos, mouse_click): self.current_time = self.game_info[c.CURRENT_TIME] = current_time if self.state == c.CHOOSE: @@ -86,6 +106,7 @@ class Level(tool.State): self.map.setMapGridType(x, y, c.MAP_EXIST) def initState(self): + # 小游戏才有CHOOSEBAR_TYPE if c.CHOOSEBAR_TYPE in self.map_data: self.bar_type = self.map_data[c.CHOOSEBAR_TYPE] else: @@ -115,7 +136,11 @@ class Level(tool.State): self.menubar = menubar.MenuBar(card_list, self.map_data[c.INIT_SUN_NAME]) else: self.menubar = menubar.MoveBar(card_list) + + # 是否拖住植物或者铲子 self.drag_plant = False + self.drag_shovel = False + self.hint_image = None self.hint_plant = False if self.background_type == c.BACKGROUND_DAY and self.bar_type == c.CHOOSEBAR_STATIC: @@ -129,7 +154,121 @@ class Level(tool.State): self.setupZombies() self.setupCars() + # 地图有铲子才添加铲子 + if self.hasShovel: + # 导入小铲子 + frame_rect = [0, 0, 71, 67] + self.shovel = tool.get_image_menu(tool.GFX[c.SHOVEL], *frame_rect, c.BLACK, 1.1) + self.shovel_rect = self.shovel.get_rect() + frame_rect = [0, 0, 77, 75] + self.shovel_positon = (550, 2) + self.shovel_box = tool.get_image_menu(tool.GFX[c.SHOVEL_BOX], *frame_rect, c.BLACK, 1.1) + self.shovel_box_rect = self.shovel_box.get_rect() + self.shovel_rect.x = self.shovel_box_rect.x = self.shovel_positon[0] + self.shovel_rect.y = self.shovel_box_rect.y = self.shovel_positon[1] + + self.setupLittleMenu() + + # 小菜单 + def setupLittleMenu(self): + # 具体运行游戏必定有个小菜单, 导入菜单和选项 + frame_rect = [0, 0, 108, 31] + self.little_menu = tool.get_image_menu(tool.GFX[c.LITTLE_MENU], *frame_rect, c.BLACK, 1.1) + self.little_menu_rect = self.little_menu.get_rect() + self.little_menu_rect.x = 650 + self.little_menu_rect.y = 0 + + frame_rect = [0, 0, 500, 500] + self.big_menu = tool.get_image_menu(tool.GFX[c.BIG_MENU], *frame_rect, c.BLACK, 1.1) + self.big_menu_rect = self.big_menu.get_rect() + self.big_menu_rect.x = 150 + self.big_menu_rect.y = 0 + + frame_rect = [0, 0, 342, 87] + self.return_button = tool.get_image_menu(tool.GFX[c.RETURN_BUTTON], *frame_rect, c.BLACK, 1.1) + self.return_button_rect = self.return_button.get_rect() + self.return_button_rect.x = 220 + self.return_button_rect.y = 440 + + frame_rect = [0, 0, 207, 45] + self.restart_button = tool.get_image_menu(tool.GFX[c.RESTART_BUTTON], *frame_rect, c.BLACK, 1.1) + self.restart_button_rect = self.restart_button.get_rect() + self.restart_button_rect.x = 295 + self.restart_button_rect.y = 325 + + frame_rect = [0, 0, 206, 43] + self.mainMenu_button = tool.get_image_menu(tool.GFX[c.MAINMENU_BUTTON], *frame_rect, c.BLACK, 1.1) + self.mainMenu_button_rect = self.mainMenu_button.get_rect() + self.mainMenu_button_rect.x = 299 + self.mainMenu_button_rect.y = 372 + + # 检查小菜单有没有被点击 + def checkLittleMenuClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.little_menu_rect.x and x <= self.little_menu_rect.right and + y >= self.little_menu_rect.y and y <= self.little_menu_rect.bottom): + return True + return False + + # 检查小菜单的返回有没有被点击 + def checkReturnClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.return_button_rect.x and x <= self.return_button_rect.right and + y >= self.return_button_rect.y and y <= self.return_button_rect.bottom): + return True + return False + + # 检查小菜单的重新开始有没有被点击 + def checkRestartClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.restart_button_rect.x and x <= self.restart_button_rect.right and + y >= self.restart_button_rect.y and y <= self.restart_button_rect.bottom): + return True + return False + + # 检查小菜单的主菜单有没有被点击 + def checkMainMenuClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.mainMenu_button_rect.x and x <= self.mainMenu_button_rect.right and + y >= self.mainMenu_button_rect.y and y <= self.mainMenu_button_rect.bottom): + return True + return False + + # 用小铲子移除植物 + def shovelRemovePlant(self, mouse_pos): + x, y = mouse_pos + map_x, map_y = self.map.getMapIndex(x, y) + for i in self.plant_groups[map_y]: + if(x >= i.rect.x and x <= i.rect.right and + y >= i.rect.y and y <= i.rect.bottom): + i.kill() + return + + # 检查小铲子的位置有没有被点击 + # 方便放回去 + def checkShovelClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.shovel_box_rect.x and x <= self.shovel_box_rect.right and + y >= self.shovel_box_rect.y and y <= self.shovel_box_rect.bottom): + return True + return False + def play(self, mouse_pos, mouse_click): + # 如果暂停 + if self.showLittleMenu: + if mouse_click[0]: + if self.checkReturnClick(mouse_pos): + # 暂停 显示菜单 + self.showLittleMenu = False + elif self.checkRestartClick(mouse_pos): + self.done = True + self.next = c.LEVEL + elif self.checkMainMenuClick(mouse_pos): + self.done = True + self.next = c.MAIN_MENU + self.persist = {c.CURRENT_TIME:0.0, c.LEVEL_NUM:c.START_LEVEL_NUM} + return + if self.zombie_start_time == 0: self.zombie_start_time = self.current_time elif len(self.zombie_list) > 0: @@ -150,6 +289,24 @@ class Level(tool.State): self.head_group.update(self.game_info) self.sun_group.update(self.game_info) + # wcb 添加 + # 检查是否点击菜单 + if mouse_click[0]: + if self.checkLittleMenuClick(mouse_pos): + # 暂停 显示菜单 + self.showLittleMenu = True + elif self.checkShovelClick(mouse_pos): + self.drag_shovel = not self.drag_shovel + if self.drag_shovel: + # 小铲子要隐藏鼠标 + pg.mouse.set_visible(False) + else: + self.removeMouseImagePlus() + elif self.drag_shovel: + # 移出这地方的植物 + self.shovelRemovePlant(mouse_pos) + + # 拖动植物或者铲子 if not self.drag_plant and mouse_pos and mouse_click[0]: result = self.menubar.checkCardClick(mouse_pos) if result: @@ -164,14 +321,20 @@ class Level(tool.State): self.addPlant() elif mouse_pos is None: self.setupHintImage() + elif self.drag_shovel: + if mouse_click[1]: + self.removeMouseImagePlus() + if self.produce_sun: if(self.current_time - self.sun_timer) > c.PRODUCE_SUN_INTERVAL: self.sun_timer = self.current_time map_x, map_y = self.map.getRandomMapIndex() x, y = self.map.getMapGridPos(map_x, map_y) self.sun_group.add(plant.Sun(x, 0, x, y)) - if not self.drag_plant and mouse_pos and mouse_click[0]: + + # 检查有没有捡到阳光 + if not self.drag_plant and not self.drag_shovel and mouse_pos and mouse_click[0]: for sun in self.sun_group: if sun.checkCollision(mouse_pos[0], mouse_pos[1]): self.menubar.increaseSunValue(sun.sun_value) @@ -181,6 +344,8 @@ class Level(tool.State): self.menubar.update(self.current_time) + + # 检查碰撞啥的 self.checkBulletCollisions() self.checkZombieCollisions() self.checkPlants() @@ -204,6 +369,7 @@ class Level(tool.State): x, y = pg.mouse.get_pos() return self.map.showPlant(x, y) + # 种植物 def addPlant(self): pos = self.canSeedPlant() if pos is None: @@ -317,6 +483,13 @@ class Level(tool.State): self.hint_image = None self.hint_plant = False + # 移除小铲子 + def removeMouseImagePlus(self): + pg.mouse.set_visible(True) + self.drag_shovel = False + self.shovel_rect.x = self.shovel_positon[0] + self.shovel_rect.y = self.shovel_positon[1] + def checkBulletCollisions(self): collided_func = pg.sprite.collide_circle_ratio(0.7) for i in range(self.map_y_len): @@ -523,6 +696,12 @@ class Level(tool.State): self.mouse_rect.centerx = x self.mouse_rect.centery = y surface.blit(self.mouse_image, self.mouse_rect) + + def drawMouseShowPlus(self, surface): + x, y = pg.mouse.get_pos() + self.shovel_rect.centerx = x + self.shovel_rect.centery = y + surface.blit(self.shovel, self.shovel_rect) def drawZombieFreezeTrap(self, i, surface): for zombie in self.zombie_groups[i]: @@ -534,6 +713,13 @@ class Level(tool.State): if self.state == c.CHOOSE: self.panel.draw(surface) elif self.state == c.PLAY: + if self.hasShovel: + # 画铲子 + 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) @@ -547,4 +733,13 @@ class Level(tool.State): self.sun_group.draw(surface) if self.drag_plant: - self.drawMouseShow(surface) \ No newline at end of file + self.drawMouseShow(surface) + + if self.hasShovel and self.drag_shovel: + self.drawMouseShowPlus(surface) + + if self.showLittleMenu: + surface.blit(self.big_menu, self.big_menu_rect) + surface.blit(self.return_button, self.return_button_rect) + surface.blit(self.restart_button, self.restart_button_rect) + surface.blit(self.mainMenu_button, self.mainMenu_button_rect) \ No newline at end of file diff --git a/source/state/mainmenu.py b/source/state/mainmenu.py index f8301fe..4ab2002 100644 --- a/source/state/mainmenu.py +++ b/source/state/mainmenu.py @@ -1,10 +1,11 @@ __author__ = 'wszqkzqk' - import pygame as pg from .. import tool from .. import constants as c +from . import level class Menu(tool.State): + def __init__(self): tool.State.__init__(self) @@ -12,12 +13,15 @@ class Menu(tool.State): self.next = c.LEVEL self.persist = persist self.game_info = persist - self.setupBackground() self.setupOption() def setupBackground(self): frame_rect = [80, 0, 800, 600] + # 1、形参中加单星号,即f(*x)则表示x为元组,所有对x的操作都应将x视为元组类型进行。 + # 2、双星号同上,区别是x视为字典。 + # 3、在变量前加单星号表示将元组(列表、集合)拆分为单个元素。 + # 4、双星号同上,区别是目标为字典,字典前加单星号的话可以得到“键”。 self.bg_image = tool.get_image(tool.GFX[c.MAIN_MENU_IMAGE], *frame_rect) self.bg_rect = self.bg_image.get_rect() self.bg_rect.x = 0 @@ -29,14 +33,27 @@ class Menu(tool.State): frame_rect = [0, 0, 165, 77] for name in frame_names: - self.option_frames.append(tool.get_image(tool.GFX[name], *frame_rect, c.BLACK, 1.7)) - + self.option_frames.append(tool.get_image_menu(tool.GFX[name], *frame_rect, c.BLACK, 1.7)) self.option_frame_index = 0 self.option_image = self.option_frames[self.option_frame_index] self.option_rect = self.option_image.get_rect() self.option_rect.x = 435 self.option_rect.y = 75 + # 退出按钮 + frame_rect = [0, 0, 500, 500] + self.option_exit = tool.get_image_menu(tool.GFX[c.EXIT], *frame_rect, c.BLACK, 1.1) + self.exit_rect = self.option_exit.get_rect() + self.exit_rect.x = 690 + self.exit_rect.y = 400 + + # 小游戏 + frame_rect = [0, 0, 317, 139] + self.option_littleGame = tool.get_image_menu(tool.GFX[c.LITTLEGAME_BUTTON], *frame_rect, c.BLACK, 0.9) + self.option_littleGame_rect = self.option_littleGame.get_rect() + self.option_littleGame_rect.x = 425 + self.option_littleGame_rect.y = 200 + self.option_start = 0 self.option_timer = 0 self.option_clicked = False @@ -48,14 +65,35 @@ class Menu(tool.State): self.option_clicked = True self.option_timer = self.option_start = self.current_time return False - + + # 点击到按钮,修改转态的done属性 + def checkExitClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.exit_rect.x and x <= self.exit_rect.right and + y >= self.exit_rect.y and y <= self.exit_rect.bottom): + self.done = True + self.next = c.EXIT + + # 检查有没有按到小游戏 + def checkLittleGameClick(self, mouse_pos): + x, y = mouse_pos + if(x >= self.option_littleGame_rect.x and x <= self.option_littleGame_rect.right and + y >= self.option_littleGame_rect.y and y <= self.option_littleGame_rect.bottom): + self.done = True + # 确实小游戏还是用的level + self.persist[c.LITTLEGAME_BUTTON] = True + def update(self, surface, current_time, mouse_pos, mouse_click): self.current_time = self.game_info[c.CURRENT_TIME] = current_time + # 没有选到选项时,检查有没有点到选项 if not self.option_clicked: if mouse_pos: self.checkOptionClick(mouse_pos) + self.checkExitClick(mouse_pos) + self.checkLittleGameClick(mouse_pos) else: + # 点到后播放动画 if(self.current_time - self.option_timer) > 200: self.option_frame_index += 1 if self.option_frame_index >= 2: @@ -64,6 +102,9 @@ class Menu(tool.State): self.option_image = self.option_frames[self.option_frame_index] if(self.current_time - self.option_start) > 1300: self.done = True + surface.blit(self.bg_image, self.bg_rect) - surface.blit(self.option_image, self.option_rect) \ No newline at end of file + surface.blit(self.option_image, self.option_rect) + surface.blit(self.option_exit, self.exit_rect) + surface.blit(self.option_littleGame, self.option_littleGame_rect) \ No newline at end of file diff --git a/source/state/screen.py b/source/state/screen.py index 2294209..379d2be 100644 --- a/source/state/screen.py +++ b/source/state/screen.py @@ -1,5 +1,4 @@ __author__ = 'wszqkzqk' - import pygame as pg from .. import tool from .. import constants as c diff --git a/source/tool.py b/source/tool.py index f9a3077..a4a1be5 100755 --- a/source/tool.py +++ b/source/tool.py @@ -1,37 +1,40 @@ __author__ = 'wszqkzqk' - import os import json import sys from abc import abstractmethod import pygame as pg +from pygame.locals import * from . import constants as c +# an abstract class, one state of automata class State(): def __init__(self): self.start_time = 0.0 self.current_time = 0.0 - self.done = False - self.next = None - self.persist = {} + self.done = False # false 代表未做完 + self.next = None # 表示这个状态退出后要转到的下一个状态 + self.persist = {} # 在状态间转换时需要传递的数据 + # 当从其他状态进入这个状态时,需要进行的初始化操作 @abstractmethod def startup(self, current_time, persist): '''abstract method''' - + # 当从这个状态退出时,需要进行的清除操作 def cleanup(self): self.done = False return self.persist - + # 在这个状态运行时进行的更新操作 @abstractmethod def update(self, surface, keys, current_time): '''abstract method''' +# control this game. do event loops class Control(): def __init__(self): self.screen = pg.display.get_surface() self.done = False - self.clock = pg.time.Clock() + self.clock = pg.time.Clock() # 创建一个对象来帮助跟踪时间 self.fps = 60 self.keys = pg.key.get_pressed() self.mouse_pos = None @@ -50,15 +53,22 @@ class Control(): self.state.startup(self.current_time, self.game_info) def update(self): + # 返回自 pygame_init() 调用以来的毫秒数 self.current_time = pg.time.get_ticks() + if self.state.done: self.flip_state() + self.state.update(self.screen, self.current_time, self.mouse_pos, self.mouse_click) self.mouse_pos = None self.mouse_click[0] = False self.mouse_click[1] = False + # 状态转移 def flip_state(self): + if self.state.next == c.EXIT: + pg.quit() + os._exit(0) previous, self.state_name = self.state_name, self.state.next persist = self.state.cleanup() self.state = self.state_dict[self.state_name] @@ -76,8 +86,11 @@ class Control(): self.mouse_pos = pg.mouse.get_pos() self.mouse_click[0], _, self.mouse_click[1] = pg.mouse.get_pressed() print('pos:', self.mouse_pos, ' mouse:', self.mouse_click) + #else: + # print(pg.event.event_name(event.type)) - def main(self): + + def run(self): while not self.done: self.event_loop() self.update() @@ -90,18 +103,31 @@ 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)) - image.set_colorkey(colorkey) + if colorkey != c.NULL: + image.set_colorkey(colorkey) image = pg.transform.scale(image, (int(rect.width*scale), int(rect.height*scale))) return image +def get_image_menu(sheet, x, y, width, height, colorkey=c.BLACK, scale=1): + # 一定要保留阿尔法通道,修复主菜单bug,游戏中car显示又有bug + image = pg.Surface([width, height], SRCALPHA) + rect = image.get_rect() + + image.blit(sheet, (0, 0), (x, y, width, height)) + image.set_colorkey(colorkey) + image = pg.transform.scale(image, + (int(rect.width*scale), + int(rect.height*scale))) + return image + def load_image_frames(directory, image_name, colorkey, accept): frame_list = [] tmp = {} # image_name is "Peashooter", pic name is 'Peashooter_1', get the index 1 index_start = len(image_name) + 1 - frame_num = 0; + frame_num = 0 for pic in os.listdir(directory): name, ext = os.path.splitext(pic) if ext.lower() in accept: @@ -119,6 +145,7 @@ def load_image_frames(directory, image_name, colorkey, accept): frame_list.append(tmp[i]) return frame_list +# colorkeys 是设置图像中的某个颜色值为透明,这里用来消除白边 def load_all_gfx(directory, colorkey=c.WHITE, accept=('.png', '.jpg', '.bmp', '.gif')): graphics = {} for name1 in os.listdir(directory): @@ -154,23 +181,24 @@ def load_all_gfx(directory, colorkey=c.WHITE, accept=('.png', '.jpg', '.bmp', '. graphics[name] = img return graphics +# 从文件加载矩形碰撞范围 def loadZombieImageRect(): - file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'source', 'data', 'entity', 'zombie.json') + file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'data', 'entity', 'zombie.json') f = open(file_path) data = json.load(f) f.close() return data[c.ZOMBIE_IMAGE_RECT] def loadPlantImageRect(): - file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'source', 'data', 'entity', 'plant.json') + file_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'resources', 'data', 'entity', 'plant.json') f = open(file_path) data = json.load(f) f.close() return data[c.PLANT_IMAGE_RECT] pg.init() -pg.display.set_caption(c.ORIGINAL_CAPTION) -SCREEN = pg.display.set_mode(c.SCREEN_SIZE) +pg.display.set_caption(c.ORIGINAL_CAPTION) # 设置标题 +SCREEN = pg.display.set_mode(c.SCREEN_SIZE) # 设置初始屏幕 GFX = load_all_gfx(os.path.join(os.path.dirname(os.path.dirname(__file__)) ,os.path.join("resources","graphics"))) ZOMBIE_RECT = loadZombieImageRect()