I've fumbled a snake game I'm writing in Python, it has problems with with the main loop it appears
Apologies in advance for any sloppiness, I'm still prototyping:
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
I'm using Pydroid on my phone, but testing it on an online interpreter got the same result: the game runs 2 iterations, then freezes, and then only runs if I touch the screen (or trigger an event I imagine), I've compared my code (especially the event loop) to Pygame samples but everything appears fine, so what's going on?
You must run the game logic and draw the scene in the application loop, but not in the event loop. The event loop is executed only when an event occurs, but the application loop is executed every frame and the number of frames is controlled by 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()