pygame (一)
一、入门
https://eyehere.net/2011/python-pygame-novice-professional-1/
1、安装
pip install pygame
补充说明,如果新建一个项目的话,以前安装的模块就不可以用了,可以这样设置:File -> settings -> Project:... -> project interpreter -> 找到以前的解析器即可
2、pygame 包含的模块
# 模块名 功能 # pygame.cdrom 访问光驱 # pygame.cursors 加载光标 # pygame.display 访问显示设备 # pygame.draw 绘制形状、线和点 # pygame.event 管理事件 # pygame.font 使用字体 # pygame.image 加载和存储图片 # pygame.joystick 使用游戏手柄或者 类似的东西 # pygame.key 读取键盘按键 # pygame.mixer 声音 # pygame.mouse 鼠标 # pygame.movie 播放视频 # pygame.music 播放音频 # pygame.overlay 访问高级视频叠加 # pygame 就是我们在学的这个东西了…… # pygame.rect 管理矩形区域 # pygame.sndarray 操作声音数据 # pygame.sprite 操作移动图像 # pygame.surface 管理图像和屏幕 # pygame.surfarray 管理点阵图像数据 # pygame.time 管理时间和帧信息 # pygame.transform 缩放和移动图像
3、关于导入:
from pygame.locals import *
# pygame.locals Pygame 定义的常量。
# 这个模块包含了 Pygame 定义的各种常量。它的内容会被自动放入到 Pygame 模块的名字空间中。你可以使用
# from pygame.locals import *将所有的 Pygame 常量导入。
# 各个常量的详细描述记录在 Pygame 各个模块的相关文档中。比如 pygame.display.set_mode() 方法用到的 HWSURFACE 常量,
# 你就可以在 display 模块的文档中找到详细的说明;事件类型在 event 模块的文档中可以找到;当产生 KEYDOWN 或 KEYUP 事件时,
# key 属性描述具体哪个按键被按下,该值是以 K_ 开头的常量(MOD_ 开头的常量表示各种组合键被按下),在 key 模块的文档中可以找到;
# 最后,TIME_RESOLUTION 被定义在 time 模块中
二、display (显示模块)
import pygame, sys from pygame.locals import * pygame.init() print(pygame.display.list_modes()) # 查看你的电脑支持哪些尺寸 # [(1920, 1080), (1680, 1050), (1680, 1050), (1600, 1200),... SCREEN_SIZE = (640, 480) screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32) print(screen) # <Surface(640x480x32 SW)> # 参数: # 1、tuple 屏幕尺寸 # 2、int 标志位:窗口模式 # pygame.FULLSCREEN:全屏 # pygame.DOUBLEBUF:双缓冲 # pygame.HWSURFACE:硬件加速,必须跟全屏一起使用:FULLSCREEN|HWSURFACE # pygame.OPENGL:opengl渲染 # pygame.RESIZABLE:可改变大小 # pygame.NOFRAME:没边框 # 0:标准,默认 # 3、int 色深 一般都是32位 # 创建窗口 # 注意:如果你的程序有什么问题,很可能进入了全屏模式就不太容易退出来了,所以最好先用窗口模式调试好,再改为全屏模式 # 这些显示模式,未必所有的操作系统都支持(放心windows、各种比较流行的Linux发行版都是没问题的),一般来说窗口就用0全屏就用FULLSCREEN,这两个总是OK的。 # 如果你想创建一个硬件显示(surface会存放在显存里,从而有着更高的速度),你必须和全屏一起使用: # screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE | FULLSCREEN, 32) # 当然你完全可以把双缓冲(更快)DOUBLEBUF也加上,这就是一个很棒的游戏显示了,不过记得你要使用pygame.display.flip() # 来刷新显示。pygame.display.update() # 是将数据画到前面显示,而这个是交替显示的意思。 # 稍微说一下双缓冲的意思,可以做一个比喻:我的任务就是出黑板报,如果只有一块黑板,那我得不停的写,全部写完了稍微Show一下就要擦掉重写, # 这样一来别人看的基本都是我在写黑板报的过程,看到的都是不完整的黑板报;如果我有两块黑板,那么可以挂一块给别人看,我自己在底下写另一块, # 写好了把原来的换下来换上新的,这样一来别人基本总是看到完整的内容了。双缓冲就是这样维护两个显示区域,快速的往屏幕上换内容,而不是每次都慢慢地重画。 # 还有OPENGL模式,这是一个得到广泛应用的3D加速显示模式。不过一旦使用了这个模式,pygame中的2D图像函数就不能用了,我们会在以后讲详细的内容。 pygame.display.set_caption("Hello, World!") # 设置窗口标题 background = pygame.image.load('images/sushiplate.jpg').convert() # 背景图片 Fullscreen = False while True: event = pygame.event.wait() if event.type == QUIT: exit() if event.type == KEYDOWN: # 全屏, if event.key == K_f: Fullscreen = not Fullscreen if Fullscreen: print('f') screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32) else: screen = pygame.display.set_mode((640, 480), 0, 32) # 拖动边框改变尺寸: if event.type == VIDEORESIZE: SCREEN_SIZE = event.size screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32) pygame.display.set_caption("Window resized to " + str(event.size)) screen_width, screen_height = SCREEN_SIZE # 这里需要重新填满窗口 for y in range(0, screen_height, background.get_height()): for x in range(0, screen_width, background.get_width()): screen.blit(background, (x, y)) # screen.blit(background, (0, 0)) pygame.display.update() # 刷新一下画面,不然整个画面黑漆漆的
三、event (事件模块)
# 事件 pygame.event # 需要把代码放置到while True:里面才能不停的捕捉到事件 # 1 get() 非阻塞,返回一个list,没有事件发生时返回[] # 2 wait() 阻塞,有事件发生时返回一个Event对象, 没有事件时程序挂起 # 3 poll() 非阻塞,随时都返回一个Event,但是,没有事件发生时event.type等于0 for event in pygame.event.get(): if event.type == pygame.QUIT: # 接收到退出事件后退出程序 sys.exit() even = pygame.event.wait() print(even) even = pygame.event.poll() if even.type != 0: print(even) # 事件 产生途径 参数 # QUIT 用户按下关闭按钮 none # ATIVEEVENT Pygame被激活或者隐藏 gain, state # KEYDOWN 键盘被按下 unicode, key, mod # KEYUP 键盘被放开 key, mod # MOUSEMOTION 鼠标移动 pos, rel, buttons # MOUSEBUTTONDOWN 鼠标按下 pos, button # MOUSEBUTTONUP 鼠标放开 pos, button # JOYAXISMOTION 游戏手柄(Joystick or pad)移动 joy, axis, value # JOYBALLMOTION 游戏球(Joy ball)?移动 joy, axis, value # JOYHATMOTION 游戏手柄(Joystick)?移动 joy, axis, value # JOYBUTTONDOWN 游戏手柄按下 joy, button # JOYBUTTONUP 游戏手柄放开 joy, button # VIDEORESIZE Pygame窗口缩放 size, w, h # VIDEOEXPOSE Pygame窗口部分公开(expose)? none # USEREVENT 触发了一个用户事件 code # 窗口事件 if event.type == pygame.QUIT: # 关闭窗口 sys.exit() # 鼠标事件: if event.type == pygame.MOUSEBUTTONDOWN: print(event, event.pos, event.button) # <Event(1025-MouseButtonDown {'pos': (440, 160), 'button': 1, 'window': None})> (440, 160) 1 print(event.pos, event.button) # (328, 151) 1 # 键盘事件 if event.type == pygame.KEYDOWN: print(event) # <Event(768-KeyDown {'unicode': '', 'key': 1073742048, 'mod': 4160, 'scancode': 224, 'window': None})> print(event.mod) # 用于测试组合键 # ctrl键:4160 shift键:4097 alt键:4352 不用死记,用的时候测试一下就行了, print(event.mod & pygame.KMOD_CTRL, event.mod & pygame.KMOD_SHIFT, event.mod & pygame.KMOD_ALT) # 64 0 0 0 1 0 0 0 256 只要值不为0 说明对应的按键已按下 print(event.key == 114) # 按下什到键, 可以用数值,也可以用常量,不用死记,测试一下就知道值是多少 print(event.key == pygame.K_DOWN) # 值可以这些等:114,1073741904,pygame.K_0, pygame.K_a, pygame.K_LEFT # 事件过滤 # 并不是所有的事件都需要处理的,就好像不是所有登门造访的人都是我们欢迎的一样。比如,俄罗斯方块就无视你的鼠标,而在游戏场景切换的时候, # 你按什么都是徒劳的。我们应该有一个方法来过滤掉一些我们不感兴趣的事件(当然我们可以不处理这些没兴趣的事件,但最好的方法还是让它们根本 # 不进入我们的事件队列,就好像在门上贴着“XXX免进”一样),我们使用pygame.event.set_blocked(事件名)来完成。如果有好多事件需要过滤 # ,可以传递一个列表,比如pygame.event.set_blocked([KEYDOWN, KEYUP]),如果你设置参数None,那么所有的事件有被打开了。与之相对的, # 我们使用pygame.event.set_allowed()来设定允许的事件。 # 自定义事件 my_event = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_SPACE, mod=0, unicode=u' ') # 你也可以像下面这样写,看起来比较清晰(但字变多了……) my_event = pygame.event.Event(pygame.KEYDOWN, {"key": pygame.K_SPACE, "mod": 0, "unicode": u' '}) pygame.event.post(my_event)
补充:
定时(重复)发送事件
pygame.time.set_timer(USEREVENT+10,10000),参数10000是发送事件的间隔时间,单位毫秒
接收事件:
for event in pygame.event.get():
elif event.type == USEREVENT+10:
print('tangjun')
取消事件:把时间间隔设置为0
pygame.time.set_timer(USEREVENT+10, 0)
如果只发送一次事件:
pygame.event.post(pygame.event.Event(USEREVENT + 10))
四、字体
pygame.font
# !/usr/bin/env python # x, y = pygame.mouse.get_pos() # # 获得鼠标位置 # 加载图片 # pygame.image.load(background_image_filename) # background = pygame.image.load(background_image_filename).convert() # mouse_cursor = pygame.image.load(mouse_image_filename).convert_alpha() # 加载图片 , 上面三个方法都会返回一个Surface对象,区别在于convert函数是将图像数据都转化为Surface对象, # 每次加载完图像以后就应该做这件事件(事实上因为 它太常用了,如果你不写pygame也会帮你做);convert_alpha相比convert, # 保留了Alpha 通道信息(可以简单理解为透明的部分),这样我们的光标才可以是不规则的形状。 # screen.blit(background, (0,0)) # #将背景图画上去 # screen.fill((200, 200, 200)) # 填充颜色 # screen.blit(background, (0, 0)) # 把图像画到屏幕上 # 参数: # 1、Surface对象 # 2、tuple 位置 # pygame.display.update() # # 刷新一下画面,不然整个画面黑漆漆的 # ------------------------------------------------- #================================================================================== import pygame from pygame.locals import * pygame.init() print(pygame.font.get_fonts()) # ['arial', 'arialblack', 'bahnschrift', 'calibri', 'cambriacambriamath', 'cambria', 'candara', 'comicsansms', # ... # '华文楷体', '华文隶书', '华文宋体', '华文细黑', '华文行楷', '华文新魏', '华文中宋', 'extra'] # print(pygame.font.get_default_font()) # freesansbold.ttf # 设置字体: # 1 使用系统字体 my_font = pygame.font.SysFont('华文行楷', 46) # print(my_font) # <pygame.font.Font object at 0x0000024AE1DBCD70> # 2 使用外部字体: # 这个语句使用了一个叫做“my_font.ttf”,这个方法之所以好是因为你可以把字体文件随游戏一起分发,避免用户机器上没有需要的字体 my_font = pygame.font.Font('C:\Windows\Fonts\STXINGKA.TTF', 30) # 说明:怎么找到相应字体的文件名:在C:\Windows\Fonts\找到需要的字体,然后右键属性,就可以看到字体文件名,比如,华文行楷的文件名就是:STXINGKA.TTF fontface = my_font.render('你好,我是一个好人,how are you ', True, (0, 0, 0), (255, 255, 255)) # 第一个参数是写的文字;第二个参数是个布尔值,以为这是否开启抗锯齿,就是说True的话字体会比较平滑,不过相应的速度有一点点影响; # 第三个参数是字体的颜色;第四个是背景色,如果你想没有背景色(也就是透明),那么可以不加这第四个参数 # 说明,如果是中文的话,一定要选对字符,否则显示不出或乱码 print(fontface) # <Surface(403x28x8 SW)> # 注意:fontface是一个Surface对象,接下来知道该怎么做了吧! pygame.image.save(fontface, 'font.png') # 可以把字体保存为一张图片
五、surface 模块 管理图像和屏幕
补充:
newsur = sur.subsurface(select_rect).copy()
获取一部分子曲面
什么时候需要cop()
如果在自己上面blit的话需要copy(),如:
sur.blit(newsur,rect)
如果是在别的曲面上blit,就不需要copy(),但是copy了也没错,所以还是建议copy吧
screen.blit(newsur,rect)
import pygame, time pygame.init() # 怎样生成Curface对象: # 方法一:应用程序界面 surf1 = pygame.display.set_mode((1000, 1000)) print(surf1) # <Surface(1000x1000x32 SW)> # 方法二:加载图像 surf2 = pygame.image.load('images/fugu.png').convert() print(surf2) # <Surface(150x122x32 SW)> # 方法三:渲染字休 surf3 = pygame.font.SysFont('隶书', 46).render(u'大家好', True, (255, 255, 255), (0, 0, 0)) print(surf3) # <Surface(138x46x8 SW)> # 方法四:用构造函数返回 surf4 = pygame.surface.Surface((100, 100), depth=24) # 在上面绘制的图形如果超出它的边界,超出部分不会显示 # 如果需要透明通道需要:flags 设置为SRCALPHA,depth深度设置为32位,4*8 等于 32,如果不设置的话,会自动设置为主控台的深度 surf4 = pygame.surface.Surface((100, 100), flags=SRCALPHA, depth=32) print(surf4) # <Surface(100x100x24 SW)> # -------------------------------------------------------- # surface的重要方法: # 1 填充颜色: surf1.fill((140, 140, 40)) # 填充屏幕,通常用于清屏 # screen.fill((0,222,0),(100,200,200,200)) # 也可以绘制一个矩形 # 2 在surface上面绘制surface: surf1.blit(surf2, (100, 100)) # 3 设置像素颜色: for x in range(10): for y in range(10): surf1.set_at((500 + x, 500 + y), (222, 222, 222)) # screen.get_at((10, 23)) # 不过记住get_at在对hardware surface操作的时候很慢,而全屏的时候总是hardware的,所以慎用这个方法! # screen.set_clip(20,20,600,440) # 参数:x, y, width, height # # 通常游戏的时候你只需要绘制屏幕的一部分。比如魔兽上面是菜单,下面是操作面板,中间的小兵和英雄打的不可开交时候,上下的部分也是保持相对不动的。 # # 为了实现这一点,surface就有了一种叫裁剪区域(clipping area)的东西,也是一个矩形,定义了哪部分会被绘制,也就是说一旦定义了这个区域, # # 那么只有这个区域内的像素会被修改,其他的位置保持不变,默认情况下,这个区域是所有地方。我们可以使用set_clip来设定,使用get_clip来获得这个区域。 # print(screen.get_clip()) # <rect(20, 20, 600, 440)> # screen.lock() #很快你就会知道这两句lock和unlock的意思了 # 这里开始绘制屏幕 # screen.unlock() # 当Pygame往surface上画东西的时候,首先会把surface锁住,以保证不会有其它的进程来干扰,画完之后再解锁。锁和解锁时自动发生的, # 所以有时候可能不那么有效率,比如上面的例子,每次画100个点,那么就得锁解锁100次,现在我们把两句注释去掉,再执行看看是不是更快了 # (好吧,其实我没感觉出来,因为现在的机器性能都不错,这么点的差异还不太感觉的出来。不过请相信我~复杂的情况下会影响效率的)? # 当你手动加锁的时候,一定不要忘记解锁,否则pygame有可能会失去响应。虽然上面的例子可能没问题,但是隐含的bug是我们一定要避免的事情 pygame.display.update() time.sleep(5)
例 1
# 打印一个16*16的色彩方块图片 import pygame pygame.init() all_colors = pygame.Surface((4096, 4096), depth=24) print(all_colors) # <Surface(4096x4096x24 SW)> for r in range(256): break # 把这一行代码去掉就可以生成图片 # print(r & 15) # 0 1 2 3....15... x = (r & 15) * 256 # print(x) 0 256 512 3840 0 512... y = (r >> 4) * 256 # print(r >> 4) 0*16 1*16 15*16 for g in range(256): for b in range(256): all_colors.set_at((x + g, y + b), (r, g, b)) pygame.image.save(all_colors, "allcolors.jpg")
例 2
# !/usr/bin/env python import pygame from pygame.locals import * from sys import exit pygame.init() # 初始化 screen = pygame.display.set_mode((640, 480), 0, 32) # 创建主控台 # 创建红、绿、蓝三个surface def create_scales(height): red_scale_surface = pygame.surface.Surface((640, height)) # 红surface green_scale_surface = pygame.surface.Surface((640, height)) # 绿surface blue_scale_surface = pygame.surface.Surface((640, height)) # 蓝surface # 为每个surface画640条垂直的线,最终形成颜色渐变的效果 for x in range(640): c = int((x / 640) * 255) # 宽是640 把640分成255个像素。 red = (c, 0, 0) green = (0, c, 0) blue = (0, 0, c) # line_rect = Rect(x, 0, 1, height) # 画宽度为1,高度为height为的矩形,其实就是画一条垂直的线 # pygame.draw.rect(red_scale_surface, red, line_rect) # pygame.draw.rect(green_scale_surface, green, line_rect) # pygame.draw.rect(blue_scale_surface, blue, line_rect) # 等效于下面三条语句 pygame.draw.line(red_scale_surface, red, (x, 0), (x, height)) pygame.draw.line(green_scale_surface, green, (x, 0), (x, height)) pygame.draw.line(blue_scale_surface, blue, (x, 0), (x, height)) return red_scale_surface, green_scale_surface, blue_scale_surface red_scale, green_scale, blue_scale = create_scales(80) color = [127, 127, 127] # 矩形大方块的初始颜色 while True: for event in pygame.event.get(): if event.type == QUIT: exit() # screen.fill((0, 0, 0)) screen.blit(red_scale, (0, 00)) screen.blit(green_scale, (0, 80)) screen.blit(blue_scale, (0, 160)) x, y = pygame.mouse.get_pos() # 根据鼠标按下的位置修改 color = [127, 127, 127] 的值 if pygame.mouse.get_pressed()[0]: # 按下鼠标左键 for component in range(3): if y > component * 80 and y < (component + 1) * 80: color[component] = int((x / 640) * 255) pygame.display.set_caption("PyGame Color Test - " + str(tuple(color))) # 绘制三个圆 for component in range(3): pos = (int((color[component] / 255.) * 639), component * 80 + 40) pygame.draw.circle(screen, (255, 255, 255), pos, 20) pygame.draw.rect(screen, tuple(color), (0, 240, 640, 240)) pygame.display.update()

浙公网安备 33010602011771号