5.5 KiB
Part 6: Doing (and Taking) Damage
Overview
Part 6 transforms our basic combat into a complete gameplay loop with visual feedback, enemy AI, and win/lose conditions. We add a health bar, message log, enemy AI that pursues the player, and proper game over handling.
What's New in Part 6
User Interface Components
Health Bar
A visual representation of the player's current health:
class HealthBar:
def create_ui(self) -> List[mcrfpy.UIDrawable]:
# Dark red background
self.background = mcrfpy.Frame(pos=(x, y), size=(width, height))
self.background.fill_color = mcrfpy.Color(100, 0, 0, 255)
# Bright colored bar (green/yellow/red based on HP)
self.bar = mcrfpy.Frame(pos=(x, y), size=(width, height))
# Text overlay showing HP numbers
self.text = mcrfpy.Caption(pos=(x+5, y+2),
text=f"HP: {hp}/{max_hp}")
The bar changes color based on health percentage:
- Green (>60% health)
- Yellow (30-60% health)
- Red (<30% health)
Message Log
A scrolling combat log that replaces console print statements:
class MessageLog:
def __init__(self, max_messages: int = 5):
self.messages: deque[str] = deque(maxlen=max_messages)
def add_message(self, message: str) -> None:
self.messages.append(message)
self.update_display()
Messages include:
- Combat actions ("Rat attacks Player for 3 hit points.")
- Death notifications ("Spider is dead!")
- Game state changes ("You have died! Press Escape to quit.")
Enemy AI System
Basic AI Component
Enemies now actively pursue and attack the player:
class BasicAI:
def take_turn(self, engine: Engine) -> None:
distance = max(abs(dx), abs(dy)) # Chebyshev distance
if distance <= 1:
# Adjacent: Attack!
MeleeAction(self.entity, attack_dx, attack_dy).perform(engine)
elif distance <= 6:
# Can see player: Move closer
MovementAction(self.entity, move_dx, move_dy).perform(engine)
Turn-Based System
After each player action, all enemies take their turn:
def handle_enemy_turns(self) -> None:
for entity in self.game_map.entities:
if isinstance(entity, Actor) and entity.ai and entity.is_alive:
entity.ai.take_turn(self)
Game Over Condition
When the player dies:
- Game state flag is set (
engine.game_over = True) - Player becomes a gravestone (sprite changes)
- Input is restricted (only Escape works)
- Death message appears in the message log
def handle_player_death(self) -> None:
self.game_over = True
self.message_log.add_message("You have died! Press Escape to quit.")
Architecture Improvements
UI Module (game/ui.py)
Separates UI concerns from game logic:
MessageLog: Manages combat messagesHealthBar: Displays player health- Clean interface for updating displays
AI Module (game/ai.py)
Encapsulates enemy behavior:
BasicAI: Simple pursue-and-attack behavior- Extensible for different AI types
- Uses existing action system
Turn Management
Player actions trigger enemy turns:
- Movement → Enemy turns
- Attack → Enemy turns
- Wait → Enemy turns
- Maintains turn-based feel
Key Implementation Details
UI Updates
Health bar updates occur:
- After player takes damage
- Automatically via
engine.update_ui() - Color changes based on HP percentage
Message Flow
Combat messages follow this pattern:
- Action generates message text
engine.message_log.add_message(text)- Message appears in UI Caption
- Old messages scroll up
AI Decision Making
Basic AI uses simple rules:
- Check if player is adjacent → Attack
- Check if player is visible (within 6 tiles) → Move toward
- Otherwise → Do nothing
Game State Management
The game_over flag prevents:
- Player movement
- Player attacks
- Player waiting
- But allows Escape to quit
Files Modified
game/ui.py: New module for UI componentsgame/ai.py: New module for enemy AIgame/engine.py: Added UI setup, enemy turns, game over handlinggame/entity.py: Added AI component to Actorgame/entity_factories.py: Attached AI to enemiesgame/actions.py: Integrated message log, added enemy turn triggersmain.py: Updated part description
What's Next
Part 7 will expand the user interface further with:
- More detailed entity inspection
- Possibly inventory display
- Additional UI panels
- Mouse interaction
Learning Points
- UI Separation: Keep UI logic separate from game logic
- Component Systems: AI as a component allows different behaviors
- Turn-Based Flow: Player action → Enemy reactions creates tactical gameplay
- Visual Feedback: Health bars and message logs improve player understanding
- State Management: Game over flag controls available actions
Running Part 6
cd simple_tcod_tutorial/build
./mcrogueface scripts/main.py
You'll now see:
- Health bar at the top showing your current HP
- Message log at the bottom showing combat events
- Enemies that chase you when you're nearby
- Enemies that attack when adjacent
- Death state when HP reaches 0
Combat Strategy
With enemy AI active, combat becomes more tactical:
- Enemies pursue when they see you
- Fighting in corridors limits how many can attack
- Running away is sometimes the best option
- Health management becomes critical
The game now has a complete combat loop with clear win/lose conditions!