I'm doing a snake game and I got a bug I can't figure out how to solve, I want to make my snake teleport trough walls, when the snake colllides with a wall it teleports to another with the opposite speed and position, like the classic game, but with my code when the snake gets near the wall it duplicates to the opposite wall, but it was supposed to not even detect collision yet
important thing: in the grid the snake is on the side of the wall, like this
SSSS
WWWW
and not like this:
SSSS
NNNN
WWWW
when S represents the snake, W represents the wall and N represents nothing.
edit: whole code
import pygame, random, os, sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((1020, 585))
pygame.display.set_caption('2snakes!')
#files location
current_path = os.path.dirname(__file__)
data_path = os.path.join(current_path, 'data')
icon = pygame.image.load(os.path.join(data_path, 'icon.png'))
press_any = pygame.image.load(os.path.join(data_path, 'press_any.png'))
pygame.display.set_icon(icon)
#collission
def collision(c1,c2):
return (c1[0] == c2[0]) and (c1[1] == c2[1])
#game over
def gameOverBlue():
print("blue")
main()
def gameOverRed():
print("red")
main()
fps = 15
def main():
#variables
direction = 'RIGHT'
direction2 = 'RIGHT'
change_to = direction
change2_to = direction2
#snake
size = 15
s_posx = 60
s_posy = 60
snake = [(s_posx + size * 2, s_posy),(s_posx + size, s_posy),(s_posx, s_posy)]
s_skin = pygame.Surface((size, size))
s_skin.fill((82,128,208))
#snake2
size2 = 15
s2_posx = 390
s2_posy = 390
snake2 = [(s2_posx + size2 * 2, s2_posy),(s2_posx + size2, s2_posy),(s2_posx, s2_posy)]
s2_skin = pygame.Surface((size2, size2))
s2_skin.fill((208,128,82))
#apple
apple = pygame.Surface((size, size))
apple_pos = ((random.randint(0, 67)) * 15, (random.randint(0, 38)) * 15)
#endregion
while True:
pygame.time.Clock().tick(fps)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
#input
elif event.type == pygame.KEYDOWN:
#snake
if event.key == ord('w'):
change_to = 'UP'
if event.key == ord('s'):
change_to = 'DOWN'
if event.key == ord('a'):
change_to = 'LEFT'
if event.key == ord('d'):
change_to = 'RIGHT'
#snake2
if event.key == pygame.K_UP:
change2_to = 'UP'
if event.key == pygame.K_DOWN:
change2_to = 'DOWN'
if event.key == pygame.K_LEFT:
change2_to = 'LEFT'
if event.key == pygame.K_RIGHT:
change2_to = 'RIGHT'
#quit game
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.quit()
#smooth snake movement
#snake
if change_to == 'UP' and direction != 'DOWN':
direction = 'UP'
if change_to == 'DOWN' and direction != 'UP':
direction = 'DOWN'
if change_to == 'LEFT' and direction != 'RIGHT':
direction = 'LEFT'
if change_to == 'RIGHT' and direction != 'LEFT':
direction = 'RIGHT'
#snake2
if change2_to == 'UP' and direction2 != 'DOWN':
direction2 = 'UP'
if change2_to == 'DOWN' and direction2 != 'UP':
direction2 = 'DOWN'
if change2_to == 'LEFT' and direction2 != 'RIGHT':
direction2 = 'LEFT'
if change2_to == 'RIGHT' and direction2 != 'LEFT':
direction2 = 'RIGHT'
#movement
#snake
new_pos = None
if direction == 'DOWN':
new_pos = (snake[0][0], snake[0][1] + size)
if direction == 'UP':
new_pos = (snake[0][0], snake[0][1] - size)
if direction == 'LEFT':
new_pos = (snake[0][0] - size, snake[0][1])
if direction == 'RIGHT':
new_pos = (snake[0][0] + size, snake[0][1])
if new_pos:
snake = [new_pos] + snake
del snake[-1]
#snake2
new_pos2 = None
if direction2 == 'DOWN':
new_pos2 = (snake2[0][0], snake2[0][1] + size2)
if direction2 == 'UP':
new_pos2 = (snake2[0][0], snake2[0][1] - size2)
if direction2 == 'LEFT':
new_pos2 = (snake2[0][0] - size2, snake2[0][1])
if direction2 == 'RIGHT':
new_pos2 = (snake2[0][0] + size2, snake2[0][1])
if new_pos2:
snake2 = [new_pos2] + snake2
del snake2[-1]
#apple collision
#snake
if collision(snake[0], apple_pos):
snake.append((-20,-20))
size = 15
s_skin = pygame.Surface((size, size))
s_skin.fill((82,128,208))
apple_pos = ((random.randint(0, 32)) * 15, (random.randint(0, 19)) * 15)
#snake2
if collision(snake2[0], apple_pos):
snake2.append((-20,-20))
apple_pos = ((random.randint(0, 67)) * 15, (random.randint(0, 38)) * 15)
#wall collisison
#snake
_pos = None
if snake[0][0] == 15:
_pos = (990, snake[0][1])
elif snake[0][1] == 15:
_pos = (snake[0][0], 555)
elif snake[0][0] == 990:
_pos = (15, snake[0][1])
elif snake[0][1] == 555:
_pos = (snake[0][0], 15)
if _pos:
snake = [_pos] + snake
del snake[-1]
#snake2
_pos2 = None
if snake2[0][0] == 15:
_pos2 = (1005, snake2[0][1])
elif snake2[0][1] == 0:
_pos2 = (snake2[0][0], 570)
elif snake2[0][0] == 1005:
_pos2 = (0, snake2[0][1])
elif snake2[0][1] == 570:
_pos2 = (snake2[0][0], 0)
if _pos2:
snake2 = [_pos2] + snake2
del snake2[-1]
#self collisison
#snake
if snake[0] in snake[1:]:
print("self collision")
gameOverBlue()
#snake2
if snake2[0] in snake2[1:]:
print("self collision")
gameOverRed()
#snakes colliding with each other
if snake2[0] == snake[0]:
print("head to head collisions")
if snake[0] in snake2:
gameOverRed()
if snake2[0] in snake:
gameOverBlue()
#rendering
apple.fill((255,0,0))
screen.fill((10,10,10))
screen.blit(apple,apple_pos)
for pos in snake:
screen.blit(s_skin,pos)
for pos2 in snake2:
screen.blit(s2_skin,pos2)
pygame.display.update()
while True:
pygame.time.Clock().tick(fps)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
#input
elif event.type == pygame.KEYDOWN:
main()
screen.blit(press_any, (0,0))
pygame.display.update()
edit: the red dot is the food/apple
You want to implement a teleporter. Therefore, once the snake is over the edge of the window, you will have to teleport to the other side. The size of your window is 1020x585. The snake is out of the window if x == -15, y == -15, x == 1020 or y == 585 Hence you have to do the following teleportations:
_pos = None
if snake[0][0] == -15:
_pos = (1005, snake[0][1])
elif snake[0][1] == -15:
_pos = (snake[0][0], 570)
elif snake[0][0] == 1020:
_pos = (0, snake[0][1])
elif snake[0][1] == 585:
_pos = (snake[0][0], 0)
if _pos:
snake = [_pos] + snake
del snake[-1]
Another simplest solution is to use the %
(modulo) operator:
x1 = (x1 + x1_change) % dis_width
y1 = (y1 + y1_change) % dis_height
>>> width = 100
>>> 101 % width
1
>>> -1 % width
99
>>>
Minimal example: repl.it/@Rabbid76/PyGame-ContinuousMovement
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
rect = pygame.Rect(0, 0, 20, 20)
rect.center = window.get_rect().center
vel = 5
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
print(pygame.key.name(event.key))
keys = pygame.key.get_pressed()
dx = (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * vel
dy = (keys[pygame.K_DOWN] - keys[pygame.K_UP]) * vel
rect.centerx = (rect.centerx + dx) % window.get_width()
rect.centery = (rect.centery + dy) % window.get_height()
window.fill(0)
pygame.draw.rect(window, (255, 0, 0), rect)
pygame.display.flip()
pygame.quit()
exit()
Note:
>>> width = 100
>>> 101 % width
1
>>> -1 % width
99
>>>