Break out packages
This commit is contained in:
parent
f91a975bf1
commit
d57e1e98e1
146
game.go
146
game.go
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
)
|
|
@ -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
11
main.go
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue