提问人:K. Russell Smith 提问时间:9/2/2023 最后编辑:Rabbid76K. Russell Smith 更新时间:9/2/2023 访问量:26
如果没有用户输入,Pygame 事件循环会阻止游戏
Pygame event loop blocks game if there's no user input
问:
我摸索了一个我正在用 Python 编写的贪吃蛇游戏,它出现的主循环有问题
对于任何草率,提前道歉,我仍在原型设计中:
import sys
import pygame
from pygame.locals import *
from libs.Touch import Touch
def sortPairs(*pairs):
result = {}
for pair in pairs:
result[pair[0]] = pair[1]
result[pair[1]] = pair[0]
return result
DIR = {
'LEFT': (-1, +0),
'RIGHT': (+1, +0),
'UP': (+0, -1),
'DOWN': (+0, +1)
}
DIR['INVERSE'] = sortPairs(
(DIR['LEFT'], DIR['RIGHT']),
(DIR['UP'], DIR['DOWN']))
class Snake:
def __init__(self,x, y):
self.dir = DIR['RIGHT']
self.nodes = [[x, y]]
def move(self):
for i in range(len(self.nodes) - 1, 0, -1):
self.nodes[i][0] = self.nodes[i - 1][0]
self.nodes[i][1] = self.nodes[i - 1][1]
self.nodes[0][0] += self.dir[0]
self.nodes[0][1] += self.dir[1]
def turn(self, turn):
dir = DIR[turn]
if len(self.nodes) == 1 or dir != DIR['INVERSE'][turn]:
self.dir = dir
def grow(self):
self.nodes.appendLeft([
self.nodes[0][0] + self.dir[0],
self.nodes[0][1] + self.dir[1]])
def draw(self, surface,x, y, node_size):
rect = pygame.Rect(
0, 0, node_size, node_size)
for node in self.nodes:
rect.left = x + node[0] * node_size
rect.top = y + node[1] * node_size
rect.right = rect.left + node_size
rect.bottom = rect.top + node_size
pygame.draw.rect(
surface,
pygame.Color("#FF0000"),
rect)
class Game:
def __init__(self, size, tick):
self.size = size
self.tick = tick
self.snake = Snake(0, 0)
def draw(self, surface):
surface.fill(pygame.Color('#161616'))
cell_size = min(
surface.get_width(),
surface.get_height()) / self.size
bounds_stroke = int(cell_size / 10)
bounds = pygame.Rect(
surface.get_width() / 2,
surface.get_height() / 2,
cell_size * self.size - bounds_stroke,
cell_size * self.size - bounds_stroke)
bounds.center = (bounds.x, bounds.y)
self.snake.draw(
surface,
int(bounds.left),
int(bounds.top),
int(cell_size))
pygame.draw.rect(
surface,
pygame.Color('#6f91b3'),
bounds,
bounds_stroke)
def update(self):
self.snake.move()
def handle_event(self, event):
if event.type == MOUSEBUTTONDOWN:
pygame.mouse.get_rel()
if event.type == MOUSEBUTTONUP:
swipe = Touch.reg_swipe(*pygame.mouse.get_rel())
if swipe != -1:
self.snake.turn(swipe)
if event.type == QUIT:
pygame.quit()
def main():
game = Game(30, 100)
pygame.init()
# Resolution is ignored on Android
surface = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
delta = 0
while True:
for ev in pygame.event.get():
game.handle_event(ev)
delta += clock.tick(60)
if delta >= game.tick:
game.update()
delta = 0
game.draw(surface)
pygame.display.flip()
if __name__ == '__main__':
main()
./libs/Touch.py:
class Touch:
max_touch_dist = 15
min_swipe_dist = 50
@staticmethod
def reg_swipe(rel_x, rel_y):
min = Touch.min_swipe_dist
if abs(rel_y) < min:
if rel_x <= -min:
return 'LEFT'
elif rel_x >= min:
return 'RIGHT'
if rel_y <= -min:
return 'UP'
elif rel_y >= min:
return 'DOWN'
return -1
我在手机上使用 Pydroid,但在在线解释器上测试它得到了相同的结果:游戏运行 2 次迭代,然后冻结,然后仅在我触摸屏幕(或触发我想象的事件)时运行),我已经将我的代码(尤其是事件循环)与 Pygame 示例进行了比较,但一切看起来都很好,那么这是怎么回事?
答:
3赞
Rabbid76
9/2/2023
#1
您必须在应用程序循环中运行游戏逻辑并绘制场景,但不能在事件循环中绘制场景。仅当事件发生时才执行事件循环,但应用程序循环每帧执行一次,帧数由 控制。clock.tick(60)
def main():
# [...]
while True:
for ev in pygame.event.get():
game.handle_event(ev)
delta += clock.tick(60)
if delta >= game.tick:
game.update()
delta = 0
game.draw(surface)
pygame.display.flip()
评论
0赞
K. Russell Smith
9/2/2023
哎呀,我没有注意到我的缩进......多么尴尬。谢谢
评论