Same parts, fourth game - fishing

The joystick went in during Part 6 and became a shooter. That made three games, and we wrote that the cabinet was next - but we decided to build one more first.

This time there are no new parts. We reuse the beer lever that has been there since Part 1 and the vibration motor added in Part 2. Treat the lever as a fishing rod and the vibration as bites and line tension, and you have fishing.

The original design - two formulas, tension and progress

Tension and progress were set up as two forces pulling in opposite directions.

tension  = (fish strength + lever) ÷ 2      → if both are high, the line snaps
progress = (lever − fish strength) ÷ 50     → the lever has to win to reel it in

The same single lever helps you on one side and threatens you on the other. On paper it is rather elegant. We added casting strength to set distance, plus the gamble that a longer cast hooks bigger fish but makes you wait longer for a bite.

We built it. We played it. It was not fun.

That is where this post actually begins. There were four moments of “something is wrong here,” and each time a vague impression had exactly one number hiding behind it.

First - four casting stages, “no idea what to do”

Casting was the problem. Pull and release the lever to cast, wait for a bite, pull again to set the hook, then fight the fish. That is four stages. You have one lever in your hand and it has to perform four different actions, so you cannot tell what you are doing.

The cleanup was simple. We removed casting entirely. The float is already in the water, you strike when a bite comes, and after that you hold on. The player’s job dropped to two things.

We changed the win condition too. Instead of the abstract “fill the progress gauge,” it became “reduce the fish’s stamina to zero.” Pull harder and the fish tires faster, but the line gets more dangerous - the trade-off survives intact and the explanation fits in one sentence.

Second - the averaged tension formula, “the line never wears down”

The tension formula is the most interesting point in the post.

Tension was (fish strength + lever) ÷ 2, an average. An average means the lever can contribute at most half, no matter how hard you pull. Pushing the lever to its physical limit gave 575 against a minnow and 650 against a crucian carp. The danger line was 800.

None of the four fish could reach the danger line. The trade-off had never once existed.

Tension formula change - from average to weighted sum

On the left, before. Even at full lever, all four bars stay below the red danger line. On the right, after. The weights sum to more than one (0.7 + 0.5), so pulling hard actually fills the gauge.

We changed it so the lever dominates and fish strength stacks on top. Even with fish strength at zero, a maxed lever gives 693 - pulling hard is dangerous even with nothing on the hook. A game where the gauge stops at half and a game where it fills to the top have completely different feel.

We learned one more thing. The user said “tension never goes all the way up,” and our first suspicion was the lever hardware. In fact the lever was reaching 990 perfectly well, and the problem was our own formula dividing that value in half. Look at your own math before you suspect the input.

Third - thrash timing, “the fish are too easy to catch”

Difficulty was still too low even with the line wearing down. There were two causes.

Thrashes arrived like a trailer. We had added stretches where the fish suddenly exerts itself, but capped the strength change at 40 per tick. Going from a normal 420 to a thrash of 950 takes 13 ticks, or 1.3 seconds. You watch the gauge creep upward and calmly lower the lever. That is not a threat, it is a public address announcement.

We changed it to swing 250 per tick, reaching maximum in 0.3 seconds. The decay stays slow, so once it bites you have to hold on for a while.

Small fish never experienced a thrash at all. The first thrash arrived after the normal interval (2.64.4 seconds), but a minnow fight ends in 2.1 seconds and a crucian carp in 3.5. Arithmetically a thrash could not happen. They were fish you caught by simply pulling. Moving the first thrash up to 0.51.2 seconds gives every fish at least one moment of crisis.

And then exactly what the user asked for: “make the line wear faster when the fish moves.” During a thrash the line now wears at double rate. A sudden shock breaking the line is more fishing-like than steady tension anyway.

FishHold on and endureEase off during thrashes
Minnowlanded in 2.1s (line down to 243)landed in 2.7s
Crucian carpline snapped at 1.8slanded in 5.0s
Carpline snapped at 1.7slanded in 8.6s
Trophy catchline snapped at 1.7slanded in 13.5s

Small fish can be muscled in; big fish absolutely must be managed. Only then did something called “skill” appear.

Fourth - the hook-set condition, “I feel no vibration at all”

The bite vibration was set to buzz on a bite, and the report was that nothing could be felt. The ladder logic checked out, and the beer game’s vibration had measured normal that morning. The motor and the wiring were both fine.

The culprit was the hook-set condition.

if (lever position >= 450) hook set

What happens if you wait for a bite with the lever already pulled? The instant the bite comes, this condition is already true. The hook sets in one scan, the bite window closes within milliseconds, and the vibration never gets time to fire. It was code that only worked in the picture in our head, where you wait with your hand off and then strike.

We changed it from absolute position to how much you raised it. After the window opens, you have to pull 350 above the lowest lever value observed. Wherever you start, you have to perform a real strike - and as a side effect the bite vibration keeps buzzing until you pull. The “now!” signal we originally intended finally works as a signal.

We hid the fish behind an identical shadow

Hiding the fish was not a fix but an addition.

The fish was visible on screen the moment it hooked. See a trophy catch and you think “careful now”; see a minnow and you think “just yank it.” Knowing the outcome in advance removes the tension.

During the fight, only the underwater shadow is visible. You can tell something heavy is on, but not what it is. Only when you land it does “a trophy catch!!” appear. Lose it and you never find out - “the line snapped, I wonder what that was.”

Four species rendered in the same state

All four species, from minnow to trophy catch, rendered in the same state. Only the stamina gauge maximum differs; the shadows are completely identical.

There was a trap here. Drawing the shadow scaled to the fish leaks its identity through size. So does movement intensity - a minnow has 150 strength and a trophy catch 420, so setting the sway from that value gives it away by amplitude alone.

So size and shape are hard-coded constants, and the sway is set not from absolute values but from a 0 to 1 normalization between this fish’s normal and thrash levels. Whatever the species, normal is 0 and thrash is 1, so the amplitude matches. And rather than eyeball it and conclude “looks about the same,” we rendered all four species in the same state and compared pixel hashes. Only matching hashes prove they really are identical.

The only clues to the size now are the vibration in your hand and the tension gauge. A game about looking at a picture became a game about reading sensations.

Fish artwork, to the generative AI again

The fish artwork went to Gemini, as with the bartender in Part 4 and the ships in Part 6. A one-line prompt produced all four species lined up in size order.

The four fish species

From the left: minnow, crucian carp, carp, and trophy catch.

This time it needed a small trick. There was an AI-generation star mark embedded at the bottom right of the image, and background removal would not erase it, because it is an island separated from the background. Analyzing connected components and keeping only the four large blobs (the fish) cleaned it up.

The side effect was entertaining. That star had been inflating the bounding box of the trophy catch sprite, so removing it corrected the trophy catch’s size from 300×287 to 300×201. That was why it had looked oddly chubby on screen.

Recap: lessons from balancing the fishing game

  • “It is not fun” always points at one number. Too fiddly → four stages. Line never snaps → an average contributing only half. Too easy → a thrash telegraphed over 1.3 seconds. No vibration → a check that completes in one scan. Four out of four.
  • Look at your own formula before you suspect the input. Told the lever would not go all the way up, we dug into hardware first; the lever reached 990 fine and the problem was our own division by 2.
  • An average halves each contribution. When combining two values into one, the habit is to average them, and then neither side can reach the maximum alone. It is worth asking once whether that is what you intended.
  • Verify “it is hidden” with a hash, not with your eyes. Looking similar and being identical are different. Leak size, shape, or motion, and the hiding was pointless.

That makes four games: beer, blackjack, shooter, and fishing. The parts are one lever, four buttons, one joystick, and one vibration motor. Four times over, we confirmed that reading the same handle differently gives you a different game.

Now it really is time to tidy up the cabinet.

“It is not fun” always points at one number you can go and fix.

Earlier chapters: Parts 1 through 6.

Contact