Break out packages

This commit is contained in:
Luke Meyers 2020-02-05 20:00:39 -08:00
parent f91a975bf1
commit d57e1e98e1
5 changed files with 176 additions and 166 deletions

146
game.go
View File

@ -1,146 +0,0 @@
package main
import (
"log"
"math/rand"
)
type state struct {
teams []team
obstacles []obstacle
gameOver bool
}
func newState() state {
var teams []team
for i := 0; i < numTeams; i++ {
var bots []bot
for j := 0; j < numBots; j++ {
b := bot{
id: i*numTeams + j,
pos: j * (steps / numBots),
}
bots = append(bots, b)
}
teams = append(teams, team{
bots: bots,
baton: baton{holder: &bots[0]},
})
}
return state{
teams: teams,
obstacles: []obstacle{
{
lane: 0,
pos: steps / 3,
},
},
}
}
type team struct {
bots []bot
baton baton
won bool
}
type bot struct {
id int
pos int
v int
a int
}
type baton struct {
holder *bot
}
type obstacle struct {
lane int
pos int
}
func updateState(sOld state) state {
s := sOld
for i, t := range s.teams {
moveBot(t.baton.holder)
maybePassBaton(&s.teams[i])
}
for _, t := range s.teams {
if won(*t.baton.holder, s) {
s.gameOver = true
}
}
return s
}
func moveBot(b *bot) {
if b.a == 0 {
b.a = 1
}
b.a += rand.Intn(3) - 1
if b.a < -maxA {
b.a = -maxA
}
if b.a > maxA {
b.a = maxA
}
b.v += b.a
if b.v > maxV {
b.v = maxV
}
if b.v < -maxV {
b.v = -maxV
}
b.pos += b.v
}
func maybePassBaton(t *team) {
for i, b := range t.bots {
h := t.baton.holder
if h.id >= b.id {
continue
}
if abs(b.pos-h.pos) <= 10 {
log.Printf("pass from %v to %v!", h.id, b.id)
t.baton.holder.v = 0
t.baton.holder.a = 0
t.baton.holder = &t.bots[i]
t.bots[i].a = 10
return
}
}
}
func won(b bot, s state) bool {
return b.pos >= steps
}
func gameOver(s state) bool {
for _, t := range s.teams {
if t.won {
return true
}
}
return false
}
const (
steps = 400
numBots = 10
numTeams = 2
maxA = 3
maxV = 20
)
func abs(n int) int {
if n < 0 {
return -n
}
return n
}

123
game/game.go Normal file
View File

@ -0,0 +1,123 @@
package game
import (
"log"
)
type State struct {
Teams []Team
Obstacles []Obstacle
GameOver bool
}
func NewState() State {
var teams []Team
for i := 0; i < NumTeams; i++ {
var bots []Bot
for j := 0; j < numBots; j++ {
b := Bot{
id: i*NumTeams + j,
Pos: j * (Steps / numBots),
}
bots = append(bots, b)
}
teams = append(teams, Team{
Bots: bots,
Baton: Baton{Holder: &bots[0]},
})
}
return State{
Teams: teams,
Obstacles: []Obstacle{
{
Lane: 0,
Pos: Steps / 3,
},
},
}
}
type Team struct {
Bots []Bot
Baton Baton
won bool
}
type Bot struct {
id int
Pos int
v int
a int
}
type Baton struct {
Holder *Bot
}
type Obstacle struct {
Lane int
Pos int
}
func UpdateState(sOld State) State {
s := sOld
for i, t := range s.Teams {
moveBot(t.Baton.Holder)
maybePassBaton(&s.Teams[i])
}
for _, t := range s.Teams {
if won(*t.Baton.Holder, s) {
s.GameOver = true
}
}
return s
}
func maybePassBaton(t *Team) {
for i, b := range t.Bots {
h := t.Baton.Holder
if h.id >= b.id {
continue
}
if abs(b.Pos-h.Pos) <= passDistance {
log.Printf("pass from %v to %v!", h.id, b.id)
t.Baton.Holder.v = 0
t.Baton.Holder.a = 0
t.Baton.Holder = &t.Bots[i]
t.Bots[i].a = baseAccel
return
}
}
}
func won(b Bot, s State) bool {
return b.Pos >= Steps
}
func gameOver(s State) bool {
for _, t := range s.Teams {
if t.won {
return true
}
}
return false
}
const (
Steps = 400
numBots = 10
NumTeams = 2
maxA = 3
maxV = 20
)
func abs(n int) int {
if n < 0 {
return -n
}
return n
}

30
game/physics.go Normal file
View File

@ -0,0 +1,30 @@
package game
import "math/rand"
func moveBot(b *Bot) {
if b.a == 0 {
b.a = 1
}
b.a += rand.Intn(3) - 1
if b.a < -maxA {
b.a = -maxA
}
if b.a > maxA {
b.a = maxA
}
b.v += b.a
if b.v > maxV {
b.v = maxV
}
if b.v < -maxV {
b.v = -maxV
}
b.Pos += b.v
}
const (
passDistance = 10
baseAccel = 10
)

View File

@ -1,7 +1,8 @@
package main
package gfx
import (
"image/color"
"relay/game"
"time"
"github.com/faiface/pixel"
@ -10,24 +11,25 @@ import (
"golang.org/x/image/colornames"
)
func render(s state, w *pixelgl.Window, d time.Duration, colors map[*team]pixel.RGBA) {
func Render(s game.State, w *pixelgl.Window, d time.Duration) {
colors := teamColors(s.Teams)
renderBots(s, w, d, colors)
renderObstacles(s, w)
}
func renderBots(s state, w *pixelgl.Window, d time.Duration, colors map[*team]pixel.RGBA) {
func renderBots(s game.State, w *pixelgl.Window, d time.Duration, colors map[*game.Team]pixel.RGBA) {
b := w.Bounds()
im := imdraw.New(nil)
for i, t := range s.teams {
for j, bot := range t.bots {
if &t.bots[j] == t.baton.holder {
for i, t := range s.Teams {
for j, bot := range t.Bots {
if &t.Bots[j] == t.Baton.Holder {
im.Color = pixel.RGB(0, 1, 0)
} else {
im.Color = colors[&s.teams[i]]
im.Color = colors[&s.Teams[i]]
}
pos := lanePos(bot.pos, i, botWidth, b)
pos := lanePos(bot.Pos, i, botWidth, b)
im.Push(pos)
@ -40,21 +42,21 @@ func renderBots(s state, w *pixelgl.Window, d time.Duration, colors map[*team]pi
}
func lanePos(pos, lane int, width float64, bounds pixel.Rect) pixel.Vec {
hOffset := bounds.Size().X / steps
vOffset := bounds.Size().Y / (numTeams + 1)
hOffset := bounds.Size().X / game.Steps
vOffset := bounds.Size().Y / (game.NumTeams + 1)
return pixel.V(bounds.Min.X+width/2+float64(pos)*hOffset,
bounds.Min.Y+float64(lane+1)*vOffset)
}
func renderObstacles(s state, w *pixelgl.Window) {
func renderObstacles(s game.State, w *pixelgl.Window) {
b := w.Bounds()
im := imdraw.New(nil)
for _, o := range s.obstacles {
for _, o := range s.Obstacles {
im.Color = pixel.RGB(1, 0, 1)
pos := lanePos(o.pos, o.lane, botWidth, b)
pos := lanePos(o.Pos, o.Lane, botWidth, b)
im.Push(pos)
@ -65,8 +67,8 @@ func renderObstacles(s state, w *pixelgl.Window) {
}
}
func teamColors(ts []team) map[*team]pixel.RGBA {
m := make(map[*team]pixel.RGBA)
func teamColors(ts []game.Team) map[*game.Team]pixel.RGBA {
m := make(map[*game.Team]pixel.RGBA)
for i := range ts {
var c color.RGBA
switch i {

11
main.go
View File

@ -2,6 +2,8 @@ package main
import (
"math/rand"
"relay/game"
"relay/gfx"
"time"
"github.com/faiface/pixel"
@ -23,20 +25,19 @@ func run() {
rand.Seed(time.Now().UnixNano())
s := newState()
colors := teamColors(s.teams)
s := game.NewState()
start := time.Now()
for !w.Closed() && !s.gameOver {
for !w.Closed() && !s.GameOver {
w.Clear(colornames.Peru)
switch {
case w.JustPressed(pixelgl.KeyQ):
return
case w.JustPressed(pixelgl.KeySpace):
s = updateState(s)
s = game.UpdateState(s)
}
render(s, w, time.Since(start), colors)
gfx.Render(s, w, time.Since(start))
w.Update()
}
}