第083讲: Pygame:提高游戏的颜值3 | 学习记录(小甲鱼零基础入门学习Python)_pygame.image.load("python.png")-程序员宅基地

技术标签: 零基础入门学习Python[小甲鱼]课后作业题  

我们说过,图像是特定像素的组合,而Surface 对象是Pygame里面对图像的描述,在Pygame里面到处都是Surface 对象,set_mode() 返回的是一个Surface对象,在界面上打印文字也需要先把文字渲染成 Surface 对象,然后再贴上去,小蛇在上面爬呀爬,其实就是不断调整Surface对象上的一些特定的像素的位置,把小蛇所在位置的像素进行移动,就是小蛇在上面爬,就是调用 blit() 方法。imag.load() 方法载入图像并会返回一个 Surface 对象,我们此前都是直接拿来用,并没有进行任何转换,这样子就是效率比较低的做法。如果你希望你的Pygame可以尽可能高效的处理你的图片,你应该在图片载入之后立刻调用 convert() 方法进行转换。

如:bg = pygame.image.load(“bg.jpg”).convert()

我们的游戏事实上都是由各种不同的图片组成的,例如说:背景是一个图片、里面的主角是图片、反派也是图片、还有路人甲乙丙都是图片。你总不可能用一个圆形或者矩阵画一个主角吧。我们只能在现实中先用Photoshop 画一个惟妙惟肖的主角,然后贴进去,然后使用 blit() 方法让它移动。

有的人就很好奇了,不是说 image.load() 返回一个 Surface 对象吗,那还转换个毛线啊,这里的转换只是像素格式的转换,而不是说转换为Surface 对象,因为image.load() 载入之后就是一个 Surface 对象,但是我们载入之后(例如我们载入一个JPG格式的图片,JPG图片也是由像素组成的,而这些像素都是有颜色的,另外我们还可以将这个JPG图片保存为PNG,GIF格式,你会发现尺寸会发生改变了,这是因为里面的像素格式发生改变了,也就是说它组合这些像素,把它描述的形式发生改变了),Surface 也有它自己的像素格式,所以我们这里的转换指的就是图片的像素格式的转换。

如果我们没有在 image.load() 之后立刻对它进行转换,但是转换非常重要,Pygame也会你在 调用 blit() 方法时自动进行转化,就是将一个图片贴到另一个图片之上的时候,因为两个图片要进行复制拷贝的操作,它们的像素格式必须相同,因此在每次 blit() 的时候,它都会强制转换一次,这样子效率就相当低了,与其让它每次循环去转换一次,我们还不如在载入时调用 convert() 方法转换为 Surface 的像素格式。

虽然现在的CPU速度都很快,这一点细微的差别你可能看不出来,但是我们都希望我们的程序小一点、效率高一点。今后我们都会在 image.load() 之后立刻调用 convert()。

还有一个就是 convert_alpha() 方法:

如:turtle = pygame.image.load(“python.png”).convert_alpha()

这两个方法有什么区别呢?一般情况下,我们使用 RGB 来描述一个颜色,然而在游戏开发中,我们常常用到的是 RGBA (RGBA是代表Red(红色) Green(绿色) Blue(蓝色)和 Alpha的色彩空间)来描述。Alpha 通道是用来表示透明度的,A 占用一个字节,也就是8位(0-255,256种层次),用序号来索引,就是0-255,0表示完全透明,255表示完全不透明。

我们都知道,image.load() 支持多种格式的图片导入,例如 gif、jpg、png等,这些都是当前流行的图片格式,对于包含 Alpha 通道的图片,我们就要用 convert_alpha() 方法来转换格式了,其它的就用 conmvert() 方法。

我们也知道,jpg 格式的图片是不包含 Alpha 通道的,因为它不能来表示透明。我们在做图片的时候,我们知道,两种常用的 透明格式就是 png和 gif 格式,而gif 还支持动图,动图在Pygame 里面是不能解析的,一般我们在Pygame 里面做的图片都是以 png 图片为主,因为 jpg 是有损的,你放大缩小它会损失精度,png 是无损压缩。

jpg 是不支持透明的,所以我们载入这类图片就用 convert();而 png 是支持透明的,所以载入就用 convert_alpha()。

大家可以看一下下面两张图片:

左边是 png 格式的原图,是透明背景的,当我另存为 jpg 格式时,背景就不透明了。

如果你载入左边的透明 png 图片,使用 convert_alpha() 方法转换和使用 convert() 方法转换,比较一下。

import pygame
import sys
 
pygame.init()
 
size = width, height = 900, 300
bg = (0, 255, 0) #为了便于区分,背景设为绿色
 
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Python Demo")
 
turtle1 = pygame.image.load("turtle.png").convert_alpha() #左图
turtle2 = pygame.image.load("turtle.png").convert() #中图
turtle3 = pygame.image.load("turtle.png") #右图
 
position1 = turtle1.get_rect()
position1.center = width // 6, height // 2#居左显示
 
position2 = turtle2.get_rect()
position2.center = width // 2, height // 2#居中显示
 
position3 = turtle3.get_rect()
position3.center = 5 * width // 6, height // 2#居右显示
 
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
            
    screen.fill(bg)
    screen.blit(turtle1, position1)
    screen.blit(turtle2, position2)
    screen.blit(turtle3, position3)
        
    pygame.display.flip()
    
    clock.tick(30)

在这里插入图片描述
Pygame 支持三种透明度类型:colorkeys,surface alphas 和 pixel alphas(温馨提示:colorkeys 是指设置图像中的某个颜色值为透明(比如说上面的乌龟有很多种绿色,我把其中一种绿色变为透明,那么在这个图片里面,与这个颜色相同的部分都不见了,取而代之的是背景的颜色,因为透明事实上就是把背景显示出来。),surface alphas 是调整整个图像的透明度,pixel alphas 则是独立设置图像中每一个像素的透明度)。

png 就是一个 piexl alphas,所以它每个像素都有一个 Alpha 通道,指定这个像素是否要变透明,透明度是多少。

surface alphas 可以和 colorkeys 混合使用,而 pixel alphas 不能和其他两个混合。

说起来很复杂,其实说白了,convert() 方法转换出来的 就支持 surface alphas 可以和 colorkeys 设置透明度,而且他们是可以混合设置的。而 convert_alpha() 方法转换之后呢,就只支持 piexl alphas ,也就是说这个图像本身每个像素就带有Alpha 通道,我们载入一个带有 Alpha 通道的图片,我们会看到有一部分是透明的,就像我们上面的小乌龟,它的背景就是透明的。

我们来做一下实验:

我们这里有两张图片,一种是 jpg,背景白色;一张是 png,背景透明。

我们首先载入这张 jpg 图片,为了更好区分,我们加了一个背景。

import pygame
import sys
from pygame.locals import *
 
pygame.init()
 
size = width, height = 640, 480
bg = (0, 0, 0)
 
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Python Demo")
 
turtle = pygame.image.load("turtle.jpg").convert()
background = pygame.image.load("background.jpg").convert()
position = turtle.get_rect()
position.center = width // 2, height // 2
 
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
 
    screen.blit(background, (0, 0))
    screen.blit(turtle, position)
    
    pygame.display.flip()
    
    clock.tick(30)

在这里插入图片描述
现在我试图使用 set_colorkey() 把所有的白丝变为透明,来看一下效果:

import pygame
import sys
from pygame.locals import *
 
pygame.init()
 
size = width, height = 640, 480
bg = (0, 0, 0)
 
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Python Demo")
 
turtle = pygame.image.load("turtle.jpg").convert()
background = pygame.image.load("background.jpg").convert()
position = turtle.get_rect()
position.center = width // 2, height // 2
 
#############################################################
"使用 set_colorkey() 把所有的白丝变为透明"
turtle.set_colorkey((255, 255, 255))
#############################################################
 
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
 
    screen.blit(background, (0, 0))
    screen.blit(turtle, position)
    
    pygame.display.flip()
    
    clock.tick(30)

在这里插入图片描述
大家可以看到,结果并不优秀,因为边缘并不是纯白色的,结果并不是我们想要的,并不理想。

我们接着使用第二个方法,用 set_alpha() 方法来调节整个图像的透明度,我们把透明度调节为200,来看一下效果:

import pygame
import sys
from pygame.locals import *
 
pygame.init()
 
size = width, height = 640, 480
bg = (0, 0, 0)
 
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Python Demo")
 
turtle = pygame.image.load("turtle.jpg").convert()
background = pygame.image.load("background.jpg").convert()
position = turtle.get_rect()
position.center = width // 2, height // 2
 
#############################################################
#使用 set_colorkey() 把所有的白丝变为透明
#turtle.set_colorkey((255, 255, 255))
 
#用 set_alpha() 方法来调节整个图像的透明度为200
turtle.set_alpha(200)
#############################################################
 
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
 
    screen.blit(background, (0, 0))
    screen.blit(turtle, position)
    
    pygame.display.flip()
    
    clock.tick(30)

在这里插入图片描述
我们看到整个图片都变得微微透明了,但是这个把背景也带上了,我们就想要小乌龟变透明,不想要白色边框。

我们把两种方法混合使用:

import pygame
import sys
from pygame.locals import *
 
pygame.init()
 
size = width, height = 640, 480
bg = (0, 0, 0)
 
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Python Demo")
 
turtle = pygame.image.load("turtle.jpg").convert()
background = pygame.image.load("background.jpg").convert()
position = turtle.get_rect()
position.center = width // 2, height // 2
 
#############################################################
#使用 set_colorkey() 把所有的白丝变为透明
turtle.set_colorkey((255, 255, 255))
 
#用 set_alpha() 方法来调节整个图像的透明度为200
turtle.set_alpha(200)
#############################################################
 
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
 
    screen.blit(background, (0, 0))
    screen.blit(turtle, position)
    
    pygame.display.flip()
    
    clock.tick(30)

在这里插入图片描述
效果依然不优秀。

我们再来试试 png,

import pygame
import sys
from pygame.locals import *
 
pygame.init()
 
size = width, height = 640, 480
bg = (0, 0, 0)
 
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Python Demo")
 
turtle = pygame.image.load("turtle.png").convert_alpha()
background  = pygame.image.load("background.jpg").convert()
position = turtle.get_rect()
position.center = width // 2, height // 2
 
#############################################################
 
#下面要加的内容都在这里面
 
#############################################################
 
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
 
    screen.blit(background, (0, 0))
    screen.blit(turtle, position)
    
    pygame.display.flip()
    
    clock.tick(30)

在这里插入图片描述
由于我们这个 png 是带 Alpha 通道的,而且我们在做这个图片的时候,已经把它的背景给扣成透明的了,下面的阴影不透明,但是不影响美观(是故意做出的效果)。

我们想把整个小乌龟调为透明度 200,让小乌龟有一种隐身的既视感。

但是我们说这个是 piexl alphas,也就是每个像素都有一个 Alpha 通道,因此我们不能使用 turtle.set_alpha(200) 方法,我们可以使用 get_at() 方法来获得单个像素的透明度,并且用 set_at() 方法来修改它。

我们先来尝试是否能够获得 单个像素的透明度。

#############################################################
#尝试是否能够获得 单个像素的透明度
 
print(turtle.get_at(position.center)) #获取中间那个像素的颜色
 
#############################################################
>>> 
============================== RESTART ==============================
pygame 1.9.4
Hello from the pygame community. https://www.pygame.org/contribute.html
(130, 131, 26, 255)

显然是四元组(R,G,B,A),前面3个值表示 RGB颜色,最后的255表示透明度为完全不透明。

这样子,我们就可以进行修改。

我们写一个循环,逐个获取每个像素的颜色,只要不是透明背景的话,就把透明度设为200。

#############################################################
for i in range(position.width):
    for j in range(position.height):
        temp = turtle.get_at((i, j))
        if temp[3] != 0:
            temp[3] = 200
        turtle.set_at((i, j), temp)
#############################################################

在这里插入图片描述
效果还是不优秀啊。而且就算效果优秀了,你这样一个一个像素的来计算透明度,效率未免也很低

没问题,程序是死的,人是活的,我这里教大家一个新技能来 搞定这个问题:

先看一下解决方案,我们再来分析:

import pygame
import sys
from pygame.locals import *
 
pygame.init()
 
size = width, height = 640, 480
bg = (0, 0, 0)
 
clock = pygame.time.Clock()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Python Demo")
 
turtle = pygame.image.load("turtle.png").convert_alpha()
background  = pygame.image.load("background.jpg").convert()
position = turtle.get_rect()
position.center = width // 2, height // 2
 
#############################################################
def blit_alpha(target, source, location, opacity):
    x = location[0]
    y = location[1]
    temp = pygame.Surface((source.get_width(), source.get_height())).convert()
    temp.blit(target, (-x, -y ))
    temp.blit(source, (0, 0))
    temp.set_alpha(opacity)        
    target.blit(temp, location)
#############################################################
 
while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            sys.exit()
 
    screen.blit(background, (0, 0))
    ############################################################
    #screen.blit(turtle, position)
    blit_alpha(screen, turtle, position, 200)
    ############################################################
    
    pygame.display.flip()
    
    clock.tick(30)

在这里插入图片描述

这是如何实现的呢?我们来逐句分析一下:

我们封装了一个名为 blit_alpha() 的函数,下面我们就不要调用 blit() 方法了,而是调用 blit_alpha(),因为我们在函数的末尾 调用了 blit() 方法。

在函数中,我们首先创建一个 Surface ,传进来的是一个带 Alpha 的,我们将其变为不带 Alpha 的,其实我们只是需要它的一个矩形区域,

即:temp = pygame.Surface((source.get_width(), source.get_height())).convert()

temp 就是下图种黑色矩形的位置,其实就是小乌龟图片的覆盖区域范围。

然后我们在上边绘制背景

即:temp.blit(target, (-x, -y ))

为什么是(-x, -y)呢?

我们知道, x = location[0],y = location[1],而形参 location对应的实参是 position,就是小乌龟图像的位置,其实(x, y)就是下图的A点,这个位置是相对于顶点B(0,0)(对于screen 来说,B就是(0,0))来说的,而 temp.blit()是相对于小乌龟图像的来粘贴背景,所以B相对于A点来说,就是(-x,-y)。

在这里插入图片描述

然后我们就在A的位置贴上背景透明的 小乌龟图片

即:temp.blit(source, (0, 0))

然后我们将整个 temp 区域设为 透明度 200,其实现在的整个 temp 区域(Surface 对象)就是A区域大小,然后背景是该区域的草地,主角是小乌龟的一幅图片。如图所示:(这个就是目前的temp了)

我们将这个图片 透明度设为 200。

即:temp.set_alpha(opacity) #opacity=200

这就巧妙的避开了 带Alpha通道的Surface 不能调用set_alpha()方法的问题。因为现在的temp 是不带Alpha通道的。

然后我们就把这个透明度为200的图片贴在背景屏幕上,

即:target.blit(temp, location)

温馨提示:这虽然是一个小技巧,但是非常实用。大家好好理解一下。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_38970783/article/details/89160731

智能推荐

时间序列分析之误差修正模型(ECM)_ecm模型-程序员宅基地

文章浏览阅读3.8w次,点赞32次,收藏163次。误差修正模型(Error Correction Model, ECM)协整(cointegration)反映的是序列中变量之间的长期均衡关系,用网上的一个例子来描述协整就是一个醉汉牵着一只狗,他们之间的距离虽然会时远时近,但是由于绳子的存在,当达到绳子的长度时,他们的距离又会拉近,这样他们之间就存在着协整关系。通过协整建立的模型是静态模型,而误差修正模型的使用就是为了建立短期的动态模型来弥补长期..._ecm模型

C#版的MapReduce_c# mapreduce-程序员宅基地

文章浏览阅读1.7k次。using System;using System.Collections.Generic;using System.Linq;using System.Text;namespace mapReduce{ public static class helper { public static Dictionary MapReduce( _c# mapreduce

DataGuard主备库上修改redo大小_dataguard 调整redo日志大小-程序员宅基地

文章浏览阅读419次。测试环境:RDBMS 11.2.0.4步骤:1 停掉备库的MRP2 在备库上添加standby logfile,大小100M (standby_file_management='manual';注意下这个参数)3 在备库上删除standby logfile,删除掉50M的4 在主库添加redo,大小为100M5 在主库删除redo ,大小为50M6 备库添加redo,大小为100M7 备库删除redo ,大小为50M8 主库添加standby ,大小为100M9 主库删除stand._dataguard 调整redo日志大小

利用matlab从TXT中读数据1_matlab读取txt中的科学计数-程序员宅基地

文章浏览阅读4.5w次,点赞12次,收藏48次。TXT是纯文本文件,常用的几种函数有load函数,importdata函数,dlmread函数,textread函数。科学计数法如1.03乘10的8次方,可简写为“1.03e+08”的形式1:examp0204.txt中只包含没有文字说明,且每行数据个数相同,只是有多种数据分隔符,此数据同样可以使用数据导入向导。9.5550 2.7027, 8.6014; 5.615..._matlab读取txt中的科学计数

洛谷P1996 约瑟夫问题【队列】_8个人站成一圈,从第1个人开始报数,报到5的人出圈,第6个人再从1开始报。依次类-程序员宅基地

文章浏览阅读340次。题目背景约瑟夫是一个无聊的人!!!题目描述n个人(n<=100)围成一圈,从第一个人开始报数,数到m的人出列,再由下一个人重新从1开始报数,数到m的人再出圈,……依次类推,直到所有的人都出圈,请输出依次出圈人的编号.输入输出格式输入格式: n m 输出格式: 出圈的编号 输入输出样例输入样例#1: 复制10 3输出样例#1: ..._8个人站成一圈,从第1个人开始报数,报到5的人出圈,第6个人再从1开始报。依次类

使用JavaScript代码制作网页年历_javascript年历-程序员宅基地

文章浏览阅读5.6k次,点赞5次,收藏43次。年历使用js代码制作网页年历生成<!doctype html><html> <head> <meta charset="utf-8"> <title>年历</title> <script> var year = parseInt(prompt('输入年份:','2019')); document.write(calendar(year)); _javascript年历

随便推点

STM32F4+AD5449芯片-程序员宅基地

文章浏览阅读129次。DA5449使用双缓冲的3线串行接口,与SPI、QSPI、MICROWIRE和大多数DSP接口标准兼容。此外,串行数据输出(SDO)引脚允许在使用多个封装时进行菊花链连接。数据读取功能允许用户通过SDO引脚读取DAC寄存器的内容。在上电时,内部移位寄存器和锁存器被填充为0,DAC输出为零量程.

jetson nano在archiconda环境里编译安装opencv(为了CUDA加速)_opencv cuda jetdon nano-程序员宅基地

文章浏览阅读2k次,点赞2次,收藏18次。DPYTHON_DEFAULT_EXECUTABLE=/home/tai/archiconda3/envs/yolo5/bin/python3.6m #这个决定安装在哪个python上。OPENCV_EXTRA_MODULES_PATH=/home/tai/open/opencv_contrib-4.5.3/modules #这个是opencv_contrib文件。记得搜索自己cv2.cpython-36m-aarch64-linux-gnu.so to cv2.so文件。..._opencv cuda jetdon nano

使用Spring Session集成redis实现Session共享_spring4集成redissession了吗-程序员宅基地

文章浏览阅读564次。在分布式系统中,session共享有很多解决方案,其中使用redis缓存是最常用的方案之一1.想要在springboot用到spring session共享功能,首先需要在springboot项目中添加相关依赖2.在application.yml添加配置属性这里为了方便,用同一个项目不同代码编译两次,代码如下@RestControllerpublic class Tes..._spring4集成redissession了吗

JavaMail API详解_有关javamail api的描述以下( )正确-程序员宅基地

文章浏览阅读5.4k次,点赞3次,收藏13次。JavaMail API详解cleverpig 发表于 2006-01-01 14:34:28作者:cleverpig&nbsp;&nbsp;&nbsp;&nbsp; 来源:Matrix摘要:JavaMail API是读取、撰写、发送电子信息的可选包。我们可用它来建立如Eudora、Foxmail、MS Outlook Express一般的邮件用户代理程序(Mail User Age..._有关javamail api的描述以下( )正确

百度天工笔记_端口1884是什么服务-程序员宅基地

文章浏览阅读883次。百度天工笔记参考资料:初识百度天工百度产品文档简介百度天工是融合了百度ABC(AI、Big Data、Cloud)的“一站式、全托管”智能物联网平台。 从端到云,从数据采集、传输、计算、存储、展现到分析,天工提供了全面的基础产品和服务。赋能物联网应用开发商和生态合作伙伴从”连接”、”理解”到”唤醒“的各项关键能力,从而轻松构建各类智能物联网应用,促进行业变革。连接:互联互通,让..._端口1884是什么服务

The 2021 ICPC Asia Jinan Regional Contest - C Optimal Strategy - 2021ICPC济南站C题 组合数学_2021 济南站icpc optimal strategy-程序员宅基地

文章浏览阅读3k次。题目大意Ena和Mizuki正在玩一个游戏。他们面前有n个项目,编号从1到n。第i个项目的价值是.Ena和Mizuki轮流操作,而Ena先操作。在一次移动中,玩家选择一个尚未被拿走的物品并将其带走。当所有物品都被拿走时,游戏结束。任何一方的目标都是使他们拿走的物品的价值之和最大。鉴于双方都以最佳方式行动,有多少个可能的游戏过程?由于这个数字可能太大,你应该输出998244353的模数。如果存在某个整数i(1≤i≤n),使第i次移动中拿走的物品的指数不同,则认为两个过程不同。输入描述._2021 济南站icpc optimal strategy

推荐文章

热门文章

相关标签