Pygame, Game Development, Physics Engine, Artificial Intelligence
Watch the trailer to get a glimpse of the exciting adventure that awaits you in "Where's My Bread".
Welcome to Where's My Bread, a 2D platformer game crafted with passion and creativity. In this game, you step into the shoes of a determined baker in Paris whose precious loaves of bread have been stolen and scattered across the city. Your mission is twofold: collect as many pieces of bread as possible and reach the end goal flag in the shortest time.
The gameplay is inspired by classic platformers like Super Mario Bros, but with a unique twist that separates the collection and speedrun elements into distinct objectives. As you traverse the beautifully designed levels, you'll encounter various challenges and enemies that test your skills and timing.
Future updates are planned to introduce new characters, levels, and features, enhancing the game's depth and replayability. Stay tuned for more exciting content!
The visual design of Where's My Bread is a labor of love. Over two and a half weeks, I meticulously hand-drew every aspect of the game using Aseprite, a professional pixel art tool. This includes the characters, enemies, environmental assets, and iconic backdrops like the Eiffel Tower.
The protagonist's design is heavily inspired by Madeline from the critically acclaimed game Celeste. By adopting a similar aesthetic, I aimed to evoke a sense of familiarity while introducing unique elements that make the game stand out.
The art style pays homage to classic 8-bit and 16-bit games, bringing a nostalgic feel that resonates with fans of retro gaming. The vibrant colors and detailed pixel art contribute to an immersive experience as you navigate through the charming streets of Paris.
One of the core aspects of any platformer is the physics engine, which governs how characters move and interact with the environment. In Where's My Bread, I built the physics engine from the ground up, paying close attention to detail to ensure smooth and responsive controls.
Developing the physics required a deep dive into concepts like gravity, acceleration, collision detection, and friction. For instance, I had to determine the optimal jump height that feels satisfying yet challenging, and adjust the gravity so that the character's movements are realistic.
Here's a simplified snippet from the Player
class demonstrating how movement and physics are handled:
def move(self, moving_left, moving_right):
# Reset movement variables
dx = 0
dy = 0
# Move left or right
if moving_left:
dx = -self.speed
self.flip = True
self.direction = -1
if moving_right:
dx = self.speed
self.flip = False
self.direction = 1
# Jump
if self.jump and not self.in_air:
self.vel_y = -9
self.jump = False
self.in_air = True
# Apply gravity
self.vel_y += GRAVITY
dy += self.vel_y
# Check for collision
for tile in world.obstacle_list:
# Horizontal collision
if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height):
dx = 0
# Vertical collision
if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height):
if self.vel_y < 0:
dy = tile[1].bottom - self.rect.top
self.vel_y = 0
elif self.vel_y >= 0:
dy = tile[1].top - self.rect.bottom
self.vel_y = 0
self.in_air = False
# Update player position
self.rect.x += dx
self.rect.y += dy
This code manages the player's movement by updating their position based on user input and physics calculations. It handles jumping, applying gravity, and checking for collisions with the environment to prevent the player from passing through walls or floors.
Crafting the physics engine was a challenging task that enhanced my understanding of game mechanics and programming principles. It was rewarding to see the character move fluidly and interact with the world as intended.
To add depth and challenge to the gameplay, I introduced enemy characters controlled by artificial intelligence (AI). These enemies, styled as mafia men, patrol the levels and attempt to stop the player from progressing. They add an element of danger and require the player to strategize their movements.
The enemies move back and forth in a semi-random pattern. This is achieved by having them change direction based on a random chance. This randomness prevents the player from easily predicting enemy patterns, keeping the gameplay engaging.
The code below shows how the enemy decides when to change direction:
if random.randint(1, 200) == 1:
self.direction *= -1 # Change direction
This gives the enemy a 0.5% chance to change direction each frame, creating a dynamic patrol behavior.
Enemies have a "vision" range represented by a rectangular area in front of them. If the player enters this area, the enemy detects the player and initiates an attack by shooting a projectile. This requires the player to be cautious and avoid being spotted or be prepared to dodge incoming attacks.
The following code snippet demonstrates how the enemy AI checks for the player's presence and reacts:
def ai(self):
if self.alive and player.alive:
if not self.idling and random.randint(1, 200) == 1:
self.idling = True
self.idling_counter = 500
if self.vision.colliderect(player.rect):
self.shoot() # Attack the player
else:
# Continue patrolling
self.move(...)
By integrating AI behavior, the game offers a more immersive experience, challenging players to think strategically.
Developing Where's My Bread was a comprehensive project that involved various aspects of game development. Here's an overview of the core components and the development process:
I chose Pygame as the foundation for the game. Pygame is a set of Python modules designed for writing video games. It provides essential functionalities such as rendering graphics, handling user input, and playing sounds, making it suitable for 2D game development.
The levels are constructed using tile maps, where each tile represents a piece of the environment like a platform or obstacle. I created a level editor tool to design the maps efficiently. The level data is stored in CSV files, which the game reads to build the levels dynamically during runtime.
All graphical assets were hand-drawn using Aseprite, ensuring a cohesive art style throughout the game. This includes character sprites with various animations (idle, run, jump), enemy sprites, background images, and UI elements like buttons and icons.
Audio enhances the gaming experience by providing feedback and setting the mood. I integrated background music and sound effects using Pygame's mixer module. Sounds like jumping, collecting bread, or enemy attacks add to the game's immersion.
The game features interactive menus, HUD elements displaying the player's health and collected bread, and other UI components. I created a custom button class to manage button states (hovered, clicked) and handle user interactions seamlessly.
Throughout the development, I faced challenges like optimizing the game loop for better performance, handling collisions accurately, and balancing gameplay difficulty. Overcoming these hurdles required research, testing, and sometimes refactoring code to improve efficiency.
This project significantly enhanced my programming skills, particularly in Python and game development principles. It also taught me valuable lessons in time management and problem-solving.
The project's source code is organized into several files and directories, each serving a specific purpose:
The full source code is available on GitHub. Feel free to explore the code, and you're welcome to contribute or provide feedback.
If you'd like to play Where's My Bread, follow these simple steps:
pip install pygame==1.9.6
git clone https://github.com/Simonlee711/Basic_Game.git
cd Basic_Game
python3 paris.py
Enjoy the game! Use the keyboard to move the character, collect bread, and reach the goal flag. Be wary of enemies and obstacles along the way.
If you have any questions, feedback, or need assistance, please feel free to reach out to me at simonlee711@gmail.com. I appreciate your interest and hope you enjoy the game!