Pygame实战!——自制PVZ(植物大战僵尸)

QQ技术分享交流互助群

 我把整个文件(这个实践的)放“喵做梦技术讨论群”里了,需者加群自取。

QQ群号:566341887   (大家一起互帮互助,共同进步,交流分享,奔赴未来!)

书接上回, 废话不多说,直接开干!

第一步、创建文件夹

第一步就迅速点,直接过。

同一级中放代码,存放图片的文件夹P和存放数据的文件夹data。

好,非常快,继续! 

第二步、搭建基本框架

也就是最最最基础,简单的,什么导入模块啊,弹出窗口啊之类了。

这里也是非常的简单,速过!

import pygame
from random import randint

pygame.init()
scsize=(1000,600)

screen=pygame.display.set_mode(scsize)
pygame.display.set_caption("乱来的PVZ")

while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
    pygame.display.flip()

顺手把帧率和字体渲染一类简单的给准备好。

import pygame
from random import randint

pygame.init()
scsize=(1000,600)

#基础
screen=pygame.display.set_mode(scsize)
pygame.display.set_caption("乱来的PVZ")
zf=pygame.time.Clock()
ts=pygame.font.SysFont("simhei",20)
tc=ts.render("",True,(0,0,0))

while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
    zf.tick(30)
    pygame.display.flip()

非常的简单喵,下一步。

第三步、状态机雏形

目前这几步都挺简单的,状态机的话,浅浅分一下:

这么来分,普通模式、娱乐模式、无尽模式、商店、各种各样……太多就先不一一举例了。

无论是什么模式,其实只要会一种了,其他的也就简单了,所以我们先从普通模式开始。

import pygame
from random import randint

pygame.init()
scsize=(1000,600)

#全局变量
menu=0
putongmark=1

#基础
screen=pygame.display.set_mode(scsize)
pygame.display.set_caption("乱来的PVZ")
zf=pygame.time.Clock()
ts=pygame.font.SysFont("simhei",20)
tc=ts.render("",True,(0,0,0))

while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
    if menu==0:#进入界面
        pass
    elif menu==1:#菜单
        pass
    zf.tick(30)
    pygame.display.flip()

第四步、基础化

1.目标

这一步的目标非常明确,是为了让游戏能运行(但是不能打僵尸目前)。

2.准备

我们要根据窗口的大小,绘制相应的图片。

并且要通过读取鼠标的坐标,以及判断是否按下来确定是否改变menu的值。

这种图片如果要还原的话,大家最好还是去网上搜原图,截下来,然后扣掉边边角角拿来用。

本喵的选择是:自己手搓,这样好玩。 

那么开始!

 我自己画了一张,非常抽象,无所谓,自己开心就行。

(通过不同状态下的login按键,提示玩家是否触屏到了按键。) 

 接下来,让我们输入一些简单的代码。(不懂的看以前写的。)

3.缝合

import pygame
from random import randint

pygame.init()
scsize=(1000,600)

#全局变量
menu=0
putongmark=1

#基础
screen=pygame.display.set_mode(scsize)
pygame.display.set_caption("乱来的PVZ")
zf=pygame.time.Clock()
ts=pygame.font.SysFont("simhei",20)
tc=ts.render("",True,(0,0,0))

#login
loginback=pygame.image.load("P/login/loginback.png")
login=pygame.image.load("P/login/loginno.png")
loginmark=0
#menu
menuback=pygame.image.load("P/menu/back.png")

while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
    mox, moy = pygame.mouse.get_pos() #实时读取鼠标x,y
    if menu==0:#进入界面
        screen.blit(loginback,(0,0))
        screen.blit(login,(400,400))
        if loginmark==0:
            login=pygame.image.load("P/login/loginno.png")
        else : login=pygame.image.load("P/login/loginyes.png")
        loginmark=0
        if mox>=400 and mox<=600:
            if moy>=400 and moy<=450:
                loginmark=1
        if loginmark==1 and event.type == pygame.MOUSEBUTTONDOWN:
            menu=1
    elif menu==1:#菜单
        screen.blit(menuback,(0,0))
    zf.tick(30)
    pygame.display.flip()

非常的简单,里面这个对loginmark的判断,就是提示玩家鼠标是否碰到该按键。

我们就先从最简单的开始。

(还要做一个进入到冒险模式的按键)

第五步、冒险模式

把这个也缝合进去之后,我们就可以真正开始了。 

import pygame
from random import randint

pygame.init()
scsize=(1000,600)

#全局变量
menu=0
putongmark=1

#基础
screen=pygame.display.set_mode(scsize)
pygame.display.set_caption("乱来的PVZ")
zf=pygame.time.Clock()
ts=pygame.font.SysFont("simhei",20)
tc=ts.render("",True,(0,0,0))

#login
loginback=pygame.image.load("P/login/loginback.png")
login=pygame.image.load("P/login/loginno.png")
loginmark=0
#menu
menuback=pygame.image.load("P/menu/back.png")
mx=pygame.image.load("P/menu/maoxianno.png")
mxmark=0

while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            pygame.quit()
    mox, moy = pygame.mouse.get_pos() #实时读取鼠标x,y
    if menu==0:#进入界面
        screen.blit(loginback,(0,0))
        screen.blit(login,(400,400))
        if loginmark==0:
            login=pygame.image.load("P/login/loginno.png")
        else : login=pygame.image.load("P/login/loginyes.png")
        loginmark=0
        if mox>=400 and mox<=600:
            if moy>=400 and moy<=450:
                loginmark=1
        if loginmark==1 and event.type == pygame.MOUSEBUTTONDOWN:
            menu=1
    elif menu==1:#菜单
        screen.blit(menuback,(0,0))
        screen.blit(mx,(700,200))
        if mxmark==0:
            mx=pygame.image.load("P/menu/maoxianno.png")
        else : mx=pygame.image.load("P/menu/maoxianyes.png")
        mxmark=0
        if mox>=700 and mox<=880:
            if moy>=200 and moy<=250:
                mxmark=1
        if mxmark==1 and event.type == pygame.MOUSEBUTTONDOWN:
            menu=2
    elif menu==2:#冒险模式
        pass
    zf.tick(30)
    pygame.display.flip()

1.要素准备

在植物大战僵尸中,关卡里面有几个重要的元素:草坪背景、阳光数量显示、卡牌、僵尸

那么就先随便画点图片(大不了后期做优化)。

但是,不急着画,先理论,后运用。毕竟这个图片大小,是有点影响后面的。

2.理论基础

(1)草坪

关卡中,我们要先知道,这个窗口的大小为1000×600,我们接下来要对其进行合理地分划。

我数出来,关卡中草坪的区块是9×5个,那么我们可以把每个区块的大小画成100×100。

 从上到下,从左到右依次为:

阳光 卡片槽 铲子 菜单
小推车 草坪 僵尸产地
### 使用 Pygame 开发类似《植物大战僵尸》的游戏 #### 游戏架构设计 为了创建一个类似于《植物大战僵尸》的游戏,需要考虑几个主要组件: - **游戏场景**:包括背景、草地、泳池等不同区域。 - **角色设定**:分为玩家可控制的角色(如向日葵、豌豆射手)和敌方单位(如僵尸)。 - **资源管理**:阳光收集机制用于购买植物;生命值表示玩家剩余防线。 #### 初始化项目结构 建立清晰的文件夹布局有助于后续开发维护工作。建议如下组织代码文件[^1]: ``` plant_vs_zombies/ ├── assets/ │ ├── images/ │ └── sounds/ └── src/ ├── main.py ├── game_objects.py └── constants.py ``` #### 安装依赖项 确保已安装最新版本 `pygame` 库以便顺利运行程序。可以通过 pip 工具完成安装操作: ```bash pip install pygame ``` #### 主要功能实现 以下是简化版的核心逻辑框架,展示了基本玩法循环以及部分对象定义方式。 ##### 导入必要的库并设置全局变量 ```python import sys, os import random import time from typing import List import pygame as pg class Constants: SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 FPS = 30 # 资源路径配置 IMAGE_PATHS = { 'sunflower': './assets/images/sunflower.png', 'peashooter': './assets/images/peashooter.png' } SOUND_PATHS = { 'shoot': './assets/sounds/shoot.wav' } pg.init() screen = pg.display.set_mode((Constants.SCREEN_WIDTH, Constants.SCREEN_HEIGHT)) clock = pg.time.Clock() # 加载图像素材函数 def load_image(name: str) -> pg.SurfaceType: fullname = os.path.join('data', name) try: image = pg.image.load(fullname).convert_alpha() except Exception as e: print(f'Cannot load image:{fullname}') raise SystemExit(e) return image ``` ##### 创建游戏角色类 ```python class GameObject(pg.sprite.Sprite): def __init__(self, position=(0, 0)): super().__init__() self.rect = None @property def pos(self): return (self.rect.x, self.rect.y) class Plant(GameObject): pass class SunFlower(Plant): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.image = load_image(Constants.IMAGE_PATHS['sunflower']) self.rect = self.image.get_rect(topleft=position) class PeaShooter(Plant): def shoot_pea(self): pea = Bullet(position=self.pos) all_sprites.add(pea) bullets_group.add(pea) sound_shoot.play() class Zombie(GameObject): def move_towards_player(self): ... ``` ##### 实现主循环流程 ```python all_sprites = pg.sprite.Group() # 所有精灵组 plants_group = pg.sprite.Group() # 植物精灵组 zombies_group = pg.sprite.Group() # 僵尸精灵组 bullets_group = pg.sprite.Group() # 子弹精灵组 sound_shoot = pg.mixer.Sound(Constants.SOUND_PATHS['shoot']) while True: clock.tick(Constants.FPS) for event in pg.event.get(): if event.type == pg.QUIT: sys.exit() elif event.type == pg.MOUSEBUTTONDOWN and not is_game_over: mouse_pos = pg.mouse.get_pos() clicked_plant_type = get_selected_plant(mouse_pos) plant_instance = create_new_plant(clicked_plant_type, mouse_pos) plants_group.add(plant_instance) all_sprites.add(plant_instance) update_all_groups_and_draw_them_on_screen() check_collision_between_bullets_and_zombies() spawn_more_zombies_if_needed() handle_sun_collection_mechanism() screen.blit(background_img, background_rect) draw_text(screen, f'Score: {score}', ...) pg.display.flip() ``` 通过上述代码片段可以看出,在构建此类塔防类型的小型休闲游戏中,合理规划好各个模块之间的关系非常重要。这里仅提供了一个非常基础的概念验证级例子,实际应用时还需要加入更多细节处理,例如碰撞检测优化、动画效果增强等方面的工作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值