Files
2026-07-15 01:28:56 -04:00

48 lines
1.4 KiB
Go

package render
import (
"time"
"symph/game"
"symph/parameter"
"symph/types"
)
// FadeGrid projects the engine's consumed-note ring onto strip coordinates for
// one frame: burn-out progress per (y, x, chord-distance). Entries outside the
// window or past ItemFadeDuration are dropped. A consumed cell at distance 0
// scrolls off on the next beat; the fade is shorter than the tightest beat, so
// it always resolves before the strip shifts
type FadeGrid struct {
value [parameter.GamePlayIndexYMax][parameter.GamePlayIndexXMax][game.TileLookaheadMaxWindow]types.Value
t [parameter.GamePlayIndexYMax][parameter.GamePlayIndexXMax][game.TileLookaheadMaxWindow]float64
}
func (f *FadeGrid) Refresh(s *game.GameState, now time.Time) {
*f = FadeGrid{}
for _, c := range s.Consumed() {
if c.Value == types.ValueNone {
continue
}
age := now.Sub(c.At)
if age < 0 || age >= parameter.ItemFadeDuration {
continue
}
d := c.Z - s.CurrentPlayIndexZ
if d < 0 || d >= game.TileLookaheadMaxWindow {
continue
}
f.value[c.Y][c.X][d] = c.Value
f.t[c.Y][c.X][d] = float64(age) / float64(parameter.ItemFadeDuration)
}
}
// At reports the item burning out at a strip cell and its progress in [0,1)
func (f *FadeGrid) At(y, x, d int) (types.Value, float64, bool) {
if d < 0 || d >= game.TileLookaheadMaxWindow {
return types.ValueNone, 0, false
}
v := f.value[y][x][d]
return v, f.t[y][x][d], v != types.ValueNone
}