Cyclops Timing Minigame - UQcsse3200/2026-studio-2 GitHub Wiki
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.
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.
- The intro text box explains the minigame. Left-click (or TAB) advances it, and the minigame starts when it closes.
- The timing bar appears. The player left-clicks to stop the marker.
- Hit: the player runs to the next rock formation.
- 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.
- 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.
- Win: after the last rock, the player reaches the end of the cave. The game plays the post-cyclops cutscene, then loads Level 2.
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.
- 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 (
PlayerFactoryis 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.
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.
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 |
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).
public CyclopsMinigameLogic(
TimingBarLogic logic,
TimingBarDisplay display,
TerrainComponent terrain,
Entity player
)The cyclops minigame logic relies on 4 classes:
- TimingBarLogic: The logic behind the sweeping marker
- TimingBarDisplay: The display of the timing bar
- TerrainComponent: The terrain that the cyclops minigame is being called in. (e.g
TerrainComponent terrain = terrainFactory.createTerrain(TerrainFactory.TerrainType.CYCLOPS_ROOM) - 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>)
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 |
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 |
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.
| 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);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.
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
}
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
}
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
}
Game area to load the map components (cave floor, player, rock formations) and loads and starts the minigame.
A transition screen element for hiding the current screen while transitioning actions take place.
classDiagram
class CyclopsHurtSoundComponent {
~String HURT_EVENT
~int HEALTH_PER_HEART
~float DEATH_VOLUME
~float DEATH_PITCH
+CyclopsHurtSoundComponent(Sound[], float[], Sound) CyclopsHurtSoundComponent
+create() void
}
Draws the cave floor strip repeated across the room, with a dark fill below it.
classDiagram
class CyclopsFloorRenderComponent {
+getLayer() int
}
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
}
Owns the intro text box and decides when the minigame should start.
classDiagram
class CyclopsIntro {
~CyclopsIntro(TextBoxComponent) CyclopsIntro
~isShowing() boolean
~advance() void
~takeStartDue() boolean
}
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
}
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
}
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.