I'm coding a simple snake game in pygame. The thing is, if the user presses UP and LEFT (just an example) too fast, the snake will collide with itself (it will not have the time to go up before trying to go left, thus colliding with its own body and dying).
I figured it could be solved if the user had to wait a quarter of a second or so before being able to move the snake again, so the snake would always have time to go up one step before changing directions. But how do I do it?
I've already tried simply reduncing the framerate of my game, but the problem remains.
import pygame
from pygame.locals import *
from sys import exit
from random import randint
pygame.init()
largura = 640
altura = 480
x_cobra = int(largura/2 - 20)
y_cobra = int(altura/2 - 25)
x_maca = randint(40,600)
y_maca = randint(50, 430)
pontos = 0
fonte = pygame.font.SysFont('arial', 40, True, True)
tela = pygame.display.set_mode((largura, altura))
pygame.display.set_caption('Jogo da cobrinha')
relogio = pygame.time.Clock()
lista_cobra = []
comprimento_inicial = 5
velocidade = 20
x_controle = velocidade
y_controle = 0
morreu = False
def aumenta_cobra(lista_cobra):
for XeY in lista_cobra:
pygame.draw.rect(tela, (0,255,0), (XeY[0],XeY[1], 20,20))
def reiniciar_jogo():
global pontos, comprimento_inicial, x_cobra, y_cobra, lista_cobra, lista_cabeca, x_maca, y_maca, morreu
pontos = 0
comprimento_inicial = 5
x_cobra = int(altuara/2)
y_cobra = int(largura/2)
lista_cobra = []
lista_cabeca = []
x_maca = randint(40,600)
y_maca = randint(50,430)
morreu = False
while True:
relogio.tick(15)
tela.fill((255,255,255))
mensagem = f'Pontos: {pontos}'
texto_formatado = fonte.render(mensagem, True, (0,0,0))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == KEYDOWN:
if event.key == K_LEFT and x_controle != velocidade:
x_controle = -velocidade
y_controle = 0
if event.key == K_DOWN and y_controle != -velocidade:
x_controle = 0
y_controle = velocidade
if event.key == K_UP and y_controle != velocidade:
x_controle = 0
y_controle = -velocidade
if event.key == K_RIGHT and x_controle != -velocidade:
x_controle = velocidade
y_controle = 0
x_cobra = x_cobra x_controle
y_cobra = y_cobra y_controle
cobra = pygame.draw.rect(tela, (0,255,0), (x_cobra, y_cobra,20,20))
maca = pygame.draw.rect(tela, (255,0,0), (x_maca, y_maca,20,20))
if cobra.colliderect(maca):
x_maca = randint(40, 600)
y_maca = randint(50, 430)
pontos = 1
comprimento_inicial = 1
lista_cabeca = []
lista_cabeca.append(x_cobra)
lista_cabeca.append(y_cobra)
lista_cobra.append(lista_cabeca)
if lista_cobra.count(lista_cabeca) > 1:
morreu = True
while morreu:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == KEYDOWN:
if event.key == K_r:
reiniciar_jogo()
if len(lista_cobra) > comprimento_inicial:
del lista_cobra[0]
aumenta_cobra(lista_cobra)
tela.blit(texto_formatado, (400, 30))
pygame.display.update()
CodePudding user response:
Just ignore any new key press events until you have updated the model for the previous key press. You could use some kind of flag in your key press event handler that is set by the key press and reset by the logic that draws the snake. If the flag is true then do nothing.
CodePudding user response:
One way to solve this is to just only accept the first input on each movement frame. So instead of allowing the event loop to run for all inputs, it stops and returns the first valid input.
Something like this (see get_keys
function):
import pygame
from pygame.locals import *
from sys import exit
from random import randint
pygame.init()
largura = 640
altura = 480
x_cobra = int(largura/2 - 20)
y_cobra = int(altura/2 - 25)
x_maca = randint(40,600)
y_maca = randint(50, 430)
pontos = 0
fonte = pygame.font.SysFont('arial', 40, True, True)
tela = pygame.display.set_mode((largura, altura))
pygame.display.set_caption('Jogo da cobrinha')
relogio = pygame.time.Clock()
lista_cobra = []
comprimento_inicial = 5
velocidade = 20
x_controle = velocidade
y_controle = 0
morreu = False
def aumenta_cobra(lista_cobra):
for XeY in lista_cobra:
pygame.draw.rect(tela, (0,255,0), (XeY[0],XeY[1], 20,20))
def reiniciar_jogo():
global pontos, comprimento_inicial, x_cobra, y_cobra, lista_cobra, lista_cabeca, x_maca, y_maca, morreu
pontos = 0
comprimento_inicial = 5
x_cobra = int(altuara/2)
y_cobra = int(largura/2)
lista_cobra = []
lista_cabeca = []
x_maca = randint(40,600)
y_maca = randint(50,430)
morreu = False
def get_keys():
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == KEYDOWN:
if event.key == K_LEFT and x_controle != velocidade:
# x_controle = -velocidade
# y_controle = 0
return [-velocidade,0]
if event.key == K_DOWN and y_controle != -velocidade:
# x_controle = 0
# y_controle = velocidade
return [0, velocidade]
if event.key == K_UP and y_controle != velocidade:
# x_controle = 0
# y_controle = -velocidade
return [0, -velocidade]
if event.key == K_RIGHT and x_controle != -velocidade:
# x_controle = velocidade
# y_controle = 0
return [velocidade, 0]
return [x_controle, y_controle] # If no valid key presses found it continues moving in the same direction.
while True:
relogio.tick(15)
tela.fill((255,255,255))
mensagem = f'Pontos: {pontos}'
texto_formatado = fonte.render(mensagem, True, (0,0,0))
[x_controle, y_controle] = get_keys()
x_cobra = x_cobra x_controle
y_cobra = y_cobra y_controle
cobra = pygame.draw.rect(tela, (0,255,0), (x_cobra, y_cobra,20,20))
maca = pygame.draw.rect(tela, (255,0,0), (x_maca, y_maca,20,20))
if cobra.colliderect(maca):
x_maca = randint(40, 600)
y_maca = randint(50, 430)
pontos = 1
comprimento_inicial = 1
lista_cabeca = []
lista_cabeca.append(x_cobra)
lista_cabeca.append(y_cobra)
lista_cobra.append(lista_cabeca)
if lista_cobra.count(lista_cabeca) > 1:
morreu = True
while morreu:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == KEYDOWN:
if event.key == K_r:
reiniciar_jogo()
if len(lista_cobra) > comprimento_inicial:
del lista_cobra[0]
aumenta_cobra(lista_cobra)
tela.blit(texto_formatado, (400, 30))
pygame.display.update()