zhangcongyu_branch
徐洁 2 years ago
parent 58bc70c436
commit 4ca4e3d936

@ -1,5 +0,0 @@
111
branch_hjj
gwx_work
pull_request_gwx
yqy_conduct

Binary file not shown.

@ -1 +0,0 @@
Subproject commit afc4ae12c7a19bee5aaa2c20e9d765e1afcccd80

@ -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)

@ -1,6 +0,0 @@
import pygame as pg
from source.main import main
if __name__=='__main__':
main()
pg.quit()

@ -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

@ -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)

@ -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)

@ -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

@ -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

@ -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}
}
}

@ -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}
}
}

@ -1,7 +0,0 @@
{
"background_type":0,
"init_sun_value":500,
"zombie_list":[
{"time":1000, "map_y":2, "name":"Zombie"}
]
}

@ -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"}
]
}

@ -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"}
]
}

@ -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"}
]
}

@ -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"}
]
}

@ -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"}
]
}

@ -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()

@ -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)

@ -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)

@ -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

@ -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()
Loading…
Cancel
Save