I have a tilemap where a character moves from tile to tile. I'm trying to make it possible for the character to move outside the screen and reappear on the other side, just like the tunnel in Pacman.
The movement works like following:
- Look for which arrow key is being pressed.
- Check if the tile where the user wants to go to is walkable. If not, go back to 1.
- If walkable, set it as target and start moving towards the tile.
- When arrived to the target, go back to 1.
The problem I have is that there're no tiles outside the screen. I've tried to set the target to the tile on the other side of the map if the target doesn't exist, but then the character would move across the whole screen.
I've tried a couple other solutions that either don't work or require lots of additional code in many different files.
Does anyone know a good solution or recommend another approach?
I'm programming in Python with Pygame but know other languages in general. Here's MVCE code for my class:
import pygame
import math
TILE_SIZE = (16, 16)
class Player(pygame.sprite.Sprite):
def __init__(self, pos, size):
super().__init__()
self.rect = pygame.Rect(pos, size) # Rectangle representing the character's pos.
self.image = pygame.Surface(size)
self.position = pos # In order to have the position in float precision, (x, y).
self.speed = 80 # Pixels per second
self.tile_index = (pos[1] // TILE_SIZE[1], pos[0] // TILE_SIZE[0]) # (Row, column).
self.moving = False
self.target = self.rect
def handle_events(self, level):
key = pygame.key.get_pressed()
if key[pygame.K_w] or key[pygame.K_UP]:
self.set_target(level, y_offset=-1)
elif key[pygame.K_s] or key[pygame.K_DOWN]:
self.set_target(level, y_offset=1)
elif key[pygame.K_a] or key[pygame.K_LEFT]:
self.set_target(level, x_offset=-1)
elif key[pygame.K_d] or key[pygame.K_RIGHT]:
self.set_target(level, x_offset=1)
def set_target(self, level, x_offset=0, y_offset=0):
tile = level.get_tile(self.tile_index, x_offset, y_offset)
if tile.is_walkable:
self.target = tile.rect
self.moving = True
def move(self, dt):
distance_x = self.target.x - self.rect.x
distance_y = self.target.y - self.rect.y
# Make sure the player move at 'speed * dt' or distance, depending on the smallest.
x = math.copysign(min(abs(distance_x), self.speed * dt), distance_x)
y = math.copysign(min(abs(distance_y), self.speed * dt), distance_y)
self.position = (self.position[0] + x, self.position[1] + y)
self.rect.topleft = self.position
def stop_if_arrived(self):
if self.rect.contains(self.target):
self.moving = False
self.tile_index = self.target.y // TILE_SIZE[1], self.target.x // TILE_SIZE[0]
def update(self, level, dt, *ignore):
if not self.moving:
self.handle_events(level)
else:
self.move(dt)
self.stop_if_arrived()