Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/titledgames/microwave-man/llms.txt

Use this file to discover all available pages before exploring further.

Every system in Microwave Man is implemented in GDScript and runs inside Godot’s physics and scene tree. This page documents the exact values and logic behind movement, collection, scoring, and the overall flow from the main menu through to the end screen, drawn directly from the source code.

Movement physics

The player character (player.gd) is a CharacterBody2D. Each physics frame, gravity is applied when the player is not on the floor, and horizontal velocity is set directly from input.
const SPEED = 200.0
const JUMP_VELOCITY = -350.0
const GRAVITY = 980

func _physics_process(delta: float) -> void:
    if not is_on_floor():
        velocity.y += GRAVITY * delta

    var direction := Input.get_axis("move_left", "move_right")

    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

    move_and_slide()
Key values:
  • Speed: 200 px/s horizontal — set instantly when a direction key is held.
  • Gravity: 980 units per second squared, applied every frame while airborne.
  • Deceleration: When no direction key is pressed, move_toward reduces horizontal velocity to 0 at a rate of SPEED (200) per second, producing immediate but smooth stopping rather than a hard snap.

Jumping

Jumping is gated to the floor. The player’s vertical velocity is set to JUMP_VELOCITY (-350) only when the jump action is pressed and is_on_floor() returns true. A sound effect plays on every valid jump.
if Input.is_action_just_pressed("jump") and is_on_floor():
    velocity.y = JUMP_VELOCITY
    audio_player.play()
There is no double-jump, coyote time, or variable jump height in the current implementation.

Animations

The player has two named animations on its AnimatedSprite2D:
  • default — plays whenever the player’s speed vector has a non-zero length (i.e., the player is moving or falling).
  • coin — plays when a coin is collected. While it is active, the is_playing_special flag prevents default from interrupting it.
func play_collect_animation():
    is_playing_special = true
    sprite.play("coin")
When neither condition is true (player is at rest, no special animation) the sprite is stopped entirely rather than showing a looping idle frame. The sprite is also flipped horizontally based on movement direction:
if direction > 0:
    sprite.flip_h = false
elif direction < 0:
    sprite.flip_h = true

Coin collection

Coins are Area2D nodes (coin.gd). When the player’s physics body enters the coin’s area, the following sequence runs:
1

Verify the body is the player

The coin checks body.is_in_group("player") to ignore non-player collisions.
2

Trigger collect animation

If the player has the play_collect_animation method, it is called, setting is_playing_special = true and playing the "coin" sprite animation.
3

Play coin sound

A new instance of coin_sfx.tscn is added to the current scene’s tree. Using a separate scene instance allows overlapping sound effects without interrupting each other.
4

Remove the coin

queue_free() removes the coin node from the scene on the next frame.
func _on_body_entered(body):
    if body.is_in_group("player"):
        if body.has_method("play_collect_animation"):
            body.play_collect_animation()
        var sound_instance = COIN_SOUND_SCENE.instantiate()
        get_tree().current_scene.add_child(sound_instance)
        queue_free()

Scoring

Score is time-based, not coin-based. A ScoreTimer node in main.gd fires on a regular interval, and each timeout increments the score by 1. Collecting coins does not affect the score counter.
func _on_score_timer_timeout() -> void:
    score += 1
    $HUD.update_score(score)
The HUD’s ScoreLabel is updated immediately after each increment via $HUD.update_score(score), which sets the label’s text to the string representation of the current score.

HUD

The HUD (hud.gd) is a CanvasLayer that overlays the gameplay scene. It manages three UI elements:
  • ScoreLabel — displays the current score as a string.
  • Message — a timed text display used for “Get Ready” and “Game Over” messages. After $MessageTimer times out the message hides automatically.
  • StartButton — shown after the Game Over message sequence completes, allowing the player to restart.
func show_game_over():
    show_message("Game Over")
    await $MessageTimer.timeout
    $Message.text = "place holder text"
    $Message.show()
    await get_tree().create_timer(1.0).timeout
    $StartButton.show()

Game flow

1

Main menu

The player sees the title screen (main_menu.tscn). The build version is displayed if set in project settings. Press Play Game to continue.
2

Get Ready

new_game() resets the score to 0, moves the player to the start position, and tells the HUD to show “Get Ready”. The StartTimer provides a brief delay before gameplay begins.
3

Gameplay

The player navigates the level, collecting coins and accumulating time-based score. The ScoreTimer runs continuously until game_over() is called.
4

Reach the end zone

Entering the end.tscn Area2D triggers a scene change to endcreen.tscn.
5

End screen

The player chooses Play Again (restarts via GameState.restart_game signal), Back to Main Menu, or Quit.

Discord Rich Presence

On desktop builds, Microwave Man sets a Discord Rich Presence status using the DiscordRPC engine singleton. This is skipped automatically on the web build.
if not OS.has_feature("web") and Engine.has_singleton("DiscordRPC"):
    var discord_rpc = Engine.get_singleton("DiscordRPC")
    discord_rpc.set("app_id", 1465471267183263922)
    discord_rpc.set("details", "Play as a microwave!")
    discord_rpc.set("state", "Playing the game!")
The status shown in Discord is:
  • Details: Play as a microwave!
  • State: Playing the game!

Build docs developers (and LLMs) love