Allow changing TPS during runtime
This commit is contained in:
parent
68124b7728
commit
92c1c72668
|
@ -55,7 +55,7 @@ var AllPlayerFrames = [][][]FrameData{
|
|||
},
|
||||
{
|
||||
T: HitboxHurt,
|
||||
R: image.Rect(0, 0, PlayerSize, PlayerSize),
|
||||
R: image.Rect(-5, -5, PlayerSize+10, PlayerSize+10),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
100
game/game.go
100
game/game.go
|
@ -137,37 +137,43 @@ func (g *Game) startNetworkGame() {
|
|||
}
|
||||
|
||||
func (g *Game) InitNetworking(localPort int, numPlayers int, players []ggpo.Player, numSpectators int) {
|
||||
var result error
|
||||
var inputBits InputBits = 0
|
||||
var inputSize int = len(encodeInputs(inputBits))
|
||||
|
||||
session := NewGameSession()
|
||||
|
||||
peer := ggpo.NewPeer(session, localPort, numPlayers, inputSize)
|
||||
//peer := ggpo.NewSyncTest(&session, numPlayers, 8, inputSize, true)
|
||||
world.Backend = &peer
|
||||
session.backend = world.Backend
|
||||
peer.InitializeConnection()
|
||||
peer.Start()
|
||||
var inputBits InputBits = 0
|
||||
inputSize := len(encodeInputs(inputBits))
|
||||
|
||||
//session.SetDisconnectTimeout(3000)
|
||||
//session.SetDisconnectNotifyStart(1000)
|
||||
peer := ggpo.NewPeer(session, localPort, numPlayers, inputSize)
|
||||
world.Backend = &peer
|
||||
session.backend = &peer
|
||||
|
||||
err := peer.InitializeConnection()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to initialize connection: %s", err)
|
||||
}
|
||||
err = peer.SetDisconnectTimeout(3000)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to set disconnect timeout: %s", err)
|
||||
}
|
||||
err = peer.SetDisconnectNotifyStart(1000)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to set disconnect notify start: %s", err)
|
||||
}
|
||||
peer.Start()
|
||||
|
||||
for i := 0; i < numPlayers+numSpectators; i++ {
|
||||
var handle ggpo.PlayerHandle
|
||||
result = peer.AddPlayer(&players[i], &handle)
|
||||
err = peer.AddPlayer(&players[i], &handle)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to add player: %s", err)
|
||||
}
|
||||
if players[i].PlayerType == ggpo.PlayerTypeLocal {
|
||||
world.CurrentPlayer = int(handle)
|
||||
}
|
||||
if result != nil {
|
||||
log.Fatalf("There's an issue from AddPlayer")
|
||||
}
|
||||
if players[i].PlayerType == ggpo.PlayerTypeLocal {
|
||||
peer.SetFrameDelay(handle, frameDelay)
|
||||
err = peer.SetFrameDelay(handle, frameDelay)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to set frame delay: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
peer.SetDisconnectTimeout(3000)
|
||||
peer.SetDisconnectNotifyStart(1000)
|
||||
}
|
||||
|
||||
func (g *Game) ReadInputs() InputBits {
|
||||
|
@ -195,7 +201,12 @@ func (g *Game) ReadInputs() InputBits {
|
|||
|
||||
func (g *Game) applyPhysics() {
|
||||
for i := 0; i < 2; i++ {
|
||||
opp := 0
|
||||
if i == 0 {
|
||||
opp = 1
|
||||
}
|
||||
p := &g.Players[i]
|
||||
o := &g.Players[opp]
|
||||
|
||||
// Apply gravity.
|
||||
if p.VY > -world.Gravity {
|
||||
|
@ -208,11 +219,21 @@ func (g *Game) applyPhysics() {
|
|||
// Apply velocity.
|
||||
p.X, p.Y = p.X+p.VX, p.Y+p.VY
|
||||
|
||||
// TODO check player collision.
|
||||
// Apply player collision.
|
||||
playerRect := world.FloatRect(g.Players[i].X, g.Players[i].Y, g.Players[i].X+float64(component.PlayerSize), g.Players[i].Y+float64(component.PlayerSize))
|
||||
oppRect := world.FloatRect(g.Players[opp].X, g.Players[opp].Y, g.Players[opp].X+float64(component.PlayerSize), g.Players[opp].Y+float64(component.PlayerSize))
|
||||
|
||||
if playerRect.Overlaps(oppRect) {
|
||||
if playerRect.Min.X < oppRect.Min.X {
|
||||
p.X = o.X - component.PlayerSize
|
||||
} else {
|
||||
p.X = o.X + component.PlayerSize
|
||||
}
|
||||
}
|
||||
|
||||
// Apply ground collision.
|
||||
if p.Y-component.PlayerSize < 0 {
|
||||
p.Y = component.PlayerSize
|
||||
if p.Y < 0 {
|
||||
p.Y = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +261,6 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
|
|||
if grounded {
|
||||
g.Players[i].VY = 20
|
||||
}
|
||||
log.Println("JUMP", grounded)
|
||||
}
|
||||
if input.isButtonOn(ButtonDown) && !component.TranslateRect(playerRect, 0, 1).Overlaps(oppRect) {
|
||||
//g.Players[i].VY = -1
|
||||
|
@ -265,12 +285,12 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
|
|||
// TODO player starts in idle action?
|
||||
if g.Players[i].ActionTicksLeft != 0 {
|
||||
// Run current frame logic.
|
||||
log.Printf("apply hitbox for player %d action %d ticks left %d", i, g.Players[i].Action, g.Players[i].ActionTicksLeft)
|
||||
|
||||
// TODO handle invulnerability and blocking
|
||||
|
||||
allFrameData := component.FrameDataForActionTick(g.Players[i].Action, g.Players[i].ActionTicksLeft)
|
||||
for _, frame := range allFrameData {
|
||||
// Apply hitbox.
|
||||
if frame.T == component.HitboxHurt {
|
||||
// Hit opponent.
|
||||
if oppRect.Overlaps(component.TranslateRect(frame.R, int(player.X), int(player.Y))) {
|
||||
|
@ -284,8 +304,6 @@ func (g *Game) UpdateByInputs(inputs []InputBits) {
|
|||
// Stun the opponent.
|
||||
opponent.Action = component.ActionStunned
|
||||
opponent.ActionTicksLeft = 7
|
||||
|
||||
log.Println("HIT")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -377,6 +395,32 @@ func (g *Game) Update() error {
|
|||
}
|
||||
}
|
||||
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyMinus) && ebiten.IsKeyPressed(ebiten.KeyControl) {
|
||||
for i, preset := range world.TPSPresets {
|
||||
if preset == world.TPS {
|
||||
if i > 0 {
|
||||
world.TPS = world.TPSPresets[i-1]
|
||||
ebiten.SetTPS(world.TPS)
|
||||
log.Printf("Set TPS to %d", world.TPS)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyEqual) && ebiten.IsKeyPressed(ebiten.KeyControl) {
|
||||
for i, preset := range world.TPSPresets {
|
||||
if preset == world.TPS {
|
||||
if i < len(world.TPSPresets)-1 {
|
||||
world.TPS = world.TPSPresets[i+1]
|
||||
ebiten.SetTPS(world.TPS)
|
||||
log.Printf("Set TPS to %d", world.TPS)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if world.ConnectPromptConfirmed && !world.ConnectionActive {
|
||||
if world.ConnectPromptText == "" {
|
||||
g.startLocalGame()
|
||||
|
|
|
@ -28,7 +28,7 @@ func (i *InputBits) isButtonOn(button InputButton) bool {
|
|||
}
|
||||
|
||||
func (i *InputBits) setButton(button InputButton) {
|
||||
*i |= (1 << button)
|
||||
*i |= 1 << button
|
||||
}
|
||||
|
||||
func readI32(b []byte) int32 {
|
||||
|
@ -48,7 +48,7 @@ func (i *Input) isButtonOn(button InputButton) bool {
|
|||
}
|
||||
|
||||
func (i *Input) setButton(button InputButton) {
|
||||
i.ButtonMap |= (1 << button)
|
||||
i.ButtonMap |= 1 << button
|
||||
}
|
||||
|
||||
func (i Input) String() string {
|
||||
|
@ -79,9 +79,7 @@ func decodeInputsGob(buffer [][]byte) []Input {
|
|||
err := dec.Decode(&inputs[i])
|
||||
if err != nil {
|
||||
log.Printf("decode error: %s. Returning empty input\n", err)
|
||||
// hack
|
||||
inputs[i] = NewInput()
|
||||
//panic("eof")
|
||||
} else {
|
||||
log.Printf("inputs properly decoded: %s\n", inputs[i])
|
||||
}
|
||||
|
|
|
@ -37,11 +37,16 @@ func (s *MapSystem) Draw(e gohan.Entity, screen *ebiten.Image) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
const groundSize = 10 // TODO
|
||||
groundColor := color.RGBA{255, 255, 255, 255}
|
||||
groundColor := color.RGBA{50, 50, 50, 255}
|
||||
|
||||
r := image.Rect(-world.ScreenWidth*2, 0, world.ScreenWidth*2, groundSize)
|
||||
r := image.Rect(-world.ScreenWidth*2, -world.ScreenHeight, world.ScreenWidth*2, 0)
|
||||
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(groundColor)
|
||||
|
||||
const groundTopHeight = 10
|
||||
groundTopColor := color.RGBA{100, 100, 100, 255}
|
||||
|
||||
r = image.Rect(-world.ScreenWidth*2, -groundTopHeight, world.ScreenWidth*2, 0)
|
||||
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(groundTopColor)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -46,16 +46,11 @@ func (s *PlayerSystem) Draw(e gohan.Entity, screen *ebiten.Image) error {
|
|||
p = &world.Player2
|
||||
}
|
||||
|
||||
r := image.Rect(int(p.X), -int(p.Y), int(p.X)+size, -int(p.Y)+size)
|
||||
r := image.Rect(int(p.X), int(p.Y), int(p.X)+size, int(p.Y)+size)
|
||||
|
||||
screen.SubImage(world.GameRectToScreen(r)).(*ebiten.Image).Fill(p.Color)
|
||||
|
||||
// TODO animate
|
||||
/*if p.ActionTicksLeft != 0 {
|
||||
frameNum := p.ActionTicksLeft - 1
|
||||
frame := component.AllPlayerFrames[p.Action][frameNum]
|
||||
log.Printf("frame %+v", frame)
|
||||
}*/
|
||||
|
||||
switch p.Action {
|
||||
case component.ActionPunch:
|
||||
|
|
62
system/ui.go
62
system/ui.go
|
@ -2,6 +2,7 @@ package system
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
|
@ -179,6 +180,24 @@ func (u *UISystem) Update(e gohan.Entity) error {
|
|||
return etk.Update()
|
||||
}
|
||||
|
||||
func (u *UISystem) drawBox(screen *ebiten.Image, fillColor color.Color, x float64, y float64, w int, h int) {
|
||||
bounds := u.hitboxImg.Bounds()
|
||||
if bounds.Dx() != w || bounds.Dy() != h {
|
||||
u.hitboxImg = ebiten.NewImage(w, h)
|
||||
}
|
||||
u.hitboxImg.Clear()
|
||||
u.hitboxImg.Fill(color.RGBA{255, 255, 255, 255})
|
||||
u.hitboxImg.SubImage(image.Rect(2, 2, w-2, h-2)).(*ebiten.Image).Fill(fillColor)
|
||||
|
||||
// Get screen position of top left corner of player.
|
||||
drawX, drawY := world.GameCoordsToScreen(x, y)
|
||||
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(drawX), float64(drawY))
|
||||
op.ColorM.Scale(1, 1, 1, 1)
|
||||
screen.DrawImage(u.hitboxImg, op)
|
||||
}
|
||||
|
||||
func (u *UISystem) Draw(e gohan.Entity, screen *ebiten.Image) error {
|
||||
if !u.initialized {
|
||||
u.initialize()
|
||||
|
@ -197,30 +216,24 @@ func (u *UISystem) Draw(e gohan.Entity, screen *ebiten.Image) error {
|
|||
} else {
|
||||
p = &world.Player2
|
||||
}
|
||||
if p.ActionTicksLeft != 0 {
|
||||
frameNum := p.ActionTicksLeft - 1
|
||||
allData := component.AllPlayerFrames[p.Action][frameNum]
|
||||
|
||||
if p.ActionTicksLeft != 0 {
|
||||
// Draw a rect over stunned players.
|
||||
if p.Action == component.ActionStunned {
|
||||
fillColor := color.RGBA{123, 30, 255, 255}
|
||||
u.drawBox(screen, fillColor, p.X, p.Y+component.PlayerSize, component.PlayerSize, component.PlayerSize)
|
||||
continue
|
||||
}
|
||||
|
||||
// Draw frame data rects.
|
||||
allData := component.FrameDataForActionTick(p.Action, p.ActionTicksLeft)
|
||||
for _, data := range allData {
|
||||
fillColor := color.RGBA{0, 255, 0, 255}
|
||||
switch data.T {
|
||||
case component.HitboxHurt:
|
||||
fillColor = color.RGBA{0, 0, 255, 255}
|
||||
}
|
||||
|
||||
bounds := u.hitboxImg.Bounds()
|
||||
if bounds.Dx() != data.R.Dx() || bounds.Dy() != data.R.Dy() {
|
||||
u.hitboxImg = ebiten.NewImage(data.R.Dx(), data.R.Dy())
|
||||
}
|
||||
u.hitboxImg.Clear()
|
||||
u.hitboxImg.Fill(fillColor)
|
||||
|
||||
drawX, drawY := world.GameCoordsToScreen(p.X, p.Y)
|
||||
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(drawX), float64(drawY))
|
||||
op.ColorM.Scale(1, 1, 1, 1)
|
||||
screen.DrawImage(u.hitboxImg, op)
|
||||
u.drawBox(screen, fillColor, p.X, p.Y+float64(data.R.Dy()), data.R.Dx(), data.R.Dy())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -254,14 +267,13 @@ func (u *UISystem) Draw(e gohan.Entity, screen *ebiten.Image) error {
|
|||
framesLabel = "BEHIND"
|
||||
}
|
||||
|
||||
ebitenutil.DebugPrintAt(screen,
|
||||
fmt.Sprintf("FRAMES %s %.0f\nPING %d\nTPS %0.0f\nFPS %0.0f",
|
||||
framesLabel,
|
||||
math.Abs(framesBehind),
|
||||
ping,
|
||||
ebiten.ActualTPS(),
|
||||
ebiten.ActualFPS()),
|
||||
2, 0)
|
||||
debugText := fmt.Sprintf("FRAMES %s %.0f\nPING %d\nTPS %0.0f\nFPS %0.0f",
|
||||
framesLabel,
|
||||
math.Abs(framesBehind),
|
||||
ping,
|
||||
ebiten.ActualTPS(),
|
||||
ebiten.ActualFPS())
|
||||
ebitenutil.DebugPrintAt(screen, debugText, 2, 0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -49,11 +49,15 @@ var (
|
|||
Backend ggpo.Backend
|
||||
)
|
||||
|
||||
var TPSPresets = []int{1, 2, 4, 10, 30, 60, 120}
|
||||
|
||||
func GameCoordsToScreen(x, y float64) (int, int) {
|
||||
return int(x) - CamX + (ScreenWidth / 2), -int(y) - CamY + (ScreenHeight - GroundHeight)
|
||||
}
|
||||
|
||||
func GameRectToScreen(r image.Rectangle) image.Rectangle {
|
||||
r = image.Rect(r.Min.X, -r.Min.Y, r.Max.X, -r.Max.Y)
|
||||
|
||||
return component.TranslateRect(r, -CamX+(ScreenWidth/2), -CamY+(ScreenHeight-GroundHeight))
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue