Add server-side linear bullet integrator
This commit is contained in:
parent
ef9cfcfab5
commit
8654b46338
3 changed files with 102 additions and 6 deletions
33
server/bullets.go
Normal file
33
server/bullets.go
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
const (
|
||||||
|
BULLET_LINEAR = iota
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
STAGE_WIDTH float64 = 90.0
|
||||||
|
STAGE_HEIGHT float64 = 160.0
|
||||||
|
BULLET_KILL_BUFFER_WIDTH float64 = 16.0
|
||||||
|
)
|
||||||
|
|
||||||
|
type Bullet struct {
|
||||||
|
Class int
|
||||||
|
SpawnTime int64
|
||||||
|
SpawnX float64
|
||||||
|
SpawnY float64
|
||||||
|
Parameters []float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Bullet) GetCurrentPos(tick int64) (float64, float64) {
|
||||||
|
switch b.Class {
|
||||||
|
case BULLET_LINEAR:
|
||||||
|
return b.SpawnX + (b.Parameters[0] * float64(tick-b.SpawnTime)), b.SpawnY + (b.Parameters[1] * float64(tick-b.SpawnTime))
|
||||||
|
default:
|
||||||
|
return b.SpawnX, b.SpawnY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Bullet) BeyondKillBoundary(tick int64) bool {
|
||||||
|
x, y := b.GetCurrentPos(tick)
|
||||||
|
return (x < 0.0-BULLET_KILL_BUFFER_WIDTH) || (x > STAGE_WIDTH+BULLET_KILL_BUFFER_WIDTH) || (y < 0.0-BULLET_KILL_BUFFER_WIDTH) || (y > STAGE_HEIGHT+BULLET_KILL_BUFFER_WIDTH)
|
||||||
|
}
|
||||||
1
server/collision.go
Normal file
1
server/collision.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package main
|
||||||
|
|
@ -3,26 +3,51 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
|
"math/rand"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/heroiclabs/nakama-common/runtime"
|
"github.com/heroiclabs/nakama-common/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MATCH_LOADING = iota
|
||||||
|
MATCH_START
|
||||||
|
SPAWN_BULLET
|
||||||
|
MATCH_END
|
||||||
|
)
|
||||||
|
|
||||||
// Interface for registering match handlers
|
// Interface for registering match handlers
|
||||||
type BattleRoyaleMatch struct{}
|
type BattleRoyaleMatch struct{}
|
||||||
|
|
||||||
|
type PlayerStageState struct {
|
||||||
|
xPos float64
|
||||||
|
yPos float64
|
||||||
|
bullets []Bullet
|
||||||
|
}
|
||||||
|
|
||||||
|
type PresenceState struct { // present time! hahahahahahahah!
|
||||||
|
presence runtime.Presence
|
||||||
|
stageState PlayerStageState
|
||||||
|
}
|
||||||
|
|
||||||
// In-memory game state
|
// In-memory game state
|
||||||
type BattleRoyaleMatchState struct {
|
type BattleRoyaleMatchState struct {
|
||||||
presences map[string]runtime.Presence
|
tickRate int
|
||||||
|
currentMatchPhase int
|
||||||
|
presences map[string]*PresenceState
|
||||||
emptyTicks int
|
emptyTicks int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run on match start, initializes game state and sets tick rate
|
// Run on match start, initializes game state and sets tick rate
|
||||||
func (m *BattleRoyaleMatch) MatchInit(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, params map[string]interface{}) (interface{}, int, string) {
|
func (m *BattleRoyaleMatch) MatchInit(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, params map[string]interface{}) (interface{}, int, string) {
|
||||||
|
tickRate := 20 // MatchLoop invocations per second
|
||||||
state := &BattleRoyaleMatchState{
|
state := &BattleRoyaleMatchState{
|
||||||
presences: map[string]runtime.Presence{},
|
tickRate: tickRate,
|
||||||
|
presences: map[string]*PresenceState{},
|
||||||
emptyTicks: 0,
|
emptyTicks: 0,
|
||||||
|
currentMatchPhase: MATCH_LOADING,
|
||||||
}
|
}
|
||||||
tickRate := 1 // MatchLoop invocations per second
|
|
||||||
label := ""
|
label := ""
|
||||||
return state, tickRate, label
|
return state, tickRate, label
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +74,14 @@ func (m *BattleRoyaleMatch) MatchJoin(ctx context.Context, logger runtime.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(presences); i++ {
|
for i := 0; i < len(presences); i++ {
|
||||||
lobbyState.presences[presences[i].GetSessionId()] = presences[i]
|
lobbyState.presences[presences[i].GetSessionId()] = &PresenceState{
|
||||||
|
presence: presences[i],
|
||||||
|
stageState: PlayerStageState{
|
||||||
|
xPos: STAGE_WIDTH * 0.5,
|
||||||
|
yPos: STAGE_HEIGHT - STAGE_HEIGHT*0.1,
|
||||||
|
bullets: []Bullet{},
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lobbyState
|
return lobbyState
|
||||||
|
|
@ -111,6 +143,36 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test bullet spawning
|
||||||
|
if tick%20 == 0 {
|
||||||
|
for _, v := range lobbyState.presences {
|
||||||
|
vel := rand.Float64()*(STAGE_WIDTH/float64(lobbyState.tickRate)) + 1.0
|
||||||
|
bullet := Bullet{
|
||||||
|
BULLET_LINEAR,
|
||||||
|
tick,
|
||||||
|
STAGE_WIDTH * rand.Float64(),
|
||||||
|
STAGE_HEIGHT * rand.Float64(),
|
||||||
|
[]float64{vel, vel},
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(bullet)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error marshalling bullet data", err)
|
||||||
|
} else {
|
||||||
|
v.stageState.bullets = append(v.stageState.bullets, bullet)
|
||||||
|
reliable := true
|
||||||
|
dispatcher.BroadcastMessage(SPAWN_BULLET, data, nil, nil, reliable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bullet cleanup
|
||||||
|
for _, v := range lobbyState.presences {
|
||||||
|
v.stageState.bullets = slices.DeleteFunc(v.stageState.bullets, func(b Bullet) bool {
|
||||||
|
return b.BeyondKillBoundary(tick)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return lobbyState
|
return lobbyState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Reference in a new issue