diff --git a/1.txt.txt b/1.txt.txt deleted file mode 100644 index 235f832..0000000 --- a/1.txt.txt +++ /dev/null @@ -1,5 +0,0 @@ -111 -branch_hjj -gwx_work -pull_request_gwx -yqy_conduct \ No newline at end of file diff --git a/PythonPlantsVsZombies.rar b/PythonPlantsVsZombies.rar deleted file mode 100644 index 57e0ebb..0000000 Binary files a/PythonPlantsVsZombies.rar and /dev/null differ diff --git a/PythonPlantsVsZombies/PythonPlantsVsZombies b/PythonPlantsVsZombies/PythonPlantsVsZombies deleted file mode 160000 index afc4ae1..0000000 --- a/PythonPlantsVsZombies/PythonPlantsVsZombies +++ /dev/null @@ -1 +0,0 @@ -Subproject commit afc4ae12c7a19bee5aaa2c20e9d765e1afcccd80 diff --git a/README-zh.md b/README-zh.md deleted file mode 100644 index 2a93825..0000000 --- a/README-zh.md +++ /dev/null @@ -1,31 +0,0 @@ -# Python版植物大战僵尸 - 一个简单的植物大战僵尸游戏。 - - `仅供个人学习和非商业用途。如果这个游戏侵犯了版权,请告诉我。` - -* 已有的植物: 向日葵, 豌豆射手, 坚果墙, 寒冰豌豆射手, 樱桃炸弹, 三向豌豆射手, 食人花, 喷射蘑菇, 土豆地雷, 杂草地刺, 胆小菇, 南瓜, 愤怒辣椒, 阳光菇, 冰冻蘑菇, 诱惑蘑菇。 -* 已有的僵尸: 普通僵尸, 带队僵尸, 路锥僵尸, 水桶僵尸, 看报僵尸。 -* 使用 JSON 格式的文件存储进度数据 (例如僵尸出现的位置和时间, 背景信息)。 -* 支持选择植物卡片在每一关的开始。 -* 支持白昼模式,夜晚模式,传送带模式和坚果保龄球模式。 - -# 系统要求 -* Python 3.7 -* 注意: Python3.7是最佳运行环境,但是不是强制性要求。 对于Linux: 如果你的 Linux 有预装的 Python3+ 就可以运行了。 LINUX Mint 操作系统直接升级到 Python 3.7 有可能导致系统自带的 python 版本无法执行。 -* Python-Pygame 1.9 - -# 怎样开始游戏 -$ python main.py - -# 怎样玩 -* 使用鼠标收集阳光,收集植物卡片和植物的种子。 -* 你可以通过更改 source/constants.py 中的 START_LEVEL_NUM 的数值来更改起始关卡: - * 1 和 2:白昼模式 - * 3: 夜晚模式 - * 4: 传送带模式 - * 5: 坚果保龄球模式 - -# 截屏 -![截屏1](https://raw.githubusercontent.com/marblexu/PythonPlantsVsZombies/master/demo/demo1.jpg) -![截屏2](https://raw.githubusercontent.com/marblexu/PythonPlantsVsZombies/master/demo/demo2.jpg) -![截屏3](https://raw.githubusercontent.com/marblexu/PythonPlantsVsZombies/master/demo/demo3.jpg) diff --git a/main.py b/main.py deleted file mode 100644 index 9421809..0000000 --- a/main.py +++ /dev/null @@ -1,6 +0,0 @@ -import pygame as pg -from source.main import main - -if __name__=='__main__': - main() - pg.quit() \ No newline at end of file diff --git a/source/__init__.py b/source/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/source/component/__init__.py b/source/component/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/source/component/map.py b/source/component/map.py deleted file mode 100644 index 0de0eda..0000000 --- a/source/component/map.py +++ /dev/null @@ -1,45 +0,0 @@ -__author__ = 'marble_xu' - -import random -import pygame as pg -from .. import tool -from .. import constants as c - -class Map(): - def __init__(self, width, height): - self.width = width - self.height = height - self.map = [[0 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 - map_y < 0 or map_y >= self.height): - return False - return True - - def isMovable(self, map_x, map_y): - return (self.map[map_y][map_x] == c.MAP_EMPTY) - - def getMapIndex(self, x, y): - x -= c.MAP_OFFSET_X - y -= c.MAP_OFFSET_Y - return (x // c.GRID_X_SIZE, y // c.GRID_Y_SIZE) - - def getMapGridPos(self, map_x, map_y): - return (map_x * c.GRID_X_SIZE + c.GRID_X_SIZE//2 + c.MAP_OFFSET_X, - map_y * c.GRID_Y_SIZE + c.GRID_Y_SIZE//5 * 3 + c.MAP_OFFSET_Y) - - def setMapGridType(self, map_x, map_y, type): - self.map[map_y][map_x] = type - - def getRandomMapIndex(self): - map_x = random.randint(0, self.width-1) - map_y = random.randint(0, self.height-1) - return (map_x, map_y) - - def showPlant(self, x, y): - pos = None - map_x, map_y = self.getMapIndex(x, y) - if self.isValid(map_x, map_y) and self.isMovable(map_x, map_y): - pos = self.getMapGridPos(map_x, map_y) - return pos diff --git a/source/component/menubar.py b/source/component/menubar.py deleted file mode 100644 index 56054a5..0000000 --- a/source/component/menubar.py +++ /dev/null @@ -1,441 +0,0 @@ -__author__ = 'marble_xu' - -import random -import pygame as pg -from .. import tool -from .. import constants as c - -PANEL_Y_START = 87 -PANEL_X_START = 22 -PANEL_Y_INTERNAL = 74 -PANEL_X_INTERNAL = 53 -CARD_LIST_NUM = 8 - -card_name_list = [c.CARD_SUNFLOWER, c.CARD_PEASHOOTER, c.CARD_SNOWPEASHOOTER, c.CARD_WALLNUT, - c.CARD_CHERRYBOMB, c.CARD_THREEPEASHOOTER, c.CARD_REPEATERPEA, c.CARD_CHOMPER, - c.CARD_PUFFSHROOM, c.CARD_POTATOMINE, c.CARD_SQUASH, c.CARD_SPIKEWEED, - c.CARD_JALAPENO, c.CARD_SCAREDYSHROOM, c.CARD_SUNSHROOM, c.CARD_ICESHROOM, - c.CARD_HYPNOSHROOM, c.CARD_WALLNUT, c.CARD_REDWALLNUT] -plant_name_list = [c.SUNFLOWER, c.PEASHOOTER, c.SNOWPEASHOOTER, c.WALLNUT, - c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA, c.CHOMPER, - c.PUFFSHROOM, c.POTATOMINE, c.SQUASH, c.SPIKEWEED, - c.JALAPENO, c.SCAREDYSHROOM, c.SUNSHROOM, c.ICESHROOM, - c.HYPNOSHROOM, c.WALLNUTBOWLING, c.REDWALLNUTBOWLING] -plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150, 0, 25, 50, 100, 125, 25, 25, 75, 75, 0, 0] -plant_frozen_time_list = [7500, 7500, 7500, 30000, 50000, 7500, 7500, 7500, 7500, 30000, - 30000, 7500, 50000, 7500, 7500, 50000, 30000, 0, 0] -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) - width = 32 - msg_image = font.render(str(sun_value), True, c.NAVYBLUE, c.LIGHTYELLOW) - msg_rect = msg_image.get_rect() - msg_w = msg_rect.width - - image = pg.Surface([width, 17]) - x = width - msg_w - - image.fill(c.LIGHTYELLOW) - image.blit(msg_image, (x, 0), (0, 0, msg_rect.w, msg_rect.h)) - image.set_colorkey(c.BLACK) - return image - -def getCardPool(data): - card_pool = [] - for card in data: - tmp = card['name'] - for i,name in enumerate(plant_name_list): - if name == tmp: - card_pool.append(i) - break - return card_pool - -class Card(): - def __init__(self, x, y, name_index, scale=0.78): - self.loadFrame(card_name_list[name_index], scale) - self.rect = self.orig_image.get_rect() - self.rect.x = x - self.rect.y = y - - self.name_index = name_index - self.sun_cost = plant_sun_list[name_index] - self.frozen_time = plant_frozen_time_list[name_index] - self.frozen_timer = -self.frozen_time - self.refresh_timer = 0 - self.select = True - - def loadFrame(self, name, scale): - frame = tool.GFX[name] - rect = frame.get_rect() - width, height = rect.w, rect.h - - self.orig_image = tool.get_image(frame, 0, 0, width, height, c.BLACK, scale) - self.image = self.orig_image - - 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): - return True - return False - - def canClick(self, sun_value, current_time): - if self.sun_cost <= sun_value and (current_time - self.frozen_timer) > self.frozen_time: - return True - return False - - def canSelect(self): - return self.select - - def setSelect(self, can_select): - self.select = can_select - if can_select: - self.image.set_alpha(255) - else: - self.image.set_alpha(128) - - def setFrozenTime(self, current_time): - self.frozen_timer = current_time - - def createShowImage(self, sun_value, current_time): - '''create a card image to show cool down status - or disable status when have not enough sun value''' - time = current_time - self.frozen_timer - if time < self.frozen_time: #cool down status - image = pg.Surface([self.rect.w, self.rect.h]) - frozen_image = self.orig_image.copy() - 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)) - 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) - else: - image = self.orig_image - return image - - def update(self, sun_value, current_time): - if (current_time - self.refresh_timer) >= 250: - self.image = self.createShowImage(sun_value, current_time) - self.refresh_timer = current_time - - def draw(self, surface): - surface.blit(self.image, self.rect) - -class MenuBar(): - def __init__(self, card_list, sun_value): - self.loadFrame(c.MENUBAR_BACKGROUND) - self.rect = self.image.get_rect() - self.rect.x = 10 - self.rect.y = 0 - - self.sun_value = sun_value - self.card_offset_x = 32 - self.setupCards(card_list) - - def loadFrame(self, name): - frame = tool.GFX[name] - rect = frame.get_rect() - frame_rect = (rect.x, rect.y, rect.w, rect.h) - - self.image = tool.get_image(tool.GFX[name], *frame_rect, c.WHITE, 1) - - def update(self, current_time): - self.current_time = current_time - for card in self.card_list: - card.update(self.sun_value, self.current_time) - - def createImage(self, x, y, num): - if num == 1: - return - img = self.image - rect = self.image.get_rect() - width = rect.w - height = rect.h - self.image = pg.Surface((width * num, height)).convert() - self.rect = self.image.get_rect() - self.rect.x = x - self.rect.y = y - for i in range(num): - x = i * width - self.image.blit(img, (x,0)) - self.image.set_colorkey(c.BLACK) - - def setupCards(self, card_list): - self.card_list = [] - x = self.card_offset_x - y = 8 - for index in card_list: - x += 55 - self.card_list.append(Card(x, y, index)) - - def checkCardClick(self, mouse_pos): - result = None - for card in self.card_list: - if card.checkMouseClick(mouse_pos): - if card.canClick(self.sun_value, self.current_time): - result = (plant_name_list[card.name_index], card) - break - return result - - def checkMenuBarClick(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): - return True - return False - - def decreaseSunValue(self, value): - self.sun_value -= value - - def increaseSunValue(self, value): - self.sun_value += value - - def setCardFrozenTime(self, plant_name): - for card in self.card_list: - if plant_name_list[card.name_index] == plant_name: - card.setFrozenTime(self.current_time) - break - - def drawSunValue(self): - self.value_image = getSunValueImage(self.sun_value) - self.value_rect = self.value_image.get_rect() - self.value_rect.x = 21 - self.value_rect.y = self.rect.bottom - 21 - - self.image.blit(self.value_image, self.value_rect) - - def draw(self, surface): - self.drawSunValue() - surface.blit(self.image, self.rect) - for card in self.card_list: - card.draw(surface) - -class Panel(): - def __init__(self, card_list, sun_value): - self.loadImages(sun_value) - self.selected_cards = [] - self.selected_num = 0 - self.setupCards(card_list) - - def loadFrame(self, name): - frame = tool.GFX[name] - rect = frame.get_rect() - frame_rect = (rect.x, rect.y, rect.w, rect.h) - - return tool.get_image(tool.GFX[name], *frame_rect, c.WHITE, 1) - - def loadImages(self, sun_value): - self.menu_image = self.loadFrame(c.MENUBAR_BACKGROUND) - self.menu_rect = self.menu_image.get_rect() - self.menu_rect.x = 0 - self.menu_rect.y = 0 - - self.panel_image = self.loadFrame(c.PANEL_BACKGROUND) - self.panel_rect = self.panel_image.get_rect() - self.panel_rect.x = 0 - self.panel_rect.y = PANEL_Y_START - - - self.value_image = getSunValueImage(sun_value) - self.value_rect = self.value_image.get_rect() - self.value_rect.x = 21 - self.value_rect.y = self.menu_rect.bottom - 21 - - self.button_image = self.loadFrame(c.START_BUTTON) - self.button_rect = self.button_image.get_rect() - self.button_rect.x = 155 - self.button_rect.y = 547 - - def setupCards(self, card_list): - self.card_list = [] - x = PANEL_X_START - PANEL_X_INTERNAL - y = PANEL_Y_START + 43 - PANEL_Y_INTERNAL - for i, index in enumerate(card_list): - if i % 8 == 0: - x = PANEL_X_START - PANEL_X_INTERNAL - y += PANEL_Y_INTERNAL - x += PANEL_X_INTERNAL - self.card_list.append(Card(x, y, index, 0.75)) - - def checkCardClick(self, mouse_pos): - delete_card = None - for card in self.selected_cards: - if delete_card: # when delete a card, move right cards to left - card.rect.x -= 55 - elif card.checkMouseClick(mouse_pos): - self.deleteCard(card.name_index) - delete_card = card - - if delete_card: - self.selected_cards.remove(delete_card) - self.selected_num -= 1 - - if self.selected_num == CARD_LIST_NUM: - return - - for card in self.card_list: - if card.checkMouseClick(mouse_pos): - if card.canSelect(): - self.addCard(card) - break - - def addCard(self, card): - card.setSelect(False) - y = 8 - x = 78 + self.selected_num * 55 - self.selected_cards.append(Card(x, y, card.name_index)) - self.selected_num += 1 - - def deleteCard(self, index): - self.card_list[index].setSelect(True) - - def checkStartButtonClick(self, mouse_pos): - if self.selected_num < CARD_LIST_NUM: - return False - - x, y = mouse_pos - if (x >= self.button_rect.x and x <= self.button_rect.right and - y >= self.button_rect.y and y <= self.button_rect.bottom): - return True - return False - - def getSelectedCards(self): - card_index_list = [] - for card in self.selected_cards: - card_index_list.append(card.name_index) - return card_index_list - - def draw(self, surface): - self.menu_image.blit(self.value_image, self.value_rect) - surface.blit(self.menu_image, self.menu_rect) - surface.blit(self.panel_image, self.panel_rect) - for card in self.card_list: - card.draw(surface) - for card in self.selected_cards: - card.draw(surface) - - if self.selected_num == CARD_LIST_NUM: - surface.blit(self.button_image, self.button_rect) - -class MoveCard(): - def __init__(self, x, y, card_name, plant_name, scale=0.78): - self.loadFrame(card_name, scale) - self.rect = self.orig_image.get_rect() - self.rect.x = x - self.rect.y = y - self.rect.w = 1 - self.image = self.createShowImage() - - self.card_name = card_name - self.plant_name = plant_name - self.move_timer = 0 - self.select = True - - def loadFrame(self, name, scale): - frame = tool.GFX[name] - rect = frame.get_rect() - width, height = rect.w, rect.h - - self.orig_image = tool.get_image(frame, 0, 0, width, height, c.BLACK, scale) - self.orig_rect = self.orig_image.get_rect() - self.image = self.orig_image - - 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): - return True - return False - - def createShowImage(self): - '''create a part card image when card appears from left''' - if self.rect.w < self.orig_rect.w: #create a part card image - image = pg.Surface([self.rect.w, self.rect.h]) - image.blit(self.orig_image, (0, 0), (0, 0, self.rect.w, self.rect.h)) - self.rect.w += 1 - else: - image = self.orig_image - return image - - def update(self, left_x, current_time): - if self.move_timer == 0: - self.move_timer = current_time - elif (current_time - self.move_timer) >= c.CARD_MOVE_TIME: - if self.rect.x > left_x: - self.rect.x -= 1 - self.image = self.createShowImage() - self.move_timer += c.CARD_MOVE_TIME - - def draw(self, surface): - surface.blit(self.image, self.rect) - -class MoveBar(): - def __init__(self, card_pool): - self.loadFrame(c.MOVEBAR_BACKGROUND) - self.rect = self.image.get_rect() - self.rect.x = 90 - self.rect.y = 0 - - self.card_start_x = self.rect.x + 8 - self.card_end_x = self.rect.right - 5 - self.card_pool = card_pool - self.card_list = [] - self.create_timer = -c.MOVEBAR_CARD_FRESH_TIME - - def loadFrame(self, name): - frame = tool.GFX[name] - rect = frame.get_rect() - frame_rect = (rect.x, rect.y, rect.w, rect.h) - - self.image = tool.get_image(tool.GFX[name], *frame_rect, c.WHITE, 1) - - def createCard(self): - if len(self.card_list) > 0 and self.card_list[-1].rect.right > self.card_end_x: - return False - x = self.card_end_x - y = 6 - index = random.randint(0, len(self.card_pool) - 1) - card_index = self.card_pool[index] - card_name = card_name_list[card_index] + '_move' - plant_name = plant_name_list[card_index] - self.card_list.append(MoveCard(x, y, card_name, plant_name)) - return True - - def update(self, current_time): - self.current_time = current_time - left_x = self.card_start_x - for card in self.card_list: - card.update(left_x, self.current_time) - left_x = card.rect.right + 1 - - if(self.current_time - self.create_timer) > c.MOVEBAR_CARD_FRESH_TIME: - if self.createCard(): - self.create_timer = self.current_time - - def checkCardClick(self, mouse_pos): - result = None - for index, card in enumerate(self.card_list): - if card.checkMouseClick(mouse_pos): - result = (card.plant_name, card) - break - return result - - def checkMenuBarClick(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): - return True - return False - - def deleateCard(self, card): - self.card_list.remove(card) - - def draw(self, surface): - surface.blit(self.image, self.rect) - for card in self.card_list: - card.draw(surface) \ No newline at end of file diff --git a/source/component/plant.py b/source/component/plant.py deleted file mode 100644 index 684065b..0000000 --- a/source/component/plant.py +++ /dev/null @@ -1,971 +0,0 @@ -__author__ = 'marble_xu' - -import random -import pygame as pg -from .. import tool -from .. import constants as c - -class Car(pg.sprite.Sprite): - def __init__(self, x, y, map_y): - pg.sprite.Sprite.__init__(self) - - rect = tool.GFX[c.CAR].get_rect() - width, height = rect.w, rect.h - self.image = tool.get_image(tool.GFX[c.CAR], 0, 0, width, height) - self.rect = self.image.get_rect() - self.rect.x = x - self.rect.bottom = y - self.map_y = map_y - self.state = c.IDLE - self.dead = False - - def update(self, game_info): - self.current_time = game_info[c.CURRENT_TIME] - if self.state == c.IDLE: - pass - elif self.state == c.WALK: - self.rect.x += 4 - if self.rect.x > c.SCREEN_WIDTH: - self.dead = True - - def setWalk(self): - if self.state == c.IDLE: - self.state = c.WALK - - def draw(self, surface): - surface.blit(self.image, self.rect) - -class Bullet(pg.sprite.Sprite): - def __init__(self, x, start_y, dest_y, name, damage, ice): - pg.sprite.Sprite.__init__(self) - - self.name = name - self.frames = [] - self.frame_index = 0 - self.load_images() - self.image = self.frames[self.frame_index] - self.rect = self.image.get_rect() - self.rect.x = x - self.rect.y = start_y - self.dest_y = dest_y - self.y_vel = 4 if (dest_y > start_y) else -4 - self.x_vel = 4 - self.damage = damage - self.ice = ice - self.state = c.FLY - self.current_time = 0 - - def loadFrames(self, frames, name): - frame_list = tool.GFX[name] - if name in tool.PLANT_RECT: - data = tool.PLANT_RECT[name] - x, y, width, height = data['x'], data['y'], data['width'], data['height'] - else: - x, y = 0, 0 - rect = frame_list[0].get_rect() - width, height = rect.w, rect.h - - for frame in frame_list: - frames.append(tool.get_image(frame, x, y, width, height)) - - def load_images(self): - self.fly_frames = [] - self.explode_frames = [] - - fly_name = self.name - if self.name == c.BULLET_MUSHROOM: - explode_name = 'BulletMushRoomExplode' - else: - explode_name = 'PeaNormalExplode' - - self.loadFrames(self.fly_frames, fly_name) - self.loadFrames(self.explode_frames, explode_name) - - self.frames = self.fly_frames - - def update(self, game_info): - self.current_time = game_info[c.CURRENT_TIME] - if self.state == c.FLY: - if self.rect.y != self.dest_y: - self.rect.y += self.y_vel - if self.y_vel * (self.dest_y - self.rect.y) < 0: - self.rect.y = self.dest_y - self.rect.x += self.x_vel - if self.rect.x > c.SCREEN_WIDTH: - self.kill() - elif self.state == c.EXPLODE: - if(self.current_time - self.explode_timer) > 500: - self.kill() - - def setExplode(self): - self.state = c.EXPLODE - self.explode_timer = self.current_time - self.frames = self.explode_frames - self.image = self.frames[self.frame_index] - - def draw(self, surface): - surface.blit(self.image, self.rect) - -class Plant(pg.sprite.Sprite): - def __init__(self, x, y, name, health, bullet_group, scale=1): - pg.sprite.Sprite.__init__(self) - - self.frames = [] - self.frame_index = 0 - self.loadImages(name, scale) - self.frame_num = len(self.frames) - self.image = self.frames[self.frame_index] - self.rect = self.image.get_rect() - self.rect.centerx = x - self.rect.bottom = y - - self.name = name - self.health = health - self.state = c.IDLE - self.bullet_group = bullet_group - self.can_sleep = False - self.animate_timer = 0 - self.animate_interval = 100 - self.hit_timer = 0 - - def loadFrames(self, frames, name, scale, color=c.BLACK): - frame_list = tool.GFX[name] - if name in tool.PLANT_RECT: - data = tool.PLANT_RECT[name] - x, y, width, height = data['x'], data['y'], data['width'], data['height'] - else: - x, y = 0, 0 - rect = frame_list[0].get_rect() - width, height = rect.w, rect.h - - for frame in frame_list: - frames.append(tool.get_image(frame, x, y, width, height, color, scale)) - - def loadImages(self, name, scale): - self.loadFrames(self.frames, name, scale) - - def changeFrames(self, frames): - '''change image frames and modify rect position''' - self.frames = frames - self.frame_num = len(self.frames) - self.frame_index = 0 - - bottom = self.rect.bottom - x = self.rect.x - self.image = self.frames[self.frame_index] - self.rect = self.image.get_rect() - self.rect.bottom = bottom - self.rect.x = x - - def update(self, game_info): - self.current_time = game_info[c.CURRENT_TIME] - self.handleState() - self.animation() - - def handleState(self): - if self.state == c.IDLE: - self.idling() - elif self.state == c.ATTACK: - self.attacking() - elif self.state == c.DIGEST: - self.digest() - - def idling(self): - pass - - def attacking(self): - pass - - def digest(self): - pass - - def animation(self): - if (self.current_time - self.animate_timer) > self.animate_interval: - self.frame_index += 1 - if self.frame_index >= self.frame_num: - self.frame_index = 0 - self.animate_timer = self.current_time - - self.image = self.frames[self.frame_index] - if(self.current_time - self.hit_timer) >= 200: - self.image.set_alpha(255) - else: - self.image.set_alpha(192) - - def canAttack(self, zombie): - if (self.state != c.SLEEP and zombie.state != c.DIE and - self.rect.x <= zombie.rect.right): - return True - return False - - def setAttack(self): - self.state = c.ATTACK - - def setIdle(self): - self.state = c.IDLE - self.is_attacked = False - - def setSleep(self): - self.state = c.SLEEP - self.changeFrames(self.sleep_frames) - - def setDamage(self, damage, zombie): - self.health -= damage - self.hit_timer = self.current_time - if self.health == 0: - self.kill_zombie = zombie - - def getPosition(self): - return self.rect.centerx, self.rect.bottom - -class Sun(Plant): - def __init__(self, x, y, dest_x, dest_y, is_big=True): - if is_big: - scale = 0.9 - self.sun_value = c.SUN_VALUE - else: - scale = 0.6 - self.sun_value = 12 - Plant.__init__(self, x, y, c.SUN, 0, None, scale) - self.move_speed = 1 - self.dest_x = dest_x - self.dest_y = dest_y - self.die_timer = 0 - - def handleState(self): - if self.rect.centerx != self.dest_x: - self.rect.centerx += self.move_speed if self.rect.centerx < self.dest_x else -self.move_speed - if self.rect.bottom != self.dest_y: - self.rect.bottom += self.move_speed if self.rect.bottom < self.dest_y else -self.move_speed - - if self.rect.centerx == self.dest_x and self.rect.bottom == self.dest_y: - if self.die_timer == 0: - self.die_timer = self.current_time - elif(self.current_time - self.die_timer) > c.SUN_LIVE_TIME: - self.state = c.DIE - self.kill() - - def checkCollision(self, x, y): - if self.state == c.DIE: - return False - if(x >= self.rect.x and x <= self.rect.right and - y >= self.rect.y and y <= self.rect.bottom): - self.state = c.DIE - self.kill() - return True - return False - -class SunFlower(Plant): - def __init__(self, x, y, sun_group): - Plant.__init__(self, x, y, c.SUNFLOWER, c.PLANT_HEALTH, None) - self.sun_timer = 0 - self.sun_group = sun_group - - def idling(self): - if self.sun_timer == 0: - self.sun_timer = self.current_time - (c.FLOWER_SUN_INTERVAL - 6000) - elif (self.current_time - self.sun_timer) > c.FLOWER_SUN_INTERVAL: - self.sun_group.add(Sun(self.rect.centerx, self.rect.bottom, self.rect.right, self.rect.bottom + self.rect.h // 2)) - self.sun_timer = self.current_time - -class PeaShooter(Plant): - def __init__(self, x, y, bullet_group): - Plant.__init__(self, x, y, c.PEASHOOTER, c.PLANT_HEALTH, bullet_group) - self.shoot_timer = 0 - - def attacking(self): - if (self.current_time - self.shoot_timer) > 2000: - self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y, - c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False)) - self.shoot_timer = self.current_time - -class RepeaterPea(Plant): - def __init__(self, x, y, bullet_group): - Plant.__init__(self, x, y, c.REPEATERPEA, c.PLANT_HEALTH, bullet_group) - self.shoot_timer = 0 - - def attacking(self): - if (self.current_time - self.shoot_timer) > 2000: - self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y, - c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False)) - self.bullet_group.add(Bullet(self.rect.right + 40, self.rect.y, self.rect.y, - c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False)) - self.shoot_timer = self.current_time - -class ThreePeaShooter(Plant): - def __init__(self, x, y, bullet_groups, map_y): - Plant.__init__(self, x, y, c.THREEPEASHOOTER, c.PLANT_HEALTH, None) - self.shoot_timer = 0 - self.map_y = map_y - self.bullet_groups = bullet_groups - - def attacking(self): - if (self.current_time - self.shoot_timer) > 2000: - offset_y = 9 # modify bullet in the same y position with bullets of other plants - for i in range(3): - tmp_y = self.map_y + (i - 1) - if tmp_y < 0 or tmp_y >= c.GRID_Y_LEN: - continue - dest_y = self.rect.y + (i - 1) * c.GRID_Y_SIZE + offset_y - self.bullet_groups[tmp_y].add(Bullet(self.rect.right, self.rect.y, dest_y, - c.BULLET_PEA, c.BULLET_DAMAGE_NORMAL, False)) - self.shoot_timer = self.current_time - -class SnowPeaShooter(Plant): - def __init__(self, x, y, bullet_group): - Plant.__init__(self, x, y, c.SNOWPEASHOOTER, c.PLANT_HEALTH, bullet_group) - self.shoot_timer = 0 - - def attacking(self): - if (self.current_time - self.shoot_timer) > 2000: - self.bullet_group.add(Bullet(self.rect.right, self.rect.y, self.rect.y, - c.BULLET_PEA_ICE, c.BULLET_DAMAGE_NORMAL, True)) - self.shoot_timer = self.current_time - -class WallNut(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.WALLNUT, c.WALLNUT_HEALTH, None) - self.load_images() - self.cracked1 = False - self.cracked2 = False - - def load_images(self): - self.cracked1_frames = [] - self.cracked2_frames = [] - - cracked1_frames_name = self.name + '_cracked1' - cracked2_frames_name = self.name + '_cracked2' - - self.loadFrames(self.cracked1_frames, cracked1_frames_name, 1) - self.loadFrames(self.cracked2_frames, cracked2_frames_name, 1) - - def idling(self): - if not self.cracked1 and self.health <= c.WALLNUT_CRACKED1_HEALTH: - self.changeFrames(self.cracked1_frames) - self.cracked1 = True - elif not self.cracked2 and self.health <= c.WALLNUT_CRACKED2_HEALTH: - self.changeFrames(self.cracked2_frames) - self.cracked2 = True - -class CherryBomb(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.CHERRYBOMB, c.WALLNUT_HEALTH, None) - self.state = c.ATTACK - self.start_boom = False - self.bomb_timer = 0 - self.explode_y_range = 1 - self.explode_x_range = c.GRID_X_SIZE - - def setBoom(self): - frame = tool.GFX[c.CHERRY_BOOM_IMAGE] - rect = frame.get_rect() - width, height = rect.w, rect.h - - old_rect = self.rect - image = tool.get_image(frame, 0, 0, width, height, c.BLACK, 1) - self.image = image - self.rect = image.get_rect() - self.rect.centerx = old_rect.centerx - self.rect.centery = old_rect.centery - self.start_boom = True - - def animation(self): - if self.start_boom: - if self.bomb_timer == 0: - self.bomb_timer = self.current_time - elif(self.current_time - self.bomb_timer) > 500: - self.health = 0 - else: - if (self.current_time - self.animate_timer) > 100: - self.frame_index += 1 - if self.frame_index >= self.frame_num: - self.setBoom() - return - self.animate_timer = self.current_time - - self.image = self.frames[self.frame_index] - -class Chomper(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.CHOMPER, c.PLANT_HEALTH, None) - self.animate_interval = 250 - self.digest_timer = 0 - self.digest_interval = 15000 - self.attack_zombie = None - self.zombie_group = None - - def loadImages(self, name, scale): - self.idle_frames = [] - self.attack_frames = [] - self.digest_frames = [] - - idle_name = name - attack_name = name + 'Attack' - digest_name = name + 'Digest' - - frame_list = [self.idle_frames, self.attack_frames, self.digest_frames] - name_list = [idle_name, attack_name, digest_name] - scale_list = [1, 1, 1] - rect_list = [(0, 0, 100, 114), None, None] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, scale_list[i]) - - self.frames = self.idle_frames - - def canAttack(self, zombie): - if (self.state == c.IDLE and zombie.state != c.DIGEST and - self.rect.x <= zombie.rect.right and - (self.rect.right + c.GRID_X_SIZE//3 >= zombie.rect.x)): - return True - return False - - def setIdle(self): - self.state = c.IDLE - self.changeFrames(self.idle_frames) - - def setAttack(self, zombie, zombie_group): - self.attack_zombie = zombie - self.zombie_group = zombie_group - self.state = c.ATTACK - self.changeFrames(self.attack_frames) - - def setDigest(self): - self.state = c.DIGEST - self.changeFrames(self.digest_frames) - - def attacking(self): - if self.frame_index == (self.frame_num - 3): - self.zombie_group.remove(self.attack_zombie) - if (self.frame_index + 1) == self.frame_num: - self.setDigest() - - def digest(self): - if self.digest_timer == 0: - self.digest_timer = self.current_time - elif (self.current_time - self.digest_timer) > self.digest_interval: - self.digest_timer = 0 - self.attack_zombie.kill() - self.setIdle() - -class PuffShroom(Plant): - def __init__(self, x, y, bullet_group): - Plant.__init__(self, x, y, c.PUFFSHROOM, c.PLANT_HEALTH, bullet_group) - self.can_sleep = True - self.shoot_timer = 0 - - def loadImages(self, name, scale): - self.idle_frames = [] - self.sleep_frames = [] - - idle_name = name - sleep_name = name + 'Sleep' - - frame_list = [self.idle_frames, self.sleep_frames] - name_list = [idle_name, sleep_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, 1) - - self.frames = self.idle_frames - - def attacking(self): - if (self.current_time - self.shoot_timer) > 3000: - self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 10, self.rect.y + 10, - c.BULLET_MUSHROOM, c.BULLET_DAMAGE_NORMAL, True)) - self.shoot_timer = self.current_time - - def canAttack(self, zombie): - if (self.rect.x <= zombie.rect.right and - (self.rect.right + c.GRID_X_SIZE * 4 >= zombie.rect.x)): - return True - return False - -class PotatoMine(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.POTATOMINE, c.PLANT_HEALTH, None) - self.animate_interval = 300 - self.is_init = True - self.init_timer = 0 - self.bomb_timer = 0 - self.explode_y_range = 0 - self.explode_x_range = c.GRID_X_SIZE//3 * 2 - - def loadImages(self, name, scale): - self.init_frames = [] - self.idle_frames = [] - self.explode_frames = [] - - init_name = name + 'Init' - idle_name = name - explode_name = name + 'Explode' - - frame_list = [self.init_frames, self.idle_frames, self.explode_frames] - name_list = [init_name, idle_name, explode_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, 1, c.WHITE) - - self.frames = self.init_frames - - def idling(self): - if self.is_init: - if self.init_timer == 0: - self.init_timer = self.current_time - elif (self.current_time - self.init_timer) > 15000: - self.changeFrames(self.idle_frames) - self.is_init = False - - def canAttack(self, zombie): - if (not self.is_init and zombie.rect.right >= self.rect.x and - (zombie.rect.x - self.rect.x) <= self.explode_x_range): - return True - return False - - def attacking(self): - if self.bomb_timer == 0: - self.bomb_timer = self.current_time - self.changeFrames(self.explode_frames) - elif (self.current_time - self.bomb_timer) > 500: - self.health = 0 - -class Squash(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.SQUASH, c.PLANT_HEALTH, None) - self.orig_pos = (x, y) - self.aim_timer = 0 - self.squashing = False - - def loadImages(self, name, scale): - self.idle_frames = [] - self.aim_frames = [] - self.attack_frames = [] - - idle_name = name - aim_name = name + 'Aim' - attack_name = name + 'Attack' - - frame_list = [self.idle_frames, self.aim_frames, self.attack_frames] - name_list = [idle_name, aim_name, attack_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, 1, c.WHITE) - - self.frames = self.idle_frames - - def canAttack(self, zombie): - if (self.state == c.IDLE and self.rect.x <= zombie.rect.right and - (self.rect.right + c.GRID_X_SIZE >= zombie.rect.x)): - return True - return False - - def setAttack(self, zombie, zombie_group): - self.attack_zombie = zombie - self.zombie_group = zombie_group - self.state = c.ATTACK - - def attacking(self): - if self.squashing: - if self.frame_index == 2: - self.zombie_group.remove(self.attack_zombie) - if (self.frame_index + 1) == self.frame_num: - self.attack_zombie.kill() - self.health = 0 - elif self.aim_timer == 0: - self.aim_timer = self.current_time - self.changeFrames(self.aim_frames) - elif (self.current_time - self.aim_timer) > 1000: - self.changeFrames(self.attack_frames) - self.rect.centerx = self.attack_zombie.rect.centerx - self.squashing = True - self.animate_interval = 300 - - def getPosition(self): - return self.orig_pos - -class Spikeweed(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.SPIKEWEED, c.PLANT_HEALTH, None) - self.animate_interval = 200 - self.attack_timer = 0 - - def loadImages(self, name, scale): - self.loadFrames(self.frames, name, 0.9, c.WHITE) - - def setIdle(self): - print('spikeweed idle') - self.animate_interval = 200 - self.state = c.IDLE - - def canAttack(self, zombie): - if (self.rect.x <= zombie.rect.right and - (self.rect.right >= zombie.rect.x)): - return True - return False - - def setAttack(self, zombie_group): - self.zombie_group = zombie_group - self.animate_interval = 50 - self.state = c.ATTACK - - def attacking(self): - if (self.current_time - self.attack_timer) > 2000: - self.attack_timer = self.current_time - for zombie in self.zombie_group: - if self.canAttack(zombie): - zombie.setDamage(1, False) - -class Jalapeno(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.JALAPENO, c.PLANT_HEALTH, None) - self.orig_pos = (x, y) - self.state = c.ATTACK - self.start_explode = False - self.explode_y_range = 0 - self.explode_x_range = 377 - - def loadImages(self, name, scale): - self.explode_frames = [] - explode_name = name + 'Explode' - self.loadFrames(self.explode_frames, explode_name, 1, c.WHITE) - - self.loadFrames(self.frames, name, 1, c.WHITE) - - def setExplode(self): - self.changeFrames(self.explode_frames) - self.animate_timer = self.current_time - self.rect.x = c.MAP_OFFSET_X - self.start_explode = True - - def animation(self): - if self.start_explode: - if(self.current_time - self.animate_timer) > 100: - self.frame_index += 1 - if self.frame_index >= self.frame_num: - self.health = 0 - return - self.animate_timer = self.current_time - else: - if (self.current_time - self.animate_timer) > 100: - self.frame_index += 1 - if self.frame_index >= self.frame_num: - self.setExplode() - return - self.animate_timer = self.current_time - self.image = self.frames[self.frame_index] - - def getPosition(self): - return self.orig_pos - -class ScaredyShroom(Plant): - def __init__(self, x, y, bullet_group): - Plant.__init__(self, x, y, c.SCAREDYSHROOM, c.PLANT_HEALTH, bullet_group) - self.can_sleep = True - self.shoot_timer = 0 - self.cry_x_range = c.GRID_X_SIZE * 2 - - def loadImages(self, name, scale): - self.idle_frames = [] - self.cry_frames = [] - self.sleep_frames = [] - - idle_name = name - cry_name = name + 'Cry' - sleep_name = name + 'Sleep' - - frame_list = [self.idle_frames, self.cry_frames, self.sleep_frames] - name_list = [idle_name, cry_name, sleep_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, 1, c.WHITE) - - self.frames = self.idle_frames - - def needCry(self, zombie): - if (zombie.state != c.DIE and self.rect.x <= zombie.rect.right and - self.rect.x + self.cry_x_range > zombie.rect.x): - return True - return False - - def setCry(self): - self.state = c.CRY - self.changeFrames(self.cry_frames) - - def setAttack(self): - self.state = c.ATTACK - self.changeFrames(self.idle_frames) - - def setIdle(self): - self.state = c.IDLE - self.changeFrames(self.idle_frames) - - def attacking(self): - if (self.current_time - self.shoot_timer) > 2000: - self.bullet_group.add(Bullet(self.rect.right, self.rect.y + 40, self.rect.y + 40, - c.BULLET_MUSHROOM, c.BULLET_DAMAGE_NORMAL, True)) - self.shoot_timer = self.current_time - -class SunShroom(Plant): - def __init__(self, x, y, sun_group): - Plant.__init__(self, x, y, c.SUNSHROOM, c.PLANT_HEALTH, None) - self.can_sleep = True - self.animate_interval = 200 - self.sun_timer = 0 - self.sun_group = sun_group - self.is_big = False - self.change_timer = 0 - - def loadImages(self, name, scale): - self.idle_frames = [] - self.big_frames = [] - self.sleep_frames = [] - - idle_name = name - big_name = name + 'Big' - sleep_name = name + 'Sleep' - - frame_list = [self.idle_frames, self.big_frames, self.sleep_frames] - name_list = [idle_name, big_name, sleep_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, 1, c.WHITE) - - self.frames = self.idle_frames - - def idling(self): - if not self.is_big: - if self.change_timer == 0: - self.change_timer = self.current_time - elif (self.current_time - self.change_timer) > 25000: - self.changeFrames(self.big_frames) - self.is_big = True - - if self.sun_timer == 0: - self.sun_timer = self.current_time - (c.FLOWER_SUN_INTERVAL - 6000) - elif (self.current_time - self.sun_timer) > c.FLOWER_SUN_INTERVAL: - self.sun_group.add(Sun(self.rect.centerx, self.rect.bottom, self.rect.right, - self.rect.bottom + self.rect.h // 2, self.is_big)) - self.sun_timer = self.current_time - -class IceShroom(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.ICESHROOM, c.PLANT_HEALTH, None) - self.can_sleep = True - self.orig_pos = (x, y) - self.start_freeze = False - - def loadImages(self, name, scale): - self.idle_frames = [] - self.snow_frames = [] - self.sleep_frames = [] - self.trap_frames = [] - - idle_name = name - snow_name = name + 'Snow' - sleep_name = name + 'Sleep' - trap_name = name + 'Trap' - - frame_list = [self.idle_frames, self.snow_frames, self.sleep_frames, self.trap_frames] - name_list = [idle_name, snow_name, sleep_name, trap_name] - scale_list = [1, 1.5, 1, 1] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, scale_list[i], c.WHITE) - - self.frames = self.idle_frames - - def setFreeze(self): - self.changeFrames(self.snow_frames) - self.animate_timer = self.current_time - self.rect.x = c.MAP_OFFSET_X - self.rect.y = c.MAP_OFFSET_Y - self.start_freeze = True - - def animation(self): - if self.start_freeze: - if(self.current_time - self.animate_timer) > 500: - self.frame_index += 1 - if self.frame_index >= self.frame_num: - self.health = 0 - return - self.animate_timer = self.current_time - else: - if (self.current_time - self.animate_timer) > 100: - self.frame_index += 1 - if self.frame_index >= self.frame_num: - if self.state == c.SLEEP: - self.frame_index = 0 - else: - self.setFreeze() - return - self.animate_timer = self.current_time - self.image = self.frames[self.frame_index] - - def getPosition(self): - return self.orig_pos - -class HypnoShroom(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.HYPNOSHROOM, 1, None) - self.can_sleep = True - self.animate_interval = 200 - - def loadImages(self, name, scale): - self.idle_frames = [] - self.sleep_frames = [] - - idle_name = name - sleep_name = name + 'Sleep' - - frame_list = [self.idle_frames, self.sleep_frames] - name_list = [idle_name, sleep_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, 1, c.WHITE) - - self.frames = self.idle_frames - -class WallNutBowling(Plant): - def __init__(self, x, y, map_y, level): - Plant.__init__(self, x, y, c.WALLNUTBOWLING, 1, None) - self.map_y = map_y - self.level = level - self.init_rect = self.rect.copy() - self.rotate_degree = 0 - self.animate_interval = 200 - self.move_timer = 0 - self.move_interval = 70 - self.vel_x = random.randint(12, 15) - self.vel_y = 0 - self.disable_hit_y = -1 - - def loadImages(self, name, scale): - self.loadFrames(self.frames, name, 1, c.WHITE) - - def idling(self): - if self.move_timer == 0: - self.move_timer = self.current_time - elif (self.current_time - self.move_timer) >= self.move_interval: - self.rotate_degree = (self.rotate_degree - 30) % 360 - self.init_rect.x += self.vel_x - self.init_rect.y += self.vel_y - self.handleMapYPosition() - if self.shouldChangeDirection(): - self.changeDirection(-1) - if self.init_rect.x > c.SCREEN_WIDTH: - self.health = 0 - self.move_timer += self.move_interval - - def canHit(self, map_y): - if self.disable_hit_y == map_y: - return False - return True - - def handleMapYPosition(self): - _, map_y1 = self.level.map.getMapIndex(self.init_rect.x, self.init_rect.centery) - _, map_y2 = self.level.map.getMapIndex(self.init_rect.x, self.init_rect.bottom) - if self.map_y != map_y1 and map_y1 == map_y2: - # wallnut bowls to another row, should modify which plant group it belongs to - self.level.plant_groups[self.map_y].remove(self) - self.level.plant_groups[map_y1].add(self) - self.map_y = map_y1 - - def shouldChangeDirection(self): - if self.init_rect.centery <= c.MAP_OFFSET_Y: - return True - elif self.init_rect.bottom + 20 >= c.SCREEN_HEIGHT: - return True - return False - - def changeDirection(self, map_y): - if self.vel_y == 0: - if self.map_y == 0: - direc = 1 - elif self.map_y == (c.GRID_Y_LEN-1): - direc = -1 - else: - if random.randint(0, 1) == 0: - direc = 1 - else: - direc = -1 - self.vel_y = self.vel_x * direc - else: - self.vel_y = - self.vel_y - - self.disable_hit_y = map_y - - def animation(self): - if (self.current_time - self.animate_timer) > self.animate_interval: - self.frame_index += 1 - if self.frame_index >= self.frame_num: - self.frame_index = 0 - self.animate_timer = self.current_time - - image = self.frames[self.frame_index] - self.image = pg.transform.rotate(image, self.rotate_degree) - # must keep the center postion of image when rotate - self.rect = self.image.get_rect(center=self.init_rect.center) - -class RedWallNutBowling(Plant): - def __init__(self, x, y): - Plant.__init__(self, x, y, c.REDWALLNUTBOWLING, 1, None) - self.orig_y = y - self.explode_timer = 0 - self.explode_y_range = 1 - self.explode_x_range = c.GRID_X_SIZE - self.init_rect = self.rect.copy() - self.rotate_degree = 0 - self.animate_interval = 200 - self.move_timer = 0 - self.move_interval = 70 - self.vel_x = random.randint(12, 15) - - def loadImages(self, name, scale): - self.idle_frames = [] - self.explode_frames = [] - - idle_name = name - explode_name = name + 'Explode' - - frame_list = [self.idle_frames, self.explode_frames] - name_list = [idle_name, explode_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, 1, c.WHITE) - - self.frames = self.idle_frames - - def idling(self): - if self.move_timer == 0: - self.move_timer = self.current_time - elif (self.current_time - self.move_timer) >= self.move_interval: - self.rotate_degree = (self.rotate_degree - 30) % 360 - self.init_rect.x += self.vel_x - if self.init_rect.x > c.SCREEN_WIDTH: - self.health = 0 - self.move_timer += self.move_interval - - def attacking(self): - if self.explode_timer == 0: - self.explode_timer = self.current_time - self.changeFrames(self.explode_frames) - elif (self.current_time - self.explode_timer) > 500: - self.health = 0 - - def animation(self): - if (self.current_time - self.animate_timer) > self.animate_interval: - self.frame_index += 1 - if self.frame_index >= self.frame_num: - self.frame_index = 0 - self.animate_timer = self.current_time - - image = self.frames[self.frame_index] - if self.state == c.IDLE: - self.image = pg.transform.rotate(image, self.rotate_degree) - else: - self.image = image - # must keep the center postion of image when rotate - self.rect = self.image.get_rect(center=self.init_rect.center) - - def getPosition(self): - return (self.rect.centerx, self.orig_y) \ No newline at end of file diff --git a/source/component/zombie.py b/source/component/zombie.py deleted file mode 100644 index 73780f1..0000000 --- a/source/component/zombie.py +++ /dev/null @@ -1,414 +0,0 @@ -__author__ = 'marble_xu' - -import pygame as pg -from .. import tool -from .. import constants as c - -class Zombie(pg.sprite.Sprite): - def __init__(self, x, y, name, health, head_group=None, damage=1): - pg.sprite.Sprite.__init__(self) - - self.name = name - self.frames = [] - self.frame_index = 0 - self.loadImages() - self.frame_num = len(self.frames) - - self.image = self.frames[self.frame_index] - self.rect = self.image.get_rect() - self.rect.centerx = x - self.rect.bottom = y - - self.health = health - self.damage = damage - self.dead = False - self.losHead = False - self.helmet = False - self.head_group = head_group - - self.walk_timer = 0 - self.animate_timer = 0 - self.attack_timer = 0 - self.state = c.WALK - self.animate_interval = 150 - self.ice_slow_ratio = 1 - self.ice_slow_timer = 0 - self.hit_timer = 0 - self.speed = 1 - self.freeze_timer = 0 - self.is_hypno = False # the zombie is hypo and attack other zombies when it ate a HypnoShroom - - def loadFrames(self, frames, name, image_x, colorkey=c.BLACK): - frame_list = tool.GFX[name] - rect = frame_list[0].get_rect() - width, height = rect.w, rect.h - width -= image_x - - for frame in frame_list: - frames.append(tool.get_image(frame, image_x, 0, width, height, colorkey)) - - def update(self, game_info): - self.current_time = game_info[c.CURRENT_TIME] - self.handleState() - self.updateIceSlow() - self.animation() - - def handleState(self): - if self.state == c.WALK: - self.walking() - elif self.state == c.ATTACK: - self.attacking() - elif self.state == c.DIE: - self.dying() - elif self.state == c.FREEZE: - self.freezing() - - def walking(self): - if self.health <= 0: - self.setDie() - elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: - self.changeFrames(self.losthead_walk_frames) - self.setLostHead() - elif self.health <= c.NORMAL_HEALTH and self.helmet: - self.changeFrames(self.walk_frames) - self.helmet = False - if self.name == c.NEWSPAPER_ZOMBIE: - self.speed = 2 - - if (self.current_time - self.walk_timer) > (c.ZOMBIE_WALK_INTERVAL * self.getTimeRatio()): - self.walk_timer = self.current_time - if self.is_hypno: - self.rect.x += self.speed - else: - self.rect.x -= self.speed - - def attacking(self): - if self.health <= 0: - self.setDie() - elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: - self.changeFrames(self.losthead_attack_frames) - self.setLostHead() - elif self.health <= c.NORMAL_HEALTH and self.helmet: - self.changeFrames(self.attack_frames) - self.helmet = False - if (self.current_time - self.attack_timer) > (c.ATTACK_INTERVAL * self.getTimeRatio()): - if self.prey.health > 0: - if self.prey_is_plant: - self.prey.setDamage(self.damage, self) - else: - self.prey.setDamage(self.damage) - self.attack_timer = self.current_time - - if self.prey.health <= 0: - self.prey = None - self.setWalk() - - def dying(self): - pass - - def freezing(self): - if self.health <= 0: - self.setDie() - elif self.health <= c.LOSTHEAD_HEALTH and not self.losHead: - if self.old_state == c.WALK: - self.changeFrames(self.losthead_walk_frames) - else: - self.changeFrames(self.losthead_attack_frames) - self.setLostHead() - if (self.current_time - self.freeze_timer) > c.FREEZE_TIME: - self.setWalk() - - def setLostHead(self): - self.losHead = True - if self.head_group is not None: - self.head_group.add(ZombieHead(self.rect.centerx, self.rect.bottom)) - - def changeFrames(self, frames): - '''change image frames and modify rect position''' - self.frames = frames - self.frame_num = len(self.frames) - self.frame_index = 0 - - bottom = self.rect.bottom - centerx = self.rect.centerx - self.image = self.frames[self.frame_index] - self.rect = self.image.get_rect() - self.rect.bottom = bottom - self.rect.centerx = centerx - - def animation(self): - if self.state == c.FREEZE: - self.image.set_alpha(192) - return - - if (self.current_time - self.animate_timer) > (self.animate_interval * self.getTimeRatio()): - self.frame_index += 1 - if self.frame_index >= self.frame_num: - if self.state == c.DIE: - self.kill() - return - self.frame_index = 0 - self.animate_timer = self.current_time - - self.image = self.frames[self.frame_index] - if self.is_hypno: - self.image = pg.transform.flip(self.image, True, False) - if(self.current_time - self.hit_timer) >= 200: - self.image.set_alpha(255) - else: - self.image.set_alpha(192) - - def getTimeRatio(self): - return self.ice_slow_ratio - - def setIceSlow(self): - '''when get a ice bullet damage, slow the attack or walk speed of the zombie''' - self.ice_slow_timer = self.current_time - self.ice_slow_ratio = 2 - - def updateIceSlow(self): - if self.ice_slow_ratio > 1: - if (self.current_time - self.ice_slow_timer) > c.ICE_SLOW_TIME: - self.ice_slow_ratio = 1 - - def setDamage(self, damage, ice=False): - self.health -= damage - self.hit_timer = self.current_time - if ice: - self.setIceSlow() - - def setWalk(self): - self.state = c.WALK - self.animate_interval = 150 - - if self.helmet: - self.changeFrames(self.helmet_walk_frames) - elif self.losHead: - self.changeFrames(self.losthead_walk_frames) - else: - self.changeFrames(self.walk_frames) - - def setAttack(self, prey, is_plant=True): - self.prey = prey # prey can be plant or other zombies - self.prey_is_plant = is_plant - self.state = c.ATTACK - self.attack_timer = self.current_time - self.animate_interval = 100 - - if self.helmet: - self.changeFrames(self.helmet_attack_frames) - elif self.losHead: - self.changeFrames(self.losthead_attack_frames) - else: - self.changeFrames(self.attack_frames) - - def setDie(self): - self.state = c.DIE - self.animate_interval = 200 - self.changeFrames(self.die_frames) - - def setBoomDie(self): - self.state = c.DIE - self.animate_interval = 200 - self.changeFrames(self.boomdie_frames) - - def setFreeze(self, ice_trap_image): - self.old_state = self.state - self.state = c.FREEZE - self.freeze_timer = self.current_time - self.ice_trap_image = ice_trap_image - self.ice_trap_rect = ice_trap_image.get_rect() - self.ice_trap_rect.centerx = self.rect.centerx - self.ice_trap_rect.bottom = self.rect.bottom - - def drawFreezeTrap(self, surface): - if self.state == c.FREEZE: - surface.blit(self.ice_trap_image, self.ice_trap_rect) - - def setHypno(self): - self.is_hypno = True - self.setWalk() - -class ZombieHead(Zombie): - def __init__(self, x, y): - Zombie.__init__(self, x, y, c.ZOMBIE_HEAD, 0) - self.state = c.DIE - - def loadImages(self): - self.die_frames = [] - die_name = self.name - self.loadFrames(self.die_frames, die_name, 0) - self.frames = self.die_frames - - def setWalk(self): - self.animate_interval = 100 - -class NormalZombie(Zombie): - def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.NORMAL_ZOMBIE, c.NORMAL_HEALTH, head_group) - - def loadImages(self): - self.walk_frames = [] - self.attack_frames = [] - self.losthead_walk_frames = [] - self.losthead_attack_frames = [] - self.die_frames = [] - self.boomdie_frames = [] - - walk_name = self.name - attack_name = self.name + 'Attack' - losthead_walk_name = self.name + 'LostHead' - losthead_attack_name = self.name + 'LostHeadAttack' - die_name = self.name + 'Die' - boomdie_name = c.BOOMDIE - - frame_list = [self.walk_frames, self.attack_frames, self.losthead_walk_frames, - self.losthead_attack_frames, self.die_frames, self.boomdie_frames] - name_list = [walk_name, attack_name, losthead_walk_name, - losthead_attack_name, die_name, boomdie_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) - - 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) - self.helmet = True - - def loadImages(self): - self.helmet_walk_frames = [] - self.helmet_attack_frames = [] - self.walk_frames = [] - self.attack_frames = [] - self.losthead_walk_frames = [] - self.losthead_attack_frames = [] - self.die_frames = [] - self.boomdie_frames = [] - - helmet_walk_name = self.name - helmet_attack_name = self.name + 'Attack' - walk_name = c.NORMAL_ZOMBIE - attack_name = c.NORMAL_ZOMBIE + 'Attack' - losthead_walk_name = c.NORMAL_ZOMBIE + 'LostHead' - losthead_attack_name = c.NORMAL_ZOMBIE + 'LostHeadAttack' - die_name = c.NORMAL_ZOMBIE + 'Die' - boomdie_name = c.BOOMDIE - - frame_list = [self.helmet_walk_frames, self.helmet_attack_frames, - self.walk_frames, self.attack_frames, self.losthead_walk_frames, - self.losthead_attack_frames, self.die_frames, self.boomdie_frames] - name_list = [helmet_walk_name, helmet_attack_name, - walk_name, attack_name, losthead_walk_name, - losthead_attack_name, die_name, boomdie_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) - - self.frames = self.helmet_walk_frames - -class BucketHeadZombie(Zombie): - def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.BUCKETHEAD_ZOMBIE, c.BUCKETHEAD_HEALTH, head_group) - self.helmet = True - - def loadImages(self): - self.helmet_walk_frames = [] - self.helmet_attack_frames = [] - self.walk_frames = [] - self.attack_frames = [] - self.losthead_walk_frames = [] - self.losthead_attack_frames = [] - self.die_frames = [] - self.boomdie_frames = [] - - helmet_walk_name = self.name - helmet_attack_name = self.name + 'Attack' - walk_name = c.NORMAL_ZOMBIE - attack_name = c.NORMAL_ZOMBIE + 'Attack' - losthead_walk_name = c.NORMAL_ZOMBIE + 'LostHead' - losthead_attack_name = c.NORMAL_ZOMBIE + 'LostHeadAttack' - die_name = c.NORMAL_ZOMBIE + 'Die' - boomdie_name = c.BOOMDIE - - frame_list = [self.helmet_walk_frames, self.helmet_attack_frames, - self.walk_frames, self.attack_frames, self.losthead_walk_frames, - self.losthead_attack_frames, self.die_frames, self.boomdie_frames] - name_list = [helmet_walk_name, helmet_attack_name, - walk_name, attack_name, losthead_walk_name, - losthead_attack_name, die_name, boomdie_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) - - self.frames = self.helmet_walk_frames - -class FlagZombie(Zombie): - def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.FLAG_ZOMBIE, c.FLAG_HEALTH, head_group) - - def loadImages(self): - self.walk_frames = [] - self.attack_frames = [] - self.losthead_walk_frames = [] - self.losthead_attack_frames = [] - self.die_frames = [] - self.boomdie_frames = [] - - walk_name = self.name - attack_name = self.name + 'Attack' - losthead_walk_name = self.name + 'LostHead' - losthead_attack_name = self.name + 'LostHeadAttack' - die_name = c.NORMAL_ZOMBIE + 'Die' - boomdie_name = c.BOOMDIE - - frame_list = [self.walk_frames, self.attack_frames, self.losthead_walk_frames, - self.losthead_attack_frames, self.die_frames, self.boomdie_frames] - name_list = [walk_name, attack_name, losthead_walk_name, - losthead_attack_name, die_name, boomdie_name] - - for i, name in enumerate(name_list): - self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x']) - - self.frames = self.walk_frames - -class NewspaperZombie(Zombie): - def __init__(self, x, y, head_group): - Zombie.__init__(self, x, y, c.NEWSPAPER_ZOMBIE, c.NEWSPAPER_HEALTH, head_group) - self.helmet = True - - def loadImages(self): - self.helmet_walk_frames = [] - self.helmet_attack_frames = [] - self.walk_frames = [] - self.attack_frames = [] - self.losthead_walk_frames = [] - self.losthead_attack_frames = [] - self.die_frames = [] - self.boomdie_frames = [] - - helmet_walk_name = self.name - helmet_attack_name = self.name + 'Attack' - walk_name = self.name + 'NoPaper' - attack_name = self.name + 'NoPaperAttack' - losthead_walk_name = self.name + 'LostHead' - losthead_attack_name = self.name + 'LostHeadAttack' - die_name = self.name + 'Die' - boomdie_name = c.BOOMDIE - - frame_list = [self.helmet_walk_frames, self.helmet_attack_frames, - self.walk_frames, self.attack_frames, self.losthead_walk_frames, - self.losthead_attack_frames, self.die_frames, self.boomdie_frames] - name_list = [helmet_walk_name, helmet_attack_name, - walk_name, attack_name, losthead_walk_name, - losthead_attack_name, die_name, boomdie_name] - - for i, name in enumerate(name_list): - if name == c.BOOMDIE: - color = c.BLACK - else: - color = c.WHITE - self.loadFrames(frame_list[i], name, tool.ZOMBIE_RECT[name]['x'], color) - - self.frames = self.helmet_walk_frames \ No newline at end of file diff --git a/source/constants.py b/source/constants.py deleted file mode 100644 index 0c4e2b6..0000000 --- a/source/constants.py +++ /dev/null @@ -1,180 +0,0 @@ -__author__ = 'marble_xu' - -START_LEVEL_NUM = 1 - -ORIGINAL_CAPTION = 'Plant VS Zombies Game' - -SCREEN_WIDTH = 800 -SCREEN_HEIGHT = 600 -SCREEN_SIZE = (SCREEN_WIDTH, SCREEN_HEIGHT) - -GRID_X_LEN = 9 -GRID_Y_LEN = 5 -GRID_X_SIZE = 80 -GRID_Y_SIZE = 100 - - -WHITE = (255, 255, 255) -NAVYBLUE = ( 60, 60, 100) -SKY_BLUE = ( 39, 145, 251) -BLACK = ( 0, 0, 0) -LIGHTYELLOW = (234, 233, 171) -RED = (255, 0, 0) -PURPLE = (255, 0, 255) -GOLD = (255, 215, 0) -GREEN = ( 0, 255, 0) - -SIZE_MULTIPLIER = 1.3 - -#GAME INFO DICTIONARY KEYS -CURRENT_TIME = 'current time' -LEVEL_NUM = 'level num' - -#STATES FOR ENTIRE GAME -MAIN_MENU = 'main menu' -LOAD_SCREEN = 'load screen' -GAME_LOSE = 'game los' -GAME_VICTORY = 'game victory' -LEVEL = 'level' - -MAIN_MENU_IMAGE = 'MainMenu' -OPTION_ADVENTURE = 'Adventure' -GAME_LOOSE_IMAGE = 'GameLoose' -GAME_VICTORY_IMAGE = 'GameVictory' - -#MAP COMPONENTS -BACKGROUND_NAME = 'Background' -BACKGROUND_TYPE = 'background_type' -INIT_SUN_NAME = 'init_sun_value' -ZOMBIE_LIST = 'zombie_list' - -MAP_EMPTY = 0 -MAP_EXIST = 1 - -BACKGROUND_OFFSET_X = 220 -MAP_OFFSET_X = 35 -MAP_OFFSET_Y = 100 - -#MENUBAR -CHOOSEBAR_TYPE = 'choosebar_type' -CHOOSEBAR_STATIC = 0 -CHOOSEBAR_MOVE = 1 -CHOSSEBAR_BOWLING = 2 -MENUBAR_BACKGROUND = 'ChooserBackground' -MOVEBAR_BACKGROUND = 'MoveBackground' -PANEL_BACKGROUND = 'PanelBackground' -START_BUTTON = 'StartButton' -CARD_POOL = 'card_pool' - -MOVEBAR_CARD_FRESH_TIME = 6000 -CARD_MOVE_TIME = 60 - -#PLANT INFO -PLANT_IMAGE_RECT = 'plant_image_rect' -CAR = 'car' -SUN = 'Sun' -SUNFLOWER = 'SunFlower' -PEASHOOTER = 'Peashooter' -SNOWPEASHOOTER = 'SnowPea' -WALLNUT = 'WallNut' -CHERRYBOMB = 'CherryBomb' -THREEPEASHOOTER = 'Threepeater' -REPEATERPEA = 'RepeaterPea' -CHOMPER = 'Chomper' -CHERRY_BOOM_IMAGE = 'Boom' -PUFFSHROOM = 'PuffShroom' -POTATOMINE = 'PotatoMine' -SQUASH = 'Squash' -SPIKEWEED = 'Spikeweed' -JALAPENO = 'Jalapeno' -SCAREDYSHROOM = 'ScaredyShroom' -SUNSHROOM = 'SunShroom' -ICESHROOM = 'IceShroom' -HYPNOSHROOM = 'HypnoShroom' -WALLNUTBOWLING = 'WallNutBowling' -REDWALLNUTBOWLING = 'RedWallNutBowling' - -PLANT_HEALTH = 5 -WALLNUT_HEALTH = 30 -WALLNUT_CRACKED1_HEALTH = 20 -WALLNUT_CRACKED2_HEALTH = 10 -WALLNUT_BOWLING_DAMAGE = 10 - -PRODUCE_SUN_INTERVAL = 7000 -FLOWER_SUN_INTERVAL = 22000 -SUN_LIVE_TIME = 7000 -SUN_VALUE = 25 - -ICE_SLOW_TIME = 2000 - -FREEZE_TIME = 7500 -ICETRAP = 'IceTrap' - -#PLANT CARD INFO -CARD_SUNFLOWER = 'card_sunflower' -CARD_PEASHOOTER = 'card_peashooter' -CARD_SNOWPEASHOOTER = 'card_snowpea' -CARD_WALLNUT = 'card_wallnut' -CARD_CHERRYBOMB = 'card_cherrybomb' -CARD_THREEPEASHOOTER = 'card_threepeashooter' -CARD_REPEATERPEA = 'card_repeaterpea' -CARD_CHOMPER = 'card_chomper' -CARD_PUFFSHROOM = 'card_puffshroom' -CARD_POTATOMINE = 'card_potatomine' -CARD_SQUASH = 'card_squash' -CARD_SPIKEWEED = 'card_spikeweed' -CARD_JALAPENO = 'card_jalapeno' -CARD_SCAREDYSHROOM = 'card_scaredyshroom' -CARD_SUNSHROOM = 'card_sunshroom' -CARD_ICESHROOM = 'card_iceshroom' -CARD_HYPNOSHROOM = 'card_hypnoshroom' -CARD_REDWALLNUT = 'card_redwallnut' - -#BULLET INFO -BULLET_PEA = 'PeaNormal' -BULLET_PEA_ICE = 'PeaIce' -BULLET_MUSHROOM = 'BulletMushRoom' -BULLET_DAMAGE_NORMAL = 1 - -#ZOMBIE INFO -ZOMBIE_IMAGE_RECT = 'zombie_image_rect' -ZOMBIE_HEAD = 'ZombieHead' -NORMAL_ZOMBIE = 'Zombie' -CONEHEAD_ZOMBIE = 'ConeheadZombie' -BUCKETHEAD_ZOMBIE = 'BucketheadZombie' -FLAG_ZOMBIE = 'FlagZombie' -NEWSPAPER_ZOMBIE = 'NewspaperZombie' -BOOMDIE = 'BoomDie' - -LOSTHEAD_HEALTH = 5 -NORMAL_HEALTH = 10 -FLAG_HEALTH = 15 -CONEHEAD_HEALTH = 20 -BUCKETHEAD_HEALTH = 30 -NEWSPAPER_HEALTH = 15 - -ATTACK_INTERVAL = 1000 -ZOMBIE_WALK_INTERVAL = 70 - -ZOMBIE_START_X = SCREEN_WIDTH + 50 - -#STATE -IDLE = 'idle' -FLY = 'fly' -EXPLODE = 'explode' -ATTACK = 'attack' -ATTACKED = 'attacked' -DIGEST = 'digest' -WALK = 'walk' -DIE = 'die' -CRY = 'cry' -FREEZE = 'freeze' -SLEEP = 'sleep' - -#LEVEL STATE -CHOOSE = 'choose' -PLAY = 'play' - -#BACKGROUND -BACKGROUND_DAY = 0 -BACKGROUND_NIGHT = 1 \ No newline at end of file diff --git a/source/data/entity/plant.json b/source/data/entity/plant.json deleted file mode 100644 index a790f7c..0000000 --- a/source/data/entity/plant.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "plant_image_rect":{ - "PeaNormal":{"x":28, "y":0, "width":28, "height":34}, - "PeaIce":{"x":26, "y":0, "width":30, "height":34}, - "Chomper":{"x":0, "y":0, "width":100, "height":114}, - "PuffShroom":{"x":0, "y":28, "width":35, "height":38}, - "PuffShroomSleep":{"x":1, "y":0, "width":39, "height":65}, - "BulletMushRoom":{"x":0, "y":1, "width":55, "height":21}, - "PotatoMine":{"x":0, "y":0, "width":75, "height":55}, - "Squash":{"x":10, "y":140, "width":80, "height":86}, - "SquashAim":{"x":10, "y":140, "width":80, "height":86}, - "Spikeweed":{"x":3, "y":0, "width":80, "height":35} - } -} \ No newline at end of file diff --git a/source/data/entity/zombie.json b/source/data/entity/zombie.json deleted file mode 100644 index bbc81fb..0000000 --- a/source/data/entity/zombie.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "zombie_image_rect":{ - "Zombie":{"x":62, "width":90}, - "ZombieAttack":{"x":62, "width":90}, - "ZombieLostHead":{"x":62, "width":90}, - "ZombieLostHeadAttack":{"x":62, "width":90}, - "ZombieDie":{"x":0, "width":164}, - "BoomDie":{"x":68, "width":80}, - "ConeheadZombie":{"x":80, "width":80}, - "ConeheadZombieAttack":{"x":79, "width":87}, - "BucketheadZombie":{"x":54, "width":90}, - "BucketheadZombieAttack":{"x":46, "width":90}, - "FlagZombie":{"x":56, "width":110}, - "FlagZombieAttack":{"x":60, "width":100}, - "FlagZombieLostHead":{"x":55, "width":110}, - "FlagZombieLostHeadAttack":{"x":55, "width":110}, - "NewspaperZombie":{"x":48, "width":92}, - "NewspaperZombieAttack":{"x":48, "width":92}, - "NewspaperZombieNoPaper":{"x":40, "width":98}, - "NewspaperZombieNoPaperAttack":{"x":48, "width":92}, - "NewspaperZombieLostHead":{"x":44, "width":96}, - "NewspaperZombieLostHeadAttack":{"x":48, "width":92}, - "NewspaperZombieDie":{"x":0, "width":100} - } -} \ No newline at end of file diff --git a/source/data/map/level_0.json b/source/data/map/level_0.json deleted file mode 100644 index c22fd75..0000000 --- a/source/data/map/level_0.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "background_type":0, - "init_sun_value":500, - "zombie_list":[ - {"time":1000, "map_y":2, "name":"Zombie"} - ] -} \ No newline at end of file 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/data/map/level_2.json b/source/data/map/level_2.json deleted file mode 100644 index b3d9170..0000000 --- a/source/data/map/level_2.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":"ConeheadZombie"}, - {"time":70000, "map_y":3, "name":"ConeheadZombie"}, - {"time":72000, "map_y":1, "name":"FlagZombie"}, - {"time":74000, "map_y":2, "name":"ConeheadZombie"}, - {"time":90000, "map_y":0, "name":"FlagZombie"}, - {"time":91000, "map_y":1, "name":"ConeheadZombie"}, - {"time":92000, "map_y":2, "name":"Zombie"}, - {"time":93000, "map_y":3, "name":"ConeheadZombie"}, - {"time":94000, "map_y":0, "name":"Zombie"}, - {"time":95000, "map_y":4, "name":"FlagZombie"}, - {"time":96000, "map_y":1, "name":"ConeheadZombie"} - ] -} \ No newline at end of file diff --git a/source/data/map/level_3.json b/source/data/map/level_3.json deleted file mode 100644 index 04ad595..0000000 --- a/source/data/map/level_3.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "background_type":1, - "init_sun_value":50, - "zombie_list":[ - {"time":20000, "map_y":0, "name":"Zombie"}, - {"time":40000, "map_y":2, "name":"ConeheadZombie"}, - {"time":50000, "map_y":4, "name":"BucketheadZombie"}, - {"time":70000, "map_y":3, "name":"BucketheadZombie"}, - {"time":72000, "map_y":1, "name":"FlagZombie"}, - {"time":74000, "map_y":2, "name":"ConeheadZombie"}, - {"time":90000, "map_y":0, "name":"BucketheadZombie"}, - {"time":91000, "map_y":1, "name":"ConeheadZombie"}, - {"time":92000, "map_y":2, "name":"Zombie"}, - {"time":93000, "map_y":3, "name":"BucketheadZombie"}, - {"time":94000, "map_y":0, "name":"Zombie"}, - {"time":95000, "map_y":4, "name":"FlagZombie"}, - {"time":96000, "map_y":1, "name":"BucketheadZombie"}, - {"time":97000, "map_y":1, "name":"FlagZombie"} - ] -} diff --git a/source/data/map/level_4.json b/source/data/map/level_4.json deleted file mode 100644 index aaa525b..0000000 --- a/source/data/map/level_4.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "background_type":0, - "choosebar_type":1, - "card_pool":[ - {"name":"Peashooter"}, - {"name":"SnowPea"}, - {"name":"WallNut"}, - {"name":"CherryBomb"}, - {"name":"RepeaterPea"}, - {"name":"Chomper"}, - {"name":"PotatoMine"} - ], - "zombie_list":[ - {"time": 1000, "map_y":1, "name":"Zombie"}, - {"time": 6000, "map_y":3, "name":"FlagZombie"}, - {"time":10000, "map_y":0, "name":"ConeheadZombie"}, - {"time":14000, "map_y":2, "name":"NewspaperZombie"}, - {"time":18000, "map_y":4, "name":"BucketheadZombie"}, - {"time":22000, "map_y":0, "name":"Zombie"}, - {"time":26000, "map_y":3, "name":"BucketheadZombie"}, - {"time":30000, "map_y":4, "name":"Zombie"}, - {"time":32000, "map_y":3, "name":"NewspaperZombie"}, - {"time":34000, "map_y":1, "name":"FlagZombie"}, - {"time":36000, "map_y":2, "name":"ConeheadZombie"}, - {"time":38000, "map_y":0, "name":"BucketheadZombie"}, - {"time":40000, "map_y":1, "name":"ConeheadZombie"}, - {"time":42000, "map_y":1, "name":"NewspaperZombie"}, - {"time":60000, "map_y":4, "name":"Zombie"}, - {"time":61000, "map_y":3, "name":"NewspaperZombie"}, - {"time":62000, "map_y":1, "name":"FlagZombie"}, - {"time":63000, "map_y":2, "name":"Zombie"}, - {"time":64000, "map_y":0, "name":"BucketheadZombie"}, - {"time":65000, "map_y":1, "name":"ConeheadZombie"}, - {"time":66000, "map_y":2, "name":"Zombie"}, - {"time":67000, "map_y":4, "name":"BucketheadZombie"}, - {"time":68000, "map_y":3, "name":"NewspaperZombie"}, - {"time":69000, "map_y":1, "name":"FlagZombie"}, - {"time":70000, "map_y":4, "name":"BucketheadZombie"}, - {"time":71000, "map_y":0, "name":"FlagZombie"} - ] -} \ No newline at end of file diff --git a/source/data/map/level_5.json b/source/data/map/level_5.json deleted file mode 100644 index 343c68b..0000000 --- a/source/data/map/level_5.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "background_type":4, - "choosebar_type":2, - "card_pool":[ - {"name":"WallNutBowling"}, - {"name":"RedWallNutBowling"} - ], - "zombie_list":[ - {"time": 1000, "map_y":1, "name":"Zombie"}, - {"time":10000, "map_y":3, "name":"FlagZombie"}, - {"time":12000, "map_y":0, "name":"ConeheadZombie"}, - {"time":14000, "map_y":2, "name":"NewspaperZombie"}, - {"time":18000, "map_y":4, "name":"BucketheadZombie"}, - {"time":22000, "map_y":3, "name":"Zombie"}, - {"time":26000, "map_y":1, "name":"BucketheadZombie"}, - {"time":30000, "map_y":4, "name":"Zombie"}, - {"time":32000, "map_y":3, "name":"NewspaperZombie"}, - {"time":34000, "map_y":1, "name":"FlagZombie"}, - {"time":36000, "map_y":2, "name":"ConeheadZombie"}, - {"time":40000, "map_y":1, "name":"ConeheadZombie"}, - {"time":42000, "map_y":1, "name":"NewspaperZombie"}, - {"time":50000, "map_y":4, "name":"Zombie"}, - {"time":54000, "map_y":3, "name":"NewspaperZombie"}, - {"time":58000, "map_y":1, "name":"FlagZombie"}, - {"time":62000, "map_y":2, "name":"Zombie"}, - {"time":64000, "map_y":1, "name":"ConeheadZombie"}, - {"time":66000, "map_y":2, "name":"Zombie"}, - {"time":68000, "map_y":3, "name":"NewspaperZombie"}, - {"time":70000, "map_y":1, "name":"FlagZombie"}, - {"time":72000, "map_y":4, "name":"BucketheadZombie"}, - {"time":74000, "map_y":0, "name":"FlagZombie"} - ] -} \ No newline at end of file diff --git a/source/main.py b/source/main.py deleted file mode 100644 index 92fcdc1..0000000 --- a/source/main.py +++ /dev/null @@ -1,14 +0,0 @@ -__author__ = 'marble_xu' - -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/__init__.py b/source/state/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/source/state/level.py b/source/state/level.py deleted file mode 100644 index 133cc28..0000000 --- a/source/state/level.py +++ /dev/null @@ -1,549 +0,0 @@ -__author__ = 'marble_xu' - -import os -import json -import pygame as pg -from .. import tool -from .. import constants as c -from ..component import map, plant, zombie, menubar - -class Level(tool.State): - def __init__(self): - tool.State.__init__(self) - - def startup(self, current_time, persist): - self.game_info = persist - self.persist = self.game_info - 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.loadMap() - self.setupBackground() - self.initState() - - def loadMap(self): - map_file = 'level_' + str(self.game_info[c.LEVEL_NUM]) + '.json' - file_path = os.path.join('source', 'data', 'map', map_file) - f = open(file_path) - self.map_data = json.load(f) - f.close() - - def setupBackground(self): - img_index = self.map_data[c.BACKGROUND_TYPE] - self.background_type = img_index - self.background = tool.GFX[c.BACKGROUND_NAME][img_index] - self.bg_rect = self.background.get_rect() - - 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() - self.head_group = pg.sprite.Group() - - self.plant_groups = [] - self.zombie_groups = [] - self.hypno_zombie_groups = [] #zombies who are hypno after eating hypnoshroom - self.bullet_groups = [] - for i in range(self.map_y_len): - self.plant_groups.append(pg.sprite.Group()) - self.zombie_groups.append(pg.sprite.Group()) - self.hypno_zombie_groups.append(pg.sprite.Group()) - self.bullet_groups.append(pg.sprite.Group()) - - def setupZombies(self): - def takeTime(element): - return element[0] - - self.zombie_list = [] - for data in self.map_data[c.ZOMBIE_LIST]: - self.zombie_list.append((data['time'], data['name'], data['map_y'])) - self.zombie_start_time = 0 - self.zombie_list.sort(key=takeTime) - - def setupCars(self): - self.cars = [] - 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: - self.choose(mouse_pos, mouse_click) - elif self.state == c.PLAY: - self.play(mouse_pos, mouse_click) - - self.draw(surface) - - def initBowlingMap(self): - print('initBowlingMap') - for x in range(3, self.map.width): - for y in range(self.map.height): - self.map.setMapGridType(x, y, c.MAP_EXIST) - - def initState(self): - if c.CHOOSEBAR_TYPE in self.map_data: - self.bar_type = self.map_data[c.CHOOSEBAR_TYPE] - else: - self.bar_type = c.CHOOSEBAR_STATIC - - if self.bar_type == c.CHOOSEBAR_STATIC: - self.initChoose() - else: - card_pool = menubar.getCardPool(self.map_data[c.CARD_POOL]) - self.initPlay(card_pool) - if self.bar_type == c.CHOSSEBAR_BOWLING: - self.initBowlingMap() - - def initChoose(self): - self.state = c.CHOOSE - self.panel = menubar.Panel(menubar.all_card_list, self.map_data[c.INIT_SUN_NAME]) - - def choose(self, mouse_pos, mouse_click): - if mouse_pos and mouse_click[0]: - self.panel.checkCardClick(mouse_pos) - if self.panel.checkStartButtonClick(mouse_pos): - self.initPlay(self.panel.getSelectedCards()) - - def initPlay(self, card_list): - self.state = c.PLAY - if self.bar_type == c.CHOOSEBAR_STATIC: - 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.hint_image = None - self.hint_plant = False - if self.background_type == c.BACKGROUND_DAY and self.bar_type == c.CHOOSEBAR_STATIC: - self.produce_sun = True - else: - self.produce_sun = False - self.sun_timer = self.current_time - - self.removeMouseImage() - self.setupGroups() - self.setupZombies() - self.setupCars() - - def play(self, mouse_pos, mouse_click): - if self.zombie_start_time == 0: - self.zombie_start_time = self.current_time - elif len(self.zombie_list) > 0: - data = self.zombie_list[0] - if data[0] <= (self.current_time - self.zombie_start_time): - self.createZombie(data[1], data[2]) - self.zombie_list.remove(data) - - for i in range(self.map_y_len): - self.bullet_groups[i].update(self.game_info) - self.plant_groups[i].update(self.game_info) - self.zombie_groups[i].update(self.game_info) - self.hypno_zombie_groups[i].update(self.game_info) - for zombie in self.hypno_zombie_groups[i]: - if zombie.rect.x > c.SCREEN_WIDTH: - zombie.kill() - - self.head_group.update(self.game_info) - self.sun_group.update(self.game_info) - - if not self.drag_plant and mouse_pos and mouse_click[0]: - result = self.menubar.checkCardClick(mouse_pos) - if result: - self.setupMouseImage(result[0], result[1]) - elif self.drag_plant: - if mouse_click[1]: - self.removeMouseImage() - elif mouse_click[0]: - if self.menubar.checkMenuBarClick(mouse_pos): - self.removeMouseImage() - else: - self.addPlant() - elif mouse_pos is None: - self.setupHintImage() - - 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]: - for sun in self.sun_group: - if sun.checkCollision(mouse_pos[0], mouse_pos[1]): - self.menubar.increaseSunValue(sun.sun_value) - - for car in self.cars: - car.update(self.game_info) - - self.menubar.update(self.current_time) - - self.checkBulletCollisions() - self.checkZombieCollisions() - self.checkPlants() - self.checkCarCollisions() - self.checkGameState() - - def createZombie(self, name, map_y): - 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, y, self.head_group)) - elif name == c.CONEHEAD_ZOMBIE: - self.zombie_groups[map_y].add(zombie.ConeHeadZombie(c.ZOMBIE_START_X, y, self.head_group)) - elif name == c.BUCKETHEAD_ZOMBIE: - self.zombie_groups[map_y].add(zombie.BucketHeadZombie(c.ZOMBIE_START_X, 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, y, self.head_group)) - - def canSeedPlant(self): - x, y = pg.mouse.get_pos() - return self.map.showPlant(x, y) - - def addPlant(self): - pos = self.canSeedPlant() - if pos is None: - return - - if self.hint_image is None: - self.setupHintImage() - x, y = self.hint_rect.centerx, self.hint_rect.bottom - map_x, map_y = self.map.getMapIndex(x, y) - if self.plant_name == c.SUNFLOWER: - new_plant = plant.SunFlower(x, y, self.sun_group) - elif self.plant_name == c.PEASHOOTER: - new_plant = plant.PeaShooter(x, y, self.bullet_groups[map_y]) - elif self.plant_name == c.SNOWPEASHOOTER: - new_plant = plant.SnowPeaShooter(x, y, self.bullet_groups[map_y]) - elif self.plant_name == c.WALLNUT: - new_plant = plant.WallNut(x, y) - elif self.plant_name == c.CHERRYBOMB: - new_plant = plant.CherryBomb(x, y) - elif self.plant_name == c.THREEPEASHOOTER: - new_plant = plant.ThreePeaShooter(x, y, self.bullet_groups, map_y) - elif self.plant_name == c.REPEATERPEA: - new_plant = plant.RepeaterPea(x, y, self.bullet_groups[map_y]) - elif self.plant_name == c.CHOMPER: - new_plant = plant.Chomper(x, y) - elif self.plant_name == c.PUFFSHROOM: - new_plant = plant.PuffShroom(x, y, self.bullet_groups[map_y]) - elif self.plant_name == c.POTATOMINE: - new_plant = plant.PotatoMine(x, y) - elif self.plant_name == c.SQUASH: - new_plant = plant.Squash(x, y) - elif self.plant_name == c.SPIKEWEED: - new_plant = plant.Spikeweed(x, y) - elif self.plant_name == c.JALAPENO: - new_plant = plant.Jalapeno(x, y) - elif self.plant_name == c.SCAREDYSHROOM: - new_plant = plant.ScaredyShroom(x, y, self.bullet_groups[map_y]) - elif self.plant_name == c.SUNSHROOM: - new_plant = plant.SunShroom(x, y, self.sun_group) - elif self.plant_name == c.ICESHROOM: - new_plant = plant.IceShroom(x, y) - elif self.plant_name == c.HYPNOSHROOM: - new_plant = plant.HypnoShroom(x, y) - elif self.plant_name == c.WALLNUTBOWLING: - new_plant = plant.WallNutBowling(x, y, map_y, self) - elif self.plant_name == c.REDWALLNUTBOWLING: - new_plant = plant.RedWallNutBowling(x, y) - - if new_plant.can_sleep and self.background_type == c.BACKGROUND_DAY: - new_plant.setSleep() - self.plant_groups[map_y].add(new_plant) - if self.bar_type == c.CHOOSEBAR_STATIC: - self.menubar.decreaseSunValue(self.select_plant.sun_cost) - self.menubar.setCardFrozenTime(self.plant_name) - else: - self.menubar.deleateCard(self.select_plant) - - if self.bar_type != c.CHOSSEBAR_BOWLING: - self.map.setMapGridType(map_x, map_y, c.MAP_EXIST) - self.removeMouseImage() - #print('addPlant map[%d,%d], grid pos[%d, %d] pos[%d, %d]' % (map_x, map_y, x, y, pos[0], pos[1])) - - def setupHintImage(self): - pos = self.canSeedPlant() - if pos and self.mouse_image: - if (self.hint_image and pos[0] == self.hint_rect.x and - pos[1] == self.hint_rect.y): - return - width, height = self.mouse_rect.w, self.mouse_rect.h - image = pg.Surface([width, height]) - image.blit(self.mouse_image, (0, 0), (0, 0, width, height)) - image.set_colorkey(c.BLACK) - image.set_alpha(128) - self.hint_image = image - self.hint_rect = image.get_rect() - self.hint_rect.centerx = pos[0] - self.hint_rect.bottom = pos[1] - self.hint_plant = True - else: - self.hint_plant = False - - def setupMouseImage(self, plant_name, select_plant): - frame_list = tool.GFX[plant_name] - if plant_name in tool.PLANT_RECT: - data = tool.PLANT_RECT[plant_name] - x, y, width, height = data['x'], data['y'], data['width'], data['height'] - else: - x, y = 0, 0 - rect = frame_list[0].get_rect() - width, height = rect.w, rect.h - - if (plant_name == c.POTATOMINE or plant_name == c.SQUASH or - plant_name == c.SPIKEWEED or plant_name == c.JALAPENO or - plant_name == c.SCAREDYSHROOM or plant_name == c.SUNSHROOM or - plant_name == c.ICESHROOM or plant_name == c.HYPNOSHROOM or - plant_name == c.WALLNUTBOWLING or plant_name == c.REDWALLNUTBOWLING): - color = c.WHITE - else: - color = c.BLACK - self.mouse_image = tool.get_image(frame_list[0], x, y, width, height, color, 1) - self.mouse_rect = self.mouse_image.get_rect() - pg.mouse.set_visible(False) - self.drag_plant = True - self.plant_name = plant_name - self.select_plant = select_plant - - def removeMouseImage(self): - pg.mouse.set_visible(True) - self.drag_plant = False - self.mouse_image = None - self.hint_image = None - self.hint_plant = False - - def checkBulletCollisions(self): - collided_func = pg.sprite.collide_circle_ratio(0.7) - for i in range(self.map_y_len): - for bullet in self.bullet_groups[i]: - if bullet.state == c.FLY: - zombie = pg.sprite.spritecollideany(bullet, self.zombie_groups[i], collided_func) - if zombie and zombie.state != c.DIE: - zombie.setDamage(bullet.damage, bullet.ice) - bullet.setExplode() - - def checkZombieCollisions(self): - if self.bar_type == c.CHOSSEBAR_BOWLING: - ratio = 0.6 - else: - ratio = 0.7 - collided_func = pg.sprite.collide_circle_ratio(ratio) - for i in range(self.map_y_len): - hypo_zombies = [] - for zombie in self.zombie_groups[i]: - if zombie.state != c.WALK: - continue - plant = pg.sprite.spritecollideany(zombie, self.plant_groups[i], collided_func) - if plant: - if plant.name == c.WALLNUTBOWLING: - if plant.canHit(i): - zombie.setDamage(c.WALLNUT_BOWLING_DAMAGE) - plant.changeDirection(i) - elif plant.name == c.REDWALLNUTBOWLING: - if plant.state == c.IDLE: - plant.setAttack() - elif plant.name != c.SPIKEWEED: - zombie.setAttack(plant) - - 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) - for zombie in zombie_list: - if zombie.state == c.DIE: - continue - if zombie.state == c.WALK: - zombie.setAttack(hypno_zombie, False) - if hypno_zombie.state == c.WALK: - hypno_zombie.setAttack(zombie, False) - - def checkCarCollisions(self): - collided_func = pg.sprite.collide_circle_ratio(0.8) - for car in self.cars: - zombies = pg.sprite.spritecollide(car, self.zombie_groups[car.map_y], False, collided_func) - for zombie in zombies: - if zombie and zombie.state != c.DIE: - car.setWalk() - zombie.setDie() - if car.dead: - self.cars.remove(car) - - def boomZombies(self, x, map_y, y_range, x_range): - for i in range(self.map_y_len): - if abs(i - map_y) > y_range: - continue - for zombie in self.zombie_groups[i]: - if abs(zombie.rect.centerx - x) <= x_range: - zombie.setBoomDie() - - def freezeZombies(self, plant): - for i in range(self.map_y_len): - for zombie in self.zombie_groups[i]: - if zombie.rect.centerx < c.SCREEN_WIDTH: - zombie.setFreeze(plant.trap_frames[0]) - - def killPlant(self, plant): - x, y = plant.getPosition() - map_x, map_y = self.map.getMapIndex(x, y) - if self.bar_type != c.CHOSSEBAR_BOWLING: - self.map.setMapGridType(map_x, map_y, c.MAP_EMPTY) - if (plant.name == c.CHERRYBOMB or plant.name == c.JALAPENO or - (plant.name == c.POTATOMINE and not plant.is_init) or - plant.name == c.REDWALLNUTBOWLING): - self.boomZombies(plant.rect.centerx, map_y, plant.explode_y_range, - plant.explode_x_range) - elif plant.name == c.ICESHROOM and plant.state != c.SLEEP: - self.freezeZombies(plant) - elif plant.name == c.HYPNOSHROOM and plant.state != c.SLEEP: - zombie = plant.kill_zombie - zombie.setHypno() - _, map_y = self.map.getMapIndex(zombie.rect.centerx, zombie.rect.bottom) - self.zombie_groups[map_y].remove(zombie) - self.hypno_zombie_groups[map_y].add(zombie) - plant.kill() - - def checkPlant(self, plant, i): - zombie_len = len(self.zombie_groups[i]) - if plant.name == c.THREEPEASHOOTER: - if plant.state == c.IDLE: - if zombie_len > 0: - plant.setAttack() - elif (i-1) >= 0 and len(self.zombie_groups[i-1]) > 0: - plant.setAttack() - elif (i+1) < self.map_y_len and len(self.zombie_groups[i+1]) > 0: - plant.setAttack() - elif plant.state == c.ATTACK: - if zombie_len > 0: - pass - elif (i-1) >= 0 and len(self.zombie_groups[i-1]) > 0: - pass - elif (i+1) < self.map_y_len and len(self.zombie_groups[i+1]) > 0: - pass - else: - plant.setIdle() - elif plant.name == c.CHOMPER: - for zombie in self.zombie_groups[i]: - if plant.canAttack(zombie): - plant.setAttack(zombie, self.zombie_groups[i]) - break - elif plant.name == c.POTATOMINE: - for zombie in self.zombie_groups[i]: - if plant.canAttack(zombie): - plant.setAttack() - break - elif plant.name == c.SQUASH: - for zombie in self.zombie_groups[i]: - if plant.canAttack(zombie): - plant.setAttack(zombie, self.zombie_groups[i]) - break - elif plant.name == c.SPIKEWEED: - can_attack = False - for zombie in self.zombie_groups[i]: - if plant.canAttack(zombie): - can_attack = True - break - if plant.state == c.IDLE and can_attack: - plant.setAttack(self.zombie_groups[i]) - elif plant.state == c.ATTACK and not can_attack: - plant.setIdle() - elif plant.name == c.SCAREDYSHROOM: - need_cry = False - can_attack = False - for zombie in self.zombie_groups[i]: - if plant.needCry(zombie): - need_cry = True - break - elif plant.canAttack(zombie): - can_attack = True - if need_cry: - if plant.state != c.CRY: - plant.setCry() - elif can_attack: - if plant.state != c.ATTACK: - plant.setAttack() - elif plant.state != c.IDLE: - plant.setIdle() - elif(plant.name == c.WALLNUTBOWLING or - plant.name == c.REDWALLNUTBOWLING): - pass - else: - can_attack = False - if (plant.state == c.IDLE and zombie_len > 0): - for zombie in self.zombie_groups[i]: - if plant.canAttack(zombie): - can_attack = True - break - if plant.state == c.IDLE and can_attack: - plant.setAttack() - elif (plant.state == c.ATTACK and not can_attack): - plant.setIdle() - - def checkPlants(self): - for i in range(self.map_y_len): - for plant in self.plant_groups[i]: - if plant.state != c.SLEEP: - self.checkPlant(plant, i) - if plant.health <= 0: - self.killPlant(plant) - - def checkVictory(self): - if len(self.zombie_list) > 0: - return False - for i in range(self.map_y_len): - if len(self.zombie_groups[i]) > 0: - return False - return True - - def checkLose(self): - for i in range(self.map_y_len): - for zombie in self.zombie_groups[i]: - if zombie.rect.right < 0: - return True - return False - - def checkGameState(self): - if self.checkVictory(): - self.game_info[c.LEVEL_NUM] += 1 - self.next = c.GAME_VICTORY - self.done = True - elif self.checkLose(): - self.next = c.GAME_LOSE - self.done = True - - def drawMouseShow(self, surface): - if self.hint_plant: - surface.blit(self.hint_image, self.hint_rect) - x, y = pg.mouse.get_pos() - self.mouse_rect.centerx = x - self.mouse_rect.centery = y - surface.blit(self.mouse_image, self.mouse_rect) - - def drawZombieFreezeTrap(self, i, surface): - for zombie in self.zombie_groups[i]: - zombie.drawFreezeTrap(surface) - - def draw(self, surface): - self.level.blit(self.background, self.viewport, self.viewport) - surface.blit(self.level, (0,0), self.viewport) - if self.state == c.CHOOSE: - self.panel.draw(surface) - elif self.state == c.PLAY: - self.menubar.draw(surface) - for i in range(self.map_y_len): - self.plant_groups[i].draw(surface) - self.zombie_groups[i].draw(surface) - self.hypno_zombie_groups[i].draw(surface) - self.bullet_groups[i].draw(surface) - self.drawZombieFreezeTrap(i, surface) - for car in self.cars: - car.draw(surface) - self.head_group.draw(surface) - self.sun_group.draw(surface) - - if self.drag_plant: - self.drawMouseShow(surface) \ No newline at end of file diff --git a/source/state/mainmenu.py b/source/state/mainmenu.py deleted file mode 100644 index 6ac345f..0000000 --- a/source/state/mainmenu.py +++ /dev/null @@ -1,69 +0,0 @@ -__author__ = 'marble_xu' - -import pygame as pg -from .. import tool -from .. import constants as c - -class Menu(tool.State): - def __init__(self): - tool.State.__init__(self) - - def startup(self, current_time, persist): - self.next = c.LEVEL - self.persist = persist - self.game_info = persist - - self.setupBackground() - self.setupOption() - - def setupBackground(self): - frame_rect = [80, 0, 800, 600] - 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 - self.bg_rect.y = 0 - - def setupOption(self): - self.option_frames = [] - frame_names = [c.OPTION_ADVENTURE + '_0', c.OPTION_ADVENTURE + '_1'] - 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_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 - - self.option_start = 0 - self.option_timer = 0 - self.option_clicked = False - - def checkOptionClick(self, mouse_pos): - x, y = mouse_pos - if(x >= self.option_rect.x and x <= self.option_rect.right and - y >= self.option_rect.y and y <= self.option_rect.bottom): - self.option_clicked = True - self.option_timer = self.option_start = self.current_time - return False - - 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) - else: - if(self.current_time - self.option_timer) > 200: - self.option_frame_index += 1 - if self.option_frame_index >= 2: - self.option_frame_index = 0 - self.option_timer = self.current_time - 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 diff --git a/source/state/screen.py b/source/state/screen.py deleted file mode 100644 index a624460..0000000 --- a/source/state/screen.py +++ /dev/null @@ -1,59 +0,0 @@ -__author__ = 'marble_xu' - -import pygame as pg -from .. import tool -from .. import constants as c - -class Screen(tool.State): - def __init__(self): - tool.State.__init__(self) - self.end_time = 3000 - - def startup(self, current_time, persist): - self.start_time = current_time - self.next = c.LEVEL - self.persist = persist - self.game_info = persist - name = self.getImageName() - self.setupImage(name) - self.next = self.set_next_state() - - def getImageName(self): - pass - - def set_next_state(self): - pass - - def setupImage(self, name): - frame_rect = [0, 0, 800, 600] - self.image = tool.get_image(tool.GFX[name], *frame_rect) - self.rect = self.image.get_rect() - self.rect.x = 0 - self.rect.y = 0 - - def update(self, surface, current_time, mouse_pos, mouse_click): - if(current_time - self.start_time) < self.end_time: - surface.fill(c.WHITE) - surface.blit(self.image, self.rect) - else: - self.done = True - -class GameVictoryScreen(Screen): - def __init__(self): - Screen.__init__(self) - - def getImageName(self): - return c.GAME_VICTORY_IMAGE - - def set_next_state(self): - return c.LEVEL - -class GameLoseScreen(Screen): - def __init__(self): - Screen.__init__(self) - - def getImageName(self): - return c.GAME_LOOSE_IMAGE - - def set_next_state(self): - return c.MAIN_MENU \ No newline at end of file diff --git a/source/tool.py b/source/tool.py deleted file mode 100644 index 1a319c8..0000000 --- a/source/tool.py +++ /dev/null @@ -1,176 +0,0 @@ -__author__ = 'marble_xu' - -import os -import json -from abc import abstractmethod -import pygame as pg -from . import constants as c - -class State(): - def __init__(self): - self.start_time = 0.0 - self.current_time = 0.0 - self.done = 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''' - -class Control(): - def __init__(self): - self.screen = pg.display.get_surface() - self.done = False - self.clock = pg.time.Clock() - self.fps = 60 - self.keys = pg.key.get_pressed() - self.mouse_pos = None - self.mouse_click = [False, False] # value:[left mouse click, right mouse click] - self.current_time = 0.0 - self.state_dict = {} - self.state_name = None - self.state = None - self.game_info = {c.CURRENT_TIME:0.0, - c.LEVEL_NUM:c.START_LEVEL_NUM} - - def setup_states(self, state_dict, start_state): - self.state_dict = state_dict - self.state_name = start_state - self.state = self.state_dict[self.state_name] - self.state.startup(self.current_time, self.game_info) - - def update(self): - 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): - previous, self.state_name = self.state_name, self.state.next - persist = self.state.cleanup() - self.state = self.state_dict[self.state_name] - self.state.startup(self.current_time, persist) - - def event_loop(self): - for event in pg.event.get(): - if event.type == pg.QUIT: - self.done = True - elif event.type == pg.KEYDOWN: - self.keys = pg.key.get_pressed() - elif event.type == pg.KEYUP: - self.keys = pg.key.get_pressed() - elif event.type == pg.MOUSEBUTTONDOWN: - 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) - - def main(self): - while not self.done: - self.event_loop() - self.update() - pg.display.update() - self.clock.tick(self.fps) - print('game over') - -def get_image(sheet, x, y, width, height, colorkey=c.BLACK, scale=1): - image = pg.Surface([width, height]) - 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; - for pic in os.listdir(directory): - name, ext = os.path.splitext(pic) - if ext.lower() in accept: - index = int(name[index_start:]) - img = pg.image.load(os.path.join(directory, pic)) - if img.get_alpha(): - img = img.convert_alpha() - else: - img = img.convert() - img.set_colorkey(colorkey) - tmp[index]= img - frame_num += 1 - - for i in range(frame_num): - frame_list.append(tmp[i]) - return frame_list - -def load_all_gfx(directory, colorkey=c.WHITE, accept=('.png', '.jpg', '.bmp', '.gif')): - graphics = {} - for name1 in os.listdir(directory): - # subfolders under the folder resources\graphics - dir1 = os.path.join(directory, name1) - if os.path.isdir(dir1): - for name2 in os.listdir(dir1): - dir2 = os.path.join(dir1, name2) - if os.path.isdir(dir2): - # e.g. subfolders under the folder resources\graphics\Zombies - for name3 in os.listdir(dir2): - dir3 = os.path.join(dir2, name3) - # e.g. subfolders or pics under the folder resources\graphics\Zombies\ConeheadZombie - if os.path.isdir(dir3): - # e.g. it's the folder resources\graphics\Zombies\ConeheadZombie\ConeheadZombieAttack - image_name, _ = os.path.splitext(name3) - graphics[image_name] = load_image_frames(dir3, image_name, colorkey, accept) - else: - # e.g. pics under the folder resources\graphics\Plants\Peashooter - image_name, _ = os.path.splitext(name2) - graphics[image_name] = load_image_frames(dir2, image_name, colorkey, accept) - break - else: - # e.g. pics under the folder resources\graphics\Screen - name, ext = os.path.splitext(name2) - if ext.lower() in accept: - img = pg.image.load(dir2) - if img.get_alpha(): - img = img.convert_alpha() - else: - img = img.convert() - img.set_colorkey(colorkey) - graphics[name] = img - return graphics - -def loadZombieImageRect(): - file_path = os.path.join('source', '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('source', '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) - -GFX = load_all_gfx(os.path.join("resources","graphics")) -ZOMBIE_RECT = loadZombieImageRect() -PLANT_RECT = loadPlantImageRect()