Skip to content

Minigame Sprite Sizing

Curren edited this page Jun 6, 2026 · 1 revision

Minigame Sprite Sizing — Developer Reference

This document explains how the fishing minigame bar and bobber sprites are positioned and rendered, and exactly which values to change when you resize or reshape those textures.


Quick reference: the five constants you may need to change

Constant Location Current value Formula
BAR GuiTextureItem FishingMinigameAnimation.java:344 (0, 0, 8, 32, 32, 32) see §Sprite definition
BOBBER GuiTextureItem FishingMinigameAnimation.java:345 (0, 0, 8, 32, 32, 32) see §Sprite definition
bobberMaxYOffset FishingMinigameAnimation.java:211 28f / 32f travelZonePx / texturePx
itemMaxYOffset FishingMinigameAnimation.java:222 26f / 32f targetZonePx / texturePx
BOBBER_SIZE FishingMinigameState.java:23 9 / 28f bobberPx / travelZonePx

The three coordinate spaces

Before changing anything, understand what space each value lives in.

1. Physics space (0–1)

Used by FishingMinigameState and FishingTarget. All game logic (gravity, impulses, collision) operates here.

  • 0 = bottom of the bar, 1 = top.
  • The bobber position ranges from 0 to MAX_POSITION = 1 − BOBBER_SIZE.
  • Target positions range from 0 to 1.

2. Texture/model space (−0.5 to +0.5)

Items rendered via fishtastic$renderItem occupy this space centered at the current matrix origin. The full texture (e.g. 32×32 px) maps to the unit square [−0.5, +0.5] in both axes.

Critical: the Y axis is flipped from what you might expect.
In the PNG image, Y=0 is the TOP of the image. In model space (and therefore on screen), Y=0 is the CENTER, with positive Y pointing down on screen. So:

  • Image top pixel row → model Y ≈ +0.5 (screen bottom)
  • Image bottom pixel row → model Y ≈ −0.5 (screen top)

This means to make the bobber appear lower on screen, it needs to sit higher in the PNG image (smaller image Y values).

3. Screen space (pixels)

The bar and bobber are rendered at the center of the screen, scaled by:

// FishingMinigameAnimation.java:205
float scale = 2 * screenHeight / 3f;

One model unit = scale pixels. The bar is exactly 2/3 of the screen height.


How the bar and bobber sprites are defined

// FishingMinigameAnimation.java:344–345
public static final GuiTextureItem BAR    = new GuiTextureItem(0, 0, 8, 32, 32, 32, ...);
public static final GuiTextureItem BOBBER = new GuiTextureItem(0, 0, 8, 32, 32, 32, ...);

The GuiTextureItem record parameters:

Param What it means Current value
u Left edge of the sprite content within the texture (px) 0
v Top edge of the sprite content within the texture (px) 0
uw Width of the sprite content (px) 8
vh Height of the sprite content (px) 32
texWidth Full texture width (px) 32
texHeight Full texture height (px) 32

calculateLocalPivot uses u, v, uw, vh, texWidth, texHeight to compute the visual center of the sprite content within model space, then renderItem shifts the item so that center lands on the coordinate origin. You do not need to manually compute a pivot offset — just keep these values accurate to your texture layout and centering is automatic.


The travel-zone concept

The bar texture is texHeight pixels tall (32 px). However, the bobber does not travel the full height — the top and bottom edges of the bar graphic have decorative borders that the bobber should not enter. The pixels the bobber is allowed to travel through are called the travel zone.

  ┌───────────────┐  ← image Y=0 (= screen bottom via Y-flip)
  │  top margin   │  ← decorative border (currently ~2px)
  ├───────────────┤
  │               │
  │  travel zone  │  ← 28 px tall in current textures
  │               │
  ├───────────────┤
  │ bottom margin │  ← decorative border (currently ~2px)
  └───────────────┘  ← image Y=31 (= screen top via Y-flip)

Define:

  • travelZonePx = pixel height of the travel zone (28 in current textures)
  • texturePx = total texture height (32 in current textures)

bobberMaxYOffset

// FishingMinigameAnimation.java:211
float bobberMaxYOffset = 28f / 32f;  // = travelZonePx / texturePx

This is the total visual range the bobber sprite can be shifted, in model-space units. It converts the physics range [0, MAX_POSITION] into the subset of model space that corresponds to the travel zone inside the bar graphic.

When normalizedBobberPosition = MAX_POSITION, the bobber's translate(0, -yOffset) shifts the sprite by exactly bobberMaxYOffset model units — moving the bobber circle from the bottom to the top of the travel zone.

itemMaxYOffset

// FishingMinigameAnimation.java:222
final float itemMaxYOffset = 26f / 32f;  // = targetZonePx / texturePx

Same concept for the target items (fish/treasure icons). They use a slightly tighter zone (26 px vs 28 px) so target icons do not visually clip the bar caps. They are rendered centered on the bar using targetPosition − 0.5, so a target at physics position 0.5 appears exactly at the bar center.


The bobber's collision size

// FishingMinigameState.java:23
private static final float BOBBER_SIZE = 9 / 28f;  // = bobberPx / travelZonePx

This is the bobber's height as a fraction of the travel zone, in physics space. It determines:

  1. MAX_POSITION = 1 − BOBBER_SIZE — the highest the bobber can reach before its top hits the travel zone ceiling.
  2. Whether a target (at some physics position) overlaps the bobber (which spans [bobberPosition, bobberPosition + BOBBER_SIZE]).

Note: the denominator is travelZonePx, not texturePx. This is the most common mistake when resizing. The bobber's size must be expressed as a fraction of the travel zone, not the full texture.


Step-by-step: changing texture dimensions

Case 1 — Upscale both textures (e.g., 32×32 → 64×64)

If you double the resolution but keep the same visual proportions:

  1. Update GuiTextureItem constructors: texWidth=64, texHeight=64; uw and vh also double (8→16, 32→64).
  2. travelZonePx doubles (28→56), texturePx doubles (32→64): bobberMaxYOffset = 56f / 64fratio is identical, so no gameplay change.
  3. BOBBER_SIZE = 18f / 56f (bobber pixel height doubles from 9→18, travel zone doubles from 28→56) — again identical.
  4. Same for itemMaxYOffset.

If you only change textures but forget to update the record parameters, calculateLocalPivot will produce the wrong centering and the bar/bobber will appear off-center horizontally on screen.


Case 2 — Make the bar taller (more travel room)

Suppose you change the bar texture from 32 px tall to 48 px tall and keep a 4 px total margin, giving a 44 px travel zone. The bobber sprite remains 9 px tall.

Changes needed:

// GuiTextureItem constructors — update texHeight and vh
BAR    = new GuiTextureItem(0, 0, 8, 48, 32, 48, ...);
BOBBER = new GuiTextureItem(0, 0, 8, 48, 32, 48, ...);

// bobberMaxYOffset — new travel zone / new texture height
float bobberMaxYOffset = 44f / 48f;

// itemMaxYOffset — if you also want targets to use the wider zone (keep 2px margins)
final float itemMaxYOffset = 40f / 48f;

// BOBBER_SIZE — bobber pixel height / new travel zone
private static final float BOBBER_SIZE = 9 / 44f;

MAX_POSITION updates automatically because it's computed from BOBBER_SIZE.


Case 3 — Make the bobber larger (easier game)

Suppose you redesign the bobber sprite to be 18 px tall within the same 32 px texture and 28 px travel zone.

The travel zone does not change, so bobberMaxYOffset stays at 28f / 32f.
Only BOBBER_SIZE changes:

// FishingMinigameState.java:23
private static final float BOBBER_SIZE = 18 / 28f;  // = newBobberPx / travelZonePx

A larger BOBBER_SIZE means a smaller MAX_POSITION, so the bobber travels less visual distance but has a wider catch window. This makes the minigame easier.


Case 4 — Change the bar's content width

If you widen the bar sprite from 8 px to 16 px within the same 32×32 texture (so uw=16):

BAR    = new GuiTextureItem(0, 0, 16, 32, 32, 32, ...);
BOBBER = new GuiTextureItem(0, 0, 16, 32, 32, 32, ...);

calculateLocalPivot recalculates x = (0 + 8) / 32 − 0.5 = −0.25 automatically. The pivot shift in renderItem will then center the wider bar on screen correctly. No other constants need to change.

If the bobber sprite is wider than the bar sprite, or positioned at a different horizontal offset (u ≠ 0), set u and uw correctly for each and the pivot logic handles the rest.


Summary: the formula sheet

travelZonePx  = texturePx − topMarginPx − bottomMarginPx
targetZonePx  = texturePx − topTargetMarginPx − bottomTargetMarginPx

bobberMaxYOffset = travelZonePx / texturePx      // in FishingMinigameAnimation
itemMaxYOffset   = targetZonePx / texturePx      // in FishingMinigameAnimation
BOBBER_SIZE      = bobberPx / travelZonePx       // in FishingMinigameState (NOT / texturePx)

The overall bar scale (2 * screenHeight / 3f) is independent of texture size and controls how much of the screen the bar occupies; change it only if you want the overlay to be larger or smaller.