前言
上一篇博客的类讲述了一半(外星人类),这次我们补全它。
这部分讲述的还是能创建一个对象的类。
飞船类
import pygame
from pygame.sprite import Sprite
class ship(Sprite):
def __init__(self,ai_settings,screen):
"""初始化飞船"""
super(ship,self).__init__()
self.screen = screen
self.ai_settings = ai_settings
#加载飞船图片并获得外接矩形
self.image = pygame.image.load('image/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
#将飞船放在最下面中间
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
#中间变量,先存着
self.center = float(self.rect.centerx)
self.moving_right = False
self.moving_left = False
def blitme(self):
"""在指定位置绘制飞船"""
self.screen.blit(self.image,self.rect)
def update(self):
"""根据运动感标志(按下、抬起按键)调整飞船的位置"""
#防止跑到界外
#没有使用elif是保证两者的优先级相同
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
self.rect.centerx = self.center
def center_ship(self):
"""保证飞船在屏幕正中心"""
self.center = self.screen_rect.centerx
飞船类相对简单一些,首先飞船是只需要一个的。
(其实也不完全准确,因为我需要在屏幕的左上角绘制剩余生命数,所以还是需要使用到sprite类的。)
和外星人差不多的导入图片,不过最开始的飞船是要贴在屏幕的底端中间,供我们进行移动。
另外飞船是有是否移动的判断变量,并且需要我们在变量为真的时候进行飞船的移动。
self.moving_right = False
self.moving_left = False
方法
update():飞船的位置是随着判断变量的真值改变的,所以我们需要不断修改center坐标,这里我们也有center变量存储float类型的中间点位置。
另外,为了防止飞船跑到界外,所以我们在进行移动的时候对边界做了判断。
可能有人会问,为什么使用了两个if而不是if_elif结构?
这样保证了两者的优先级相同,而不是在判断不是向左之后才判断向右。
(可能是同时按下左右键,这时应当保证飞船不移动)
center_ship():我们需要在每一次失败或者重开游戏将飞船居中,所以单独列了一个方法。
blitme():我们的飞船只是选好了位置,但是还没有放上去呢,所以我们给了一个绘制飞船的方式:
使用display.set_mdoe()方法返回的screen是一个surface类型的变量,blit的方法能将一个图片糊在surface上。
blit有两个参数,第一个是要贴的图片,第二个是位置,我们采用的是将get_rect()生成的rect作为坐标。
子弹类
import pygame
from pygame.sprite import Sprite
class bullet(Sprite): #导入类是为了同时控制多个元素
"""一个对发射的子弹进行管理的类"""
def __init__(self,ai_settings,screen,ship):
super(bullet,self).__init__()
self.screen = screen
#先在(0,0)创建一个子弹,然后再修改位置
#因为子弹并非基于图像,所以就需要调用方法创建矩形
self.rect = pygame.Rect(0,0,ai_settings.bullet_width,ai_settings.bullet_height)
self.rect.centerx = ship.rect.centerx
self.rect.top = ship.rect.top
#小数格式的子弹位置
self.y = float(self.rect.y)
self.color = ai_settings.bullet_color
self.ship_speed_factor = ai_settings.bullet_speed_factor
def update(self):
"""向上移动子弹"""
self.y -= self.ship_speed_factor
self.rect.y = self.y
def draw_bullet(self):
"""绘制子弹"""
pygame.draw.rect(self.screen,self.color,self.rect)
子弹类和外星人类差的还是比较多的,因为这里的子弹类我们采取的是画矩形,而不是之前的贴图。
使用pygame.Rect()方法,(不是起名这么随意的吗),输入参数有四个,一个坐标(这里是取左上角(0,0) ),另外两个参数为矩形的宽度和高度。
不过这时我们的子弹是知道在哪的:要放在飞船的顶端,这样保证看起来是从飞船顶端发射的。
所以我们将矩形的中心和船的中心对齐并且顶端对齐。
两个方法:
一个是update(),和上面的飞船相同,都是处理移动的。
另一个draw_bullet()则是绘制,调用了draw.rect方法,参数为:背景+颜色+矩形框。
按钮类
import pygame.font #为了渲染
class Button():
def __init__(self,ai_settings,screen,msg): #msg为显示的文本
"""初始化按钮的属性"""
self.screen = screen
self.screen_rect = screen.get_rect()
#设置按钮尺寸和其他属性
self.width,self.height = 200,50
self.button_color = (0,255,0)
self.text_color = (255,255,255)
self.font = pygame.font.SysFont(None,48) #默认字体,48号
#创建按钮的rect对象,并居中
self.rect = pygame.Rect(0,0,self.width,self.height)
self.rect.center = self.screen_rect.center
#按钮标签只创建一次
self.prep_msg(msg)
def prep_msg(self,msg):
"""msg渲染为图像,并在按钮上居中"""
self.msg_image = self.font.render(msg,True,self.text_color,self.button_color)
self.msg_image_rect = self.msg_image.get_rect()
self.msg_image_rect.center = self.rect.center
def draw_button(self):
#绘制一个用颜色填充的按钮,再绘制文本
self.screen.fill(self.button_color,self.rect)
self.screen.blit(self.msg_image,self.msg_image_rect)
按钮是指开始游戏界面的那个play按钮。
因为py没有现成的按钮类可以使用,所以我们采取画一个矩形然后在上面附上文字的方式来实现。
这里采用font为了方便渲染。
按钮只有一个,所以没有采用sprite的子类方式。
我们还是使用Rect方法创建了一个矩形,然后将矩形居中。
至于文本,因为每一次运行程序我们只需要创建一次,所以定义了方法prep_msg,其中传入的msg为文本内容。
方法中调用了font.render()方法,在原来的基础上绘制文字。
- 第一个参数为文本信息
- 第二个参数就有一点诡异了,查了一下也没看到,一般来说给True就行了
- 第三个参数是文本的颜色
- 第四个参数是按钮的颜色(也就是要覆盖部分的背景颜色)
- 返回的是一个surface类型
2021.4.4更新:找到了第二个参数,antialias:是否平滑(???)
随后我们对返回值使用rect方法,将得到的矩形居中。
绘制按钮的方法:
首先使用颜色填充方法fill(),参数为颜色和矩形;
然后在得到的矩形上进行文本渲染,调用bilt方法。(bilt方法之前提过需要使用一个图片)
计分板类
import pygame.font
from pygame.sprite import Group
from ship import ship
class Scoreboard():
"""显示得分的类"""
def __init__(self,ai_settings,screen,stats):
self.screen = screen
self.screen_rect = screen.get_rect()
self.ai_settings = ai_settings
self.stats = stats
#显示得分的字体设置
self.text_color = (30,30,30)
self.font = pygame.font.SysFont(None,48)
#准备初始得分图像
self.prep_score()
self.prep_high_score()
self.prep_level()
self.prep_ships()
def prep_score(self):
"""将得分转换成一幅渲染的图像"""
rounded_score = round(self.stats.score,-1)
"""笔记——round函数
将数字精确到多少位,看第二个参数,如果第二个参数为负数,比如-1就是10的整数倍
"""
score_str = "{:,}".format(rounded_score) #只能输出文本,使用format能自动插入逗号
self.score_image =self.font.render(score_str,True,self.text_color,self.ai_settings.bg_color)
#将得分放在屏幕右上角,上、右各20像素
self.score_rect = self.score_image.get_rect()
self.score_rect.right = self.screen_rect.right-20
self.score_rect.top = 20
def prep_high_score(self):
"""将最高分转换成图像"""
high_score = round(self.stats.high_score,-1)
high_score_str = "{:,}".format(high_score)
self.high_score_image = self.font.render(high_score_str,True,self.text_color,self.ai_settings.bg_color)
"""将最高分放在屏幕定端正中央"""
self.high_score_rect = self.high_score_image.get_rect()
self.high_score_rect.centerx = self.screen_rect.centerx
self.high_score_rect.top = self.score_rect.top
def prep_level(self):
"""将等级渲染为图像"""
self.level_image = self.font.render(str(self.stats.level),True,self.text_color,self.ai_settings.bg_color)
#将等级放置在分数下面
self.level_rect = self.level_image.get_rect()
self.level_rect.right = self.score_rect.right
self.level_rect.top = self.score_rect.bottom +10
def prep_ships(self):
"""显示剩下多少艘飞船"""
self.ships = Group()
for ship_number in range(self.stats.ships_left):
Ship = ship(self.ai_settings,self.screen)
Ship.rect.x = 10+ship_number*Ship.rect.width
Ship.rect.y = 10
self.ships.add(Ship)
def show_score(self):
"""在屏幕上显示得分"""
self.screen.blit(self.score_image,self.score_rect)
self.screen.blit(self.high_score_image,self.high_score_rect)
self.screen.blit(self.level_image,self.level_rect)
#绘制飞船
self.ships.draw(self.screen)
计分板包括的内容可能多一点,比如剩余生命数、等级、得分和最高分。
主体部分都是正常的定义,唯有不同的就是下面的四个方法。
prep_score():
首先我们将得分进行处理,round()方法接受两个参数,一个是要处理的数据,另一个是保留的位数,这里的"-1"表示将结果保留为十的倍数。
format方法则有一点像php之类的正则表达式,很是复杂,自己也不说搞懂了,这里实现的是将分数每三位加一个逗号输出(文本形式)
然后就是将得到的文本处理成surface类型,然后使用rect方法并进行定位。
这个懂了剩下的三个也就差不多了,唯一的区别就是地方可能会不一样。
最后一个方法实现的是将得到的矩形和surface渲染到screen上,就完成了我们的目的。
总结
这次讲完了所有的类,接下来就是讲解各种各样的事件处理以及最终的主函数拼接了。
本文详细介绍了游戏开发中飞船和子弹类的设计方法,包括如何控制飞船移动、发射子弹及绘制界面元素等关键技术。
655

被折叠的 条评论
为什么被折叠?



