python实现外星人入侵——2.类的介绍下

本文详细介绍了游戏开发中飞船和子弹类的设计方法,包括如何控制飞船移动、发射子弹及绘制界面元素等关键技术。

前言

上一篇博客的类讲述了一半(外星人类),这次我们补全它。
这部分讲述的还是能创建一个对象的类。

飞船类

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()方法,在原来的基础上绘制文字。

  1. 第一个参数为文本信息
  2. 第二个参数就有一点诡异了,查了一下也没看到,一般来说给True就行了
  3. 第三个参数是文本的颜色
  4. 第四个参数是按钮的颜色(也就是要覆盖部分的背景颜色)
  5. 返回的是一个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上,就完成了我们的目的。

总结

这次讲完了所有的类,接下来就是讲解各种各样的事件处理以及最终的主函数拼接了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值