I am a python beginner and have recently started watching DaFluffyPotato's pygame platformer tutorial, and attempting to code my own simple platformer. I have gotten to the collisions part of the tutorial, and attempted to model a player entity on a surface of tiles. I wanted to make the player (44x46) be able to stand on the tiles (32x32), however making it be larger than the tiles produces this weird visual effect.effect.
Physics engine:
import pygameclass Entity: def __init__(self, game, etype, pos, size,): self.game = game self.type = etype self.pos = list(pos) self.size=size self.velocity = [0, 0] self.collisions = {'up': False, 'down': False, 'right': False, 'left': False} def rect(self): return pygame.Rect(self.pos[0], self.pos[1], self.size[0], self.size[1]) def update(self, tilemap, movement=(0, 0)): self.collisions= {"up": False, "down": False, "right": False, "left": False} frame_movement = (movement[0] + self.velocity[0], movement[1] + self.velocity[1]) self.pos[0] += frame_movement[0] entity_rect = self.rect() for rect in tilemap.physics_rects_around(self.pos): if entity_rect.colliderect(rect): if frame_movement[0] > 0: entity_rect.right = rect.left self.collisions["right"] = True if frame_movement[0] < 0: entity_rect.left = rect.right self.collisions["left"] = True self.pos[0] = entity_rect.x self.pos[1] += frame_movement[1] entity_rect = self.rect() for rect in tilemap.physics_rects_around(self.pos): if entity_rect.colliderect(rect): if frame_movement[1] > 0: entity_rect.bottom= rect.top self.collisions["down"] = True if frame_movement[1] < 0: entity_rect.top = rect.bottom self.collisions["up"] = True self.pos[1] = entity_rect.y self.velocity[1] = min(5, self.velocity[1] + 0.1) if self.collisions["down"] or self.collisions["up"]: self.velocity[1] = 0 def render(self, surf): surf.blit(self.game.assets["player"], self.pos)Tilemap:
import pygamePHYSICS_TILES={"grass"}NEIGHBOR_OFFSETS = [(-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (0, 0), (-1, 1), (0, 1), (1, 1)]class Tilemap: def __init__(self, game, tile_size): self.game=game self.tile_size = tile_size self.tilemap = {} self.offgrid_tiles = [] for i in range(10): self.tilemap[str(3+i) +";10"]={"type": "grass", "pos": (3+i, 10)} def tiles_around(self, pos): tiles = [] tile_loc =(int(pos[0] // self.tile_size), int(pos[1] // self.tile_size)) for offset in NEIGHBOR_OFFSETS: check_loc = str(tile_loc[0]+offset[0]) +";" + str(tile_loc[1]+offset[1]) if check_loc in self.tilemap: tiles.append(self.tilemap[check_loc]) return tiles def physics_rects_around(self, pos): rects = [] for tile in self.tiles_around(pos): if tile["type"] in PHYSICS_TILES: rects.append(pygame.Rect(tile["pos"][0]*self.tile_size, tile["pos"][1]*self.tile_size, self.tile_size, self.tile_size)) return rects def render(self, surf): for tile in self.offgrid_tiles: surf.blit(self.game.assets[tile["type"]], tile["pos"]) for loc in self.tilemap: tile = self.tilemap[loc] surf.blit(self.game.assets[tile["type"]],(tile["pos"][0]*self.tile_size, tile["pos"][1]*self.tile_size))Game:
import sysimport pygamefrom Scripts.entities import Entityfrom Scripts.util import load_imagefrom Scripts.tilemap import Tilemapclass Game: def __init__(self): pygame.init() self.screen = pygame.display.set_mode((640, 480)) self.clock = pygame.time.Clock() self.movement= [False, False] self.ymovement= [False, False] self.assets = {"player": load_image("bonk.png"),"grass": load_image("grass.png") } self.tilemap = Tilemap(self, tile_size=32) self.player=Entity(self, "player", (100,50), (44, 46)) def run(self): while True: self.screen.fill((0, 0, 0)) self.tilemap.render(self.screen) self.player.update(self.tilemap, (self.movement[1] - self.movement[0], 0)) self.player.render(self.screen) for event in pygame.event.get(): if event.type==pygame.QUIT: pygame.quit() sys.exit() if event.type==pygame.KEYDOWN: if event.key==pygame.K_w: self.player.velocity[1] = -3 if event.key==pygame.K_a: self.movement[0] = True if event.key==pygame.K_d: self.movement[1] = True if event.type==pygame.KEYUP: if event.key==pygame.K_a: self.movement[0] = False if event.key==pygame.K_d: self.movement[1] = False pygame.display.update() self.clock.tick(60)Game().run()I tested this with larger player entity sizes, and the effect is more pronounced.