版本
pygame 2.4.0 (SDL 2.26.4, Python 3.8.2)
Hello from the pygame community. https://www.pygame.org/contribute.html
Python开发基础
Pygame常用模块
background_image_filename = "bg.jpg"#设置图像文件名称
mouse_image_filename = "ship.bmp"
# 将import pygame和from pygame.locals import *分两次写是为了区分导入pygame模块
# 和导入pygame.locals模块中的常量和枚举类型,以便代码的可读性和维护性
import pygame
from pygame.locals import *
# pygame.locals模块提供了一些常量和枚举类型,用于表示键盘、鼠标、事件等相关的常量和状态。
from sys import exit#从sys模块导入函数exit()用于退出程序
pygame.init()#初始化pygame,使用硬件做准备
screen = pygame.display.set_mode((640, 480), pygame.DOUBLEBUF | pygame.RESIZABLE, 32)#创建一个窗口
pygame.display.set_caption("Hello, World!")#设置窗口标题
#下面两行代码加载并转换图像
background = pygame.image.load(background_image_filename).convert()
mouse_cursor = pygame.image.load(mouse_image_filename).convert_alpha()
#主循环 ● 处理事件。● 更新游戏状态。● 在屏幕上绘制游戏状态。
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
screen.blit(background, (0,0))#将背景图画上去
x, y = pygame.mouse.get_pos()#获得鼠标位置
# 下面两行代码计算光标左上角位置
# 使鼠标光标和光标图像中心对齐
# pygame.mouse.set_visible(False)#隐藏鼠标
print("旧")
print(x, y)
x -= mouse_cursor.get_width() / 2
y -= mouse_cursor.get_height() / 2
print("新")
print(x, y)
# print(mouse_cursor.get_width() / 2,mouse_cursor.get_height() / 2)
screen.blit(mouse_cursor, (x, y)) #绘制光标
#把光标画上去
pygame.display.update() #刷新画面
set_mode()
set_mode()方法用于创建一个窗口或全屏幕显示,它的函数签名为:
set_mode(resolution=(0,0), flags=0, depth=0)
其中,set_mode()方法有三个参数,分别为:
- resolution:表示窗口的分辨率,它是一个二元组,包含了窗口的宽度和高度。例如,(640, 480)表示窗口宽度为640像素,高度为480像素。如果将resolution设置为(0, 0),则表示创建一个全屏窗口。
- flags:表示窗口的特性,它是一个整数,可以通过按位或运算符(|)来组合多个特性。常用的特性包括:
- pygame.FULLSCREEN:创建全屏窗口。
- pygame.DOUBLEBUF:使用双缓冲技术,可以避免屏幕闪烁。
- pygame.RESIZABLE:窗口可以调整大小。
- pygame.HWSURFACE:使用硬件加速,可以提高绘制速度。
- pygame.NOFRAME:创建一个没有边框的窗口。
- depth:表示颜色深度,它表示每个像素使用的位数。默认值为0,表示使用当前显示器的颜色深度。可以设置为16、24或32等值,表示使用16位、24位或32位颜色深度。
Surface对象
在Pygame中,Surface对象是表示图像和屏幕的基本类型,它是一个**二维的像素数组,**可以用来表示图像、屏幕、文本等。Surface对象可以通过加载图像文件、创建空白Surface对象、从屏幕截取图像等方式来创建。
Surface对象具有很多属性和方法,可以用来操作和绘制图像。一些常用的属性和方法包括:
- get_width():返回Surface对象的宽度。
- get_height():返回Surface对象的高度。
- get_size():返回Surface对象的尺寸,是一个二元组。
- blit():将一个Surface对象绘制到另一个Surface对象上。
- fill():使用指定的颜色填充Surface对象。
- convert():将Surface对象转换为指定的像素格式。
- convert_alpha():将Surface对象转换为带有alpha通道的像素格式(保留了透明的部分,这样移动的光标才是不规则形状)。
主循环
游戏的主循环是一个无限循环,直到用户跳出。在这个主循环里做的事情就是不停地画背景和更新光标位置,虽然背景是不动的,但还是需要每次都画它,否则鼠标覆盖过的位置就不能恢复正常了
大都带有这样的一些while True循环,并且带有一条将该循环称为“main game loop”的注释。游戏循环(game loop,也叫作主循环main loop)中的代码做如下3件事情。
-
处理事件。
-
更新游戏状态。
-
在屏幕上绘制游戏状态。
游戏状态
游戏状态(game state)只不过是针对游戏程序中用到的所有变量的一组值的一种叫法
事件基础
事件
在Pygame中,事件是指用户与程序交互时产生的动作,例如按键、鼠标移动、窗口关闭等。Pygame通过pygame.event模块来处理事件,可以使用pygame.event.get()函数获取当前所有的事件,并通过遍历事件队列来处理不同类型的事件。
pygame.quit()
在Event对象中有一个名为type的成员变量,其功能是告诉对象表示哪一种事件。针对pygame.locals模块中每一种可能的类型,Pygame都有一个常量变量。
pygame.quit()是pygame.init()的相反函数
pygame.event.Event对象
在任何时候,当用户按下一个按键或者把鼠标移动到程序的窗口上面等动作时,Pygame库就会创建一个pygame.event.Event对象来记录这个动作,这就是事件。我们可以调用函数pygame.event.get()来获取发生的事件,此函数会返回pygame.event.Event对象(简称为Event对象)的一个列表。这个Event对象的列表包含了自上次调用pygame.event.get()函数之后所发生的所有事件(如果从来没有调用过pygame.event.get(),会包括自程序启动以来所发生的所有事件)。
处理鼠标事件
在Pygame框架中,MOUSEMOTION事件会在鼠标动作的时候发生,它有如下所示的3个参数。
-
buttons:一个含有3个数字的元组,3个值分别代表左键、中键和右键,1就说明按下了。
-
pos:位置。
-
rel:代表现在距离上次产生鼠标事件时的距离。和MOUSEMOTION类似,常用的鼠标事件还有MOUSEBUTTONDOWN和MOUSEBUTTONUP两个。这两个事件的参数如下所示。
-
button:这个值代表了哪个按键被操作。
-
pos:位置。
import pygame
#判断一个点是否在指定范围内
def is_rect(pos,rect):
x, y = pos
rx, ry, rw, rh = rect
if(rx <= x <= rx+rw) and (ry <= y <= ry+rh):
return True
return False
if __name__ == "__main__":
pygame.init()
screen = pygame.display.set_mode((600,600))
screen.fill((255,255,255))
pygame.display.set_caption("图片拖拽")
#显示一张图片
image = pygame.image.load("bg.jpg")
image_x = 100
image_y = 100
screen.blit(image, (image_x, image_y))
pygame.display.flip()
#用来存储图片是否可以移动
is_move = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
#鼠标按下,让状态可以移动
if event.type == pygame.MOUSEBUTTONDOWN:
w, h = image.get_size()
if is_rect(event.pos, (image_x,image_y,w,h)):
is_move = True
if event.type == pygame.MOUSEMOTION:
if is_move:
screen.fill((255,255,255,255))
x, y = event.pos
image_w, image_h=image.get_size()
#保证鼠标在图片的中心
image_x=x-image_h/2
image_y=y-image_w/2
screen.blit(image,(image_x,image_y))
pygame.display.update()
处理键盘事件
在Pygame框架中,键盘和游戏手柄的事件比较类似,处理键盘的事件为KEYDOWN和KEYUP。KEYDOWN和KEYUP事件的参数描述如下所示。
- key:按下或者放开的键值,是一个数字,因为很少有人可以记住,所以在Pygame中可以使用K_xxx来表示,比如字母a就是K_a,还有K_SPACE和K_RETURN等。
- mod:包含了组合键信息,如果mod &KMOD_CTRL是真的话,表示用户同时按下了〈Ctrl〉键。类似的还有KMOD_SHIFT和KMOD_ALT。
- unicode:代表按下键对应的Unicode值。例如在下面的实例文件shi.py中,演示了在Pygame框架中处理键盘事件的过程。
background_image_filename = "bg.jpg"
import pygame
from pygame.locals import *
from sys import exit
pygame.init()
screen = pygame.display.set_mode((640, 480), 0, 32)
#下面一行代码加载并转换图像
background = pygame.image.load(background_image_filename).convert()
x, y = 0, 0#设置初始位置
move_x, move_y = 0, 0#水平纵向两个方向的移动距离
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:#如果键盘有按键按下
if event.key == K_LEFT:
move_x = -1
elif event.key == K_RIGHT:
move_y = 1
elif event.key == K_UP:
move_y = -1
elif event.key == K_DOWN:
move_y = 1
elif event.type == KEYUP:#如果按键放开,不移动
move_x = 0
move_y = 0
#下面两行计算出新的坐标
x += move_x
y += move_y
screen.fill((0,0,0))#屏幕填充黑色
screen.blit(background, (x, y))
#在新的位置画图
pygame.display.update()#更新绘制操作后屏幕的显示
事件过滤
在现实应用中,并不是所有的事件都是需要处理的。应该有一个方法来过滤掉一些不感兴趣的事件。
-
这时需要使用pygame.event.set_blocked(事件名)来完成。如果有好多事件需要过滤,可以传递一个专用列表来实现比如pygame.event.set_blocked([KEYDOWN,KEYUP]),如果设置参数None,那么所有的事件又被打开了。与之相对应的是,使用**pygame.event.set_allowed()**函数来设定允许的事件。
-
pygame.event.set_blocked():控制哪些事件禁止进入队列。
- set_blocked(type)-> Noneset_blocked(typelist)-> None
- set_blocked(None)-> None参数指定类型的事件均不允许出现在事件队列中。默认是允许所有事件进入队列的。多次禁止同一类型的事件并不会引发什么问题。如果传入None,则表示允许所有的事件进入队列。
-
pygame.event.set_allowed():控制哪些事件允许进入队列。
- set_allowed(type)-> None
- set_allowed(typelist)-> None
- set_allowed(None)-> None参数指定类型的事件均允许出现在事件队列中。默认是允许所有事件进入队列。多次允许同一类型的事件并不会引发什么问题。如果传入None,则表示禁止所有的事件进入队列。
-
pygame.event.get_blocked():检测某一类型的事件是否被禁止进入队列
- get_blocked(type)-> bool如果参数指定类型的事件被禁止进入队列,则返回
产生事件
有时候需要模拟出一些对应的事件,可以自定义一个全新事件
案例
move_ball.py
from sys import exit
import pygame
from pygame.locals import *
#事件类型:"键盘输入",就根据方向键计算出这个速度(默认从左向右为1,从上向下为1)
def control_ball(event):
speed = [0, 0]#设置相对位移
speed_offset = 1
if event.type == KEYDOWN:
if event.key == pygame.K_LEFT:
speed[0] -= speed_offset
if event.key == pygame.K_RIGHT:
speed[0] = speed_offset
print(event.key)
if event.key == pygame.K_UP:#Y轴朝下是正
speed[1] -= speed_offset
if event.key == pygame.K_DOWN:
speed[1] = speed_offset
#如果没有按键输入速度为0小球不动
if event.type == KEYUP:
speed = [0, 0]
return speed
def play_ball():
pygame.init()
window_size = Rect(0, 0, 806, 480)
screen = pygame.display.set_mode(window_size.size)
pygame.display.set_caption("坤坤找不到他的篮球了")
ball_image = pygame.image.load("ball01.png").convert_alpha()
back_image = pygame.image.load("bg1.jpg")
ball_rect = ball_image.get_rect()#获取小球图片所在区域
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
control_speed = control_ball(event)#获取小球移动方向
ball_rect = ball_rect.move(control_speed).clamp(window_size)#限制小球图片在window_size这个区域里
screen.blit(back_image, (0, 0))#绘制游戏窗口
screen.blit(ball_image, ball_rect)#把小球绘制到背景Surface上
# pygame.display.flip()
pygame.display.update()
if __name__ == "__main__":
play_ball()
pygame.Rect()
Rect()是Pygame中的一个类,用于创建矩形对象。它接受四个参数,分别是矩形的左上角x坐标、左上角y坐标、矩形的宽度和高度。
Rect().size()返回一个元组,包含矩形的宽度和高度
pygame.Surface.get_rect()
get_rect():是
Surface
对象的一个方法,用于获取表示该表面的矩形区域的Rect
对象。
get_rect()
方法返回一个Rect
对象,该对象表示了Surface
的矩形区域。这个矩形区域的左上角坐标为(0, 0),宽度和高度与Surface
的尺寸相匹配。
get_rect()
方法还接受一个可选的关键字参数kwargs
,可以用于设置Rect
对象的属性。例如,可以使用kwargs
参数来设置矩形区域的位置或大小。
pygame.Rect.clamp()
clamp()
moves the rectangle inside another
clamp(Rect) -> Rect
更新窗口内容
pygame.display.flip Update the full display Surface to the screen pygame.display.update Update portions of the screen for software displays
pygame.display.flip()
:flip()
函数用于交换屏幕缓冲区的内容。在绘制完成后,调用flip()
函数可以将绘制的内容立即显示在屏幕上。flip()
函数没有参数,它会更新整个屏幕的显示。flip()
函数比较简单,适用于简单的图形绘制场景。
pygame.display.update()
:update()
函数用于更新屏幕的部分区域。它可以接受一个可选的参数,表示要更新的矩形区域。如果不指定参数,update()
函数将更新整个屏幕。update()
函数可以更加灵活地控制屏幕的更新。您可以选择只更新需要更新的部分,以提高性能。update()
函数可以接受一个矩形列表作为参数,表示要更新的多个矩形区域。
主程序运行
if __name__ == "__main__": 是一个常见的Python代码约定,用于判断当前模块是否作为主程序直接运行。
当一个Python脚本作为主程序直接运行时,__name__变量的值会被设置为__main__。而当一个脚本被作为模块导入时,__name__变量的值会是模块的名称。
因此,使用if __name__ == "__main__": 来判断__name__的值,可以使得一部分代码只在脚本作为主程序运行时执行,而在被导入时不执行。
在您的代码中,play_ball()函数会在if __name__ == "__main__": 条件满足时被调用。这意味着当您的脚本作为主程序直接运行时,play_ball()函数会被执行。但如果您的脚本被作为模块导入,play_ball()函数不会被执行。
这种约定可以用于将一些测试代码或调试代码放在if __name__ == "__main__": 条件下,以便在开发和调试阶段执行,而在实际使用时不执行。