Difficulty and Accessibility
Learning Objectives: By the end of this lesson, you will be able to:
- Design difficulty systems that serve diverse player skill levels
- Implement accessibility features that expand your audience
- Balance challenge with frustration across different contexts
- Create adaptive difficulty that feels fair
- Apply industry accessibility standards to game design
1. Welcome and Introduction (5 minutes)
Icebreaker Activity
Think about a game you quit because it was too hard. Now think about one you quit because it was too easy. Both are difficulty design failuresβbut so different in their causes. And have you ever played a game that worked perfectly for your friend but was unplayable for you due to colorblindness, hearing, or motor control?
Good difficulty and accessibility design ensures every player can have their optimal experience.
Lesson Overview
- Duration: 90-120 minutes
- Prerequisites: Lessons 1-8 (All previous content)
- Materials Needed: Access to games with good accessibility options
2. Learning Objectives and Session Outline (5 minutes)
What We’ll Cover Today:
- Difficulty Philosophy - What difficulty should accomplish
- Difficulty Approaches - Static, dynamic, systemic, and modular
- Accessibility Fundamentals - Visual, auditory, motor, and cognitive
- Implementation Strategies - How to add accessibility effectively
- Testing and Validation - Ensuring your features work
- Case Studies - Learning from accessibility leaders
Success Criteria:
By the end of this session, you should be able to design both difficulty options and accessibility features for any game concept.
3. Foundation Knowledge (15-20 minutes)
Core Concepts
What is Difficulty Design?
Difficulty is the balance between player capability and game challenge. Good difficulty design ensures:
- Players of different skill levels can enjoy the game
- Challenge creates engagement, not frustration
- Growth and mastery feel rewarding
- The intended experience is preserved
Real-World Analogy: A good climbing gym has routes of different difficulty grades. Beginners have paths they can complete, experts have challenges that push them. The best gyms don’t just have “one wall” with one difficulty.
What is Accessibility?
Accessibility ensures people with disabilities can play your game. This includes:
- Visual: Blindness, low vision, colorblindness
- Auditory: Deafness, hard of hearing
- Motor: Limited mobility, tremors, fatigue
- Cognitive: Learning disabilities, attention difficulties
Key Insight: Accessibility often benefits everyone. Subtitles help non-native speakers. Colorblind modes help in bright lighting. Remappable controls help players with any preference.
Key Terminology
- Assist Mode: Optional features that reduce difficulty
- Dynamic Difficulty Adjustment (DDA): Game automatically adapts to player
- WCAG: Web Content Accessibility Guidelines (adapted for games)
- Motor Impairment: Difficulty with physical input
- Cognitive Load: Mental effort required to play
4. Detailed Explanation and Examples (25-30 minutes)
Difficulty Approaches
Static Difficulty Levels
Player selects difficulty at start.
Easy: -30% enemy damage, +50% player damage, more checkpoints
Normal: Intended balance
Hard: +30% enemy damage, -20% player damage, fewer checkpoints
Nightmare: +100% enemy damage, permadeath
Pros:
- Simple to implement
- Clear player expectations
- Easy to balance
Cons:
- Players may choose “wrong” difficulty
- Can’t adjust mid-game (or feels like failure)
- One-size-fits-all doesn’t work
Dynamic Difficulty Adjustment (DDA)
Game monitors performance and adjusts automatically.
class DynamicDifficulty:
def __init__(self):
self.difficulty_score = 50 # 0-100 scale
self.recent_deaths = []
self.recent_clear_times = []
def on_player_death(self):
self.recent_deaths.append(time.now())
# Clean old data (last 10 minutes)
self.recent_deaths = [d for d in self.recent_deaths
if time.now() - d < 600]
if len(self.recent_deaths) > 5:
self.difficulty_score -= 5 # Make easier
def on_level_clear(self, clear_time, par_time):
ratio = clear_time / par_time
if ratio < 0.8: # Too easy
self.difficulty_score += 3
elif ratio > 1.5: # Struggled
self.difficulty_score -= 3
def get_enemy_damage_mult(self):
return 0.5 + (self.difficulty_score / 100) # 0.5x to 1.5x
def get_enemy_health_mult(self):
return 0.5 + (self.difficulty_score / 100)
Pros:
- Adapts to actual player skill
- No “choosing wrong” at start
- Seamless experience
Cons:
- Can feel invisible/manipulative
- Hard to tune correctly
- Players who enjoy challenge may feel cheated
Systemic/Player-Driven Difficulty
Difficulty emerges from player choices.
Examples:
- Dark Souls: Summon help = easier, go solo = harder
- BotW: Better equipment = easier, stick with starter gear = harder
- Risk of Rain 2: Spend more time = harder enemies
- Celeste: Collect strawberries for challenge, skip for easier
Pros:
- Player agency preserved
- Natural feeling
- No “easy mode stigma”
Cons:
- Uneven experience
- Some players stuck without knowing options
- Can accidentally be too hard/easy
Modular/Granular Difficulty
Let players customize specific aspects.
Combat Difficulty: [Easy] [Normal] [Hard]
Puzzle Difficulty: [Easy] [Normal] [Hard]
Time Pressure: [Off] [Relaxed] [Standard] [Intense]
Assists:
[x] Invincibility when falling
[ ] Infinite stamina
[x] Extended timers
[ ] Skip combat encounters
Pros:
- Maximum player control
- Accessibility + difficulty in one
- Respects player preferences
Cons:
- Can overwhelm with options
- Harder to balance/test
- May require UI investment
Accessibility Categories
Visual Accessibility
| Feature | Who It Helps | Implementation |
|---|---|---|
| Colorblind modes | 8% of males, 0.5% of females | Alternative color palettes |
| High contrast mode | Low vision | Stronger outlines, less detail |
| Scalable UI | Low vision | User-controlled text/icon size |
| Screen reader support | Blind players | Text-to-speech, audio cues |
| Visual indicators for audio | Deaf players | Subtitles, visual sound cues |
Colorblind Mode Implementation:
# Instead of red vs green
normal_colors = {'enemy': (255, 0, 0), 'ally': (0, 255, 0)}
# Deuteranopia-friendly
colorblind_colors = {'enemy': (255, 150, 0), 'ally': (0, 150, 255)}
# Best practice: Use shapes + colors
def draw_marker(target_type):
if target_type == 'enemy':
draw_circle(color=palette['enemy']) # Circle
elif target_type == 'ally':
draw_diamond(color=palette['ally']) # Diamond
Auditory Accessibility
| Feature | Who It Helps | Implementation |
|---|---|---|
| Subtitles | Deaf/HoH, non-native speakers | Text for dialogue |
| Closed captions | Deaf/HoH | Text for ALL sounds |
| Visual sound indicators | Deaf/HoH | Icons showing sound direction |
| Mono audio option | Single-sided deafness | Combine stereo channels |
| Adjustable volume per type | Hearing sensitivity | Separate music/SFX/voice |
Motor Accessibility
| Feature | Who It Helps | Implementation |
|---|---|---|
| Remappable controls | All motor impairments | Any action to any button |
| One-handed modes | Single-arm users | All inputs accessible one-handed |
| Toggle vs hold | Fatigue, limited strength | Option for both |
| Auto-aim assist | Tremors, limited precision | Adjustable aim magnetism |
| Time slowing | Reaction time issues | Slow-mo for critical moments |
| Reduced button mashing | Fatigue, RSI | Hold instead of mash |
Cognitive Accessibility
| Feature | Who It Helps | Implementation |
|---|---|---|
| Tutorial options | Different learning needs | Repeatable, skippable, detailed |
| Goal reminders | Memory, attention | Quest log, objective markers |
| Reduced UI complexity | Cognitive overload | Simplified mode |
| Pause in conversations | Processing time | Player-controlled text advance |
| Difficulty adjustment | Frustration avoidance | Generous, non-stigmatizing options |
Common Misconceptions
-
Misconception: “Accessibility is separate from difficulty” Reality: They overlap significantly. Many difficulty options are also accessibility features.
-
Misconception: “Adding easy mode ruins the game” Reality: Optional difficulty never affects those who don’t use it.
-
Misconception: “Accessibility is expensive” Reality: Many features are cheap (remapping, subtitles). Plan early for bigger ones.
-
Misconception: “Disabled players are a tiny market” Reality: ~20% of population has some disability. Plus, accessibility helps everyone.
5. Live Coding Demonstration (20-25 minutes)
Example 1: Modular Difficulty System
class ModularDifficulty:
def __init__(self):
# Core difficulty settings
self.combat_difficulty = 'normal' # easy, normal, hard
self.puzzle_difficulty = 'normal'
self.exploration_difficulty = 'normal'
# Assist toggles
self.assists = {
'invincibility': False,
'infinite_stamina': False,
'auto_aim': False,
'extended_timers': False,
'skip_puzzles': False,
'show_solutions': False,
}
# Granular sliders (0.0 to 2.0, 1.0 = normal)
self.damage_taken_mult = 1.0
self.damage_dealt_mult = 1.0
self.enemy_speed_mult = 1.0
self.timer_mult = 1.0
def apply_combat_preset(self, preset):
if preset == 'easy':
self.damage_taken_mult = 0.5
self.damage_dealt_mult = 1.5
self.enemy_speed_mult = 0.8
elif preset == 'normal':
self.damage_taken_mult = 1.0
self.damage_dealt_mult = 1.0
self.enemy_speed_mult = 1.0
elif preset == 'hard':
self.damage_taken_mult = 1.5
self.damage_dealt_mult = 0.8
self.enemy_speed_mult = 1.2
def calculate_damage_to_player(self, base_damage):
if self.assists['invincibility']:
return 0
return base_damage * self.damage_taken_mult
def calculate_player_damage(self, base_damage):
return base_damage * self.damage_dealt_mult
def get_timer_duration(self, base_duration):
if self.assists['extended_timers']:
return base_duration * 2.0
return base_duration * self.timer_mult
def should_show_puzzle_solution(self):
return self.assists['show_solutions']
def can_skip_current_puzzle(self):
return self.assists['skip_puzzles']
# Usage
settings = ModularDifficulty()
# Player who loves combat but hates puzzles
settings.apply_combat_preset('hard')
settings.assists['skip_puzzles'] = True
# Player with motor issues
settings.assists['auto_aim'] = True
settings.assists['extended_timers'] = True
settings.damage_taken_mult = 0.7 # Custom slider
Example 2: Accessibility Feature Implementation
class AccessibilityManager:
def __init__(self):
# Visual settings
self.colorblind_mode = None # None, 'deuteranopia', 'protanopia', 'tritanopia'
self.ui_scale = 1.0
self.high_contrast = False
self.screen_shake = True
self.flash_effects = True
# Audio settings
self.subtitles = True
self.closed_captions = False # Includes sound effects
self.mono_audio = False
self.visual_sound_cues = False
# Motor settings
self.hold_to_toggle = {} # Action -> 'hold' or 'toggle'
self.auto_aim_strength = 0.0 # 0 = off, 1 = maximum
self.qte_auto_complete = False
# Cognitive settings
self.objective_reminders = True
self.mini_map_always_on = True
self.simplified_ui = False
def get_color(self, color_name, default_color):
"""Return appropriate color for colorblind mode"""
if not self.colorblind_mode:
return default_color
# Color mappings for common colorblind types
colorblind_palettes = {
'deuteranopia': {
'red': (255, 100, 0),
'green': (0, 100, 255),
},
'protanopia': {
'red': (200, 200, 0),
'green': (0, 200, 255),
}
}
palette = colorblind_palettes.get(self.colorblind_mode, {})
return palette.get(color_name, default_color)
def should_show_subtitle(self, text, speaker=None):
return self.subtitles
def should_show_sound_caption(self, sound_type, direction):
if self.visual_sound_cues:
return True
if self.closed_captions:
return True
return False
def get_sound_caption(self, sound_type, direction):
"""Generate visual indicator for sound"""
captions = {
'footsteps': 'π£',
'gunshot': 'π₯',
'explosion': 'π£',
'voice': 'π£οΈ',
'alarm': 'π',
}
direction_arrows = {
'left': 'β',
'right': 'β',
'behind': 'β',
'front': 'β',
}
icon = captions.get(sound_type, 'π')
arrow = direction_arrows.get(direction, '')
return f"{arrow} {icon}"
def calculate_aim_assist(self, aim_point, target_point, max_distance):
"""Pull aim toward target if within range"""
if self.auto_aim_strength <= 0:
return aim_point
distance = ((aim_point[0] - target_point[0])**2 +
(aim_point[1] - target_point[1])**2)**0.5
if distance > max_distance:
return aim_point
# Lerp toward target based on strength
lerp_factor = self.auto_aim_strength * (1 - distance/max_distance)
new_aim = [
aim_point[0] + (target_point[0] - aim_point[0]) * lerp_factor,
aim_point[1] + (target_point[1] - aim_point[1]) * lerp_factor
]
return new_aim
# Usage
accessibility = AccessibilityManager()
accessibility.colorblind_mode = 'deuteranopia'
accessibility.visual_sound_cues = True
accessibility.auto_aim_strength = 0.5
# Get colorblind-safe color for enemy
enemy_color = accessibility.get_color('red', (255, 0, 0))
print(f"Enemy color: {enemy_color}")
# Generate sound caption
caption = accessibility.get_sound_caption('footsteps', 'left')
print(f"Sound indicator: {caption}")
Example 3: Celeste-Style Assist Mode
class CelesteStyleAssist:
"""
Inspired by Celeste's excellent assist mode
"""
def __init__(self):
self.enabled = False
# Individual options
self.game_speed = 100 # 50-100% in 10% increments
self.invincibility = False
self.infinite_stamina = False
self.infinite_dashes = False
def show_assist_menu(self):
return """
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ASSIST MODE β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Assist Mode is designed to help you experience the story β
β and gameplay of our game regardless of skill level. β
β β
β Using Assist Mode will not affect achievements or progress. β
β This is YOUR experience - play it YOUR way. β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Game Speed: [{self.game_speed}%] ββββββββββββββββββΊ β
β Invincibility: [{' ON' if self.invincibility else 'OFF'}]β
β Infinite Stamina: [{' ON' if self.infinite_stamina else 'OFF'}]β
β Infinite Dashes: [{' ON' if self.infinite_dashes else 'OFF'}]β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""".format(self=self)
def get_time_scale(self):
return self.game_speed / 100.0
def should_take_damage(self, damage_source):
if self.invincibility:
return False
return True
def get_stamina_cost(self, action):
if self.infinite_stamina:
return 0
costs = {
'climb': 1,
'grab': 0.5,
'boost': 2
}
return costs.get(action, 1)
def get_dash_count(self, base_count):
if self.infinite_dashes:
return 999
return base_count
# The key message: No judgment, no punishment, just options
print(CelesteStyleAssist().show_assist_menu())
6. Hands-On Practice (30-40 minutes)
Exercise 1: Accessibility Audit (10 minutes)
Objective: Evaluate accessibility of a known game
Instructions:
- Choose a game you’ve played recently
- Evaluate it against this checklist:
VISUAL:
[ ] Colorblind mode available?
[ ] UI scaling option?
[ ] High contrast mode?
[ ] Subtitles available?
AUDIO:
[ ] Subtitles for all dialogue?
[ ] Sound direction indicators?
[ ] Volume controls per type?
[ ] Mono audio option?
MOTOR:
[ ] Remappable controls?
[ ] Toggle/hold options?
[ ] Adjustable timings?
[ ] Auto-aim option?
COGNITIVE:
[ ] Difficulty options?
[ ] Objective reminders?
[ ] Tutorial replay option?
[ ] Pause during dialogue?
- Rate overall accessibility (1-5)
- Identify top 3 missing features
Exercise 2: Design Difficulty Options (15 minutes)
Objective: Create a complete difficulty system
Scenario: Design difficulty options for a 2D action platformer:
- Core audience: Ages 12-25
- Desired experience: Challenging but fair
- Must be accessible to players with motor impairments
Deliverables:
- 3-4 difficulty presets with descriptions
- Modular options players can customize
- 3 accessibility features that affect difficulty
- UI mockup or description of the settings screen
Exercise 3: Ethical Evaluation (15 minutes)
Objective: Navigate difficulty ethics
Scenarios to evaluate:
- Reviewer Difficulty: Should reviewers be required to play on normal?
- Achievement Locking: Should achievements require specific difficulties?
- DDA Transparency: Should games tell players when adjusting difficulty?
- Patronizing Language: How should easy mode be described?
For each scenario:
- State your position
- Explain your reasoning
- Consider counterarguments
- Propose a specific policy
7. Common Pitfalls and Troubleshooting (10 minutes)
Frequent Mistakes
-
Problem: “Easy mode” feels like an insult Cause: Condescending naming/messaging Solution: Neutral language, positive framing
-
Problem: Accessibility features are hidden Cause: Late implementation, afterthought approach Solution: Surface options early, mention in tutorials
-
Problem: DDA feels unfair Cause: Too aggressive, too visible Solution: Subtle adjustments, player control option
-
Problem: Colorblind mode doesn’t work Cause: Only changed colors, not shapes Solution: Shapes + colors, high contrast + colors
Warning Signs
| Symptom | Likely Problem | Check This |
|---|---|---|
| Players quit on first level | Too hard early | Onboarding difficulty |
| Players breeze through | Too easy overall | Core difficulty |
| Accessibility complaints | Missing features | Feature coverage |
| “Easy mode” stigma reports | Bad messaging | Option framing |
8. Best Practices and Professional Tips (5 minutes)
Industry Standards
- Microsoft Accessibility Guidelines: 23 best practices
- AbleGamers Foundation: Consultation services available
- Can I Play That: Review site for accessibility
Resources
- Xbox Accessibility Guidelines: https://docs.microsoft.com/gaming/accessibility
- Game Accessibility Guidelines: http://gameaccessibilityguidelines.com
- AbleGamers Includification Guide
Design Philosophy
“An easy mode never forces anyone to use it. It only enables those who want it.”
“Difficulty is about matching challenge to skill. Accessibility is about matching input to ability. Both serve the same goal: letting players experience your game.”
9. Summary and Review (5 minutes)
Key Takeaways
- Difficulty and accessibility are related but distinct concerns
- Multiple approaches exist - static, dynamic, systemic, modular
- Accessibility helps everyone - not just disabled players
- Framing matters - how you present options affects stigma
- Plan early - accessibility is cheaper at the start
Quick Review Questions
- What are the four main categories of accessibility?
- What’s the difference between DDA and modular difficulty?
- Why might colorblind mode need more than just different colors?
- How should difficulty options be presented to avoid stigma?
For Instructors
Teaching Tips
- Have students try games with accessibility features disabled
- Discuss game discourse around difficulty (Sekiro, etc.)
- Invite disabled players to share experiences
- Show accessibility reviews from Can I Play That
Assessment Ideas
- Accessibility audit of a commercial game
- Difficulty system design document
- Ethics position paper on difficulty
- Implementation of accessibility features
Adaptation Notes
- For beginners: Focus on common accessibility features
- For advanced: Discuss economic arguments for accessibility
- For programmers: Implement accessibility features
- For UX designers: Focus on option UI and communication