python入门07 事件 pygame

目录

 

事件

一、概念

①、事件循环

②、事件队列

③、事件处理器

二、键盘事件

① 、先左右移动

②、添加按键事件——上下移动

③、重复按键

④、事件名和按键名

三、鼠标事件

①、让沙滩球随着鼠标位置移动

②、在鼠标按钮保持按下时才让鼠标控制起作用

四、定时器事件


事件

一、概念

 大多数程序自始至终沿着一条可以预测的路径运行,可能中间穿插着循环和判断,还存在一种特殊程序——事件驱动程序(event-driven program),事件驱动程序基本“原地不动”,什么都不做,等待事件发生,一旦有事件发生,就会做出反应,完成该事件所涉及的一些程序。有点类似单片机的中断

如:Windows 操作系统(或者其他 GUI)就是一个很好的例子。打开 Windows 计算机时,启动后它只是“原地不动”,不会启动任何程序,也不会看到鼠标光标在屏幕上移动。不过,如果开始移动或点击鼠标,就会有情况发生。鼠标光标会在屏幕上移动,“开始”菜单会弹出,或者会做其他事情。

①、事件循环

为了让一个事件驱动程序“看到”有事件发生,必须“寻找”这些事件。程序必须不断地扫描计算机内存中用来指示事件发生的部分。

running = True
while running:       
    for event in pygame.event.get():
        #添加事件
        if event.type == pygame.QUIT: 
            running = False
           
pygame.quit()

②、事件队列

只要移动或点击了鼠标或者按下了按键,就会发生事件。这些事件将会保存在事件队列 

事件队列:事件循环会一直不断搜索内存某个部分,内存中储存事件部分;发生的所有事件的列表,这些事件按它们发生的顺序排列

python入门07 事件 pygame_第1张图片

③、事件处理器

程序需要找到用户什么时候按下按键或其他动作,以及知道怎么应对这些事件,处理这些事件。

程序中处理某个事件部分 ———— 事件处理器

二、键盘事件

在 Pygame 中,按下键盘上的某个键值这个事件是 KEYDOWN。

以小球为例:

① 、先左右移动

  • 使用动画精灵;
  • 使用  clock.tick() 而不是 time.delay()。
import sys, pygame
from random import *

pygame.init()
#设置窗口大小和颜色    
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background.fill([255, 255, 255])
clock = pygame.time.Clock()

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        if self.rect.left <= screen.get_rect().left or \
           self.rect.right >= screen.get_rect().right:
            self.speed[0] = -self.speed[0]

        self.rect = self.rect.move(self.speed)


my_ball = MyBallClass("beach_ball.png", [20, 20], [10, 0])


running = True
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    clock.tick(30)
    screen.blit(background, (0, 0))
    my_ball.move()
    screen.blit(my_ball.image,my_ball.rect)
    pygame.display.flip()
    
pygame.quit()

 

在新位置上重画球之前要从原位置“擦除”动画精灵有两种方法:

  1. 在每个动画精灵的原位置上涂上背景颜色
  2. 直接重绘每一帧的整个背景

         方式一:screen.fill()

        方式二:screen = pygame.display.set_mode([640,480]) 
                       background = pygame.Surface(screen.get_size()) 

                       background.fill([255, 255, 255])  #绘制白色

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

②、添加按键事件——上下移动

pygame.event.get() :从事件队列得到所有事件的一个列表

python入门07 事件 pygame_第2张图片

 

import sys, pygame
from random import *

pygame.init()
#设置窗口大小和颜色    
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background.fill([255, 255, 255])
clock = pygame.time.Clock()

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        if self.rect.left <= screen.get_rect().left or \
           self.rect.right >= screen.get_rect().right:
            self.speed[0] = -self.speed[0]

        self.rect = self.rect.move(self.speed)

my_ball = MyBallClass("beach_ball.png", [20, 20], [10, 0])

running = True
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            #do something
            if event.key == pygame.K_UP:
                my_ball.rect.top = my_ball.rect.top - 10
            elif event.key == pygame.K_DOWN:
                my_ball.rect.top = my_ball.rect.top + 10 

    clock.tick(30)
    screen.blit(background, (0, 0))
    my_ball.move()
    screen.blit(my_ball.image,my_ball.rect)
    pygame.display.flip()
    
pygame.quit()

③、重复按键

在长按按键时,球只会向按的方向移动一步,因为在设置的按键事件处理程序中只执行了处理一次。

 在Pygame 中有一个设置,可以在按键一直按下时生成多个 KEYDOWN 事件。这称为按键重复(key repeat)

  • 需要设置在开始重复前等待多少时间
  • 还需指出多长时间重复一次
delay = 100              #在开始重复前等待多长时间
interval = 50            #定义按键要以多快速度重复,及各个按键事件之间要间隔多久
pygame.key.set_repeat(delay, interval)
import sys, pygame
from random import *

pygame.init()
#设置窗口大小和颜色    
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background.fill([255, 255, 255])
clock = pygame.time.Clock()

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        if self.rect.left <= screen.get_rect().left or \
           self.rect.right >= screen.get_rect().right:
            self.speed[0] = -self.speed[0]

        self.rect = self.rect.move(self.speed)


my_ball = MyBallClass("beach_ball.png", [20, 20], [10, 0])

delay = 100              #在开始重复前等待多长时间
interval = 50            #定义按键要以多快速度重复,及各个按键事件之间要间隔多久
pygame.key.set_repeat(delay, interval)

running = True
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            #do something
            if event.key == pygame.K_UP:
                my_ball.rect.top = my_ball.rect.top - 10
            elif event.key == pygame.K_DOWN:
                my_ball.rect.top = my_ball.rect.top + 10 

    clock.tick(30)
    screen.blit(background, (0, 0))
    my_ball.move()
    screen.blit(my_ball.image,my_ball.rect)
    pygame.display.flip()
    
pygame.quit()

效果可以看见长按,小球还可以继续移动。

④、事件名和按键名

pygame有相当多的事件。在官网文档中提供所有事件的列表——http://www.pygame.org/docs/ref/event.html

 

三、鼠标事件

最常用的 3 类鼠标事件如下:

  • MOUSEBUTTONUP 
  • MOUSEBUTTONDOWN 
  • MOUSEMOTION

例子用鼠标控制球只要鼠标在 Pygame 窗口中移动,就让沙滩球随着鼠标位置移动。

①、让沙滩球随着鼠标位置移动

使用球的 rect.center 属性。让球的中心跟着鼠标移动,只要鼠标移动,球就跟着移动。若没有鼠标事件(可能因为鼠标没有移动,或者鼠标光标落在 Pygame 窗口之外),球就会继续在左右两边反弹。

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEMOTION:
            #do something
            my_ball.rect.center = event.pos      #鼠标的位置(x和y坐标)
import sys, pygame
from random import *

pygame.init()
#设置窗口大小和颜色    
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background.fill([255, 255, 255])
clock = pygame.time.Clock()

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        if self.rect.left <= screen.get_rect().left or \
           self.rect.right >= screen.get_rect().right:
            self.speed[0] = -self.speed[0]

        self.rect = self.rect.move(self.speed)

my_ball = MyBallClass("beach_ball.png", [20, 20], [10, 0])

running = True
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEMOTION:
            #do something
            my_ball.rect.center = event.pos

    clock.tick(30)
    screen.blit(background, (0, 0))
    my_ball.move()
    screen.blit(my_ball.image,my_ball.rect)
    pygame.display.flip()
    
pygame.quit()

②、在鼠标按钮保持按下时才让鼠标控制起作用

鼠标按钮保持按下时移动鼠标称为拖动(dragging),但在pygame没有直接可以鼠标拖动的事件,需要使用现有的事件来得到需要的效果。

操作:拖动意味着鼠标移动时鼠标按钮一直保持按下。可以利用 MOUSEBUTTONDOWN 事件得到鼠标按钮何时按下,另外利用 MOUSEBUTTONUP事件可以得到按钮何时松开(还原,不再按下),这样只需要跟踪按钮状态。

held_down = False   #跟踪按钮状态
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            #do something
            held_down = True
        elif event.type == pygame.MOUSEBUTTONUP:
            held_down = False
        elif event.type == pygame.MOUSEMOTION:
            if held_down:
                my_ball.rect.center = event.pos

效果:在按下并拖动时球才会移动

import sys, pygame
from random import *

pygame.init()
#设置窗口大小和颜色    
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background.fill([255, 255, 255])
clock = pygame.time.Clock()

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        if self.rect.left <= screen.get_rect().left or \
           self.rect.right >= screen.get_rect().right:
            self.speed[0] = -self.speed[0]

        self.rect = self.rect.move(self.speed)

my_ball = MyBallClass("beach_ball.png", [20, 20], [10, 0])

running = True
held_down = False   #跟踪按钮状态
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            #do something
            held_down = True
        elif event.type == pygame.MOUSEBUTTONUP:
            held_down = False
        elif event.type == pygame.MOUSEMOTION:
            if held_down:
                my_ball.rect.center = event.pos

    clock.tick(30)
    screen.blit(background, (0, 0))
    my_ball.move()
    screen.blit(my_ball.image,my_ball.rect)
    pygame.display.flip()
    
pygame.quit()

四、定时器事件

定时器事件(timer event)。定时器会按固定的间隔生成事件,如同闹钟一样:设好闹钟,并把闹铃打开,每天它都会在固定的时刻响起来。

将pygame定时器设置为任意间隔,如果定时器到时间,能执行设置的用户事件(user event)

pygame 0 - NUMEVENTS 的定义事件,其中使用USERWVENT -  NUMEVENTS 为用户自定义事件。下面代码可以知道共65535个事件, 32847 - 65535 为自定义事件, 0- 32847为pygame事件。

>>> import pygame
>>> pygame.USEREVENT
32847
>>> pygame.NUMEVENTS
65535

 Pygame 中设置定时器:

pygame.time.set_timer(EVENT_NUMBER, interval) 
#EVENT_NUMBER 是事件编号,interval 是定时器多长时间(单位是毫秒)到期并生成一个事件。


小球设置定时器事件:
pygame.time.set_timer(pygame.USEREVENT, 1000)
后面自定义事件在pygame.USEREVENT + 1 

效果:让小球左右移动过程中,经过一定事件上移或下移,且左右两边反弹还会在上下边反弹。

import sys, pygame
from random import *

pygame.init()
#设置窗口大小和颜色    
size = width, height = 640, 480
screen = pygame.display.set_mode(size)
background = pygame.Surface(screen.get_size())
background.fill([255, 255, 255])
clock = pygame.time.Clock()

class MyBallClass(pygame.sprite.Sprite):
    def __init__(self, image_file, location, speed):
        pygame.sprite.Sprite.__init__(self)        #初始化动画精灵
        self.image = pygame.image.load(image_file) #加载图片
        self.rect = self.image.get_rect()          #得到定义图像边界矩形
        self.rect.left, self.rect.top = location   #设置球的初始位置
        self.speed = speed                         #创建一个速度

    def move(self):
        if self.rect.left <= screen.get_rect().left or \
           self.rect.right >= screen.get_rect().right:
            self.speed[0] = -self.speed[0]

        self.rect = self.rect.move(self.speed)

my_ball = MyBallClass("beach_ball.png", [20, 20], [10, 0])

pygame.time.set_timer(pygame.USEREVENT, 1000)
direction = 1
running = True
held_down = False   #跟踪按钮状态
 
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.USEREVENT:
            my_ball.rect.centery = my_ball.rect.centery + (30 * direction)
            if my_ball.rect.top <=0 or \
               my_ball.rect.bottom >= screen.get_rect().bottom:
                direction = -direction
          

    clock.tick(30)
    screen.blit(background, (0, 0))
    my_ball.move()
    screen.blit(my_ball.image,my_ball.rect)
    pygame.display.flip()
    
pygame.quit()

 

参考:

父与子的编程之旅:与小卡特一起学Python

你可能感兴趣的:(python)