[Pygame]对话框制作教程.part1

在大部分游戏中都会有对话框的存在,能推动剧情发展,能让玩家玩懂游戏。

那么在Pygame中,应该怎么制作这种对话框呢?

 Pygame中基础的文字渲染和绘制:

#创建文字库
my_font = pygame.font.Font(font_family,size)
#前后参数分别为字体,大小
my_text = my_font.render(text,color,bool)
#渲染文字,参数分别为 文字内容,颜色(R,G,B),是否抗锯齿(True/False)
surface.blit(my_text,(x,y))
#绘制文字

但是问题是:渲染文字这一块十分的耗费性能,就和加载导入图片一样,是很吃帧数的。于是,我就通过提前渲染并储存在一个列表里来尽量做到优化。

竟然对话框的字是一个一个出现的,而且还有彩色文字,那么,我想到的方法是将每一个字拆分开放在列表中,并且写入对应坐标,就比如:

import pygame,sys
from pygame.locals import *

pygame.init()
#初始化pygame,否则用到字体这一块会报错

window_w,window_h = 1280,720
screen = pygame.display.set_mode((window_w,window_h))
#创建宽1280高720的屏幕

my_font = pygame.font.Font("font.ttf",40)
#这里是直接导入字体文件而并非系统自带字体

t1 = my_font.render("你",(128,128,128),True)
t2 = my_font.render("好",(255,255,255),True)
lst = [(t1,(0,0)),(t2,(40,0))]

while True:#开启循环
    
    screen.fill((0,0,0))#填充背景为纯黑

    for event in pygame.event.get(): #监听事件,比如退出
        if event.type == pygame.QUIT:
            sys.exit()
                
    for i in lst:#遍历列表绘制文字
        screen.blit(i[0],i[1])

    pygame.display.flip()#刷新屏幕

这样就能绘制出两个紧密连接并且颜色不同的字了

不过我会把特殊效果和基础输出分开讲的,这篇主要讲文字输出

竟然要做出一个方便,好用的对话框,

我们可以将整一个对话框存储在一个类里边,先搞参数:

class WordsOutput():
    def __init__(self,text,name,portrait):
        self.text = text #对话框内容
        self.name = name #名字
        self.portrait = portrait #头像,存储surface对象
        self.start_x = 0
        if self.portrait != None:
            self.start_x = self.portrait.get_size()[0]
        self.start_y = 0
        if self.name != None:
            self.start_y = self.name.get_size()[1]

那么,光有内容可是不行的啊,要有头像,名字的对吧,于是就添加了两个参数:name名字,portrait头像

无头像:

 有头像:

 

区别在于,文字渲染的起始位置是不同的

所以,我添加了一个参数start_x,值为0,若有头像则设置为头像的宽度

有无名字的区别也是这样,就不多bb

接着,就是分析模块,因为当文字长度到达一定值时,就会超出屏幕边缘,所以需要换行。

所以就有了参数:start_y绘制高度,和start_x是一个原理

文字分析器的原理:

遍历一整段文字,将每个文字都单独分开,单个渲染出来,获取当行文字长度,检测是否超出边缘。

超出边缘:换行。没有超出:继续渲染并储存在列表里,记录其位置信息

最后,绘制时只需遍历列表即可。

如果看不懂的话,上代码,看注释,研究一下

def makeWords(txt, size, color):#文字渲染,返回 渲染的对象和尺寸
    my_font = pygame.font.Font('../font.ttf', size)
    r = my_font.render(str(txt), True, color)
    return (r, r.get_size())


class WordsOutput():
    def __init__(self, text, name, portrait):
        self.startx = 0  # 起始位置
        self.endx = 1280  # 边缘位置
        self.text = text
        self.name = name
        self.portrait = portrait #头像为surface对象
        self.portrait = pygame.transform.scale(self.portrait,(192,192))#压缩图片尺寸到192×192
        if self.portrait != None:  # 如果有头像则改变起始位置
            self.startx = 192#将起始x位置设置为头像宽度
        self.words = []  # 储存渲染出来的文字的列表
        self.analyzed = False  # 是否分析过
        self.interval = time.time()  # 计时器
        self.output_speed = 0.02  # 输出文字的间隔时间
        self.finished_writing = False  # 是否结束输出文字
        self.out_num = 0 #输出的文字编号
    def analyze(self):
        txt = self.text  # 将txt赋值为内容
        height = makeWords(txt[0], 35, (255, 255, 255))[1][1]  # 单个文字高度,用第一个字的高度
        txt_list = []  # 渲染出来的文字列表
        w_last = 0  # 叠加文字后的整体长度
        #初始高度位置
        start_y = 0
        #检测是否有头像
        if self.portrait != None:
            txt_list.append((self.portrait, (0, start_y)))
        #若有名字则将名字渲染出来存储进列表,改变排版
        if self.name != None:
            a = makeWords(self.name, 35, (255, 255, 0))
            txt_list.append((a[0], (self.startx, start_y)))
            start_y += a[1][1]
        #开始遍历文字
        for i in range(len(txt)):
            a = makeWords(txt[i], 35, (255, 255, 255))  # 渲染文字
            if self.startx+w_last+a[1][0] <= self.endx:  # 检测是否超出设定边缘
                #未超出则记录位置,渲染文字,存储进列表
                pos = (self.startx+w_last, start_y)
                txt_list.append((a[0], pos))
                w_last += a[1][0]
            else:
                #超出:换行,将x坐标设置为初始值,y则增加一个字的高度
                start_split = i-1
                start_y += a[1][1]
                w_last = 0
                a = makeWords(txt[i], 35, (255,255,255))
                pos = (self.startx+w_last, start_y)
                txt_list.append((a[0], pos))
                w_last += a[1][0]
        self.words = txt_list
        self.analyzed = True
    def paint(self):
        if self.analyzed == False:
            self.analyze()
        if time.time() >= self.interval + self.output_speed and self.out_num < len(self.words):#检测是否到输出下一个文字的时间并且还未输出完
            self.out_num+=1
            self.interval = time.time()#重置计时器
        for i in range(self.out_num):#绘制到达的文字
            img, pos = self.words[i]
            screen.blit(img, pos)
        if self.out_num == len(self.words): #如果绘制完了
            self.finished_writing = True #将变量设置为True

这一版的自由度并不高,只能自定义内容,名字,头像,其他的功能实现在下一篇会讲到。

使用方式:

#创建计时器,通俗讲就是帧数限制器
clock = pygame.time.Clock()
#创建对话框列表,存储对话框
w1 = []
#实例化类,写入参数,分别为 内容,名字,头像
w1.append(WordsOutput("Hello pygame",None,None))
w1.append(WordsOutput("Hello pygame, let's go", "名字", None))
while True:
    screen.fill((0,0,0))#填充背景
    for event in pygame.event.get():
        if event.type == pygame.QUIT:#检测退出
            exit()
        if event.type == MOUSEBUTTONDOWN:#检测鼠标是否按下
            if event.button == 1 and len(w1) > 0:#检测是否按下了左键,并且w1不是空列表
                if w1[0].finished_writing:#如果文字输出完成了,则删除显示的这一项
                    w1.pop(0)
    if len(w1) > 0:#如果w1不是空列表,则调用其第一项
        w1[0].paint()
    clock.tick(0)#将帧数限制设为无限制
    pygame.display.flip()#刷新屏幕

用到的模块有:pygame,time

导入图片代码:

img = pygame.image.load(path).convert_alpha()#path:路径
#convert_alpha()通俗来讲就是优化,提高帧数,并且保留图片的透明像素
#convert()不保留透明像素

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值