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:

  1. Difficulty Philosophy - What difficulty should accomplish
  2. Difficulty Approaches - Static, dynamic, systemic, and modular
  3. Accessibility Fundamentals - Visual, auditory, motor, and cognitive
  4. Implementation Strategies - How to add accessibility effectively
  5. Testing and Validation - Ensuring your features work
  6. 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

  1. Misconception: “Accessibility is separate from difficulty” Reality: They overlap significantly. Many difficulty options are also accessibility features.

  2. Misconception: “Adding easy mode ruins the game” Reality: Optional difficulty never affects those who don’t use it.

  3. Misconception: “Accessibility is expensive” Reality: Many features are cheap (remapping, subtitles). Plan early for bigger ones.

  4. 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:

  1. Choose a game you’ve played recently
  2. 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?
  1. Rate overall accessibility (1-5)
  2. 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:

  1. 3-4 difficulty presets with descriptions
  2. Modular options players can customize
  3. 3 accessibility features that affect difficulty
  4. UI mockup or description of the settings screen

Exercise 3: Ethical Evaluation (15 minutes)

Objective: Navigate difficulty ethics

Scenarios to evaluate:

  1. Reviewer Difficulty: Should reviewers be required to play on normal?
  2. Achievement Locking: Should achievements require specific difficulties?
  3. DDA Transparency: Should games tell players when adjusting difficulty?
  4. 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

  1. Problem: “Easy mode” feels like an insult Cause: Condescending naming/messaging Solution: Neutral language, positive framing

  2. Problem: Accessibility features are hidden Cause: Late implementation, afterthought approach Solution: Surface options early, mention in tutorials

  3. Problem: DDA feels unfair Cause: Too aggressive, too visible Solution: Subtle adjustments, player control option

  4. 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

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

  1. Difficulty and accessibility are related but distinct concerns
  2. Multiple approaches exist - static, dynamic, systemic, modular
  3. Accessibility helps everyone - not just disabled players
  4. Framing matters - how you present options affects stigma
  5. Plan early - accessibility is cheaper at the start

Quick Review Questions

  1. What are the four main categories of accessibility?
  2. What’s the difference between DDA and modular difficulty?
  3. Why might colorblind mode need more than just different colors?
  4. 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