Graphics · 3D game, no engine
BombArena
A 3D Bomberman-style arena game in Python and PyOpenGL, built without a game engine: bombs, power-ups, enemies and a multi-phase boss.
Stack
- Python
- PyOpenGL
- GLUT
- NumPy
- game engines: OpenGL and GLUT only
- 0
- game engines: OpenGL and GLUT only
- power-ups: bombs, range, speed
- 3
- power-ups: bombs, range, speed
- boss phases before victory
- 3
- boss phases before victory

What it does
You control a bomber in a circular arena. Place bombs to clear blocks, collect the power-ups they drop, and avoid both the explosions and the alien enemies that roam the arena. Survive long enough and a boss arrives. Defeat it to win.


| Key | Action |
|---|---|
| W A S D | Move |
| Space | Place a bomb |
| C | Toggle cheat mode (invincibility) |
| P | Restart after game over |
| Esc | Quit |
Building without an engine
With no engine, everything an engine normally provides had to be written by hand. All mutable state lives in a single GameState object, and GLUT drives the program through callbacks:
Input
glutIdleFunc(update)
glutDisplayFunc(display)
- Input:
keyboardandkeyboard_upmaintain a set of held keys, so movement stays smooth and diagonal movement works, instead of relying on key-repeat events. - Update: each tick computes elapsed time, so bomb fuses and movement run on real time rather than frame count.
- Rendering: the player, enemies and boss are composed from small
draw_cube,draw_sphereanddraw_cylinderhelpers in immediate-mode OpenGL, with lighting enabled and a particle system for the boss phase.
Arena generation and collision
The arena is a square grid clipped to a circle: a cell exists only if the whole obstacle fits inside the arena radius. Obstacles are sampled from the free cells at a fixed density, the spawn cell is always kept clear, and enemies only spawn on cells that are neither obstacles nor the spawn.
Collision is distance-based. That suits a circular arena and round characters, and is cheap enough to check against every obstacle each frame:
def can_move_to(x, z): if math.sqrt(x*x + z*z) > ARENA_RADIUS - 0.4: return False # Check obstacle collisions for obstacle in game.obstacles: ox, _, oz = obstacle dist = math.sqrt((x - ox)**2 + (z - oz)**2) if dist < CELL_SIZE * 0.8: # Collision detected return False return TrueBombs, explosions and scoring
The player moves freely, but bombs snap to the grid. That keeps the classic Bomberman feel and makes it simple to stop two bombs from sharing a cell:
def place_bomb(): # Check if player has bombs available active_bomb_count = len([b for b in game.active_bombs if b[3] > 0]) if active_bomb_count >= game.player_bombs: return # Round to nearest grid cell x, y, z = game.player_pos grid_x = round(x / CELL_SIZE) * CELL_SIZE grid_z = round(z / CELL_SIZE) * CELL_SIZE # Check if bomb already exists at this location for bomb in game.active_bombs: bx, _, bz, _, _ = bomb if abs(bx - grid_x) < 0.1 and abs(bz - grid_z) < 0.1: return bomb = [grid_x, y, grid_z, BOMB_TIMER, game.player_range] game.active_bombs.append(bomb)When a fuse runs out, the blast radius is the player's range × cell size. It destroys blocks (+50, with a chance to drop one of three power-ups), kills enemies (+200), damages the boss (+500), and ends the game if it reaches the player, unless cheat mode is on. Explosions linger for half a second after detonation so they stay visible.
The boss fight
The boss shoots fireballs, takes several bomb hits to bring down, and changes the mood of the arena with a snow particle effect. When it is defeated it comes back twice with fresh health. Each time it respawns at a random point that is inside the arena, clear of obstacles and at least five units from the player, with a fallback to the center if 100 attempts fail. Only the third defeat wins the game.