Add grace-controlled grazing
This commit is contained in:
parent
651adcc71a
commit
122590d10b
3 changed files with 37 additions and 10 deletions
|
|
@ -18,6 +18,6 @@ const (
|
||||||
BULLET_OFFSCREEN_BUFFER_WIDTH float64 = 16.0
|
BULLET_OFFSCREEN_BUFFER_WIDTH float64 = 16.0
|
||||||
PLAYER_HIT_COL_RADIUS_MULTIPLIER float64 = 0.01
|
PLAYER_HIT_COL_RADIUS_MULTIPLIER float64 = 0.01
|
||||||
PLAYER_GRAZE_COL_RADIUS_MULTIPLIER float64 = 0.04
|
PLAYER_GRAZE_COL_RADIUS_MULTIPLIER float64 = 0.04
|
||||||
PLAYER_DEATH_TIMER_MAX int64 = 180
|
PLAYER_DEATH_TIMER_MAX int64 = 240
|
||||||
GRAZE_ADDITION_MULTIPLIER int = 1000
|
GRAZE_ADDITION_MULTIPLIER int = 1000
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/heroiclabs/nakama-common/runtime"
|
"github.com/heroiclabs/nakama-common/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ type PlayerStageState struct {
|
||||||
updatePlayerPos bool
|
updatePlayerPos bool
|
||||||
health int
|
health int
|
||||||
graze int
|
graze int
|
||||||
score int
|
grazePerTick map[int64]int
|
||||||
deathTick int64
|
deathTick int64
|
||||||
dead bool
|
dead bool
|
||||||
cancelDeath bool
|
cancelDeath bool
|
||||||
|
|
@ -25,6 +25,15 @@ type PlayerStageState struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PlayerStageState) ProcessPlayerInputs(tick int64) {
|
func (s *PlayerStageState) ProcessPlayerInputs(tick int64) {
|
||||||
|
// Lock-in the earned graze
|
||||||
|
cutoffTick := tick - GRACE_WINDOW_TICKS
|
||||||
|
for t, v := range s.grazePerTick {
|
||||||
|
if t < cutoffTick {
|
||||||
|
s.graze += v
|
||||||
|
delete(s.grazePerTick, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up inputs outside the grace window
|
// Clean up inputs outside the grace window
|
||||||
s.playerInputs = slices.DeleteFunc(s.playerInputs, func(input *ClientUpdate) bool {
|
s.playerInputs = slices.DeleteFunc(s.playerInputs, func(input *ClientUpdate) bool {
|
||||||
return tick-input.Tick > GRACE_WINDOW_TICKS
|
return tick-input.Tick > GRACE_WINDOW_TICKS
|
||||||
|
|
@ -37,7 +46,7 @@ func (s *PlayerStageState) ProcessPlayerInputs(tick int64) {
|
||||||
|
|
||||||
// Replay each tick within the grace window
|
// Replay each tick within the grace window
|
||||||
s.survivedGraceWindow = true
|
s.survivedGraceWindow = true
|
||||||
for t := tick - GRACE_WINDOW_TICKS; t < tick; t++ {
|
for t := tick - GRACE_WINDOW_TICKS; t <= tick; t++ {
|
||||||
// Find the input for the current tick
|
// Find the input for the current tick
|
||||||
var currentInput *ClientUpdate
|
var currentInput *ClientUpdate
|
||||||
for _, input := range s.playerInputs {
|
for _, input := range s.playerInputs {
|
||||||
|
|
@ -58,7 +67,15 @@ func (s *PlayerStageState) ProcessPlayerInputs(tick int64) {
|
||||||
// If the player dies in the grace window, don't cancel their death
|
// If the player dies in the grace window, don't cancel their death
|
||||||
if s.CheckPlayerDeadOnTick(t) {
|
if s.CheckPlayerDeadOnTick(t) {
|
||||||
s.survivedGraceWindow = false
|
s.survivedGraceWindow = false
|
||||||
|
|
||||||
|
for grazeT := range s.grazePerTick {
|
||||||
|
if grazeT > t {
|
||||||
|
delete(s.grazePerTick, grazeT)
|
||||||
|
}
|
||||||
|
}
|
||||||
break
|
break
|
||||||
|
} else {
|
||||||
|
s.grazePerTick[t] = s.CalculateGrazeDelta(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,6 +86,7 @@ func NewPlayerStage() *PlayerStageState {
|
||||||
grazeCol: ffi.NewCircle(STAGE_WIDTH*0.5, STAGE_HEIGHT-STAGE_HEIGHT*0.1, STAGE_WIDTH*PLAYER_GRAZE_COL_RADIUS_MULTIPLIER),
|
grazeCol: ffi.NewCircle(STAGE_WIDTH*0.5, STAGE_HEIGHT-STAGE_HEIGHT*0.1, STAGE_WIDTH*PLAYER_GRAZE_COL_RADIUS_MULTIPLIER),
|
||||||
bullets: []*ffi.Bullet{},
|
bullets: []*ffi.Bullet{},
|
||||||
updatePlayerPos: true,
|
updatePlayerPos: true,
|
||||||
|
grazePerTick: make(map[int64]int),
|
||||||
health: 3,
|
health: 3,
|
||||||
deathTick: PLAYER_ALIVE,
|
deathTick: PLAYER_ALIVE,
|
||||||
}
|
}
|
||||||
|
|
@ -162,12 +180,14 @@ func (s *PlayerStageState) CheckPlayerDeadOnTick(tick int64) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PlayerStageState) UpdateGrazeMultiplier(tick int64) {
|
func (s *PlayerStageState) CalculateGrazeDelta(tick int64) int {
|
||||||
if slices.ContainsFunc(s.bullets, func(b *ffi.Bullet) bool {
|
count := 0
|
||||||
return b.CollidesWith(s.grazeCol, tick)
|
for _, b := range s.bullets {
|
||||||
}) {
|
if b.CollidesWith(s.grazeCol, tick) {
|
||||||
s.graze += GRAZE_ADDITION_MULTIPLIER
|
count++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return count * GRAZE_ADDITION_MULTIPLIER
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PlayerStageState) AddBullet(b *ffi.Bullet) {
|
func (s *PlayerStageState) AddBullet(b *ffi.Bullet) {
|
||||||
|
|
@ -223,7 +243,13 @@ func (s *PlayerStageState) GetBoardStateDiff(tick int64) []map[string]any {
|
||||||
|
|
||||||
func (s *PlayerStageState) MakeServerTick(tick int64) *ServerTickUpdate {
|
func (s *PlayerStageState) MakeServerTick(tick int64) *ServerTickUpdate {
|
||||||
hitPosX, hitPosY := s.hitCol.GetPos()
|
hitPosX, hitPosY := s.hitCol.GetPos()
|
||||||
grazePosX, grazePosY := s.hitCol.GetPos()
|
grazePosX, grazePosY := s.grazeCol.GetPos()
|
||||||
|
|
||||||
|
prospectiveGraze := 0
|
||||||
|
for _, v := range s.grazePerTick {
|
||||||
|
prospectiveGraze += v
|
||||||
|
}
|
||||||
|
|
||||||
var tickData = ServerTickUpdate{
|
var tickData = ServerTickUpdate{
|
||||||
Tick: tick,
|
Tick: tick,
|
||||||
PlayerHitPos: map[string]any{
|
PlayerHitPos: map[string]any{
|
||||||
|
|
@ -238,7 +264,7 @@ func (s *PlayerStageState) MakeServerTick(tick int64) *ServerTickUpdate {
|
||||||
},
|
},
|
||||||
StageStateDiff: s.GetBoardStateDiff(tick),
|
StageStateDiff: s.GetBoardStateDiff(tick),
|
||||||
ForcePlayerPos: s.updatePlayerPos,
|
ForcePlayerPos: s.updatePlayerPos,
|
||||||
Graze: s.graze,
|
Graze: s.graze + prospectiveGraze,
|
||||||
Dead: s.dead,
|
Dead: s.dead,
|
||||||
CancelDeath: s.cancelDeath,
|
CancelDeath: s.cancelDeath,
|
||||||
DeathTick: s.deathTick,
|
DeathTick: s.deathTick,
|
||||||
|
|
|
||||||
Reference in a new issue