diff --git a/game/game.go b/game/game.go index 4dc01bb..32a5380 100644 --- a/game/game.go +++ b/game/game.go @@ -95,7 +95,9 @@ func (g *Game) Layout(_, _ int) (screenWidth, screenHeight int) { func (g *Game) startLocalGame() { log.Println("Playing against the computer") - // TODO + world.Local = true + world.ConnectionActive = true + world.ConnectPromptVisible = false } func (g *Game) startNetworkGame() { @@ -191,28 +193,28 @@ func (g *Game) ReadInputs() InputBits { var in InputBits if ebiten.IsKeyPressed(ebiten.KeyArrowUp) || ebiten.IsKeyPressed(ebiten.KeyW) { - in.setButton(ButtonUp) + in.setButtonOn(ButtonUp) } if ebiten.IsKeyPressed(ebiten.KeyArrowDown) || ebiten.IsKeyPressed(ebiten.KeyS) { - in.setButton(ButtonDown) + in.setButtonOn(ButtonDown) } if ebiten.IsKeyPressed(ebiten.KeyArrowLeft) || ebiten.IsKeyPressed(ebiten.KeyA) { - in.setButton(ButtonLeft) + in.setButtonOn(ButtonLeft) } if ebiten.IsKeyPressed(ebiten.KeyArrowRight) || ebiten.IsKeyPressed(ebiten.KeyD) { - in.setButton(ButtonRight) + in.setButtonOn(ButtonRight) } if ebiten.IsKeyPressed(ebiten.KeyH) { - in.setButton(ButtonPunch) + in.setButtonOn(ButtonPunch) } if ebiten.IsKeyPressed(ebiten.KeyL) { - in.setButton(ButtonTaunt) + in.setButtonOn(ButtonTaunt) } if ebiten.IsKeyPressed(ebiten.KeyEnter) { - in.setButton(ButtonStart) + in.setButtonOn(ButtonStart) } return in @@ -306,6 +308,8 @@ func (g *Game) applyPhysics() { } else { p.X = o.X + component.PlayerSize } + + p.VX, o.VX = o.VX, p.VX // TODO } if g.Winner == 0 && p.Y < -world.GroundHeight { @@ -341,6 +345,38 @@ func (g *Game) UpdateByInputs(inputs []InputBits) { g.Players[i].VY = g.Players[i].VY * 0.8 if g.Players[i].Action == component.ActionIdle { + if input.isButtonOn(ButtonTaunt) { + var tauntAction component.PlayerAction + switch { + case input.isButtonOn(ButtonUp): + tauntAction = component.ActionTaunt1 + case input.isButtonOn(ButtonRight): + tauntAction = component.ActionTaunt2 + case input.isButtonOn(ButtonDown): + tauntAction = component.ActionTaunt3 + case input.isButtonOn(ButtonLeft): + tauntAction = component.ActionTaunt4 + } + if tauntAction != 0 { + g.Players[i].Action = tauntAction + g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[tauntAction]) + continue + } + } + + if input.isButtonOn(ButtonPunch) { + if !g.Players[i].NoPunch { + g.Players[i].Action = component.ActionPunch + g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[component.ActionPunch]) // TODO + + g.Players[i].NoPunch = true + + continue + } + } else if g.Players[i].NoPunch { + g.Players[i].NoPunch = false + } + if input.isButtonOn(ButtonUp) && !component.TranslateRect(playerRect, 0, -1).Overlaps(oppRect) { var grounded bool for _, physRect := range world.PhysicsRects { @@ -363,34 +399,6 @@ func (g *Game) UpdateByInputs(inputs []InputBits) { if input.isButtonOn(ButtonRight) && !component.TranslateRect(playerRect, 1, 0).Overlaps(oppRect) { g.Players[i].VX = 1 } - - if input.isButtonOn(ButtonPunch) { - if !g.Players[i].NoPunch { - g.Players[i].Action = component.ActionPunch - g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[component.ActionPunch]) // TODO - - g.Players[i].NoPunch = true - - continue - } - } else if g.Players[i].NoPunch { - g.Players[i].NoPunch = false - } - - if input.isButtonOn(ButtonTaunt) { - switch { - case input.isButtonOn(ButtonRight): - g.Players[i].Action = component.ActionTaunt2 - case input.isButtonOn(ButtonDown): - g.Players[i].Action = component.ActionTaunt3 - case input.isButtonOn(ButtonLeft): - g.Players[i].Action = component.ActionTaunt4 - default: // ButtonUp or no direction specified - g.Players[i].Action = component.ActionTaunt1 - } - g.Players[i].ActionTicksLeft = len(component.AllPlayerFrames[g.Players[i].Action]) - continue - } } // TODO player starts in idle action? @@ -469,6 +477,17 @@ func (g *Game) playerStateUpdated() { world.Winner = g.Winner } +func (g *Game) RunLocalFrame() { + inputs := make([]InputBits, 2) + inputs[0] = g.ReadInputs() + if world.Mirror || true { + inputs[1] = mirrorInput(inputs[0]) + } + g.UpdateByInputs(inputs) + + g.playerStateUpdated() +} + func (g *Game) RunFrame() { input := g.ReadInputs() buffer := encodeInputs(input) @@ -568,12 +587,16 @@ func (g *Game) Update() error { } if world.ConnectionActive { - err := world.Backend.Idle(0) - if err != nil { - panic(err) - } + if !world.Local { + err := world.Backend.Idle(0) + if err != nil { + panic(err) + } - g.RunFrame() + g.RunFrame() + } else { + g.RunLocalFrame() + } } err := gohan.Update() diff --git a/game/inputs.go b/game/inputs.go index 62f413b..d4932b2 100644 --- a/game/inputs.go +++ b/game/inputs.go @@ -29,10 +29,14 @@ func (i *InputBits) isButtonOn(button InputButton) bool { return *i&(1< 0 } -func (i *InputBits) setButton(button InputButton) { +func (i *InputBits) setButtonOn(button InputButton) { *i |= 1 << button } +func (i *InputBits) setButtonOff(button InputButton) { + *i &^= 1 << button +} + func readI32(b []byte) int32 { if len(b) < 4 { return 0 @@ -98,3 +102,34 @@ func encodeInputsGob(inputs Input) []byte { } return buf.Bytes() } + +func mirrorInput(inputs InputBits) InputBits { + left, right := inputs.isButtonOn(ButtonRight), inputs.isButtonOn(ButtonLeft) + down, up := inputs.isButtonOn(ButtonUp), inputs.isButtonOn(ButtonDown) + + if left { + inputs.setButtonOn(ButtonLeft) + } else { + inputs.setButtonOff(ButtonLeft) + } + + if right { + inputs.setButtonOn(ButtonRight) + } else { + inputs.setButtonOff(ButtonRight) + } + + if down { + inputs.setButtonOn(ButtonDown) + } else { + inputs.setButtonOff(ButtonDown) + } + + if up { + inputs.setButtonOn(ButtonUp) + } else { + inputs.setButtonOff(ButtonUp) + } + + return inputs +} diff --git a/system/ui.go b/system/ui.go index 6634034..890be00 100644 --- a/system/ui.go +++ b/system/ui.go @@ -226,7 +226,7 @@ func (u *UISystem) Draw(e gohan.Entity, screen *ebiten.Image) error { if p.ActionTicksLeft != 0 { // Draw a rect over stunned players. if p.Action == component.ActionStunned { - playerRect := world.FloatRect(p.X, p.Y, p.X+float64(component.PlayerSize), p.Y+float64(component.PlayerSize)) + playerRect := world.FloatRect(p.X, p.Y, p.X+float64(component.PlayerWidth), p.Y+float64(component.PlayerHeight)) fillColor := color.RGBA{123, 30, 255, 255} u.drawBox(screen, fillColor, playerRect) @@ -291,7 +291,7 @@ func (u *UISystem) Draw(e gohan.Entity, screen *ebiten.Image) error { if world.Debug != 0 { var ping int64 var framesBehind float64 - if !world.ConnectPromptVisible { + if !world.ConnectPromptVisible && !world.Local { p1Stats, err := world.Backend.GetNetworkStats(ggpo.PlayerHandle(1)) if err != nil { return fmt.Errorf("failed to get network stats for player 1: %s", err) diff --git a/world/world.go b/world/world.go index 5e69e71..0d0f26f 100644 --- a/world/world.go +++ b/world/world.go @@ -50,6 +50,9 @@ var ( CurrentPlayer = 1 + Local bool // Playing against computer + Mirror bool // AI should mirror player movements + Backend ggpo.Backend // These variables are cached to prevent race conditions.