-
Notifications
You must be signed in to change notification settings - Fork 0
Minigame Sprite Sizing
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.
| 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 |
Before changing anything, understand what space each value lives in.
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
0toMAX_POSITION = 1 − BOBBER_SIZE. - Target positions range from
0to1.
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).
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.
// 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 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)
// FishingMinigameAnimation.java:211
float bobberMaxYOffset = 28f / 32f; // = travelZonePx / texturePxThis 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.
// FishingMinigameAnimation.java:222
final float itemMaxYOffset = 26f / 32f; // = targetZonePx / texturePxSame 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.
// FishingMinigameState.java:23
private static final float BOBBER_SIZE = 9 / 28f; // = bobberPx / travelZonePxThis is the bobber's height as a fraction of the travel zone, in physics space. It determines:
-
MAX_POSITION = 1 − BOBBER_SIZE— the highest the bobber can reach before its top hits the travel zone ceiling. - 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.
If you double the resolution but keep the same visual proportions:
- Update
GuiTextureItemconstructors:texWidth=64, texHeight=64;uwandvhalso double (8→16, 32→64). -
travelZonePxdoubles (28→56),texturePxdoubles (32→64):bobberMaxYOffset = 56f / 64f— ratio is identical, so no gameplay change. -
BOBBER_SIZE = 18f / 56f(bobber pixel height doubles from 9→18, travel zone doubles from 28→56) — again identical. - 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.
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.
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 / travelZonePxA 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.
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.
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.