教你用Python写一个植物大战僵尸小游戏


Posted in Python onApril 25, 2021

一、前言

上次写了一个俄罗斯方块,感觉好像大家都看懂了,这次就更新一个植物大战僵尸吧

二、引入模块

import pygame
import random

三、完整代码

配置图片地址

IMAGE_PATH = 'imgs/'

设置页面宽高

scrrr_width = 800
scrrr_height = 560

创建控制游戏结束的状态

GAMEOVER = False

图片加载报错处理

LOG = '文件:{}中的方法:{}出错'.format(__file__, __name__)

创建地图类

class Map():

存储两张不同颜色的图片名称

map_names_list = [IMAGE_PATH + 'map1.png', IMAGE_PATH + 'map2.png']

初始化地图

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

加载地图

def load_map(self):
    MainGame.window.blit(self.image, self.position)

植物类

class Plant(pygame.sprite.Sprite):
    def __init__(self):
        super(Plant, self).__init__()
        self.live = True

加载图片

def load_image(self):
    if hasattr(self, 'image') and hasattr(self, 'rect'):
        MainGame.window.blit(self.image, self.rect)
    else:
        print(LOG)

向日葵类

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
        # 5 时间计数器
        self.time_count = 0

新增功能:生成阳光

def produce_money(self):
    self.time_count += 1
    if self.time_count == 25:
        MainGame.money += 5
        self.time_count = 0

向日葵加入到窗口中

def display_sunflower(self):
    MainGame.window.blit(self.image, self.rect)

豌豆射手类

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
        # 6 发射计数器
        self.shot_count = 0

增加射击方法

def shot(self):
    # 6 记录是否应该射击
    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
    # 6 如果活着
    if self.live and should_fire:
        self.shot_count += 1
        # 6 计数器到25发射一次
        if self.shot_count == 25:
            # 6 基于当前豌豆射手的位置,创建子弹
            peabullet = PeaBullet(self)
            # 6 将子弹存储到子弹列表中
            MainGame.peabullet_list.append(peabullet)
            self.shot_count = 0

将豌豆射手加入到窗口中的方法

def display_peashooter(self):
    MainGame.window.blit(self.image, self.rect)

豌豆子弹类

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):
        # 7 在屏幕范围内,实现往右移动
        if self.rect.x < scrrr_width:
            self.rect.x += self.speed
        else:
            self.live = False

    # 7 新增,子弹与僵尸的碰撞
    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()
    # 7闯关方法

    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)

僵尸类

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
    # 9 僵尸的移动

    def move_zombie(self):
        if self.live and not self.stop:
            self.rect.x -= self.speed
            if self.rect.x < -80:
                # 8 调用游戏结束方法
                MainGame().gameOver()

    # 9 判断僵尸是否碰撞到植物,如果碰撞,调用攻击植物的方法
    def hit_plant(self):
        for plant in MainGame.plants_list:
            if pygame.sprite.collide_rect(self, plant):
                # 8  僵尸移动状态的修改
                self.stop = True
                self.eat_plant(plant)
    # 9 僵尸攻击植物

    def eat_plant(self, plant):
        # 9 植物生命值减少
        plant.hp -= self.damage
        # 9 植物死亡后的状态修改,以及地图状态的修改
        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
            # 8 修改僵尸的移动状态
            self.stop = False

    # 9 将僵尸加载到地图中

    def display_zombie(self):
        MainGame.window.blit(self.image, self.rect)

四、主程序

class MainGame():
    # 2 创建关数,得分,剩余分数,钱数
    shaoguan = 1
    score = 0
    remnant_score = 100
    money = 200
    # 3 存储所有地图坐标点
    map_points_list = []
    # 3 存储所有的地图块
    map_list = []
    # 4 存储所有植物的列表
    plants_list = []
    # 7 存储所有豌豆子弹的列表
    peabullet_list = []
    # 9 新增存储所有僵尸的列表
    zombie_list = []
    count_zombie = 0
    produce_zombie = 100
    # 1 加载游戏窗口

    def init_window(self):
        # 1 调用显示模块的初始化
        pygame.display.init()
        # 1 创建窗口
        MainGame.window = pygame.display.set_mode([scrrr_width, scrrr_height])

    # 2 文本绘制
    def draw_text(self, content, size, color):
        pygame.font.init()
        font = pygame.font.SysFont('kaiti', size)
        text = font.render(content, True, color)
        return text

    # 2 加载帮助提示
    def load_help_text(self):
        text1 = self.draw_text('1.按左键创建向日葵 2.按右键创建豌豆射手', 26, (255, 0, 0))
        MainGame.window.blit(text1, (5, 5))

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

    # 3 初始化地图
    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)

    # 3 将地图加载到窗口中
    def load_map(self):
        for temp_map_list in MainGame.map_list:
            for map in temp_map_list:
                map.load_map()

    # 6 增加豌豆射手发射处理
    def load_plants(self):
        for plant in MainGame.plants_list:
            # 6 优化加载植物的处理逻辑
            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)

    # 7 加载所有子弹的方法
    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)

    # 8事件处理

    def deal_events(self):
        # 8 获取所有事件
        eventList = pygame.event.get()
        # 8 遍历事件列表,判断
        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)
                # 8 增加创建时候的地图装填判断以及金钱判断
                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

    # 9 新增初始化僵尸的方法
    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)

    # 9将所有僵尸加载到地图中
    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 开始游戏

    def start_game(self):
        # 1 初始化窗口
        self.init_window()
        # 3 初始化坐标和地图
        self.init_plant_points()
        self.init_map()
        # 9 调用初始化僵尸的方法
        self.init_zombies()
        # 1 只要游戏没结束,就一直循环
        while not GAMEOVER:
            # 1 渲染白色背景
            MainGame.window.fill((255, 255, 255))
            # 2 渲染的文字和坐标位置
            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()

            # 3 需要反复加载地图
            self.load_map()
            # 6 调用加载植物的方法
            self.load_plants()
            # 7  调用加载所有子弹的方法
            self.load_peabullets()
            # 8 调用事件处理的方法
            self.deal_events()
            # 9 调用展示僵尸的方法
            self.load_zombies()
            # 9 计数器增长,每数到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


if __name__ == '__main__':
    game = MainGame()
    game.start_game()

五、效果演示

教你用Python写一个植物大战僵尸小游戏

到此这篇关于教你用Python写一个植物大战僵尸小游戏的文章就介绍到这了,更多相关python植物大战僵尸内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python3访问sina首页中文的处理方法
Feb 24 Python
在Django中使用Sitemap的方法讲解
Jul 22 Python
Python学习笔记整理3之输入输出、python eval函数
Dec 14 Python
Python内置函数 next的具体使用方法
Nov 24 Python
Python网络编程基于多线程实现多用户全双工聊天功能示例
Apr 10 Python
Python统计python文件中代码,注释及空白对应的行数示例【测试可用】
Jul 25 Python
python 动态生成变量名以及动态获取变量的变量名方法
Jan 20 Python
Python的UTC时间转换讲解
Feb 26 Python
python学习将数据写入文件并保存方法
Jun 07 Python
Python获取浏览器窗口句柄过程解析
Jul 25 Python
python 爬虫如何实现百度翻译
Nov 16 Python
Python 用户输入和while循环的操作
May 23 Python
python爬取新闻门户网站的示例
Apr 25 #Python
python自然语言处理之字典树知识总结
Python自然语言处理之切分算法详解
Apr 25 #Python
Python网络编程之ZeroMQ知识总结
Python 文本滚动播放器的实现代码
Apr 25 #Python
Python基于Opencv识别两张相似图片
matplotlib之pyplot模块实现添加子图subplot的使用
You might like
php笔记之:初探PHPcms模块开发介绍
2013/04/26 PHP
PHP实现批量修改文件后缀名的方法
2015/07/30 PHP
PHP数组生成XML格式数据的封装类实例
2016/11/10 PHP
php微信开发之百度天气预报
2016/11/18 PHP
小程序微信退款功能实现方法详解【基于thinkPHP】
2019/05/05 PHP
javascript 全等号运算符使用说明
2010/05/31 Javascript
js 文本滚动效果的实例代码
2013/08/17 Javascript
javascript实现点击商品列表checkbox实时统计金额的方法
2015/05/15 Javascript
JavaScript脚本判断蜘蛛来源的方法
2015/09/22 Javascript
AngularJS使用ng-repeat指令实现下拉框
2016/08/23 Javascript
基于Vue.js实现简单搜索框
2020/03/26 Javascript
从零学习node.js之搭建http服务器(二)
2017/02/21 Javascript
js实现字符全排列算法的简单方法
2017/05/01 Javascript
jQuery遮罩层实例讲解
2017/05/11 jQuery
JavaScript实现鼠标滚轮控制页面图片切换功能示例
2017/10/14 Javascript
详解在vue-cli项目中使用mockjs(请求数据删除数据)
2017/10/23 Javascript
JavaScript new对象的四个过程实例浅析
2018/07/31 Javascript
在小程序中使用canvas的方法示例
2018/09/17 Javascript
layui table表格数据的新增,修改,删除,查询,双击获取行数据方式
2019/11/14 Javascript
vue-cli3.0实现一个多页面应用的历奇经历记录总结
2020/03/16 Javascript
[01:09:50]VP vs Pain 2018国际邀请赛小组赛BO2 第二场
2018/08/20 DOTA
python定时采集摄像头图像上传ftp服务器功能实现
2013/12/23 Python
python妹子图简单爬虫实例
2015/07/07 Python
Python脚本简单实现打开默认浏览器登录人人和打开QQ的方法
2016/04/12 Python
python面向对象多线程爬虫爬取搜狐页面的实例代码
2018/05/31 Python
pyqt5让图片自适应QLabel大小上以及移除已显示的图片方法
2019/06/21 Python
解决Numpy中sum函数求和结果维度的问题
2019/12/06 Python
使用OpenCV校准鱼眼镜头的方法
2020/11/26 Python
一套带网友答案的.NET笔试题
2016/12/06 面试题
12月小学生校园广播稿
2014/02/04 职场文书
开展党的群众路线教育实践活动方案
2014/02/05 职场文书
经济职业学院毕业生自荐书
2014/03/17 职场文书
工厂仓管员岗位职责范本
2014/07/17 职场文书
2015年感恩母亲节活动方案
2015/05/04 职场文书
关于flex 上下文中自动 margin的问题(完整例子)
2021/05/20 HTML / CSS
利用 SQL Server 过滤索引提高查询语句的性能分析
2021/07/15 SQL Server