Cyclops Timing Minigame - UQcsse3200/2026-studio-2 GitHub Wiki

Introduction

Cyclops Timing Minigame is a minigame where the player attempts to move between rock formations (safe locations) in the cyclops' cave to hide from a cyclops enemy. Before moving to the next rock, the player attempts a timing minigame: a marker sweeps across a bar, and the player needs to stop the marker in the target zone (gold area).

Missing the timing costs the player a heart. Losing all 5 hearts ends the minigame with a game-over menu. Reaching the end of the cave wins the minigame and moves the player on to the next cutscene and Level 2.

Key Components

These are the key components necessary for the cyclops timing minigame to run as a self sustaining minigame:

  • TimingBarLogic: The logic that moves a marker back and forward along a bar

  • TimingBarDisplay: The display element that shows the timing bar

  • CyclopsMinigameLogic: Game logic for minigame. Handles showing and running timing bar minigame, moving the player to the next location, and the loss / retreat / death states

  • CyclopsMinigameArea: Game area to load the map components (cave background, cave floor, player, rock formations, the cyclops on his rock) and loads and starts the minigame.

  • BlankTransitionScreenCover: A transition screen element for hiding the current screen while transitioning actions take place.

  • CyclopsHurtSoundComponent: Plays a hurt voice each time the player loses a heart. The voice gets more intense as hearts run out, and a heavier version plays on death.

  • CyclopsFloorRenderComponent: Draws the cave floor strip repeated across the room, with a dark fill below it.

  • CyclopsCameraFollowComponent: Moves the camera to follow the player horizontally, keeping the view inside the room. Shakes the camera briefly each time the cyclops lands.

  • CyclopsIntro: Owns the intro text box and decides when the minigame should start. The intro is skipped when restarting from the game-over menu.

  • CyclopsAnimationController: Plays the cyclops's animations. He sleeps on a rock in the middle of the cave. When the player is caught he jumps down next to them and swings his club, then jumps home and falls asleep again once the player is back at a rock.

  • CyclopsSoundComponent: Plays the cyclops's sounds: snoring while asleep, a roar when he wakes, a thud when he lands and a crack when his club hits.

Gameplay Loop

  1. The intro text box explains the minigame. Left-click (or TAB) advances it, and the minigame starts when it closes.
  2. The timing bar appears. The player left-clicks to stop the marker.
  3. Hit: the player runs to the next rock formation.
  4. Miss: the player is caught in the gap. The cyclops wakes with a roar, jumps down next to the player and swings his club. When the club lands, the player loses 1 heart (2 HP) and plays a hurt sound, then runs back to the last rock and retries. The cyclops jumps back to his rock and goes back to sleep.
  5. Death: at 0 hearts, a heavier death sound plays and the GAME OVER menu appears with Restart, Main Menu and Exit Game. Restart reloads the minigame and skips the intro.
  6. Win: after the last rock, the player reaches the end of the cave. The game plays the post-cyclops cutscene, then loads Level 2.

Difficulty

The target zone shrinks as the player progresses, going linearly from 20% of the bar at the first rock to 10% at the last. With 6 rocks, that is 20% → 18% → 16% → 14% → 12% → 10%. The zone flashes white when it shrinks, so the player notices the change.

Room Layout

  • 6 rock formations, spaced evenly across an 80-tile-wide room. The 3 formation sprites cycle across the 6 positions, and each is scaled to be about 1.7x the player's height.
  • The player is 1.5x bigger in the minigame only (PlayerFactory is unchanged).
  • The cave floor sits 20% up the screen, and the camera follows the player along the room.
  • A cave background sits behind the room and scrolls slower than the camera (parallax).
  • The cyclops sleeps standing on a rock platform in the middle of the room, drawn behind the rock formations and the player.

Usage

Loading the Cyclops Minigame

Loading the cyclops minigame involves switching to the minigame screen.

game.setScreen(GdxGame.ScreenType.CYCLOPS_MINIGAME);
/* Where game :  GdxGame */

Alternatively,

The cyclops minigame can be loaded and switched to by triggering the load command from the CyclopsMinigameEventHandler, which is retrieved via ServiceLocator.getCyclopsMinigameEventHandler(). Then trigger("load"). This saves the current player (see the PlayerSnapshot Saving System page) and plays the pre-cyclops cutscene (cutscene2) before switching to the minigame screen.

Debug Terminal Commands

Open the terminal with F1 and run cyclopsMinigame <command>:

Command What it does
load Saves the player, plays the pre-cyclops cutscene and loads the minigame
start / stop / restart Starts, stops or restarts the minigame
success / failure Forces a timing hit or miss
show / hide Shows or hides the timing bar

Loading Cyclops Minigame Area

To create and load the Cyclops Minigame Area, call the following code from a screen.

CameraComponent camera = renderer.getCamera();
TerrainFactory terrainFactory = new TerrainFactory(renderer.getCamera());

CyclopsMinigameArea minigame = new CyclopsMinigameArea(camera, terrainFactory);
minigame.create();

On create, the minigame area handles loading assets and spawning the terrain, cave floor, rock formations and player. The minigame itself is started by CyclopsMinigameRoomScreen, which triggers start once the intro text box is dismissed (or straight away when restarting from the game-over menu).

Creating the Minigame Logic

public CyclopsMinigameLogic(
    TimingBarLogic logic,
    TimingBarDisplay display,
    TerrainComponent terrain,
    Entity player
)

The cyclops minigame logic relies on 4 classes:

  1. TimingBarLogic: The logic behind the sweeping marker
  2. TimingBarDisplay: The display of the timing bar
  3. TerrainComponent: The terrain that the cyclops minigame is being called in. (e.g TerrainComponent terrain = terrainFactory.createTerrain(TerrainFactory.TerrainType.CYCLOPS_ROOM)
  4. Entity: The player entity

The terrain component is necessary as the cyclops minigame logic handles moving the player between safe / loss locations. Both of which are given through calls to: setWinLocation(Gridpoint2), setLossLocations(List<Gridpoint2>), setSafeLocations(List<Gridpoint2>)

Implementation Specifics and UML Diagram

Minigame States

CyclopsMinigameLogic runs as a state machine:

State What happens
STOP Minigame is not running
SHOW_DELAY Short pause before the timing bar appears
PLAY Timing bar is active, waiting for the player to click
HIDE_DELAY Short pause after the click, before the outcome
PRE_MOVE / MOVING Player runs to the next rock
LOSS Player is caught in the gap and takes damage
RETREAT Player runs back to the last rock to retry
DEATH Player has 0 hearts; the game-over menu is shown
WIN Player reached the end of the cave

Cyclops States

CyclopsAnimationController runs its own state machine, driven by the cyclopsWake and cyclopsSleep events:

State Animation What happens
ASLEEP sleep Snoring on his rock
CHARGING charge_start Winds up, facing the player
JUMPING jump Jumps in an arc to land next to the player. The camera shakes on landing
ATTACKING attack Swings his club. On frame 8 the club lands and triggers cyclopsHit
AWAKE idle Stands awake while the player runs back
RETURNING jump Jumps back to his rock, then goes back to ASLEEP

CyclopsMinigameEventHandler

The CyclopsMinigameEventHandler is designed to handle the loading of the cyclops minigame from anywhere in the LibGDX game, as well as handle any dev commands implemented into the minigame logic.

Events

Event Triggered by Purpose
start, stop, restart Commands / screen Control the minigame
success, failure Debug commands Force a timing hit or miss
win CyclopsMinigameLogic Player reached the end; the screen loads the next cutscene and Level 2
died CyclopsMinigameLogic Player lost all hearts; the screen shows the game-over menu
cyclopsWake CyclopsMinigameLogic The player was caught after a miss. The cyclops wakes up and attacks
cyclopsSleep CyclopsMinigameLogic The player is safely back at a rock after retreating, or the minigame restarted. The cyclops jumps home and goes back to sleep
cyclopsHit CyclopsAnimationController The cyclops's club landed on the caught player. CyclopsMinigameLogic takes the heart and moves to LOSS or DEATH

Example of hooking cyclops art up to the cyclops waking up:

ServiceLocator.getCyclopsMinigameEventHandler()
    .addListener(CyclopsMinigameLogic.CYCLOPS_WAKE_EVENT, this::openEye);

Assets & Sound Effects

Game Area:

  • "sounds/minigames/cyclops/cave_background_noise.mp3"
  • "images/minigames/Cyclops/CyclopsCaveFloor.png"
  • "images/minigames/Cyclops/cave_formation_1.png"
  • "images/minigames/Cyclops/cave_formation_2.png"
  • "images/minigames/Cyclops/cave_formation_3.png"
  • "images/minigames/Cyclops/cave_background.png"
  • "images/minigames/Cyclops/cave_rock_platform.png"

Timing Bar:

  • "images/minigames/Cyclops/timing_bar_frame.png"

Minigame Logic:

  • "sounds/walkingSounds/walkingSound.mp3"
  • "sounds/minigames/cyclops/marker-hit.ogg"
  • "sounds/minigames/cyclops/marker-miss.ogg"

Hurt Sounds (from the sound effects work in #184):

  • "sounds/hurt_player_1.wav"
  • "sounds/hurt_player_2.wav"
  • "sounds/hurt_player_3.wav"
  • "sounds/hurt_player_4.wav"

Cyclops:

  • "images/minigames/Cyclops/cyclops.atlas" (animations: sleep, idle, charge_start, jump, attack)
  • "sounds/minigames/cyclops/snore.wav"
  • "sounds/minigames/cyclops/roar.wav"
  • "sounds/minigames/cyclops/landing.wav"
  • "sounds/minigames/cyclops/club-hit.wav"

All minigame sounds follow the volume slider in settings through GameVolume.

Class Diagrams of Components

TimingBarLogic

The logic that moves a marker back and forward along a bar

classDiagram
    class TimingBarLogic {
        %% Attributes %%
        -float barStart
        -float barWidth
        -float scoringAreaSize
        -float markerSpeed
        -int direction
        -float markerX
        -float greenStart
        -float greenEnd
        -boolean isStopped
        %% Methods %%
        +TimingBarLogic(float) TimingBarLogic
        +getMarkerX() float
        +getScoringAreaSize() float
        +changeScoringAreaWidth(float) void
        +update(float) void
        +stopMarker() void
        +startMarker() void
        +resetMarker() void
        +checkHit() boolean
    }
Loading

TimingBarDisplay

The display element that shows the timing bar, styled to match the game's royal UI (copper frame, teal track, gold target zone, ivory marker). The target zone resizes and flashes when it shrinks.

classDiagram
    class TimingBarDisplay {
        %% Attributes %%
        ~float MARKER_WIDTH
        ~float BAR_WIDTH
        ~float BAR_HEIGHT
        ~String FRAME_TEXTURE
        ~int FLASH_FRAMES
        -TimingBarLogic logic
        -Image scoringZone
        -Image marker
        -boolean visible
        %% Methods %%
        +TimingBarDisplay(TimingBarLogic) TimingBarDisplay
        +setVisible(boolean) void
        +isVisible() boolean
        +create() void
        +update() void
        #draw(SpriteBatch) void
        +dispose() void
    }
Loading

CyclopsMinigameLogic

Game logic for minigame. Handles showing and running timing bar minigame, moving the player to the next location, and the loss / retreat / death states

classDiagram
    class CyclopsMinigameLogic {
        %% Attributes %%
        ~int MISS_DAMAGE
        ~float START_SCORING_PERCENT
        ~float END_SCORING_PERCENT
        ~float CAUGHT_TIMEOUT
        +String CYCLOPS_WAKE_EVENT
        +String CYCLOPS_SLEEP_EVENT
        +String CYCLOPS_HIT_EVENT
        %% Methods %%
        +CyclopsMinigameLogic(TimingBarLogic, TimingBarDisplay, TerrainComponent, Entity) CyclopsMinigameLogic
        +setWinLocation(GridPoint2) void
        +setLossLocations(List~GridPoint2~) void
        +setSafeLocations(List~GridPoint2~) void
        +setPlayerOffset(Vector2) void
        +areNextSafeLocations() boolean
        ~scoringPercentForRock(int, int) float
        ~timingSuccess() void
        ~timingFailure() void
        ~takeCyclopsHit() void
        +startMinigame() void
        +stopMinigame() void
        +restartMinigame() void
        +create() void
        +update() void
        +dispose() void
    }
Loading

CyclopsMinigameArea

Game area to load the map components (cave floor, player, rock formations) and loads and starts the minigame.

BlankTransitionScreenCover

A transition screen element for hiding the current screen while transitioning actions take place.

CyclopsHurtSoundComponent

classDiagram
    class CyclopsHurtSoundComponent {
        ~String HURT_EVENT
        ~int HEALTH_PER_HEART
        ~float DEATH_VOLUME
        ~float DEATH_PITCH
        +CyclopsHurtSoundComponent(Sound[], float[], Sound) CyclopsHurtSoundComponent
        +create() void
    }
Loading

CyclopsFloorRenderComponent

Draws the cave floor strip repeated across the room, with a dark fill below it.

classDiagram
    class CyclopsFloorRenderComponent {
        +getLayer() int
    }
Loading

CyclopsCameraFollowComponent

Moves the camera to follow the player horizontally, keeping the view inside the room. Shakes the camera when the cyclops lands.

classDiagram
    class CyclopsCameraFollowComponent {
        ~float SHAKE_DURATION
        ~float SHAKE_STRENGTH
        +CyclopsCameraFollowComponent(Entity, Camera, float, float) CyclopsCameraFollowComponent
        +update() void
        +shake() void
    }
Loading

CyclopsIntro

Owns the intro text box and decides when the minigame should start.

classDiagram
    class CyclopsIntro {
        ~CyclopsIntro(TextBoxComponent) CyclopsIntro
        ~isShowing() boolean
        ~advance() void
        ~takeStartDue() boolean
    }
Loading

CyclopsAnimationController

Plays the cyclops's animations and moves him when the player is caught.

classDiagram
    class CyclopsAnimationController {
        +float ATTACK_FRAME_TIME
        +String LANDED_EVENT
        ~int IMPACT_FRAME
        ~float CLUB_REACH
        ~float JUMP_DURATION
        ~float JUMP_HEIGHT
        ~String WOKE_UP_EVENT
        ~String CLUB_LANDED_EVENT
        ~String FELL_ASLEEP_EVENT
        +CyclopsAnimationController(Entity, float) CyclopsAnimationController
        +create() void
        +update() void
        ~getState() State
    }
Loading

CyclopsSoundComponent

Plays the cyclops's snoring, roar, landing and club sounds.

classDiagram
    class CyclopsSoundComponent {
        +String SNORE_PATH
        +String ROAR_PATH
        +String LANDING_PATH
        +String CLUB_HIT_PATH
        ~float SNORE_VOLUME
        ~float ROAR_VOLUME
        ~float LANDING_VOLUME
        ~float CLUB_HIT_VOLUME
        +create() void
        +dispose() void
    }
Loading

Testing

The cyclops minigame is covered by unit tests in source/core/src/test:

Test class What it covers
CyclopsMinigameLogicTest Loss / retreat states, damage and death, difficulty (zone shrinking), wake / sleep events
TimingBarDisplayTests Bar restyle, zone resizing and flash
CyclopsHurtSoundComponentTest Correct hurt voice per heart, heavier death sound
CyclopsMinigameRoomScreenTest Game-over menu, restart skipping the intro
CyclopsIntroTest Intro starting / skipping the minigame
CyclopsRoomLayoutTest Rock spacing across the room
CyclopsCaveFormationTest Formation textures cycle in order and are taller than the player
CyclopsCameraFollowComponentTest Camera follows the player and stays inside the room
CyclopsMinigameAreaTest Area setup
CyclopsMinigameCommandTest Terminal command
CyclopsMinigameDisplayTest Minigame display
CyclopsMinigameLogicTest Loss / retreat, damage on the cyclops's hit, death, difficulty, wake / sleep events
CyclopsCameraFollowComponentTest Follows the player, stays in the room, shakes on landing
CyclopsAnimationControllerTest Sleep, jump, attack and return
CyclopsSoundComponentTest Snore, roar, landing and club sounds

Manual testing: run the game, open the terminal with F1 and run cyclopsMinigame load. Miss a few times to check the hurt sounds and run-back, lose all hearts to check the game-over menu and Restart, and win through all 6 rocks to check the cutscene and Level 2 transition.

⚠️ **GitHub.com Fallback** ⚠️