- Stack
-
- Python
- Source code
- marekh19/jumpy-knight
What is Jumpy Knight?
Jumpy Knight is a simple 2D platformer game built with Python and Pygame. Think of it as the lovechild of Google Chrome’s dinosaur game and a medieval knight’s training session. You control a pixelated knight who must jump over obstacles to survive as long as possible.
The game features:
- Two enemy types: Bats (flying) and Shadowwalkers (ground-based)
- Score system: 1 point per second survived
- Local high score tracking: Stored in a simple text file
- Pixel art aesthetics: Custom sprites with animation frames
The Learning Journey
Built after just a couple of months of Python experience, this project was an experiment in game development fundamentals. While the code structure leaves much to be desired (everything crammed into one file, hardcoded values galore), it successfully demonstrates several core game development concepts.
Key Concepts Explored
1. The Game Loop
The heart of any game is the main loop that runs continuously:
while True:
for event in pygame.event.get():
# Handle events (keyboard, mouse, etc.)
if game_active:
# Update game state
# Render everything
# Check collisions
pygame.display.update()
clock.tick(60) # 60 FPS2. Gravity Implementation
A simple but effective gravity system:
def apply_gravity(self):
self.gravity += 1 # Gravity increases over time
self.rect.y += self.gravity # Apply gravity to position
if self.rect.bottom >= 500: # Ground collision
self.rect.bottom = 5003. Sprite Animation
Basic frame-based animation using a timer:
def animation_state(self):
self.animation_index += 0.1
if self.animation_index >= len(self.frames):
self.animation_index = 0
self.image = self.frames[int(self.animation_index)]4. Collision Detection
Simple sprite collision checking:
def collision_sprite():
if pygame.sprite.spritecollide(player.sprite, obstacle_group, False):
obstacle_group.empty()
return False
else:
return TrueWhat I Learned
Despite the “everything in one file” approach, this project successfully taught:
- Game loop mechanics - How to structure continuous game execution
- Physics simulation - Basic gravity and collision detection
- Sprite management - Loading, animating, and organizing game objects
- Event handling - Responding to user input and game events
- State management - Switching between game states (active, game over, intro)
Technical Implementation
Obstacle Generation
The game uses a timer-based system to spawn enemies:
obstacle_timer = pygame.USEREVENT + 1
pygame.time.set_timer(obstacle_timer, 1400) # Spawn every 1.4 seconds
# In the event loop:
if event.type == obstacle_timer:
obstacle_group.add(Obstacle(choice(['bat', 'shadowwalker', 'shadowwalker'])))High Score Persistence
Simple file-based score saving:
def read_highscore():
high_score_file = open(r'highscore', 'w+')
high_score_from_file = high_score_file.read()
if high_score_from_file == '':
high_score_from_file = 0
high_score = int(high_score_from_file)
high_score_file.close()
return high_scoreVisual Elements



Code Quality Notes
Let’s be honest - this code has some… interesting characteristics:
- Single file architecture - Everything from player logic to main loop in one place
- Magic numbers - Hardcoded positions like
(640, 360)scattered throughout - Mixed responsibilities - Game logic, rendering, and input handling all tangled together
- File I/O in main loop - High score file opened and closed every frame
But hey, it works! And sometimes that’s the most important thing when learning.
Key Takeaways
Building Jumpy Knight taught me that functionality comes before perfection. While the code structure isn’t ideal, the game successfully demonstrates fundamental game development concepts that can be applied to more complex projects.
Sometimes the best way to learn is to build something that works, even if it’s not pretty. You can always refactor later.