Skip to content

Commit d2ea39a

Browse files
committed
Refactor fuel state
1 parent be1cd1b commit d2ea39a

8 files changed

Lines changed: 45 additions & 43 deletions

File tree

pkg/audio/sound.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func (s *SoundSystem) Update(gs *state.GameState) {
7878
}
7979

8080
s.updateEngine(gs.Speed)
81-
s.updateLowFuel(gs.Controls.LowFuel)
81+
s.updateLowFuel(gs.Controls.FuelState == state.FuelStateLow)
8282
s.updateRefuel(gs)
8383
s.updateFire(gs)
8484
s.updateExplosion(gs)
@@ -142,10 +142,10 @@ func (s *SoundSystem) updateLowFuel(low bool) {
142142
}
143143

144144
// updateRefuel plays the refueling beep once per frame while actively receiving fuel.
145-
// Suppressed when the tank is full (FuelFull is set) — no fuel is being added.
145+
// Suppressed when the tank is full — no fuel is being added.
146146
// The beep (~14.6 ms) finishes well before the next frame, so there is no overlap.
147147
func (s *SoundSystem) updateRefuel(gs *state.GameState) {
148-
if gs.GameplayMode == domain.GameplayRefuel && !gs.Controls.FuelFull {
148+
if gs.GameplayMode == domain.GameplayRefuel && gs.Controls.FuelState != state.FuelStateFull {
149149
rewindAndPlay(s.refuel)
150150
}
151151
}
@@ -176,9 +176,8 @@ func (s *SoundSystem) updateBonusLife(gs *state.GameState) {
176176

177177
// updateFuelFull plays the tank-full beep when the fuel cap is hit.
178178
func (s *SoundSystem) updateFuelFull(gs *state.GameState) {
179-
if gs.Controls.FuelFull {
179+
if gs.Controls.FuelState == state.FuelStateFull {
180180
rewindAndPlay(s.fuelFull)
181-
gs.Controls.FuelFull = false
182181
}
183182
}
184183

pkg/logic/collision.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ func checkFirstHit(s striker, targets []target, r *CollisionResult) (hitResult,
258258
}
259259

260260
// checkFuelOverlap returns true and the object index when the plane overlaps a
261-
// fuel depot. Fuel is not a valid striker target (playerPlane.canHit returns
261+
// fuel depot. FuelState is not a valid striker target (playerPlane.canHit returns
262262
// false for ObjectFuel), so it must be checked separately.
263263
func checkFuelOverlap(plane playerPlane, vp *state.Viewport) bool {
264264
px, py, pw, ph := plane.bounds()

pkg/logic/death_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ func TestResetPerLife_FuelRestored(t *testing.T) {
249249
ResetPerLife(s, noopTerrain)
250250

251251
if s.Fuel != fuelRefuelCap {
252-
t.Errorf("Fuel = %d, want %d", s.Fuel, fuelRefuelCap)
252+
t.Errorf("FuelState = %d, want %d", s.Fuel, fuelRefuelCap)
253253
}
254254
}
255255

pkg/logic/fuel.go

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package logic
22

3-
// Fuel system constants.
3+
import "github.com/morozov/river-raid-ebiten/pkg/state"
4+
5+
// FuelState system constants.
46
const (
57
fuelConsumeTickMask = 1 // consume on even frames
68
fuelConsumeAmount = 1 // fuel consumed per eligible frame
@@ -9,41 +11,30 @@ const (
911
fuelRefuelCap = 252 // "tank full" cap during refueling
1012
)
1113

12-
// FuelResult describes what happened during fuel processing.
13-
type FuelResult int
14-
15-
// Fuel results.
16-
const (
17-
FuelResultNormal FuelResult = iota
18-
FuelResultLowFuel
19-
FuelResultNoFuel
20-
FuelResultFullFuel
21-
)
22-
2314
// UpdateFuel processes fuel consumption and refueling for one frame.
2415
// tick is the current frame counter. refueling is true if the plane is over a depot.
2516
// Returns the new fuel level and any triggered events.
26-
func UpdateFuel(fuel, tick int, refueling bool) (int, FuelResult) {
17+
func UpdateFuel(fuel, tick int, refueling bool) (int, state.FuelState) {
2718
if refueling {
2819
fuel += fuelIntakeAmount
2920

3021
if fuel >= fuelRefuelCap {
3122
if fuel > fuelRefuelCap {
3223
fuel = fuelRefuelCap
3324
}
34-
return fuel, FuelResultFullFuel
25+
return fuel, state.FuelStateFull
3526
}
3627
} else if tick&fuelConsumeTickMask == 0 {
3728
fuel -= fuelConsumeAmount
3829
}
3930

4031
if fuel <= 0 {
41-
return 0, FuelResultNoFuel
32+
return 0, state.FuelStateEmpty
4233
}
4334

4435
if fuel < fuelLowThreshold {
45-
return fuel, FuelResultLowFuel
36+
return fuel, state.FuelStateLow
4637
}
4738

48-
return fuel, FuelResultNormal
39+
return fuel, state.FuelStateNormal
4940
}

pkg/logic/fuel_test.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package logic
22

3-
import "testing"
3+
import (
4+
"testing"
5+
6+
"github.com/morozov/river-raid-ebiten/pkg/state"
7+
)
48

59
func TestUpdateFuel_ConsumesOnEvenTick(t *testing.T) {
610
t.Parallel()
@@ -42,37 +46,37 @@ func TestUpdateFuel_EmptyTriggersDeath(t *testing.T) {
4246
t.Errorf("fuel = %d, want 0", fuel)
4347
}
4448

45-
if result != FuelResultNoFuel {
46-
t.Error("expected FuelResultNoFuel")
49+
if result != state.FuelStateEmpty {
50+
t.Error("expected FuelStateEmpty")
4751
}
4852
}
4953

5054
func TestUpdateFuel_LowFuelWarning(t *testing.T) {
5155
t.Parallel()
5256

5357
_, result := UpdateFuel(63, 1, false)
54-
if result != FuelResultLowFuel {
55-
t.Error("expected FuelResultLowFuel at 63")
58+
if result != state.FuelStateLow {
59+
t.Error("expected FuelStateLow at 63")
5660
}
5761

5862
_, result = UpdateFuel(64, 1, false)
59-
if result != FuelResultNormal {
60-
t.Error("expected no FuelResultNormal at 64")
63+
if result != state.FuelStateNormal {
64+
t.Error("expected FuelStateNormal at 64")
6165
}
6266
}
6367

6468
func TestUpdateFuel_FuelFullOnCapTransition(t *testing.T) {
6569
t.Parallel()
6670

67-
// Fuel just below cap → transitions to cap: FuelFull should be set.
71+
// FuelState just below cap → transitions to cap: FuelFull should be set.
6872
_, result := UpdateFuel(250, 0, true)
69-
if result != FuelResultFullFuel {
70-
t.Error("expected FuelResultFullFuel when fuel reaches cap")
73+
if result != state.FuelStateFull {
74+
t.Error("expected FuelStateFull when fuel reaches cap")
7175
}
7276

7377
// Not refueling with enough fuel.
7478
_, result = UpdateFuel(250, 0, false)
75-
if result != FuelResultNormal {
76-
t.Error("expected no FuelResultNormal when not refueling")
79+
if result != state.FuelStateNormal {
80+
t.Error("expected FuelStateNormal when not refueling")
7781
}
7882
}

pkg/logic/gameplay.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,8 @@ func step(s *state.GameState, in input.Interface, terrain TerrainRenderer) {
131131
advanceAndRender(s, int(s.Speed), terrain)
132132

133133
// step 10: Handle fuel consumption.
134-
var fuelResult FuelResult
135-
s.Fuel, fuelResult = UpdateFuel(s.Fuel, int(s.Tick), s.GameplayMode == domain.GameplayRefuel)
136-
s.Controls.LowFuel = fuelResult == FuelResultLowFuel
137-
s.Controls.FuelFull = fuelResult == FuelResultFullFuel
138-
if fuelResult == FuelResultNoFuel {
134+
s.Fuel, s.Controls.FuelState = UpdateFuel(s.Fuel, int(s.Tick), s.GameplayMode == domain.GameplayRefuel)
135+
if s.Controls.FuelState == state.FuelStateEmpty {
139136
triggerDeath(s)
140137
return
141138
}

pkg/state/fuel.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package state
2+
3+
// FuelState represents the current fuel condition.
4+
type FuelState int
5+
6+
// FuelState states.
7+
const (
8+
FuelStateNormal FuelState = iota
9+
FuelStateLow
10+
FuelStateEmpty
11+
FuelStateFull
12+
)

pkg/state/state.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ import (
99
// ControlFlags holds the expanded state of the original control byte.
1010
type ControlFlags struct {
1111
Speed domain.Speed
12+
FuelState FuelState
1213
FireSound bool
13-
LowFuel bool
14-
FuelFull bool
1514
BonusLife bool
1615
Exploding bool
1716
}

0 commit comments

Comments
 (0)