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

前言

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

子弹模块

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

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

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

bullet

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

import pygameclass 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.centerxself.rect.top = ship.rect.topdef 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 pygameclass 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.centerxself.rect.top = ship.rect.top# 子弹颜色self.color = setting.bullet_colordef move(self):"""向上移动子弹"""# 更新子弹位置self.rect.y -= 1def draw_bullet(self):"""在屏幕上绘制子弹"""pygame.draw.rect(self.screen, self.color, self.rect)

发射子弹

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

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

子弹组

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

import pygame
from pygame.sprite import Spriteclass 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.centerxself.rect.top = ship.rect.top# 子弹颜色self.color = setting.bullet_color# 原来是move,继承后改成updatedef update(self):"""向上移动子弹"""# 更新子弹位置self.rect.y -= 1def 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 = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_UP:ship.moving_top = Trueelif event.key == pygame.K_DOWN:ship.moving_bottom = Trueelif 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 = Falseelif event.key == pygame.K_LEFT:ship.moving_left = Falseelif event.key == pygame.K_UP:ship.moving_top = Falseelif event.key == pygame.K_DOWN:ship.moving_bottom = Falsedef 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 = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_UP:ship.moving_top = Trueelif event.key == pygame.K_DOWN:ship.moving_bottom = Trueelif 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 = Falseelif event.key == pygame.K_LEFT:ship.moving_left = Falseelif event.key == pygame.K_UP:ship.moving_top = Falseelif 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.speedself.rect.y = self.y

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

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

代码示例

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

`main`模块:import pygame
from pygame.sprite import Groupimport alien_invasion.game_functions as gf
from alien_invasion.setting import Setting
from alien_invasion.ship import Shipdef run_game():"""启动游戏"""# 初始化pygamepygame.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 Spriteclass 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.centerxself.rect.top = ship.rect.top# 子弹颜色self.color = setting.bullet_color# 子弹位置self.y = float(self.rect.y)# 子弹速度self.speed = setting.bullet_speeddef update(self):"""向上移动子弹"""# 更新子弹位置self.y -= self.speedself.rect.y = self.ydef 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 pygamefrom alien_invasion.bullet import Bulletdef 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 = Trueelif event.key == pygame.K_LEFT:ship.moving_left = Trueelif event.key == pygame.K_UP:ship.moving_top = Trueelif event.key == pygame.K_DOWN:ship.moving_bottom = Trueelif 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 = Falseelif event.key == pygame.K_LEFT:ship.moving_left = Falseelif event.key == pygame.K_UP:ship.moving_top = Falseelif event.key == pygame.K_DOWN:ship.moving_bottom = Falsedef 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://xiahunao.cn/news/3268056.html

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

相关文章

UML通信图建模技术及应用例

新书速览|《UML 2.5基础、建模与设计实践》 在对系统的动态行为进行建模时&#xff0c;通信图常被用于按组织结构对控制流进行建模。与顺序图一样&#xff0c;一个单独的通信图只能显示一个控制流。 使用通信图建模时可以遵循如下策略&#xff1a; &#xff08;1&#xff09…

普通人这一生逆袭的唯一机会

普通人这一生逆袭的唯一机会 在人生的长河中&#xff0c;每个普通人心中都藏着一个逆袭的梦想。梦想着从平凡走向卓越&#xff0c;从底层攀至顶峰。但梦想与现实之间&#xff0c;究竟有多远的距离&#xff1f;今天&#xff0c;让我们一起探索那些看似遥不可及&#xff0c;却又…

Unity UGUI 之 自动布局组件

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本&#xff0c;请注意分别 1.什么是自动布局组件…

微服务注册中心

目录 1.微服务的注册中心 1.1 注册中⼼的主要作⽤ 1.2 常⻅的注册中⼼ 2.nacos简介 2.1 nacos实战⼊⻔ 2.2.1 搭建nacos环境 2.2.2 将商品微服务注册到nacos 3.服务调⽤Ribbon⼊⻔ 3.1 Ribbon概述 3.1.1 什么是Ribbon 3.1.2 Ribbon的主要作⽤ 3.2.2 ⼯程改造 4.服务…

openmv学习笔记(24电赛备赛笔记)

#openmv简介 openmv一种小型&#xff0c;可编程机器视觉摄像头&#xff0c;设计应用嵌入式应用和计算边缘&#xff0c;是图传模块&#xff0c;或者认为是一种&#xff0c;具有图像处理功能的单片机&#xff0c;提供多种接口&#xff08;I2C SPI UART CAN ADC DAC &#xff0…

204、【动态规划】牛客网 ——DP3 跳台阶扩展问题(Python版本)

题目描述 原题链接&#xff1a;DP3 跳台阶扩展问题 解题思路 一个DP问题&#xff0c;相比于普通爬楼&#xff08;只能爬一层或者两层&#xff09;对应的状态函数为 d p [ i ] d p [ i − 1 ] d p [ i − 2 ] dp[i] dp[i - 1] dp[i - 2] dp[i]dp[i−1]dp[i−2]。本题的dp…

vue3+g2plot实现词云图

词云图 效果预览: 核心代码: import {WordCloud } from @antv/g2plot;fetch(https://gw.alipayobjects.com/os/antfincdn/jPKbal7r9r/mock.json).then((res) => res.json()).then((data) => {const wordCloud = new WordCloud(container, {data,wordField: x,weigh…

秒懂Linux之权限

目录 一.Linux用户 二.文件权限 2.1 权限属性 chmod命令 chown与chgrp命令 2.2 文件类型 file指令 常见类型 2.3 常见权限问题 问题一&#xff1a; 问题二&#xff1a; 问题三&#xff1a; 一.Linux用户 Linux 下有两种用户&#xff1a;超级用户&#xff08; root …

kettle从入门到精通 第八十课 ETL之kettle kettle中的json对象字段写入postgresql中的json字段

场景&#xff1a;源数据库表为mysql的其中有json字段&#xff0c;通过kettle 查询出来 插入到目标数据库 postgresql中&#xff0c;对应的表中也有json字段。。但是报错&#xff0c;提示kettle查询出来是varchar的的字段&#xff0c;无法插入到目标数据库中。 1、创建测试表。 …

VBA技术资料MF180:将某个文件夹中的某类图片导入Word

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

【C++进阶学习】第九弹——哈希的原理与实现——开放寻址法的讲解

前言&#xff1a; 在前面&#xff0c;我们已经学习了很多存储机构&#xff0c;包括线性存储、树性存储等&#xff0c;并学习了多种拓展结构&#xff0c;效率也越来越高&#xff0c;但是是否有一种存储结构可以在大部分问题中都一次找到目标值呢&#xff1f;哈希可能能实现 目录…

【C++】C++应用案例-翻转数组

翻转数组&#xff0c;就是要把数组中元素的顺序全部反过来。比如一个数组{1,2,3,4,5,6,7,8}&#xff0c;翻转之后就是{8,7,6,5,4,3,2,1}。 &#xff08;1&#xff09;另外创建数组&#xff0c;反向填入元素 数组是将元素按照顺序依次存放的&#xff0c;长度固定。所以如果想要…

C++ | Leetcode C++题解之第283题移动零

题目&#xff1a; 题解&#xff1a; class Solution { public:void moveZeroes(vector<int>& nums) {int n nums.size(), left 0, right 0;while (right < n) {if (nums[right]) {swap(nums[left], nums[right]);left;}right;}} };

Go语言编程 学习笔记整理 第2章 顺序编程 前半部分

前言&#xff1a;《Go语言编程》编著 许式伟 吕桂华 等 1.1 变量 var v1 int var v2 string var v3 [10]int // 数组 var v4 []int // 数组切片 var v5 struct { f int } var v6 *int // 指针 var v7 map[string]int // map&#xff0c;key为string类型&#xff0c;value为in…

shell脚本(fifteen day)

一、shell概述 1、shell概念 &#xff08;1&#xff09;shell 英文翻译过来是外壳的意思&#xff0c;作为计算机语言来理解可以认为它是操作系统的外壳。可以通过shell 命令来操作和控制操作系统&#xff0c;比如Linux中的shell命令就包括 ls、cd、pwd 等等。 &#xff08;2&a…

postgres启动错误

说明&#xff1a;记录一次在Linux上启动postgres数据错误&#xff1b; 问题&#xff1a;安装好postgres数据库后&#xff0c;我使用systemctl启动数据库&#xff0c;报下面的错误 ● postgresql-15.service - PostgreSQL 15 database serverLoaded: loaded (/usr/lib/systemd…

【研路导航】保研英语面试高分攻略,助你一路过关斩将

面试攻略之 千锤百炼英语口语 写在前面 在保研面试中&#xff0c;英语口语往往是让许多同学感到头疼的一部分。如何在面试中展现出自信和流利的英语表达能力&#xff0c;是我们今天要探讨的主题。以下是一些有效的英语口语练习方法和常见题型解析&#xff0c;帮助你在保研面试…

使用PyTorch导出JIT模型:C++ API与libtorch实战

PyTorch导出JIT模型并用C API libtorch调用 本文将介绍如何将一个 PyTorch 模型导出为 JIT 模型并用 PyTorch 的 CAPI libtorch运行这个模型。 Step1&#xff1a;导出模型 首先我们进行第一步&#xff0c;用 Python API 来导出模型&#xff0c;由于本文的重点是在后面的部署…

Java-----栈

目录 1.栈&#xff08;Stack&#xff09; 1.1概念 1.2栈的使用 1.3栈的模拟实现 1.4栈的应用场景 1.5栈、虚拟机栈、栈帧有什么区别呢 1.栈&#xff08;Stack&#xff09; 1.1概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操…

Java基础入门14:常用API(Object(s)类、包装类、Math、Arrays、日期时间、Lambda表达式、方法引用)

Object类 Object类是Java中所有类的祖宗类&#xff0c;因此&#xff0c;Java中所有类的对象都可以直接使用Object类中提供的一些方法。 Object类的常见方法&#xff1a; package com.itchinajie.d12_api_object;public class Test {public static void main(String[] args) {…