Arrow Selection Wheel Sprint 3 - UQcsse3200/2026-studio-2 GitHub Wiki
Arrow Selection Wheel Sprint 3
The backend for this feature was built in Sprint 2 and is documented on Arrow Selection Wheel. Sprint 3 added the on-screen display, cut the wheel down to the three arrow types the player can actually carry, and fixed the wheel going out of sync when arrows run out.
What changed this sprint
| Change | Why |
|---|---|
| Wheel reduced from four types to three | Poison had no matching ItemType, so that wedge could be highlighted but never selected |
ArrowWheelDisplay added |
The wheel had no visuals, so the player could not see what they were selecting |
getWheelTypes() added |
The display and the direction maths now read the same list, so they cannot drift apart |
| Fallback when arrows run out | The wheel could keep reporting an arrow the player could no longer fire |
PoisonBuff end time changed to long |
A millisecond timestamp was stored in a float and lost precision over a long session |
Three arrow types
| Wedge | Position | Inventory item |
|---|---|---|
| Standard | top | STANDARD_ARROW |
| Fire | 120 degrees clockwise | FIRE_ARROW |
| Ice | 240 degrees clockwise | ICE_ARROW |
ArrowType.forDirection() splits 360 degrees evenly across whatever is in WHEEL_TYPES, so
adding or removing a type needs no change to the direction maths. The list is exposed so the
UI reads the same source of truth:
ArrowType[] types = ArrowType.getWheelTypes(); // {STANDARD, FIRE, ICE}, clockwise from the top
Rope arrow (ArrowType.GRAPPLE) is a real arrow item but is deliberately left off the wheel,
because it is a movement tool rather than a combat arrow. It stays on the hotbar.
Drawing the wheel
ArrowWheelDisplay renders the wheel while it is open. It lays its wedges out from
getWheelTypes(), so the wedge drawn under the pointer is always the one forDirection()
will return.
- The wedge under the pointer is drawn brighter and slightly larger.
- A type the player has no arrows for is greyed out.
- Each label carries its ammo count, for example
Fire x3. - The centre shows the type currently selected.
Running out of arrows
When the last arrow of the selected type is spent, InventoryComponent empties the slot and
moves its selection to the next occupied slot on its own. That slot can hold a potion, which
used to leave the wheel showing an arrow the player could no longer fire.
ArrowWheelComponent now listens for inventorySelectionChanged and falls back to an arrow
type the player still holds, firing arrowSelected so the display updates without the player
reopening the wheel. If the player has no arrows at all, the selection is left alone and
nothing throws.
This needed no change to ItemUseComponent, which is shared across the team.
Read API
| Method | Returns |
|---|---|
isOpen() |
whether the wheel should be drawn |
getHighlighted() |
the type under the pointer, or null in the centre deadzone |
getSelected() |
the type the bow currently fires |
isAvailable(type) |
whether the type can be chosen (unlocked and in the inventory) |
setAvailable(type, unlocked) |
locks or unlocks a type |
Events
| Event | When |
|---|---|
openArrowWheel / closeArrowWheel |
input, on TAB down and up |
arrowWheelPointerMoved |
input, with the pointer's offset from the wheel centre |
arrowWheelOpened / arrowWheelClosed |
the wheel opened or closed |
arrowHighlighted |
the pointer moved onto a different wedge |
arrowSelected |
a type was chosen, or fallen back to |
arrowSelectionRejected |
the highlighted type could not be selected |
inventorySelectionChanged |
listened for, to re-sync when arrows run out |
Testing
| Test class | Covers |
|---|---|
ArrowWheelComponentTest |
opening and closing, pointer highlighting, availability, inventory slot selection, out-of-ammo fallback |
ArrowTypeTest |
wedge geometry for three types, the centre deadzone, directions between wedge centres |
ArrowWheelDisplayTest |
ammo labels, greyed-out and highlighted wedge colours |
ArrowWheelComponent sits at 96.1% line coverage and ArrowType at 97.0%, against a project
average of 58.3%.
Known gaps
ArrowWheelDisplayis a placeholder drawn withShapeRenderer. The UI team is replacing it with a styled version (PR #212).POISONandPOTIONremain inArrowTypefor the thrown poison flask, but neither is a selectable arrow. They should either be documented as such or moved out of the enum.