diff --git a/demo/demo3.jpg b/demo/demo3.jpg new file mode 100644 index 0000000..6f3f89b Binary files /dev/null and b/demo/demo3.jpg differ diff --git a/source/component/map.py b/source/component/map.py index e4ffba9..acd0718 100644 --- a/source/component/map.py +++ b/source/component/map.py @@ -26,7 +26,7 @@ class Map(): 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, + return (map_x * c.GRID_X_SIZE + c.GRID_X_SIZE//8 + 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): diff --git a/source/component/menubar.py b/source/component/menubar.py index 64a8a92..6d114a7 100644 --- a/source/component/menubar.py +++ b/source/component/menubar.py @@ -5,11 +5,11 @@ from .. import tool from .. import constants as c 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_CHERRYBOMB, c.CARD_THREEPEASHOOTER, c.CARD_REPEATERPEA, c.CARD_CHOMPER] plant_name_list = [c.SUNFLOWER, c.PEASHOOTER, c.SNOWPEASHOOTER, c.WALLNUT, - c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA] -plant_sun_list = [50, 100, 175, 50, 150, 325, 200] -card_list = [0, 1, 2, 3, 4, 5, 6] + c.CHERRYBOMB, c.THREEPEASHOOTER, c.REPEATERPEA, c.CHOMPER] +plant_sun_list = [50, 100, 175, 50, 150, 325, 200, 150] +card_list = [0, 1, 2, 3, 4, 5, 7] class Card(): def __init__(self, x, y, name_index): diff --git a/source/component/plant.py b/source/component/plant.py index a1d1e31..195f8e0 100644 --- a/source/component/plant.py +++ b/source/component/plant.py @@ -103,11 +103,11 @@ class Plant(pg.sprite.Sprite): self.frames = [] self.frame_index = 0 - self.loadFrames(self.frames, name, scale) + 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.x = x self.rect.bottom = y self.name = name @@ -115,15 +115,23 @@ class Plant(pg.sprite.Sprite): self.state = c.IDLE self.bullet_group = bullet_group self.animate_timer = 0 - - def loadFrames(self, frames, name, scale): + self.animate_interval = 100 + + def loadFrames(self, frames, name, scale, frame_rect=None): frame_list = tool.GFX[name] - rect = frame_list[0].get_rect() - width, height = rect.w, rect.h + if frame_rect == None: + x, y = 0, 0 + rect = frame_list[0].get_rect() + width, height = rect.w, rect.h + else: + x, y, width, height = frame_rect[0], frame_rect[1], frame_rect[2], frame_rect[3] for frame in frame_list: frames.append(tool.get_image(frame, 0, 0, width, height, c.BLACK, scale)) - + + def loadImages(self, name, scale): + self.loadFrames(self.frames, name, scale) + def update(self, game_info): self.current_time = game_info[c.CURRENT_TIME] self.handleState() @@ -134,8 +142,8 @@ class Plant(pg.sprite.Sprite): self.idling() elif self.state == c.ATTACK: self.attacking() - elif self.state == c.ATTACKED: - self.attacked() + elif self.state == c.DIGEST: + self.digest() def idling(self): pass @@ -143,11 +151,11 @@ class Plant(pg.sprite.Sprite): def attacking(self): pass - def attacked(self): - self.attacking() + def digest(self): + pass def animation(self): - if (self.current_time - self.animate_timer) > 100: + 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 @@ -162,8 +170,7 @@ class Plant(pg.sprite.Sprite): self.state = c.IDLE def setAttacked(self): - self.state = c.ATTACKED - self.frame_index = 0 + pass def setDamage(self, damage): self.health -= damage @@ -343,3 +350,77 @@ class CherryBomb(Plant): 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], rect_list[i]) + + self.frames = self.idle_frames + + def canAttack(self, zombie): + if (self.state == c.IDLE and zombie.state != c.DIGEST and + (self.rect.right + c.GRID_X_SIZE//3 * 2 >= 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() + + 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 diff --git a/source/constants.py b/source/constants.py index f3927cb..f5a2725 100644 --- a/source/constants.py +++ b/source/constants.py @@ -68,6 +68,7 @@ WALLNUT = 'WallNut' CHERRYBOMB = 'CherryBomb' THREEPEASHOOTER = 'Threepeater' REPEATERPEA = 'RepeaterPea' +CHOMPER = 'Chomper' CHERRY_BOOM_IMAGE = 'Boom' PLANT_HEALTH = 5 @@ -90,6 +91,7 @@ CARD_WALLNUT = 'card_wallnut' CARD_CHERRYBOMB = 'card_cherrybomb' CARD_THREEPEASHOOTER = 'card_threepeashooter' CARD_REPEATERPEA = 'card_repeaterpea' +CARD_CHOMPER = 'card_chomper' #BULLET INFO BULLET_PEA = 'PeaNormal' @@ -122,6 +124,7 @@ FLY = 'fly' EXPLODE = 'explode' ATTACK = 'attack' ATTACKED = 'attacked' +DIGEST = 'digest' WALK = 'walk' DIE = 'die' diff --git a/source/state/level.py b/source/state/level.py index 1029b53..eeb8650 100644 --- a/source/state/level.py +++ b/source/state/level.py @@ -154,7 +154,7 @@ class Level(tool.State): if self.hint_image is None: self.setupHintImage() - x, y = self.hint_rect.centerx, self.hint_rect.bottom + x, y = self.hint_rect.x, self.hint_rect.bottom map_x, map_y = self.map.getMapIndex(x, y) if self.plant_name == c.SUNFLOWER: self.plant_groups[map_y].add(plant.SunFlower(x, y, self.sun_group)) @@ -170,6 +170,8 @@ class Level(tool.State): self.plant_groups[map_y].add(plant.ThreePeaShooter(x, y, self.bullet_groups, map_y)) elif self.plant_name == c.REPEATERPEA: self.plant_groups[map_y].add(plant.RepeaterPea(x, y, self.bullet_groups[map_y])) + elif self.plant_name == c.CHOMPER: + self.plant_groups[map_y].add(plant.Chomper(x, y)) self.menubar.decreaseSunValue(self.plant_cost) self.map.setMapGridType(map_x, map_y, c.MAP_EXIST) @@ -189,7 +191,7 @@ class Level(tool.State): image.set_alpha(128) self.hint_image = image self.hint_rect = image.get_rect() - self.hint_rect.centerx = pos[0] + self.hint_rect.x = pos[0] self.hint_rect.bottom = pos[1] self.hint_plant = True else: @@ -259,37 +261,44 @@ class Level(tool.State): self.boomZombies(plant.rect.centerx, map_y) 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 + else: + if (plant.state == c.IDLE and zombie_len > 0): + plant.setAttack() + elif (plant.state == c.ATTACK and zombie_len == 0): + plant.setIdle() + + if plant.health <= 0: + self.killPlant(plant) + def checkPlants(self): for i in range(self.map_y_len): - if len(self.zombie_groups[i]) > 0: - for plant in self.plant_groups[i]: - if plant.state == c.IDLE: - plant.setAttack() - if plant.health <= 0: - self.killPlant(plant) - if (i-1) >= 0: - for plant in self.plant_groups[i-1]: - if plant.name == c.THREEPEASHOOTER and plant.state == c.IDLE: - plant.setAttack() - if (i+1) < self.map_y_len: - for plant in self.plant_groups[i+1]: - if plant.name == c.THREEPEASHOOTER and plant.state == c.IDLE: - plant.setAttack() - else: - for plant in self.plant_groups[i]: - if plant.state == c.ATTACK: - if plant.name == c.THREEPEASHOOTER: - if (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() - else: - plant.setIdle() - if plant.health <= 0: - self.killPlant(plant) - + for plant in self.plant_groups[i]: + self.checkPlant(plant, i) + def checkVictory(self): if len(self.zombie_list) > 0: return False