前言
大家早好、午好、晚好吖 ❤ ~欢迎光临本文章
晃着脑袋生产阳光的向日葵,突突突吐着子弹的豌豆射手!
行动迟缓种类丰富的僵尸……
印象最深的是“僵尸吃掉了你的脑子!”
还有疯狂的戴夫,无一不唤醒着我们的童年记忆
山民们闯到哪一关了?解锁了哪些植物?
在今天,就让我们来上一个大工程,制作植物大战僵尸小游戏里的冒险模式~
(有一个简单版和复刻版嘚~)
软件安装
-
Python 3.8 / 编译器
-
Pycharm 2021.2版本 / 代码编辑器
简单版
游戏素材
代码展示
引入需要的模块
import pygame
import random
- 1
- 2
配置图片地址
IMAGE_PATH = 'imgs/'
- 1
设置页面宽高
scrrr_width = 800
scrrr_height = 560
- 1
- 2
创建控制游戏结束的状态
GAMEOVER = False
- 1
图片加载报错处理
LOG = '文件:{}中的方法:{}出错'.format(__file__, __name__)
- 1
创建地图类
class Map():
- 1
- 2
存储两张不同颜色的图片名称
map_names_list = [IMAGE_PATH + 'map1.png', IMAGE_PATH + 'map2.png']
- 1
初始化地图
def __init__(self, x, y, img_index):
self.image = pygame.image.load(Map.map_names_list[img_index])
self.position = (x, y)
# 是否能够种植
self.can_grow = True
- 1
- 2
- 3
- 4
- 5
加载地图
def load_map(self):
MainGame.window.blit(self.image, self.position)
- 1
- 2
植物类
class Plant(pygame.sprite.Sprite):
def __init__(self):
super(Plant, self).__init__()
self.live = True
- 1
- 2
- 3
- 4
加载图片
def load_image(self):
if hasattr(self, 'image') and hasattr(self, 'rect'):
MainGame.window.blit(self.image, self.rect)
else:
print(LOG)
- 1
- 2
- 3
- 4
- 5
向日葵类
class Sunflower(Plant):
def __init__(self, x, y):
super(Sunflower, self).__init__()
self.image = pygame.image.load('imgs/sunflower.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.price = 50
self.hp = 100
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
时间计数器
self.time_count = 0
- 1
新增功能:生成阳光
def produce_money(self):
self.time_count += 1
if self.time_count == 25:
MainGame.money += 5
self.time_count = 0
- 1
- 2
- 3
- 4
- 5
向日葵加入到窗口中
def display_sunflower(self):
MainGame.window.blit(self.image, self.rect)
- 1
- 2
豌豆射手类
class PeaShooter(Plant):
def __init__(self, x, y):
super(PeaShooter, self).__init__()
# self.image 为一个 surface
self.image = pygame.image.load('imgs/peashooter.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.price = 50
self.hp = 200
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
发射计数器
self.shot_count = 0
- 1
增加射击方法
def shot(self):
- 1
记录是否应该射击
should_fire = False
for zombie in MainGame.zombie_list:
if zombie.rect.y == self.rect.y and zombie.rect.x < 800 and zombie.rect.x > self.rect.x:
should_fire = True
- 1
- 2
- 3
- 4
如果活着
if self.live and should_fire:
self.shot_count += 1
- 1
- 2
计数器到25发射一次
if self.shot_count == 25:
- 1
基于当前豌豆射手的位置,创建子弹
peabullet = PeaBullet(self)
- 1
将子弹存储到子弹列表中
MainGame.peabullet_list.append(peabullet)
self.shot_count = 0
- 1
- 2
将豌豆射手加入到窗口中的方法
def display_peashooter(self):
MainGame.window.blit(self.image, self.rect)
- 1
- 2
豌豆子弹类
class PeaBullet(pygame.sprite.Sprite):
def __init__(self, peashooter):
self.live = True
self.image = pygame.image.load('imgs/peabullet.png')
self.damage = 50
self.speed = 10
self.rect = self.image.get_rect()
self.rect.x = peashooter.rect.x + 60
self.rect.y = peashooter.rect.y + 15
def move_bullet(self):
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
在屏幕范围内,实现往右移动
if self.rect.x < scrrr_width:
self.rect.x += self.speed
else:
self.live = False
- 1
- 2
- 3
- 4
新增,子弹与僵尸的碰撞
def hit_zombie(self):
for zombie in MainGame.zombie_list:
if pygame.sprite.collide_rect(self, zombie):
# 打中僵尸之后,修改子弹的状态,
self.live = False
# 僵尸掉血
zombie.hp -= self.damage
if zombie.hp <= 0:
zombie.live = False
self.nextLevel()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
闯关方法
def nextLevel(self):
MainGame.score += 20
MainGame.remnant_score -= 20
for i in range(1, 100):
if MainGame.score == 100 * i and MainGame.remnant_score == 0:
MainGame.remnant_score = 100 * i
MainGame.shaoguan += 1
MainGame.produce_zombie += 50
def display_peabullet(self):
MainGame.window.blit(self.image, self.rect)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
僵尸类
class Zombie(pygame.sprite.Sprite):
def __init__(self, x, y):
super(Zombie, self).__init__()
self.image = pygame.image.load('imgs/zombie.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.hp = 1000
self.damage = 2
self.speed = 1
self.live = True
self.stop = False
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
僵尸的移动
def move_zombie(self):
if self.live and not self.stop:
self.rect.x -= self.speed
if self.rect.x < -80:
- 1
- 2
- 3
- 4
调用游戏结束方法
MainGame().gameOver()
- 1
判断僵尸是否碰撞到植物,如果碰撞,调用攻击植物的方法
def hit_plant(self):
for plant in MainGame.plants_list:
if pygame.sprite.collide_rect(self, plant):
- 1
- 2
- 3
僵尸移动状态的修改
self.stop = True
self.eat_plant(plant)
- 1
- 2
僵尸攻击植物
def eat_plant(self, plant):
- 1
植物生命值减少
plant.hp -= self.damage
- 1
植物死亡后的状态修改,以及地图状态的修改
if plant.hp <= 0:
a = plant.rect.y // 80 - 1
b = plant.rect.x // 80
map = MainGame.map_list[a][b]
map.can_grow = True
plant.live = False
- 1
- 2
- 3
- 4
- 5
- 6
修改僵尸的移动状态
self.stop = False
- 1
将僵尸加载到地图中
def display_zombie(self):
MainGame.window.blit(self.image, self.rect)
- 1
- 2
主程序
class MainGame():
- 1
创建关数,得分,剩余分数,钱数
shaoguan = 1
score = 0
remnant_score = 100
money = 200
- 1
- 2
- 3
- 4
存储所有地图坐标点
map_points_list = []
- 1
存储所有的地图块
map_list = []
- 1
存储所有植物的列表
plants_list = []
- 1
存储所有豌豆子弹的列表
peabullet_list = []
- 1
新增存储所有僵尸的列表
zombie_list = []
count_zombie = 0
produce_zombie = 100
- 1
- 2
- 3
加载游戏窗口
def init_window(self):
- 1
调用显示模块的初始化
pygame.display.init()
- 1
创建窗口
MainGame.window = pygame.display.set_mode([scrrr_width, scrrr_height])
- 1
文本绘制
def draw_text(self, content, size, color):
pygame.font.init()
font = pygame.font.SysFont('kaiti', size)
text = font.render(content, True, color)
return text
- 1
- 2
- 3
- 4
- 5
加载帮助提示
def load_help_text(self):
text1 = self.draw_text('1.按左键创建向日葵 2.按右键创建豌豆射手', 26, (255, 0, 0))
MainGame.window.blit(text1, (5, 5))
- 1
- 2
- 3
初始化坐标点
def init_plant_points(self):
for y in range(1, 7):
points = []
for x in range(10):
point = (x, y)
points.append(point)
MainGame.map_points_list.append(points)
print("MainGame.map_points_list", MainGame.map_points_list)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
初始化地图
def init_map(self):
for points in MainGame.map_points_list:
temp_map_list = list()
for point in points:
# map = None
if (point[0] + point[1]) % 2 == 0:
map = Map(point[0] * 80, point[1] * 80, 0)
else:
map = Map(point[0] * 80, point[1] * 80, 1)
# 将地图块加入到窗口中
temp_map_list.append(map)
print("temp_map_list", temp_map_list)
MainGame.map_list.append(temp_map_list)
print("MainGame.map_list", MainGame.map_list)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
将地图加载到窗口中
def load_map(self):
for temp_map_list in MainGame.map_list:
for map in temp_map_list:
map.load_map()
- 1
- 2
- 3
- 4
增加豌豆射手发射处理
def load_plants(self):
for plant in MainGame.plants_list:
- 1
- 2
优化加载植物的处理逻辑
if plant.live:
if isinstance(plant, Sunflower):
plant.display_sunflower()
plant.produce_money()
elif isinstance(plant, PeaShooter):
plant.display_peashooter()
plant.shot()
else:
MainGame.plants_list.remove(plant)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
加载所有子弹的方法
def load_peabullets(self):
for b in MainGame.peabullet_list:
if b.live:
b.display_peabullet()
b.move_bullet()
# v1.9 调用子弹是否打中僵尸的方法
b.hit_zombie()
else:
MainGame.peabullet_list.remove(b)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
事件处理
def deal_events(self):
- 1
获取所有事件
eventList = pygame.event.get()
- 1
遍历事件列表,判断
for e in eventList:
if e.type == pygame.QUIT:
self.gameOver()
elif e.type == pygame.MOUSEBUTTONDOWN:
# print('按下鼠标按键')
print(e.pos)
# print(e.button)#左键1 按下滚轮2 上转滚轮为4 下转滚轮为5 右键 3
x = e.pos[0] // 80
y = e.pos[1] // 80
print(x, y)
map = MainGame.map_list[y - 1][x]
print(map.position)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
增加创建时候的地图装填判断以及金钱判断
if e.button == 1:
if map.can_grow and MainGame.money >= 50:
sunflower = Sunflower(map.position[0], map.position[1])
MainGame.plants_list.append(sunflower)
print('当前植物列表长度:{}'.format(len(MainGame.plants_list)))
map.can_grow = False
MainGame.money -= 50
elif e.button == 3:
if map.can_grow and MainGame.money >= 50:
peashooter = PeaShooter(
map.position[0], map.position[1])
MainGame.plants_list.append(peashooter)
print('当前植物列表长度:{}'.format(len(MainGame.plants_list)))
map.can_grow = False
MainGame.money -= 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
新增初始化僵尸的方法
def init_zombies(self):
for i in range(1, 7):
dis = random.randint(1, 5) * 200
zombie = Zombie(800 + dis, i * 80)
MainGame.zombie_list.append(zombie)
- 1
- 2
- 3
- 4
- 5
将所有僵尸加载到地图中
def load_zombies(self):
for zombie in MainGame.zombie_list:
if zombie.live:
zombie.display_zombie()
zombie.move_zombie()
# v2.0 调用是否碰撞到植物的方法
zombie.hit_plant()
else:
MainGame.zombie_list.remove(zombie)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
开始游戏
def start_game(self):
- 1
初始化窗口
self.init_window()
- 1
初始化坐标和地图
self.init_plant_points()
self.init_map()
- 1
- 2
调用初始化僵尸的方法
self.init_zombies()
- 1
只要游戏没结束,就一直循环
while not GAMEOVER:
- 1
渲染白色背景
MainGame.window.fill((255, 255, 255))
- 1
渲染的文字和坐标位置
MainGame.window.blit(
self.draw_text(
'当前钱数$: {}'.format(
MainGame.money), 26, (255, 0, 0)), (500, 40))
MainGame.window.blit(
self.draw_text(
'当前关数{},得分{},距离下关还差{}分'.format(
MainGame.shaoguan,
MainGame.score,
MainGame.remnant_score),
26,
(255,
0,
0)),
(5,
40))
self.load_help_text()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
需要反复加载地图
self.load_map()
- 1
调用加载植物的方法
self.load_plants()
- 1
调用加载所有子弹的方法
self.load_peabullets()
- 1
调用事件处理的方法
self.deal_events()
- 1
调用展示僵尸的方法
self.load_zombies()
- 1
计数器增长,每数到100,调用初始化僵尸的方法
MainGame.count_zombie += 1
if MainGame.count_zombie == MainGame.produce_zombie:
self.init_zombies()
MainGame.count_zombie = 0
pygame.time.wait(10)
pygame.display.update()
def gameOver(self):
MainGame.window.blit(
self.draw_text(
'游戏结束', 50, (255, 0, 0)), (300, 200))
print('游戏结束')
pygame.time.wait(400)
global GAMEOVER
GAMEOVER = True
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
运行
if __name__ == '__main__':
game = MainGame()
game.start_game()
- 1
- 2
- 3
效果展示
复刻版
游戏素材
代码展示
import pygame as pg
from source.main import main
if __name__=='__main__':
main()
pg.quit()
- 1
- 2
- 3
- 4
- 5
- 6
__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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
__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
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
完整代码太多,需要的小可耐们可以点击文章下方名片找我领取呐
__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()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
完整代码太多,需要的小可耐们可以点击文章下方名片找我领取呐`
效果展示(部分)
首页
挑选植物页面
战斗页面
战斗胜利页面
经典语录
? 我会一直很努力地笑着为你制造阳光
因为我知道你喜欢阳光灿烂的感觉。——向日葵
? 我不会防守,也不会进攻,连当个炮灰都显得那么微不足道,
可是我有着承载的力量,我会为你承担。——荷叶
? 只需要一点点的时间 !
我就会告诉你为了你我有多么的奋不顾身。——土豆雷
? 我很平凡,我很普通,我知道,现在的我已经渐渐被你遗忘,甚至抛弃
但至少,我曾经是你的唯。一——豌豆射手
? 舍生取义的一跳之后,留给你的,是一片寂静的天地。
你会记得我蔑视敌人的眼神吗?我从来都不懂得害怕为何物。——窝瓜
? 我生长在黑暗中,为你消除一个又一个隐患。
我会和他们同归于尽,为你修整出宽阔的道路。——墓碑吞噬者
? 你喜欢谁,我就是谁,你需要谁,我就是谁。
没有自我,是不是很可悲呢?没关系,你开心就好。——模仿者
? 不要埋怨那个坑好吗?
我只是想在这个战场,留下一点点证明我曾经存在过的痕迹。——毁灭菇
? 我的出现就是为了毁灭,毁灭敌人,还有我自己。
你会记住我吗?就算只有一刹那,我也觉得,自己很美丽。——樱桃
尾语
好了,今天的分享就差不多到这里了!
完整代码、更多资源、疑惑解答直接点击下方名片自取即可。
对下一篇大家想看什么,可在评论区留言哦!看到我会更新哒(ง •_•)ง
喜欢就关注一下博主,或点赞收藏评论一下我的文章叭!!!