I'm currently making a Sonic game using Pygame (full project here: https://github.com/Dingleberry-Epstein/Sonic-Pygame-Test) and I am stuck on how to perfectly handle loops, slopes and overall tile handling. I am aware that developing such a system is a giant rabbit hole just like the development of the original Genesis games (key difference being there was a team behind those and a solo dev for this game). With all that being said however, I do know that this system can be achieved as there is a series of videos on YouTube that prove it. I have used Tiled to make the map and I have created two layers, one with "collision masks" and one for the normal tiles. The collision masks have been turned into a tileset and contain an attribute with the specific angle of the mask. I use this info to make the initial map with the masks and then in the other layer, overlay the masks with the tiles and assign each tile with an angle matching that of the mask. One problem is that the tiles don't always match up as the masks are for Genesis games that use 128x128 chunks for levels whereas the tileset is from Sonic Advance (Gameboy Advance game) that uses 96x96 chunks and the tiles are slightly off. From there, I use code that checks what tile the character touches and adjusts their angle attribute to use that tile's angle. Then, I use code to make the character run on a vector with that angle. from levels.py: for tile in self.tile_group: if self.character.mask.overlap(tile.mask, (tile.rect.x - self.character.hitbox.x, tile.rect.y - self.character.hitbox.y)): # Sonic collides with the tile self.character.Yvel = 0 self.character.grounded = True self.character.jumped = False if getattr(tile, "angle"): # Interpolate angle for smooth transition angle_difference = (tile.angle - self.character.angle) % 360 if angle_difference > 180: angle_difference -= 360 # Take the shortest rotation direction # Adjust speed of rotation based on Sonic's speed rotation_speed = max(5, abs(self.character.groundSpeed) * 0.3) # Faster when moving fast self.character.angle += angle_difference * 0.2 * rotation_speed elif not getattr(tile, "angle", 0): continue break # Stop checking after the first collision if not self.character.grounded: # Reset angle smoothly back to 0 when in air self.character.angle += (0 - self.character.angle) * 0.15 from characters.py: # Create a movement vector based on ground speed movement_vector = pygame.math.Vector2(self.groundSpeed, 0) movement_vector = movement_vector.rotate(-self.angle) # Rotate along the slope self.Xvel = movement_vector.x self.Yvel = movement_vector.y At the moment, the basic premise of angled movement works but its implementation is less than subpar. Below is footage of what my game's angular movement looks like and how it should actually look: https://imgur.com/a/mqVNIS2 (my game) https://info.sonicretro.org/images/5/53/SPGCollisionDemo.gif (how it should work) With that being said how do I not simply just "improve collisions" but rather, how do I implement a more accurate system where Sonic doesn't phase through tiles and runs exactly on the curves of each tile? Edit: As my post has been rejected, I will make more clarifications here; clarify what the exact problem is: I have no idea how to implement a smooth angled movement system. How I implemented it is explained above with the use of Tiled and some code. what you expect to happen: Sonic should be able to run through loops smoothly, without phasing through adjacent tiles. He should be able to run on the edges of the tiles. Footage of how it should look is linked above. what happens instead: The loop implementation doesn't work properly. Sonic is able to go up loops but will phase into adjacent tiles and thus, if he touches an adjacent tile that does not have an "angle" attribute, he will snap to 0 degrees and break out of the loop. Similarly, once he goes up a loop, if he tries to run back down, he is slightly misaligned and instead of touching the top of the ground tile when exiting, he phases into it a little bit. Footage is linked above. Continue reading...