pygame入门

说明

在学习pygame时,主要参考了目光博客的教程。目光博客

原教程是2011年写的,年代比较久远了,使用Python2。我学习时使用python3将代码重新实现了一遍,同时补充了一些细节。相比较原博客,少了一些实例。

一、pygame的安装

pip install pygame

1

安装好后,可以用下面的方法确认有没有安装成功

>>>import pygame

>>>print(pygame.ver)

1.9.3

1

2

3

二、pygame模块概览

三、pygame的“hello world”

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

background_image = 'image/sushiplate.jpg'

mouse_image = 'image/fugu.png'

# 初始化pygame,为使用硬件做准备

pygame.init()

# 创建了一个窗口

screen = pygame.display.set_mode((640, 480), 0, 32)

# 设置窗口标题

pygame.display.set_caption("hello world")

# 加载并转换图像

background = pygame.image.load(background_image).convert()

mouse_cursor = pygame.image.load(mouse_image).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() # 获得鼠标位置

# 计算光标左上角位置

x -= mouse_cursor.get_width()/2

y -= mouse_cursor.get_height()/2

# 画上光标

screen.blit(mouse_cursor, (x, y))

# 刷新画面

pygame.display.update()

set_mode:返回一个Surface对象,代表了桌面上出现的窗口。第一个参数代表分辨率;第二个参数是标志位,如果不需要使用热河特性,则指定为0;第三个为色深。

标志位功能

FULLSCREEN

创建一个全屏窗口 (create a fullscreen display)

DOUBLEBUF

创建一个“双缓冲”窗口,建议在HWSURFACE或者OPENGL时使用( recommended for HWSURFACE or OPENGL)

HWSURFACE

创建一个硬件加速的窗口,必须和FULLSCREEN同时使用( hardware accelerated, only in FULLSCREEN)

OPENGL

创建一个OPENGL渲染的窗口 (create an OpenGL-renderable display)

RESIZABLE

创建一个可以改变大小的窗口 (display window should be sizeable)

NOFRAME

创建一个没有边框的窗口 (display window will have no border or controls)

convert:将图像转化为Surface对象,每次加载完图像后就要使用这个函数.

convert_alpha:相比convert,保留了Alpha 通道信息(可以简单理解为透明的部分),这样我们的光标才可以是不规则的形状。可以试试不用convert_alpha()生成的效果。

blit:第一个参数为一个Surface对象,第二个为左上角位置。画完以后得用update更新,否则画面一片漆黑。

四、事件

理解事件

我们上一个程序,一直运行直到关闭窗口而产生了一个QUIT事件,Pygame会接受用户的各种操作(比如按键盘,移动鼠标等)产生事件。事件随时可能发生,而且量也可能会很大,Pygame的做法是把一系列的事件存放一个队列里,逐个的处理。

事件检索

上个程序中,使用了pygame.event.get()来处理所有的事件;也可以使用pygame.event.wait(),pygame会等到发生一个时间才继续下去;另外一个方法pygame.event.poll(),一旦调用,它会根据现在的情形返回一个真实的事件,或者一个“什么都没有”。下表是一个常用事件集:

事件产生途径参数

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

接下来我们写一个把所有发生的事件输出的程序

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

pygame.init()

SCREEN_SIZE = (640, 480)

screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)

font = pygame.font.SysFont("MicrosoftYaHei", 16)

font_height = font.get_linesize()

event_text = []

while True:

event = pygame.event.wait()

event_text.append(str(event))

# 保证event_text里面只保留一个屏幕的文字

event_text = event_text[-SCREEN_SIZE[1]//font_height:]

if event.type == QUIT:

exit()

screen.fill((255, 255, 255))

# 寻找一个合适的起笔位置,最下面开始,留一行的空

y = SCREEN_SIZE[1] - font_height

for text in reversed(event_text):

screen.blit(font.render(text, True, (0, 0, 0)), (0, y))

y -= font_height

pygame.display.update()

结果如下,会将发生的事件列出。在程序中使用wait(),因为这个程序只要在有动作时执行就好了。

处理鼠标事件

MOUSEMOTION事件会在鼠标动作的时候发生,它有三个参数:

buttons – 一个含有三个数字的元组,三个值分别代表左键、中键和右键,1就是按下了。

pos – 位置

rel – 代表了现在距离上次产生鼠标事件时的距离

和MOUSEMOTION类似的,我们还有MOUSEBUTTONDOWN和MOUSEBUTTONUP两个事件。它们的参数为:

button – 这个值代表了哪个按键被操作

pos – 位置

处理键盘事件

键盘的事件为KEYDOWN和KEYUP。

下面这个例子演示的是使用方向键来移动图片。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

background_image = '../image/sushiplate.jpg'

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).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_x = 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()

KEYDOWN和KEYUP的参数描述如下:具体描述请点击这里

key – 按下或者放开的键值,是一个数字,Pygame中可以使用K_xxx来表示,比如字母a就是K_a,还有K_SPACE和K_RETURN等。

mod – 包含了组合键信息,如果mod & KMOD_CTRL是真的话,表示用户同时按下了Ctrl键。类似的还有KMOD_SHIFT,KMOD_ALT。

unicode – 代表了按下键的Unicode值

事件过滤

并不是所有的事件都需要处理。我们使用pygame.event.set_blocked(type)来完成。如果有好多事件需要过滤,可以传递一个列表,比如pygame.event.set_blocked([KEYDOWN, KEYUP]),如果你设置参数None,那么所有的事件有被打开了。与之相对的,我们使用pygame.event.set_allowed()来设定允许的事件。

产生事件

通常玩家做什么,Pygame就产生对应的事件就可以了,不过有的时候我们需要模拟出一些事件来,比如录像回放的时候,我们就要把用户的操作再现一遍。

为了产生事件,必须先造一个出来,然后再传递它:

my_event = pygame.event.Event(KEYDOWN, key=K_SPACE, mod=0, unicode=' ')

# 你也可以像下面这样写

my_event = pygame.event.Event(KEYDOWN, {"key":K_SPACE, "mod":0, "unicode":' '})

pygame.event.post(my_event)

1

2

3

4

Event():Event(type, dict) 或者 Event(type, **attributes),

post():把新的事件放在事件队列的最后。

也可以产生一个完全自定义的全新事件。

import pygame

from pygame.locals import *

pygame.init()

my_event = pygame.event.Event(KEYDOWN, key=K_SPACE, mod=0, unicode=' ')

# my_event = pygame.event.Event(KEYDOWN,{"key":K_SPACE, "mod":0, "unicode":' '})

pygame.event.post(my_event)

###############

# 产生一个自定义的全新事件

CATONKEYBOARD = USEREVENT + 1

my_event = pygame.event.Event(CATONKEYBOARD, message="bad act!")

pygame.event.post(my_event)

# 获得这个事件

for event in pygame.event.get():

if event.type == CATONKEYBOARD:

print( event.message)

五、显示

全屏显示

在第一个例子“hello world”中,使用了如下语句

screen = pygame.display.set_mode((640, 480), 0, 32)

1

如果把第二个参数设置成FULLSCREEN,就会得到一个全屏显示的窗口。

在全屏模式下,显卡可能就切换了一种模式,你可以用如下代码获得您的机器支持的显示模式

>>> import pygame

>>> pygame.init()

>>> pygame.display.list_modes()

1

2

3

接下来这个程序,按“f键实现全屏和窗口之间的切换。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

background_image = '../image/sushiplate.jpg'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).convert()

Fullscreen = False

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

if event.type == KEYDOWN:

if event.key == K_f:

Fullscreen = not Fullscreen

if Fullscreen:

screen = pygame.display.set_mode((640, 480), FULLSCREEN, 32)

else:

screen = pygame.display.set_mode((640, 480), 0, 32)

screen.blit(background, (0, 0))

pygame.display.update()

改变窗口尺寸

pygame的默认显示窗口是不支持拖动边框改变大小的,改变set_mode函数的参数后可以实现。

screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32)

1

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

background_image = '../image/sushiplate.jpg'

SCREEN_SIZE = (640, 480)

pygame.init()

screen = pygame.display.set_mode(SCREEN_SIZE, RESIZABLE, 32)

background = pygame.image.load(background_image).convert()

while True:

event = pygame.event.wait()

if event.type == QUIT:

exit()

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))

pygame.display.update()

VIDEORESIZE事件,它包含如下内容:

size — 一个二维元组,值为更改后的窗口尺寸,size[0]为宽,size[1]为高

w — 宽

h — 高

复合模式

screen = pygame.display.set_mode(SCREEN_SIZE, HWSURFACE | FULLSCREEN, 32)

1

其他

当使用OPENGL时,不能使用pygame.display.update()来更新窗口,而是pygame.display.flip()。

flip和update的说明如下:

六、字体

创建font对象

Pygame可以直接调用系统字体,或者也可以使用TTF字体。

SysFont(name, size, bold=False, italic=False)

my_font = pygame.font.SysFont("arial", 16)

1

第一个参数是字体名,第二个是大小。该函数返回一个系统字体,这个字体与“bold”和“italic”两个flag相匹配。如果找不到,就会使用pygame的默认字体。可以使用pygame.font.get_fonts()来获得当前系统所有可用字体。

Font(filename, size) 或者Font(object, size)

my_font = pygame.font.Font("simsun.ttf", 16)

1

使用这个方法,需要把字体文件随同游戏一起发送,这样可以避免使用者机器上没有所需的字体

使用字体

render(text, antialias, color, background=None)

text_surface = my_font.render("Pygame is cool!", True, (0,0,0), (255, 255, 255))

1

第一个参数文字;第二个参数是个布尔值,表示是否开启抗锯齿,如果为True,字体会比较平滑,不过相应的速度有一点点影响;第三个参数是字体的颜色;第四个是背景色,如果你想没有背景色(也就是透明),就不加这第四个参数。

中文字体

下面这个例子演示了用pygame书写中文

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background_image = 'image/sushiplate.jpg'

background = pygame.image.load(background_image).convert()

# 以下两种方法都可以,第一种需要把字体文件复制到代码文件目录下

font = pygame.font.Font("simsun.ttc", 40)

# font = pygame.font.SysFont("simsunnsimsun", 40)

text_surface = font.render("你好", True, (0, 0, 255))

x = 0

y = (480 - text_surface.get_height())/2

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

screen.blit(background, (0, 0))

x -= 1

if x < -text_surface.get_width():

x = 640 - text_surface.get_width()

screen.blit(text_surface, (x, y))

pygame.display.update()

七、颜色

一般的32位RGB,每个像素可以显示16.7百万种颜色。

第一个例子,可以生成所有的颜色。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

pygame.init()

screen = pygame.display.set_mode((640, 480))

all_colors = pygame.Surface((4096, 4096), depth=24)

for r in range(256):

print(r + 1, "out of 256")

x = (r & 15) * 256

y = (r >> 4) * 256

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.bmp")

第二个例子,用鼠标移动三个点,代表三原色的值,下方是三原色混合得到的结果。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

def create_scales(height):

red_scale_surface = pygame.surface.Surface((640, height))

green_scale_surface = pygame.surface.Surface((640, height))

blue_scale_surface = pygame.surface.Surface((640, height))

for x in range(640):

c = int((x / 640) * 255)

red = (c, 0, 0)

green = (0, c, 0)

blue = (0, 0, c)

line_rect = Rect(x, 0, 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)

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, 0))

screen.blit(green_scale, (0, 80))

screen.blit(blue_scale, (0, 160))

x, y = pygame.mouse.get_pos()

if pygame.mouse.get_pressed()[0]:

for component in range(3):

if y > component * 80 and y < (component + 1) * 80:

color[component] = int((x / 639) * 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()

八、图像

使用Surface对象

加载图片用pygame.image.load,返回一个Surface对象。事实上,屏幕也只是一个surface对象,pygame.display.set_mode返回一个屏幕的surface对象。

创建Surface对象

除了上面说的pygame.image.load外,还可以指定尺寸创建一个空的surface。

>>> a = pygame.Surface((256,256))

这个Surface对象是全黑的。除了大小外,Surface函数还有flags和depth两个参数。

HWSURFACE – creates the image in video memory

SRCALPHA – the pixel format will include a per-pixel alpha。创建有Alpha通道的surface,选择这个选项需要depth为32。

alpha_surface = pygame.Surface((256,256), flags=SRCALPHA, depth=32)

转换Surfaces

convert(): Creates a new copy of the Surface with the pixel format changed. 当一个surface多次使用blit时,最好使用convert。转换后的surface没有alpha。

convert_alpha(): change the pixel format of an image including per pixel alphas.

矩形对象(Rectangle Objects)

pygame中有Rect类,用来存储和处理矩形对象(包含在pygame.locals)中。

Rect(left, top, width, height)

Rect((left, top), (width, height))

有了Rect对象之后,可以对其做很多操作,例如调整大小、位置,判断一个点是否在其中等。

剪裁(Clipping)

surface中有裁剪区域(clip area),是一个矩形,定义了哪部分会被绘制,即若定义了这个区域,只有这个区域内的像素会被修改。

set_clip(screen_rect=None): 设定区域,当参数为None时,重置。一个surface对象默认的剪裁区域为这个surface。

get_clip() : 得到剪裁区域,返回一个Rect对象。

子表面(Subsurfaces)

Subsurfaces是在一个surface中再提取出一个surface。当在subsurface上操作时,同时也向父表面上操作。这可以用来绘制图形文字,比如吧文字变成多种颜色。把整张图读入后,用subsurface将每个字分隔开。

my_font_image = Pygame.load("font.png")

letters = []

letters["a"] = my_font_image.subsurface((0,0), (80,80))

letters["b"] = my_font_image.subsurface((80,0), (80,80))

填充Surface

fill(color, rect=None, special_flags=0)

当rect参数为默认参数时,整个surface都会被填充。color参数可以为RGB或者RGBA。如果使用RGBA,除非surface有alpha通道(使用了SRCALPHA flag),否则RGBA的Alpha会被忽略。

设置Surface的像素

set_at((x, y), Color) : 设置单个像素的颜色

get_at((x, y)) : 得到单个像素的颜色

锁定Surface

当对像素进行读或写操作时,surface会被锁定。一个锁定的surface,经常不能被显示或被pygame操作,所以除非必要,在手动lock之后不要忘了unlock。

所有pygame的函数如过需要锁定和解锁,这些操作时自动发生的。如果不想发生自动的lock和unlock(有些时候为了提高效率),可以在一些会造成自动锁定和解锁的语句前后注释掉这两句。

import pygame

from pygame.locals import *

from sys import exit

from random import randint

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

rand_col = (randint(0, 255), randint(0, 255), randint(0, 255))

# screen.lock)()

for _ in range(100):

rand_pos = (randint(0, 639), randint(0, 479))

screen.set_at(rand_pos, rand_col)

# screen.unlock()

pygame.display.update()

blit

blit(source, dest, area=None, special_flags = 0)

将源图像画到目标位置,dest可以为一个点,也可以是一个矩形,但只有矩形的左上角会被使用,矩形的大小不会造成影响。

area参数可以指定源图像中的一部分被画到目标位置。

九、绘制各种图形

pygame使用pygame.draw来绘制图形。其包含以下几种函数。

函数作用用法

rect

绘制矩形

rect(Surface, color, Rect, width=0)

polygon

绘制多边形

polygon(Surface, color, pointlist, width=0)

circle

绘制圆

circle(Surface, color, pos, radius, width=0)

ellipse

绘制椭圆

ellipse(Surface, color, Rect, width=0)

arc

绘制圆弧

arc(Surface, color, Rect, start_angle, stop_angle, width=1)

line

绘制线

line(Surface, color, start_pos, end_pos, width=1)

lines

绘制一系列的线

lines(Surface, color, closed, pointlist, width=1)

aaline

绘制一根平滑的线

aaline(Surface, color, startpos, endpos, blend=1)

aalines

绘制一系列平滑的线

aalines(Surface, color, closed, pointlist, blend=1)

一些说明

width参数:width参数为0或省略,则填充。

画填充的矩形,有另一个方法Surface.fill(),事实上,这种方法速度更快。

lines函数的closed为一个布尔变量,如果closed为真,则会画一条连接第一个和最后一个点的线,是整个图形闭合。

十、运动

直线运动

下面这个程序让“hello world”程序中的鱼动起来。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

background_image = '../image/sushiplate.jpg'

sprite_image = '../image/fugu.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).convert()

sprite = pygame.image.load(sprite_image)

# sprite的起始坐标

x = 0

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

screen.blit(background, (0, 0))

screen.blit(sprite, (x, 100))

x += 1

if x>640:

x = 0

pygame.display.update()

时间

在上面的程序中,帧率是很高的。而且电脑的性能不同,鱼的速度就会不同,如果动画的的元素很多,速度就会下降。

为了解决这个问题,可以使用pygame的时间模块。

clock = pygame.time.Clock()

time_passed = clock.tick()

time_passed = clock.tick(30)

第一行初始化了一个Clock对象。第二行返回了距上一次调用这个函数,过去了多长时间(注意,得到的值是以毫秒为单位的)。第三行,在函数中添加了framerate参数,这个函数会延时使得游戏的帧率不会超过给定值。

给定的值仅仅是最大帧率,当动作复杂或机器性能不足时,实际帧率无法达到这个值,需要一种手段控制动画效果。比如给吾提一个恒定的速度,再通过时间,计算出移动的距离。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

background_image = '../image/sushiplate.jpg'

sprite_image = '../image/fugu.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).convert()

sprite = pygame.image.load(sprite_image)

# clock对象

clock = pygame.time.Clock()

x = 0

speed = 250

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

screen.blit(background, (0, 0))

screen.blit(sprite, (x, 100))

time_passed = clock.tick()

time_passed_seconds = time_passed/1000

distance_moved = time_passed_seconds * speed

x += distance_moved

if x > 640:

x -= 640

pygame.display.update()

斜线运动

接下来这个程序,使得物体斜线运动并且触边反弹。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

background_image = '../image/sushiplate.jpg'

sprite_image = '../image/fugu.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).convert()

sprite = pygame.image.load(sprite_image)

clock = pygame.time.Clock()

x, y = 100, 100

speed_x, speed_y = 133, 170

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

screen.blit(background, (0, 0))

screen.blit(sprite, (x, y))

time_passed = clock.tick(30)

time_passed_seconds = time_passed/1000

x += speed_x * time_passed_seconds

y += speed_y * time_passed_seconds

# 到达边界后速度反向

if x > 640 - sprite.get_width():

speed_x = -speed_x

x = 640 - sprite.get_width()

elif x < 0:

speed_x = -speed_x

x = 0

if y > 480 - sprite.get_height():

speed_y = -speed_y

y = 480 - sprite.get_height()

elif y < 0:

speed_y = -speed_y

y = 0

pygame.display.update()

向量

下面这个例子,使用向量代替之前的x和y的计算,实现了鱼在鼠标周围游动的效果。

使用向量类来存储和计算向量。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

from vector import Vec2d

background_image = '../image/sushiplate.jpg'

sprite_image = '../image/fugu.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).convert()

sprite = pygame.image.load(sprite_image)

clock = pygame.time.Clock()

position = Vec2d(100, 100)

heading = Vec2d((0, 0))

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

screen.blit(background, (0, 0))

screen.blit(sprite, position)

time_passed = clock.tick(30)

time_passed_seconds = time_passed/1000

# 在参数前面加*意味着把列表或元组展开

destination = Vec2d(*pygame.mouse.get_pos()) - Vec2d(*sprite.get_size())/2

# 计算当鱼儿当前位置到鼠标位置的向量

vector_to_mouse = Vec2d.__sub__(destination, position)

vector_to_mouse.normalized()

# heading可以看做是鱼的速度,鱼的速度大小、方向不断改变

heading = heading + (vector_to_mouse * 0.1)

position += heading * time_passed_seconds

pygame.display.update()

十一、用户输入

键盘输入

在之前的例子中使用过键盘输入,使用pygame.event.get()获取所有事件,当event.type==KEYDOWN时,再判断event.key的种类。也可以使用pygame.key.get_pressed()来获取所有按下的键值,它会返回一个元组,这个元祖的索引就是键值,对应的值为True就是按下。

但是,如果要处理文本输入,这个函数不是正确的方法。因为我们不知道按键被按下的顺序。

key模块下还有如下的函数:

key.get_focused —— 返回当前的pygame窗口是否激活

key.get_mods —— 按下的组合键(Alt, Ctrl, Shift)

if pygame.key.get_mods() & KMOD_SHIFT:

1

key.set_mods —— 你也可以模拟按下组合键的效果(KMOD_ALT, KMOD_CTRL, KMOD_SHIFT)

key.set_repeat —— 参数为(delay,interval)。当有参数时,即repeat被激活时,被按住的键会产生多次KEYDOWN事件。第一次发送KEYDOWN事件后,经过delay时间(ms)发送第二次,然后每隔interval时间(ms)发送一次事件。如果没有参数,不产生重复按键事件。当pygame初始化之后,重复按键默认为disabled

key.name —— 接受键值返回键名

使用键盘控制方向

下面这个例子使用ASDW控制方向。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

from vector import Vec2d

background_image = '../image/sushiplate.jpg'

sprite_image = '../image/fugu.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).convert()

sprite = pygame.image.load(sprite_image)

clock = pygame.time.Clock()

sprite_pos = Vec2d(200, 150)

sprite_speed = 300

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

pressed_keys = pygame.key.get_pressed()

key_direction = Vec2d(0, 0)

if pressed_keys[K_LEFT]:

key_direction.x = -1

elif pressed_keys[K_RIGHT]:

key_direction.x = +1

if pressed_keys[K_UP]:

key_direction.y = -1

elif pressed_keys[K_DOWN]:

key_direction.y = +1

key_direction.normalized()

screen.blit(background, (0, 0))

screen.blit(sprite, sprite_pos)

time_passed = clock.tick(30)

time_passed_seconds = time_passed/1000

sprite_pos += key_direction * sprite_speed * time_passed_seconds

pygame.display.update()

接下来这个例子,使鱼做到全方位移动。先转向,再移动。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

from vector import Vec2d

from math import *

background_image = '../image/sushiplate.jpg'

sprite_image = '../image/fugu.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).convert()

sprite = pygame.image.load(sprite_image)

clock = pygame.time.Clock()

sprite_pos = Vec2d(200, 150)

sprite_speed = 300

sprite_rotation = 0

sprite_rotation_speed = 360

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

pressed_keys = pygame.key.get_pressed()

rotation_direction = 0

movement_direction = 0

# 更改角度

if pressed_keys[K_LEFT]:

rotation_direction = +1

elif pressed_keys[K_RIGHT]:

rotation_direction = -1

# 前进、后退

if pressed_keys[K_UP]:

movement_direction = +1.

if pressed_keys[K_DOWN]:

movement_direction = -1.

screen.blit(background, (0, 0))

# 将鱼转向

rotated_sprite = pygame.transform.rotate(sprite, sprite_rotation)

# 转向后,图片的长宽会变化,因为图片永远是矩形,为了放得下一个转向后的矩形,外接的矩形势必会比较大

w, h = rotated_sprite.get_size()

sprite_draw_pos = Vec2d(sprite_pos.x - w / 2, sprite_pos.y - h / 2)

screen.blit(rotated_sprite, sprite_draw_pos)

time_passed = clock.tick(30)

time_passed_seconds = time_passed/1000

# 图片的转向速度也通过时间来

控制

sprite_rotation += rotation_direction * sprite_rotation_speed * time_passed_seconds

# 获得前进(x方向和y方向)

heading_x = sin(sprite_rotation * pi / 180)

heading_y = cos(sprite_rotation * pi / 180)

# 转换为单位速度向量

heading = Vec2d(heading_x, heading_y)

# 转换为速度

heading *= movement_direction

sprite_pos += heading * sprite_speed * time_passed_seconds

pygame.display.update()

鼠标控制

我们可以从MOUSEMOTION和pygame.mouse.get_pos()获得鼠标坐标。我们可以使用这个坐标来控制方向,如使用鼠标的偏移量来控制视角。在接下来的这个例子中,使用鼠标左右移动来转动鱼。

#!/usr/bin/env python

# -*- coding:utf-8 -*-

import pygame

from pygame.locals import *

from sys import exit

from vector import Vec2d

from math import *

background_image = '../image/sushiplate.jpg'

sprite_image = '../image/fugu.png'

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image).convert()

sprite = pygame.image.load(sprite_image)

clock = pygame.time.Clock()

pygame.mouse.set_visible(False)

# 使所有的输入都锁定在这个程序中

pygame.event.set_grab(True)

sprite_pos = Vec2d(200, 150)

sprite_speed = 300

sprite_rotation = 0

sprite_rotation_speed = 360

while True:

for event in pygame.event.get():

if event.type == QUIT:

exit()

# 按Esc,退出游戏

if event.type == KEYDOWN:

if event.key == K_ESCAPE:

exit()

pressed_keys = pygame.key.get_pressed()

pressed_mouse = pygame.mouse.get_pressed()

rotation_direction = 0

movement_direction = 0

# 得到鼠标的偏移量(x, y)

rotation_direction = pygame.mouse.get_rel()[0]/5

if pressed_keys[K_LEFT]:

rotation_direction = -1

elif pressed_keys[K_RIGHT]:

rotation_direction = +1

if pressed_keys[K_UP] or pressed_mouse[0]:

movement_direction = -1

if pressed_keys[K_DOWN] or pressed_mouse[2]:

movement_direction = +1

screen.blit(background, (0, 0))

rotated_sprite = pygame.transform.rotate(sprite, sprite_rotation)

w, h = rotated_sprite.get_size()

sprite_draw_pos = Vec2d(sprite_pos.x - w / 2, sprite_pos.y - h / 2)

screen.blit(rotated_sprite, sprite_draw_pos)

time_passed = clock.tick(30)

time_passed_seconds = time_passed/1000

sprite_rotation += rotation_direction * sprite_rotation_speed * time_passed_seconds

heading_x = sin(sprite_rotation * pi / 180)

heading_y = cos(sprite_rotation * pi / 180)

heading = Vec2d(heading_x, heading_y)

heading *= movement_direction

sprite_pos += heading * sprite_speed * time_passed_seconds

pygame.display.update()

pygame.mouse的函数:

pygame.mouse.get_pressed —— 返回按键按下情况,返回的是一元组,分别为(左键, 中键, 右键),如按下则为True

pygame.mouse.get_rel —— 返回相对偏移量,(x方向, y方向)的一元组

pygame.mouse.get_pos —— 返回当前鼠标位置(x, y)

pygame.mouse.set_pos —— 设置鼠标位置

pygame.mouse.set_visible —— 设置鼠标光标是否可见

pygame.mouse.get_focused —— 检查窗口是否接受鼠标事件,即鼠标是否focus到窗口

pygame.mouse.set_cursor —— 设置鼠标光标式样

pyGame.mouse.get_cursor ——得到鼠标图片

版本信息

1.0 20180209

--------------------- 本文来自 FengF2017 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/fengf2017/article/details/79300801?utm_source=copy

python blit_pygame入门相关推荐

  1. python数据分析要学什么_python数据分析学什么?python数据分析入门

    有很多没有基础的新手想学习python数据分析,却在纠结python数据分析难不难学?下面万古网校小编给大家整理了资料,为各位分享! 1.python难不难? Python可以说是目前比较主流而且易学 ...

  2. Python培训入门基础知识学什么?

    Python培训基础知识主要是针对一些零基础的同学安排的,虽说Python是相对比较简单的一门编程语言,但是没有基础的同学还是要进行系统的学习,那么Python培训入门基础知识学什么呢?来看看下面小编 ...

  3. Python从入门到精通 - 入门篇 (下)

    上一讲回顾:Python从入门到精通 - 入门篇 (上) 接着上篇继续后面两个章节,函数和解析式. 4 函数 Python 里函数太重要了 (说的好像在别的语言中函数不重要似的).函数的通用好处就不用 ...

  4. python爬虫入门教程--优雅的HTTP库requests(二)

    requests 实现了 HTTP 协议中绝大部分功能,它提供的功能包括 Keep-Alive.连接池.Cookie持久化.内容自动解压.HTTP代理.SSL认证等很多特性,下面这篇文章主要给大家介绍 ...

  5. python爬虫入门教程--快速理解HTTP协议(一)

    http协议是互联网里面最重要,最基础的协议之一,我们的爬虫需要经常和http协议打交道.下面这篇文章主要给大家介绍了关于python爬虫入门之快速理解HTTP协议的相关资料,文中介绍的非常详细,需要 ...

  6. 【python教程入门学习】Python实现自动玩贪吃蛇程序

    这篇文章主要介绍了通过Python实现的简易的自动玩贪吃蛇游戏的小程序,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学一学 实现效果 先看看效果 这比我手动的快多了,而且是单机的,自动玩没惹 ...

  7. 【python教程入门学习】Python零基础入门爬虫项目

    Python入门爬虫项目 这是我的第一个python项目,分享给大家. 需求 我们目前正在开发一款产品其功能大致是:用户收到短信如:购买了电影票或者火车票机票之类的事件.然后app读取短信,解析短信, ...

  8. Python 从入门到精通:一个月就够了?真的能行嘛?

    毫无疑问,Python 是当下最火的编程语言之一.对于许多未曾涉足计算机编程的领域「小白」来说,深入地掌握 Python 看似是一件十分困难的事.其实,只要掌握了科学的学习方法并制定了合理的学习计划, ...

  9. 哈佛大学(2020)《CS50 Python人工智能入门》课程资料下载

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! [导读]本课程探讨现代人工智能基础上的概念和算法,深入探讨游戏引擎.手写识别和机器 ...

最新文章

  1. 基因测序3——三、四代测序技术来势汹汹,国产化仍在布局二代测序?
  2. python元素平方和,模长
  3. 如何在一个程序集中序列化在另一个中反序列化
  4. 使用AngularJS 进行Hybrid App 开发已经有一年多时间了,这里做一个总结
  5. 【习题 5-14 UVA - 1598】Exchange
  6. 【计算机类】大学生计算机专业电子书汇总
  7. 阿里云HiShop海商创新合作—线上商城这样做更合适
  8. 【C/C++】值传递和址传递区别解析
  9. C语言中多维数组的内存分配和释放(malloc与free)(转)
  10. 会员积分消费系统 php,会员消费管理系统充值营销系统会员积分消费系统.net源码...
  11. mysql主从配置详解_MySQL主从配置详解
  12. 不小心格式化了硬盘怎么恢复数据?
  13. 形而上者谓之道,形而下者谓之器(java 多态、泛型)
  14. 背篼酥课堂-GPS定位(一) nodemcu 解析gps
  15. h5常见的几种表现形式
  16. 解决导出Excel表的时候,中文文件名出现乱码的问题
  17. 空指针异常的原因分析
  18. 动物大全和动物识别系统毕业设计,动物大全和动物AI识别系统设计与实现,动物识别系统论文毕设作品参考
  19. 数据结构-排序算法总结与感悟
  20. 合成大西瓜小游戏微信小程序源码

热门文章

  1. 大牛程序员是如何入行的?(附带Web开发者入行指南)
  2. 10G ORACLE RAC 搭建实战之LINUX LVM划分
  3. base-kernel-partion
  4. Jetpack 叒一新成员 DragAndDrop 框架:大大简化拖放手势开发
  5. centos配置nginx
  6. gcc编译参数-fPIC的一些问题
  7. JPEG有损压缩过程介绍
  8. 揭开RTMP播放流程的神秘面纱
  9. 三种前端实现VR全景看房的方案!说不定哪天就用得上!(收藏)
  10. bootstrap validator简单非空校验(data-bv-notempty)