Python学习笔记45:游戏篇之外星人入侵(六)

news2024/11/15 8:19:40

前言

飞船模块的功能基本已经完成。今天继续完成子弹模块的功能。

子弹模块

子弹和飞船模块,在游戏逻辑中有一种生成与被生成的表面关系,因为子弹在游戏中是由飞船发射的。但是在我们实际抽象的过程中,飞船与子弹并不是is的关系,甚至可以说不是has的关系。因此我们需要将两个对象封装到不同模块来完成我们的功能。

考虑子弹是由飞船’'生成",我们在子弹对象生成渲染的时候,应该将飞船实时位置传递到子弹对象中。

此外,相比于飞船,子弹是需要一直生成的,因此屏幕可以存在多个子弹,我们需要一些容器对子弹进行管理。同时子弹的移动不像飞船到了边界就要停止,通常来说子弹触碰到窗口边界的时候子弹就应该消失,可以直接不管让子弹移动到窗口外不被加载,也可以让子弹在到达边界时自己销毁。

bullet

bullet.py模块的基础信息我们在最开始就写好了,现在我们需要根据我们实际的游戏业务进行填充。

import pygame


class Bullet:
    def __init__(self, setting, screen, ship):
        super(Bullet, self).__init__()
        self.screen = screen
        # 创建子弹矩形
        self.rect = pygame.Rect(0, 0, setting.bullet_width, setting.bullet_height)
        self.rect.centerx = ship.rect.centerx
        self.rect.top = ship.rect.top

    def move(self):
        """向上移动子弹"""
        pass

首先是介绍子弹的属性以及值。

  1. self.screen
    游戏窗口信息,这个不多做介绍,毕竟子弹是在窗口上显示的。
  2. self.rect
    子弹矩形,我们可以将子弹理解为一个实心矩形,并且通过系统设置文件配置子弹的长度和宽度。
  3. self.rect.centerx
    这个相信大家已经很熟了,子弹矩形的中心x坐标是飞船中心x坐标。
  4. self.rect.top
    这个应该也不陌生,子弹矩形的顶部,设置等于飞船的顶部。这样就会有一种子弹从飞船出来的感觉。大家也可以改造一下定义一个self.rect.bottom的属性,至于值,大家自己发挥,很简单的我不写出来了。

填充业务代码

上色

我们需要个给子弹上一个颜色!

self.color = setting.bullet_color

移动

子弹是自行移动的,所以我们的移动函数并不需要按键控制,只要每次渲染的时候调用一下move函数即可。

    def move(self):
        """向上移动子弹"""
        # 更新子弹位置
        self.rect.y -= 1

生成子弹

我们需要一个新的函数,在调用这个函数的时候,飞船的上方出现一个子弹。也就是我们说的发射子弹的函数。

函数比较简单,就是在窗口中绘制一个矩形就行。

  def draw_bullet(self):
        """在屏幕上绘制子弹"""
        pygame.draw.rect(self.screen, self.color, self.rect)

至此,我们的子弹模块已经填充好了。

import pygame


class Bullet:
    def __init__(self, setting, screen, ship):
        super(Bullet, self).__init__()
        self.screen = screen
        # 创建子弹矩形
        self.rect = pygame.Rect(0, 0, setting.bullet_width, setting.bullet_height)
        self.rect.centerx = ship.rect.centerx
        self.rect.top = ship.rect.top
        # 子弹颜色
        self.color = setting.bullet_color

    def move(self):
        """向上移动子弹"""
        # 更新子弹位置
        self.rect.y -= 1

    def draw_bullet(self):
        """在屏幕上绘制子弹"""
        pygame.draw.rect(self.screen, self.color, self.rect)

发射子弹

在编写这部分代码以前,我们需要理解一下信息:

  • 在游戏中,我们定义按下空格发射子弹,因此我们要对空格键按下的进行监听并处理。
  • 游戏中并不是只存在一个子弹,我们需要一个能管理多个子弹的容器。
  • 子弹会一直往上移动,但是当子弹穿过上边界时,我们需要移除该子弹。如果能容忍资源的浪费,也可以不管。

子弹组

在pygame中,我们要实现组的功能,需要继承Sprite。改造bullet模块代码如下:

import pygame
from pygame.sprite import Sprite


class Bullet(Sprite):
    def __init__(self, setting, screen, ship):
        super(Bullet, self).__init__()
        self.screen = screen
        # 创建子弹矩形
        self.rect = pygame.Rect(0, 0, setting.bullet_width, setting.bullet_height)
        self.rect.centerx = ship.rect.centerx
        self.rect.top = ship.rect.top
        # 子弹颜色
        self.color = setting.bullet_color
	
	# 原来是move,继承后改成update
    def update(self):
        """向上移动子弹"""
        # 更新子弹位置
        self.rect.y -= 1

    def draw_bullet(self):
        """在屏幕上绘制子弹"""
        pygame.draw.rect(self.screen, self.color, self.rect)

我们需要在main模块中创建管理多个子弹的容器,而pygame的中group可以很好的完成这个任务。

	# 创建子弹编组
    bullets = Group()

同时我们处理监听事件时需要把新建的这个子弹组传入,因为我们每次按下空格,就需要将一枚子弹放入这个组中。

gf.check_events(ship, setting, screen, bullets)

最后我们需要更新子弹的位置,并在屏幕绘制中绘制子弹

 	# 更新子弹
    gf.update_bullets(setting, screen, bullets)
    # 更新屏幕
    gf.update_screen(setting, screen, ship, bullets)

监听事件

每次按下空格键,我们就需要调用一个名叫fire的函数,将子弹放入子弹组中。

def check_event(ship, setting, screen, bullets):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = True
            elif event.key == pygame.K_LEFT:
                ship.moving_left = True
            elif event.key == pygame.K_UP:
                ship.moving_top = True
            elif event.key == pygame.K_DOWN:
                ship.moving_bottom = True
            elif event.key == pygame.K_q:
                pygame.quit()
            elif event.key == pygame.K_SPACE:
                fire(bullets, screen, setting, ship)
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_RIGHT:
                ship.moving_right = False
            elif event.key == pygame.K_LEFT:
                ship.moving_left = False
            elif event.key == pygame.K_UP:
                ship.moving_top = False
            elif event.key == pygame.K_DOWN:
                ship.moving_bottom = False


def fire(bullets, screen, setting, ship):
    # 创建一颗子弹,并将其加入到编组bullets中
    new_bullet = Bullet(setting, screen, ship)
    bullets.add(new_bullet)

可以看到移动飞船的代码占据很长篇幅,我们再次封装一下这些参数。

def check_event(ship, setting, screen, bullets):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event, ship, setting, screen, bullets)
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, ship)


def fire(bullets, screen, setting, ship):
    # 创建一颗子弹,并将其加入到编组bullets中
    new_bullet = Bullet(setting, screen, ship)
    bullets.add(new_bullet)
    
    
def check_keydown_events(event, ship, setting, screen, bullets):
    """响应按键"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_UP:
        ship.moving_top = True
    elif event.key == pygame.K_DOWN:
        ship.moving_bottom = True
    elif event.key == pygame.K_SPACE:
        fire(bullets, screen, setting, ship)
    elif event.key == pygame.K_q:
        sys.exit()


def check_keyup_events(event, ship):
    """响应松开"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
    elif event.key == pygame.K_UP:
        ship.moving_top = False
    elif event.key == pygame.K_DOWN:
        ship.moving_bottom = False

这样如果再有按键的监听时间,直接对应到check_keydown_eventscheck_keyup_events两个函数中操作即可。

更新子弹

main模块中,我们调用了gf模块的更新子弹函数,这里我们需要填充这部分代码。

def update_bullets(bullets):
    """更新子弹"""
    bullets.update()
    # 删除已经消失的子弹
    for bullet in bullets.copy():
        # 当子弹矩形底部坐标小于0,说明子弹已经出了上边界
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)

另外我们在更新屏幕函数中也要绘制子弹。

def update_screen(setting, screen, ship, bullets):
    """更新屏幕"""
    # 填充背景色
    screen.fill(setting.bg_color)
    # 加载飞船
    ship.blitme()
    # 绘制子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    # 让最近绘制的屏幕可见
    pygame.display.flip()

发射子弹

当上面代码编写完毕,运行main模块,在屏幕上已经可以自由移动飞船并发射子弹了!

效果图:

在这里插入图片描述

但是你发现子弹移动速度有点快,怎么办呢?我们可以给子弹移动设置一个速度,每次移动以这个速度为单位。

那么我们需要改造bullet模块,代码改造如下:

属性

 		 # 子弹位置
        self.y = float(self.rect.y)
        # 子弹速度
        self.speed = setting.bullet_speed

函数

	def update(self):
		"""向上移动子弹"""
		# 更新子弹位置
		self.y -= self.speed
		self.rect.y = self.y

这个时候,可以看到我们子弹速度已经没有之前快了。

ps: 飞船也可以设置速度移动哦!

代码示例

贴一下本次修改后模块代码。

`main`模块:

import pygame
from pygame.sprite import Group

import alien_invasion.game_functions as gf
from alien_invasion.setting import Setting
from alien_invasion.ship import Ship


def run_game():
    """启动游戏"""

    # 初始化pygame
    pygame.init()
    # 定义一个系统设置对象
    setting = Setting()
    # 新建窗口
    screen = pygame.display.set_mode((setting.screen_width, setting.screen_height))
    # 窗口命名
    pygame.display.set_caption(setting.caption)
    # 定义一个飞船对象
    ship = Ship(setting, screen)
    # 创建子弹编组
    bullets = Group()

    while True:
        # 处理监听事件
        gf.check_event(ship, setting, screen, bullets)
        # 移动飞船
        ship.move()
        # 更新子弹位置
        gf.update_bullets(bullets)
        # 刷新屏幕
        gf.update_screen(setting, screen, ship, bullets)


if __name__ == '__main__':
    run_game()

bullet模块:

import pygame
from pygame.sprite import Sprite


class Bullet(Sprite):
    def __init__(self, setting, screen, ship):
        super(Bullet, self).__init__()
        self.screen = screen
        # 创建子弹矩形
        self.rect = pygame.Rect(0, 0, setting.bullet_width, setting.bullet_height)
        self.rect.centerx = ship.rect.centerx
        self.rect.top = ship.rect.top
        # 子弹颜色
        self.color = setting.bullet_color
        # 子弹位置
        self.y = float(self.rect.y)
        # 子弹速度
        self.speed = setting.bullet_speed

    def update(self):
        """向上移动子弹"""
        # 更新子弹位置
        self.y -= self.speed
        self.rect.y = self.y

    def draw_bullet(self):
        """在屏幕上绘制子弹"""
        pygame.draw.rect(self.screen, self.color, self.rect)

setting模块:

class Setting:
    """系统设置类"""
    def __init__(self):
        # 窗口宽
        self.screen_width = 1200
        # 窗口高
        self.screen_height = 800
        # 背景颜色
        self.bg_color = (230, 230, 230)
        # 窗口名
        self.caption = "Alien Invasion"
        # 子弹宽
        self.bullet_width = 3
        # 子弹长
        self.bullet_height = 15
        # 子弹颜色
        self.bullet_color = (60, 60, 60)
        # 飞船移动速度
        self.bullet_speed = 0.2

gf模块:

import sys
import pygame

from alien_invasion.bullet import Bullet


def check_event(ship, setting, screen, bullets):
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown_events(event, ship, setting, screen, bullets)
        elif event.type == pygame.KEYUP:
            check_keyup_events(event, ship)


def fire(bullets, screen, setting, ship):
    # 创建一颗子弹,并将其加入到编组bullets中
    new_bullet = Bullet(setting, screen, ship)
    bullets.add(new_bullet)


def check_keydown_events(event, ship, setting, screen, bullets):
    """响应按键"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = True
    elif event.key == pygame.K_LEFT:
        ship.moving_left = True
    elif event.key == pygame.K_UP:
        ship.moving_top = True
    elif event.key == pygame.K_DOWN:
        ship.moving_bottom = True
    elif event.key == pygame.K_SPACE:
        fire(bullets, screen, setting, ship)
    elif event.key == pygame.K_q:
        sys.exit()


def check_keyup_events(event, ship):
    """响应松开"""
    if event.key == pygame.K_RIGHT:
        ship.moving_right = False
    elif event.key == pygame.K_LEFT:
        ship.moving_left = False
    elif event.key == pygame.K_UP:
        ship.moving_top = False
    elif event.key == pygame.K_DOWN:
        ship.moving_bottom = False


def update_screen(setting, screen, ship, bullets):
    """更新屏幕"""
    # 填充背景色
    screen.fill(setting.bg_color)
    # 加载飞船
    ship.blitme()
    # 绘制子弹
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    # 让最近绘制的屏幕可见
    pygame.display.flip()


def update_bullets(bullets):
    """更新子弹"""
    bullets.update()
    # 删除已经消失的子弹
    for bullet in bullets.copy():
        # 当子弹矩形底部坐标小于0,说明子弹已经出了上边界
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)

如果运行有问题,可以对照代码参考或者私信我。

结尾

目前我们已经可以自由移动飞船并发射子弹了,后面我们就要生成外星人了。

加油!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1950791.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【机器学习】机器学习之多变量线性回归-Multiple_Variable_Soln

引言 扩展数据结构和之前开发的例程&#xff0c;以支持多个特征。有几个例程被更新&#xff0c;使得实验看起来有些冗长&#xff0c;但实际上只是对之前的例程进行了小的调整&#xff0c;因此快速回顾是可行的 文章目录 引言一、多变量线性回归1.1 目标1.2 工具 二、问题陈述2.…

2024年【山东省安全员C证】考试题及山东省安全员C证复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年山东省安全员C证考试题为正在备考山东省安全员C证操作证的学员准备的理论考试专题&#xff0c;每个月更新的山东省安全员C证复审考试祝您顺利通过山东省安全员C证考试。 1、【多选题】.以下属于建设单位的质量行…

【SpringBoot教程:从入门到精通】掌握Springboot开发技巧和窍门(四)-Vue项目配置环境、导航栏

主要写前端页面&#xff0c;采用vue框架写页面的导航栏&#xff01;&#xff01;&#xff01; 文章目录 前言 Vue项目配置环境 安装依赖 创建菜单 总结 前言 主要写前端页面&#xff0c;采用vue框架写页面的导航栏&#xff01;&#xff01;&#xff01; Vue项目配置环境 安装…

[练习]如何使用递归算法?

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;算法(Java)&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1. 递归概述 2.汉诺塔问题 题目描述​编辑 题解 代码实现 3…

扫雷小游戏纯后端版

package com.wind;import java.util.Random; import java.util.Scanner;public class ResultLei {static Random random new Random();public static void main(String[] args) {boolean end true;while (end) {System.out.println("请输入你选择的难度对应的数字&#…

虚拟机centos9搭建wordpress

目录 1. 更换yum源更新系统软件包&#xff1a; 1.1备份yum源 1.1.1创建备份目录&#xff1a; 1.1.2移动现有仓库配置文件到备份目录&#xff1a; 1.1.3验证备份&#xff1a; 1.2更换yum源 1.2.1添加yum源 1.2.2删除和建立yum缓存 1.3更新系统软件包 1.4 yum与dnf介绍…

springboot使用Gateway做网关并且配置全局拦截器

一、为什么要用网关 统一入口&#xff1a; 作用&#xff1a;作为所有客户端请求的统一入口。说明&#xff1a;所有客户端请求都通过网关进行路由&#xff0c;网关负责将请求转发到后端的微服务 路由转发&#xff1a; 作用&#xff1a;根据请求的URL、方法等信息将请求路由到…

线程池的理解以及实现线程池

线程池可以干什么&#xff1a; 帮助我们减少线程的创建和销毁提高系统资源的利用率&#xff0c;同时控制并发执行的线程数量便于管理且提高响应速度 线程池的工作流程&#xff1a; 1.创建线程池 线程池的创建是通过 Executors 工厂方法或直接使用 ThreadPoolExecutor 构造函…

遇到Websocket就不会测了?别慌,学会这个Jmeter插件轻松解决....

websocket 是一种双向通信协议&#xff0c;在建立连接后&#xff0c;websocket服务端和客户端都能主动向对方发送或者接收数据&#xff0c;而在http协议中&#xff0c;一个request只能有一个response&#xff0c;而且这个response也是被动的&#xff0c;不能主动发起。 websoc…

C语言 ——— 数组指针的定义 数组指针的使用

目录 前言 数组指针的定义 数组指针的使用 前言 之前有编写过关于 指针数组 的相关知识 C语言 ——— 指针数组 & 指针数组模拟二维整型数组-CSDN博客 指针数组 顾名思义就是 存放指针的数组 那什么是数组指针呢&#xff1f; 数组指针的定义 何为数组指针&#xf…

FastAPI(七十七)实战开发《在线课程学习系统》接口开发-- 课程编辑和查看评论

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 课程编辑 先来看下课程编辑 1.判断是否登录 2.判断课程是否存在 3.是否有权限&#xff08;只有自己可以修改自己的课程&#xff09; 4.名称是否重复…

Redis的操作以及SpringCache框架

目录 一.什么是Redis&#xff1f; 二.Redis的相关知识&#xff1a; 三.如何操作Redis&#xff1f; 1&#xff0c;常用命令&#xff1a; 2.Spring Data Redis &#xff08;1&#xff09; pom.xml 配置&#xff1a; &#xff08;2&#xff09;配置Redis数据源&#xff1a; …

IE11添加收藏、关闭窗口时弹出的对话框字体又大又粗很难看的解决办法

原因已查明&#xff0c;在win7 sp1 32位系统下&#xff0c;安装“2020-01 适用于基于 x86 的系统的 Windows 7 月度安全质量汇总&#xff08;KB4534310&#xff09;”这个更新会导致IE11的窗口字体变大变粗&#xff0c;把这个更新卸载了就可以了&#xff0c;无需重装IE11浏览器…

【芯智雲城】详解智能电机驱动在汽车中的应用

随着汽车系统中传统的机械化设计被电子化设计逐渐取代&#xff0c;电机在汽车电子化系统中扮演的角色越来越重要。例如在汽车的动力系统中&#xff0c;由传统的燃油发动机逐步发展为现在的有刷同步电机、感应电机&#xff0c;真正的实现了新能源车的动力革命&#xff1b;传统的…

论文快过(图像配准|Coarse_LoFTR_TRT)|适用于移动端的LoFTR算法的改进分析 1060显卡上45fps

项目地址&#xff1a;https://github.com/Kolkir/Coarse_LoFTR_TRT 创建时间&#xff1a;2022年 相关训练数据&#xff1a;BlendedMVS LoFTR [19]是一种有效的深度学习方法&#xff0c;可以在图像对上寻找合适的局部特征匹配。本文报道了该方法在低计算性能和有限内存条件下的…

Android AutoSize屏幕适配:适配不同屏幕大小的尺寸,让我们无需去建立多个尺寸资源文件

目录 AutoSize是什么 AutoSize如何使用 一、AndroidautoSize是什么 在开发产品的时候&#xff0c;我们会遇到各种各样尺寸的屏幕&#xff0c;如果只使用一种尺寸去定义控件、文字的大小&#xff0c;那么到时候改起来就头皮发麻。以前使用dime的各种类库&#xff0c;文件太多…

一种提供改进的通道迁移率和高可靠性的SiC沟槽MOSFET概念

来源&#xff1a;A SiC Trench MOSFET concept offering improved channel mobility and high reliability&#xff08;2017 19th European Conference on Power Electronics and Applications (EPE’17 ECCE Europe)&#xff09; 摘要 这项工作讨论了与硅基同类产品相比&…

性能测试工具 - Siege

在快速发展的技术时代&#xff0c;网站和应用的性能对于用户体验和业务成功至关重要。作为测试工程师&#xff0c;找到高效的性能测试工具显得尤为重要。今天&#xff0c;我们来聊聊一个备受推崇的性能测试工具——Siege。 为什么Siege能够在众多性能测试工具中脱颖而出&#x…

C++ 内存与编译问题总结

目录 C内存结构 作用域与生存周期 堆与栈 内存对齐 智能指针 shared_ptr 循环引用问题 编译与链接 内存泄漏 补充问题 include “ ”与<> 大端与小端 C内存结构 C程序内存分区 代码区 文件中所有的函数代码、常量以及字符串常量只读&#xff0c;保护程序不会被…

在invidia jetpack4.5.1上运行c++版yolov8(tensorRT)

心路历程(可略过) 为了能在arm64上跑通yolov8,我试过很多很多代码,太多对库版本的要求太高了; 比如说有一个是需要依赖onnx库的,(https://github.com/UNeedCryDear/yolov8-opencv-onnxruntime-cpp) 运行成功了报错error: IOrtSessionOptionsAppendExecutionProvider C…