[英]Python + PyGame - handling simultaneous mouse and keyboard events
我完全願意承認我的硬件是這里問題的原因,但老實說我不這么認為,因為我確實看到計算機使用其他軟件/游戲/等同時處理兩種輸入,所以我猜這里的錯誤是我對 PyGame 事件處理程序的處理方法。
我隨便弄亂了 Python 和 PyGame,並且只是試圖一次積累我的知識,並通過在我學習的過程中構建一個“游戲”來表達這些知識。 這在很大程度上是一項正在進行的工作,沒有實現碰撞檢測或記分之類的任何東西,我認為可以稍后實現。
這里的相關難題是游戲將執行 MOUSEMOTION 事件和 KEYDOWN 事件,它似乎不想同時處理它們。 “玩家”object在移動中不能射擊,在射擊中不能移動。 由於大多數游戲玩家都喜歡邊射擊邊移動的奢侈,我認為這是一個障礙。
import pygame, random, sys
from pygame.locals import *
pygame.init()
width = 640
height = 480
DISPLAYSURF = pygame.display.set_mode((width, height))
pygame.display.set_caption('It moves!')
pygame.mouse.set_visible(0)
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.width = 50
self.height = 25
self.playerRect = None
def update(self, event):
if event.type == MOUSEMOTION:
self.x, self.y = event.pos
#get a new playerRect and draw it
self.playerRect = pygame.Rect(self.x, self.y, self.width, self.height)
pygame.draw.ellipse(DISPLAYSURF, RED, (self.playerRect), 3)
def shotcheck(self, event):
if event.type == KEYDOWN:
if event.key == K_KP8:
return (True, 'up')
elif event.key == K_KP2:
return (True, 'down')
elif event.key == K_KP4:
return (True, 'left')
elif event.key == K_KP6:
return (True, 'right')
elif event.key == K_KP7:
return (True, 'upleft')
elif event.key == K_KP1:
return (True, 'downleft')
elif event.key == K_KP9:
return (True, 'upright')
elif event.key == K_KP3:
return (True, 'downright')
else:
return (0, 0)
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
#self.body = pygame.rect.Rect(self.x, self.y, 15, 15)
self.speed = 5
self.xmove = 0
self.ymove = 0
def update(self, event):
self.x += self.speed
if self.x > 350:
self.speed *= -1
elif self.x < 25:
self.speed *= -1
pygame.draw.rect(DISPLAYSURF, BLUE, (self.x, self.y, 15, 15), 4)
#pass it a directional value when fired based on the key
#may have to divide speed / 2 if moving diagonally
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, direction):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.direction = direction
self.width = 4
self.height = 4
self.bulletRect = None
self.speed = 8
def update(self, event):
if self.direction == 'up':
self.y -= self.speed
elif self.direction == 'down':
self.y += self.speed
elif self.direction == 'left':
self.x -= self.speed
elif self.direction == 'right':
self.x += self.speed
elif self.direction == 'upleft':
self.x -= (self.speed/2)
self.y -= (self.speed/2)
elif self.direction == 'downleft':
self.x -= (self.speed/2)
self.y += (self.speed/2)
elif self.direction == 'upright':
self.x += (self.speed/2)
self.y -= (self.speed/2)
elif self.direction == 'downright':
self.x += (self.speed/2)
self.y += (self.speed/2)
self.bulletRect = pygame.Rect(self.x, self.y, 4, 4)
pygame.draw.ellipse(DISPLAYSURF, GREEN, (self.bulletRect), 2)
FPS = 30
fpsClock = pygame.time.Clock()
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
ship = Player(width / 2, height / 2)
bads = Enemy(width / 2, height / 2)
queue = pygame.sprite.Group()
queue.add(ship)
queue.add(bads)
while True:
DISPLAYSURF.fill(BLACK)
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
#passes 'event' to everything in the queue and calls
#their obj.update(). in this way the gameloop
#is a bit more readable
for thing in queue:
thing.update(event)
try: #i'm not married to this bit of code :/
checkForShot, shotDirection = ship.shotcheck(event)
if checkForShot:
shotx, shoty = ship.playerRect.center
shot = Bullet(shotx, shoty, shotDirection)
queue.add(shot)
except TypeError:
pass
pygame.display.flip()
fpsClock.tick(FPS)
我知道這基本上會產生一個真正沒有靈感的 Robotron 克隆,但正如我所說,這是我的一個蹣跚學步的項目,我在運行在線教程時將其放在一起。 是的,現在有一個不必要的“隨機導入”,以后會很重要。
我猜有幾個問題; 對於初學者來說,我不喜歡處理子彈創建的方式(在我看來,玩家 object 應該將它們添加到游戲隊列本身而不是返回 True/False 元組,但這似乎有點不直觀讓玩家 object 直接提到隊列。用 try/except 處理它感覺很懶惰,但也許我很挑剔)。 然而,我也感覺到這個問題等同於弄清楚如何處理讓事件處理程序正確地進行 thing.update() 以同時移動 (MOUSEMOTION) 和射擊 (KEYDOWN)。
而且我也在猜測,為了讓它表現得更“像人們期望的那樣”,我需要告訴它也處理 KEYUP 事件。 但是,我仍然對為什么事件處理程序似乎選擇一個 event.type 而忽略另一個感到困惑(根據我的經驗,無論哪個先出現)。
看一下這個!
import pygame, random, sys
from pygame.locals import *
pygame.init()
width = 640
height = 480
DISPLAYSURF = pygame.display.set_mode((width, height))
pygame.display.set_caption('It moves!')
pygame.mouse.set_visible(0)
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.width = 50
self.height = 25
self.playerRect = None
def update(self, event):
if event.type == MOUSEMOTION:
self.x, self.y = event.pos
#get a new playerRect and draw it
self.playerRect = pygame.Rect(self.x, self.y, self.width, self.height)
pygame.draw.ellipse(DISPLAYSURF, RED, (self.playerRect), 3)
def shotcheck(self, event):
if event.type == KEYDOWN:
if event.key == K_KP8:
return (True, 'up')
elif event.key == K_KP2:
return (True, 'down')
elif event.key == K_KP4:
return (True, 'left')
elif event.key == K_KP6:
return (True, 'right')
elif event.key == K_KP7:
return (True, 'upleft')
elif event.key == K_KP1:
return (True, 'downleft')
elif event.key == K_KP9:
return (True, 'upright')
elif event.key == K_KP3:
return (True, 'downright')
else:
return (0, 0)
class Enemy(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
#self.body = pygame.rect.Rect(self.x, self.y, 15, 15)
self.speed = 5
self.xmove = 0
self.ymove = 0
def update(self, event):
self.x += self.speed
if self.x > 350:
self.speed *= -1
elif self.x < 25:
self.speed *= -1
pygame.draw.rect(DISPLAYSURF, BLUE, (self.x, self.y, 15, 15), 4)
#pass it a directional value when fired based on the key
#may have to divide speed / 2 if moving diagonally
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, direction):
pygame.sprite.Sprite.__init__(self)
self.x = x
self.y = y
self.direction = direction
self.width = 4
self.height = 4
self.bulletRect = None
self.speed = 8
def update(self, event):
if self.direction == 'up':
self.y -= self.speed
elif self.direction == 'down':
self.y += self.speed
elif self.direction == 'left':
self.x -= self.speed
elif self.direction == 'right':
self.x += self.speed
elif self.direction == 'upleft':
self.x -= (self.speed/2)
self.y -= (self.speed/2)
elif self.direction == 'downleft':
self.x -= (self.speed/2)
self.y += (self.speed/2)
elif self.direction == 'upright':
self.x += (self.speed/2)
self.y -= (self.speed/2)
elif self.direction == 'downright':
self.x += (self.speed/2)
self.y += (self.speed/2)
self.bulletRect = pygame.Rect(self.x, self.y, 4, 4)
pygame.draw.ellipse(DISPLAYSURF, GREEN, (self.bulletRect), 2)
FPS = 30
fpsClock = pygame.time.Clock()
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
ship = Player(width / 2, height / 2)
bads = Enemy(width / 2, height / 2)
queue = pygame.sprite.Group()
queue.add(ship)
queue.add(bads)
while True:
DISPLAYSURF.fill(BLACK)
for event in pygame.event.get():
if event.type == QUIT:
sys.exit()
#passes 'event' to everything in the queue and calls
#their obj.update(). in this way the gameloop
#is a bit more readable
for thing in queue:
thing.update(event)
try: #i'm not married to this bit of code :/
checkForShot, shotDirection = ship.shotcheck(event)
if checkForShot:
shotx, shoty = ship.playerRect.center
shot = Bullet(shotx, shoty, shotDirection)
queue.add(shot)
except TypeError:
pass
pygame.display.flip()
fpsClock.tick(FPS)
問題出在處理拉取(從 pygame 中檢索它們)的代碼中。 您制作了獲取每個事件的循環。 但是后來你“更新”了你的游戲 state 不是每一個,而是最后一個。 我認為糾正縮進就足夠了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.