Skip to main content

Overview

Food Catch challenges players to move a character horizontally to catch healthy fish while avoiding trash items. Featuring dynamic difficulty that increases speed and spawn rates over time. Scene Path: res://minigames/food_catch/main.gd

Cognitive Skills Developed

  • Hand-Eye Coordination: Aligning character with falling items
  • Visual Discrimination: Distinguishing food from trash
  • Decision Making: Choosing which items to pursue
  • Sustained Attention: Tracking multiple falling objects
  • Categorization: Identifying item types quickly

How to Play

Controls

  • Touch Left Area: Move character left
  • Touch Right Area: Move character right
  • Keyboard: Arrow keys or A/D for desktop
  • Back Button: Pause game

Objective

Maximize score by catching food while avoiding trash. You have 3 lives.

Gameplay

  1. Start: Tap “Play” on intro screen
  2. Move: Position player under falling items
  3. Catch Food: +10 points per fish
  4. Avoid Trash: -1 life per trash item
  5. Bonus Items: +50 points (5% spawn rate)
  6. Survive: Game ends at 0 lives

Scoring System

Point Values

func _on_item_resolved(is_trash: bool) -> void:
    if is_trash:
        lives -= 1
    else:
        score += 10

func _on_bonus_resolved(points: int) -> void:
    score += points  # Default: 50 points
  • Regular Food: 10 points
  • Bonus Items: 50 points (configurable)
  • Trash Penalty: -1 life (not score)

Coin Conversion

var coins_earned = int(score * 0.1)
score_manager.add_coins(coins_earned)
Coins = 10% of final score

Difficulty Progression

Dynamic Speed Multiplier

@export var difficulty_interval: float = 30.0
@export var speed_multiplier: float = 1.2
@export var spawn_multiplier: float = 0.85

func _on_DifficultyTimer_timeout() -> void:
    difficulty_stage += 1
    FallingItem.global_speed_multiplier = pow(speed_multiplier, difficulty_stage)
    $SpawnTimer.wait_time *= spawn_multiplier
  • Initial Speed: 1.0x
  • Every 30s: Speed *= 1.2 (20% faster)
  • Spawn Rate: Decreases by 15% each stage
  • Visual Feedback: “¡Más rápido!” message on difficulty increase

Item Spawn Probabilities

@export var bonus_probability: float = 0.05    # 5%
@export var trash_probability: float = 0.35    # 35%
# Food probability: 60% (remainder)

var roll := randf()
if roll < bonus_probability:
    scene = bonus_scene
elif roll < bonus_probability + trash_probability:
    scene = trash_scene
else:
    scene = food_scene

Key Code Examples

Item Spawning System

func _on_spawn_timer_timeout() -> void:
    var scene: PackedScene
    var roll := randf()
    
    if roll < bonus_probability:
        scene = bonus_scene
    elif roll < bonus_probability + trash_probability:
        scene = trash_scene
    else:
        scene = food_scene

    var item = scene.instantiate()
    item.z_index = 20
    
    var spawn_x = randf_range(40.0, max(40.0, screen_size.x - 40.0))
    item.position = Vector2(spawn_x, -40.0)
    
    if item is BonusItem:
        item.connect("resolved_bonus", _on_bonus_resolved)
    else:
        item.connect("resolved", _on_item_resolved)
    
    add_child(item)

Touch Control Implementation

func _ready() -> void:
    touch_left.gui_input.connect(_on_touch_input.bind(-1))
    touch_right.gui_input.connect(_on_touch_input.bind(1))

func _on_touch_input(event: InputEvent, dir: float) -> void:
    if player == null:
        return

    if event is InputEventScreenTouch or event is InputEventMouseButton:
        if event.pressed:
            player.touch_dir = dir
        else:
            player.touch_dir = 0.0

Visual Feedback System

func _on_item_resolved(is_trash: bool) -> void:
    if is_trash:
        _play_varied(sfx_bad, 0.9, 1.0)
        _hud_damage_flash()
        _flash_damage_overlay()
        if player.has_method("play_damage_flash"):
            player.play_damage_flash()
    else:
        _play_varied(sfx_eat, 1.0, 1.15)
        _hud_pop_flash()
        if player.has_method("play_catch_pop"):
            player.play_catch_pop()
        _spawn_floating_text("+10", Color(1, 1, 0.5))

Audio Variation

func _play_varied(player: AudioStreamPlayer, pmin := 0.95, pmax := 1.05) -> void:
    if player == null:
        return
    if player.playing:
        player.stop()
    player.pitch_scale = randf_range(pmin, pmax)
    player.play()
Randomized pitch prevents audio fatigue during repeated actions.

Lives System

var lives: int = 3

func _check_game_over() -> void:
    if lives > 0:
        return
    
    $SpawnTimer.stop()
    
    if player and player.has_method("play_hide_animation"):
        player.play_hide_animation()
        player.play_damage_flash()
    
    await get_tree().create_timer(0.8).timeout
    _show_game_over()

HUD Animation

func _flash_label(label: Label, flash_color: Color, in_time := 0.06, out_time := 0.22):
    var base := label.modulate
    var t := create_tween()
    t.tween_property(label, "modulate", flash_color, in_time)
    t.tween_property(label, "modulate", base, out_time)

func _hud_damage_flash(): 
    _flash_label(lives_label, Color(1.0, 0.4, 0.4))

func _hud_pop_flash():    
    _flash_label(score_label, Color("60e55aff"))

Particle Effects

Food Catch includes decorative underwater particles:
@onready var pescao1der: CPUParticles2D = $pescao1der
@onready var pescao1izq: CPUParticles2D = $pescao1izq
@onready var pescao2der: CPUParticles2D = $pescao2der
@onready var bubbles: CPUParticles2D = $bubbles

func pause_all_particles(pause: bool):
    var particles = [pescao1der, pescao1izq, pescao2der, bubbles]
    for particle in particles:
        if pause:
            particle.emitting = false
            particle.speed_scale = 0.0
        else:
            particle.speed_scale = 1.0
            particle.emitting = true

Screen Configuration

# Portrait mode with underwater theme
DisplayServer.screen_set_orientation(DisplayServer.SCREEN_PORTRAIT)
get_tree().root.set_content_scale_size(Vector2i(270, 480))
  • FallingItem: Base class for all falling objects
  • BonusItem: High-value collectibles with special effects
  • Player Node: Character with horizontal movement and animations
  • DamageBorder: Shader-based screen flash on trash caught

Worm Bucket

Similar catching mechanics with active targeting

Minigames Overview

Return to all minigames

Build docs developers (and LLMs) love