Support logging in
This commit is contained in:
parent
63d44b37af
commit
23fba33928
5 changed files with 746 additions and 183 deletions
539
game/board.go
539
game/board.go
|
@ -1,40 +1,57 @@
|
|||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"math/rand"
|
||||
|
||||
"github.com/llgcode/draw2d/draw2dimg"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
"time"
|
||||
|
||||
"code.rocketnine.space/tslocum/fibs"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
"github.com/hajimehoshi/ebiten/v2/text"
|
||||
"github.com/llgcode/draw2d/draw2dimg"
|
||||
)
|
||||
|
||||
type stateUpdate struct {
|
||||
from int
|
||||
to int
|
||||
v []int
|
||||
}
|
||||
|
||||
type board struct {
|
||||
Sprites *Sprites
|
||||
op *ebiten.DrawImageOptions
|
||||
|
||||
spaces [][]*Sprite
|
||||
|
||||
backgroundImage *ebiten.Image
|
||||
|
||||
dragging *Sprite
|
||||
|
||||
dragTouchId ebiten.TouchID
|
||||
|
||||
touchIDs []ebiten.TouchID
|
||||
|
||||
x, y int
|
||||
w, h int
|
||||
|
||||
spaceWidth int // spaceWidth is also the width and height of checkers
|
||||
op *ebiten.DrawImageOptions
|
||||
|
||||
backgroundImage *ebiten.Image
|
||||
|
||||
Sprites *Sprites
|
||||
|
||||
spaces [][]*Sprite // Space contents
|
||||
spaceRects [][4]int
|
||||
|
||||
dragging *Sprite
|
||||
moving *Sprite // Moving automatically
|
||||
|
||||
dragTouchId ebiten.TouchID
|
||||
touchIDs []ebiten.TouchID
|
||||
|
||||
spaceWidth int
|
||||
barWidth int
|
||||
triangleOffset float64
|
||||
horizontalBorderSize int
|
||||
verticalBorderSize int
|
||||
overlapSize int
|
||||
|
||||
lastDirection int
|
||||
V []int
|
||||
|
||||
moveQueue chan *stateUpdate
|
||||
|
||||
debug int // Print and draw debug information
|
||||
}
|
||||
|
||||
func NewBoard() *board {
|
||||
|
@ -48,27 +65,31 @@ func NewBoard() *board {
|
|||
sprites: make([]*Sprite, 30),
|
||||
num: 30,
|
||||
},
|
||||
spaces: make([][]*Sprite, 26),
|
||||
spaces: make([][]*Sprite, 26),
|
||||
spaceRects: make([][4]int, 26),
|
||||
V: make([]int, 42),
|
||||
moveQueue: make(chan *stateUpdate, 10),
|
||||
}
|
||||
|
||||
for i := range b.Sprites.sprites {
|
||||
s := &Sprite{}
|
||||
|
||||
r := rand.Intn(2)
|
||||
s.colorWhite = r != 1
|
||||
|
||||
s.w, s.h = imgCheckerWhite.Size()
|
||||
s := b.newSprite(i%2 == 1)
|
||||
|
||||
b.Sprites.sprites[i] = s
|
||||
|
||||
space := (i % 24) + 1
|
||||
if i > 25 {
|
||||
space = 3
|
||||
space := i
|
||||
if space > 25 {
|
||||
if space%2 == 0 {
|
||||
space = 0
|
||||
} else {
|
||||
space = 25
|
||||
}
|
||||
}
|
||||
|
||||
b.spaces[space] = append(b.spaces[space], s)
|
||||
}
|
||||
|
||||
go b.handlePieceMoves()
|
||||
|
||||
b.op = &ebiten.DrawImageOptions{}
|
||||
|
||||
b.dragTouchId = -1
|
||||
|
@ -76,13 +97,11 @@ func NewBoard() *board {
|
|||
return b
|
||||
}
|
||||
|
||||
// relX, relY
|
||||
func (b *board) spacePosition(index int) (int, int) {
|
||||
if index <= 12 {
|
||||
return b.spaceWidth * (index - 1), 0
|
||||
}
|
||||
// TODO add innerW innerH
|
||||
return b.spaceWidth * (index - 13), (b.h - (b.verticalBorderSize)*2) - b.spaceWidth
|
||||
func (b *board) newSprite(white bool) *Sprite {
|
||||
s := &Sprite{}
|
||||
s.colorWhite = white
|
||||
s.w, s.h = imgCheckerWhite.Size()
|
||||
return s
|
||||
}
|
||||
|
||||
func (b *board) updateBackgroundImage() {
|
||||
|
@ -104,7 +123,7 @@ func (b *board) updateBackgroundImage() {
|
|||
img = ebiten.NewImageFromImage(box)
|
||||
img.Fill(borderColor)
|
||||
b.op.GeoM.Reset()
|
||||
b.op.GeoM.Translate(float64(b.horizontalBorderSize-borderSize), float64(b.verticalBorderSize))
|
||||
b.op.GeoM.Translate(float64(b.horizontalBorderSize-borderSize), 0)
|
||||
b.backgroundImage.DrawImage(img, b.op)
|
||||
|
||||
// Face
|
||||
|
@ -128,7 +147,7 @@ func (b *board) updateBackgroundImage() {
|
|||
|
||||
// Draw triangles
|
||||
for i := 0; i < 2; i++ {
|
||||
triangleTip := float64(b.h / 2)
|
||||
triangleTip := float64((b.h - (b.verticalBorderSize * 2)) / 2)
|
||||
if i == 0 {
|
||||
triangleTip -= b.triangleOffset
|
||||
} else {
|
||||
|
@ -171,8 +190,7 @@ func (b *board) draw(screen *ebiten.Image) {
|
|||
b.op.GeoM.Translate(float64(b.x), float64(b.y))
|
||||
screen.DrawImage(b.backgroundImage, b.op)
|
||||
|
||||
for i := 0; i < b.Sprites.num; i++ {
|
||||
sprite := b.Sprites.sprites[i]
|
||||
drawSprite := func(sprite *Sprite) {
|
||||
b.op.GeoM.Reset()
|
||||
b.op.GeoM.Translate(float64(sprite.x), float64(sprite.y))
|
||||
|
||||
|
@ -182,35 +200,112 @@ func (b *board) draw(screen *ebiten.Image) {
|
|||
screen.DrawImage(imgCheckerBlack, b.op)
|
||||
}
|
||||
}
|
||||
|
||||
b.iterateSpaces(func(space int) {
|
||||
var numPieces int
|
||||
for _, sprite := range b.spaces[space] {
|
||||
if sprite == b.dragging || sprite == b.moving {
|
||||
continue
|
||||
}
|
||||
numPieces++
|
||||
|
||||
drawSprite(sprite)
|
||||
|
||||
if numPieces > 5 {
|
||||
label := fmt.Sprintf("%d", numPieces)
|
||||
labelColor := color.RGBA{255, 255, 255, 255}
|
||||
if sprite.colorWhite {
|
||||
labelColor = color.RGBA{0, 0, 0, 255}
|
||||
}
|
||||
|
||||
bounds := text.BoundString(mplusNormalFont, label)
|
||||
overlayImage := ebiten.NewImage(bounds.Dx()*2, bounds.Dy()*2)
|
||||
text.Draw(overlayImage, label, mplusNormalFont, 0, bounds.Dy(), labelColor)
|
||||
|
||||
x, y, w, h := b.stackSpaceRect(space, numPieces)
|
||||
x += (w / 2) - (bounds.Dx() / 2)
|
||||
y += (h / 2) - (bounds.Dy() / 2)
|
||||
x, y = b.offsetPosition(x, y)
|
||||
|
||||
b.op.GeoM.Reset()
|
||||
b.op.GeoM.Translate(float64(x), float64(y))
|
||||
screen.DrawImage(overlayImage, b.op)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Draw moving sprite
|
||||
if b.moving != nil {
|
||||
drawSprite(b.moving)
|
||||
}
|
||||
|
||||
// Draw dragged sprite
|
||||
if b.dragging != nil {
|
||||
drawSprite(b.dragging)
|
||||
}
|
||||
|
||||
if b.debug == 2 {
|
||||
b.iterateSpaces(func(space int) {
|
||||
x, y, w, h := b.spaceRect(space)
|
||||
spaceImage := ebiten.NewImage(w, h)
|
||||
if space%2 == 0 {
|
||||
spaceImage.Fill(color.RGBA{0, 0, 0, 150})
|
||||
} else {
|
||||
spaceImage.Fill(color.RGBA{255, 255, 255, 150})
|
||||
}
|
||||
|
||||
br := ""
|
||||
if b.bottomRow(space) {
|
||||
br = "B"
|
||||
}
|
||||
|
||||
ebitenutil.DebugPrint(spaceImage, fmt.Sprintf(" %d %s", space, br))
|
||||
|
||||
x, y = b.offsetPosition(x, y)
|
||||
|
||||
b.op.GeoM.Reset()
|
||||
b.op.GeoM.Translate(float64(x), float64(y))
|
||||
screen.DrawImage(spaceImage, b.op)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (b *board) setRect(x, y, w, h int) {
|
||||
if b.x == x && b.y == y && b.w == w && b.h == h {
|
||||
return
|
||||
}
|
||||
const stackAllowance = 0.97 // TODO configurable
|
||||
|
||||
b.x, b.y, b.w, b.h = x, y, w, h
|
||||
|
||||
b.horizontalBorderSize = 0
|
||||
|
||||
b.triangleOffset = float64(b.h) / 30
|
||||
b.triangleOffset = float64(b.h-(b.verticalBorderSize*2)) / 33
|
||||
|
||||
for {
|
||||
b.verticalBorderSize = 0 // TODO configurable
|
||||
b.verticalBorderSize = 7 // TODO configurable
|
||||
|
||||
b.spaceWidth = (b.w - (b.horizontalBorderSize * 2)) / 13
|
||||
|
||||
b.barWidth = b.spaceWidth
|
||||
|
||||
b.overlapSize = (((b.h - (b.verticalBorderSize * 2)) - (int(b.triangleOffset) * 2)) / 2) / 5
|
||||
if b.overlapSize >= b.spaceWidth {
|
||||
b.overlapSize = b.spaceWidth
|
||||
o := int(float64(b.spaceWidth) * stackAllowance)
|
||||
if b.overlapSize >= o {
|
||||
b.overlapSize = o
|
||||
break
|
||||
}
|
||||
|
||||
b.horizontalBorderSize++
|
||||
}
|
||||
|
||||
extraSpace := b.w - (b.spaceWidth * 12)
|
||||
largeBarWidth := int(float64(b.spaceWidth) * 1.25)
|
||||
if extraSpace >= largeBarWidth {
|
||||
b.barWidth = largeBarWidth
|
||||
}
|
||||
// TODO barwidth in calcs is wrong
|
||||
|
||||
b.horizontalBorderSize = ((b.w - (b.spaceWidth * 12)) - b.barWidth) / 2
|
||||
if b.horizontalBorderSize < 0 {
|
||||
b.horizontalBorderSize = 0
|
||||
|
@ -222,6 +317,7 @@ func (b *board) setRect(x, y, w, h int) {
|
|||
s.w, s.h = imgCheckerWhite.Size()
|
||||
}
|
||||
|
||||
b.setSpaceRects()
|
||||
b.updateBackgroundImage()
|
||||
b.positionCheckers()
|
||||
}
|
||||
|
@ -231,7 +327,7 @@ func (b *board) offsetPosition(x, y int) (int, int) {
|
|||
}
|
||||
|
||||
func (b *board) positionCheckers() {
|
||||
for space := 1; space < 25; space++ {
|
||||
for space := 0; space < 26; space++ {
|
||||
sprites := b.spaces[space]
|
||||
|
||||
for i := range sprites {
|
||||
|
@ -240,33 +336,327 @@ func (b *board) positionCheckers() {
|
|||
continue
|
||||
}
|
||||
|
||||
x, y := b.spacePosition(space)
|
||||
x, y, w, _ := b.stackSpaceRect(space, i)
|
||||
s.x, s.y = b.offsetPosition(x, y)
|
||||
if (space > 6 && space < 13) || (space > 18 && space < 25) {
|
||||
s.x += b.barWidth
|
||||
}
|
||||
s.x += (b.spaceWidth - s.w) / 2
|
||||
s.y += i * b.overlapSize
|
||||
// Center piece in space
|
||||
s.x += (w - s.w) / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *board) spriteAt(x, y int) *Sprite {
|
||||
for i := 0; i < b.Sprites.num; i++ {
|
||||
s := b.Sprites.sprites[i]
|
||||
if x >= s.x && y >= s.y && x <= s.x+s.w && y <= s.y+s.h {
|
||||
// Bring sprite to front
|
||||
b.Sprites.sprites = append(b.Sprites.sprites[:i], b.Sprites.sprites[i+1:]...)
|
||||
b.Sprites.sprites = append(b.Sprites.sprites, s)
|
||||
space := b.spaceAt(x, y)
|
||||
if space == -1 {
|
||||
return nil
|
||||
}
|
||||
pieces := b.spaces[space]
|
||||
if len(pieces) == 0 {
|
||||
return nil
|
||||
}
|
||||
return pieces[len(pieces)-1]
|
||||
}
|
||||
|
||||
return s
|
||||
func (b *board) spaceAt(x, y int) int {
|
||||
for i := 0; i < 26; i++ {
|
||||
sx, sy, sw, sh := b.spaceRect(i)
|
||||
sx, sy = b.offsetPosition(sx, sy)
|
||||
if x >= sx && x <= sx+sw && y >= sy && y <= sy+sh {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return -1
|
||||
}
|
||||
|
||||
// TODO move to fibs library
|
||||
func (b *board) iterateSpaces(f func(space int)) {
|
||||
if b.V[fibs.StateDirection] == 1 {
|
||||
for space := 0; space <= 25; space++ {
|
||||
f(space)
|
||||
}
|
||||
return
|
||||
}
|
||||
for space := 25; space >= 0; space-- {
|
||||
f(space)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *board) translateSpace(space int) int {
|
||||
if b.V[fibs.StateDirection] == -1 {
|
||||
// Spaces range from 24 - 1.
|
||||
if space == 0 || space == 25 {
|
||||
space = 25 - space
|
||||
} else if space <= 12 {
|
||||
space = 12 + space
|
||||
} else {
|
||||
space = space - 12
|
||||
}
|
||||
}
|
||||
return space
|
||||
}
|
||||
|
||||
func (b *board) setSpaceRects() {
|
||||
var x, y, w, h int
|
||||
for i := 0; i < 26; i++ {
|
||||
trueSpace := i
|
||||
|
||||
space := b.translateSpace(i)
|
||||
if !b.bottomRow(trueSpace) {
|
||||
y = 0
|
||||
} else {
|
||||
y = (b.h / 2) - b.verticalBorderSize
|
||||
}
|
||||
|
||||
w = b.spaceWidth
|
||||
|
||||
var hspace int // horizontal space
|
||||
var add int
|
||||
if space == 0 {
|
||||
hspace = 6
|
||||
w = b.barWidth
|
||||
} else if space == 25 {
|
||||
hspace = 6
|
||||
w = b.barWidth
|
||||
} else if space <= 6 {
|
||||
hspace = space - 1
|
||||
} else if space <= 12 {
|
||||
hspace = space - 1
|
||||
add = b.barWidth
|
||||
} else if space <= 18 {
|
||||
hspace = 24 - space
|
||||
add = b.barWidth
|
||||
} else {
|
||||
hspace = 24 - space
|
||||
}
|
||||
|
||||
x = (b.spaceWidth * hspace) + add
|
||||
|
||||
h = (b.h - (b.verticalBorderSize * 2)) / 2
|
||||
|
||||
b.spaceRects[trueSpace] = [4]int{x, y, w, h}
|
||||
}
|
||||
}
|
||||
|
||||
// relX, relY
|
||||
func (b *board) spaceRect(space int) (x, y, w, h int) {
|
||||
rect := b.spaceRects[space]
|
||||
return rect[0], rect[1], rect[2], rect[3]
|
||||
}
|
||||
|
||||
func (b *board) bottomRow(space int) bool {
|
||||
bottomStart := 1
|
||||
bottomEnd := 12
|
||||
bottomBar := 25
|
||||
if b.V[fibs.StateDirection] == 1 {
|
||||
bottomStart = 13
|
||||
bottomEnd = 24
|
||||
bottomBar = 0
|
||||
}
|
||||
return space == bottomBar || (space >= bottomStart && space <= bottomEnd)
|
||||
}
|
||||
|
||||
// relX, relY
|
||||
func (b *board) stackSpaceRect(space int, stack int) (x, y, w, h int) {
|
||||
x, y, w, h = b.spaceRect(space)
|
||||
|
||||
// Stack pieces
|
||||
osize := float64(stack)
|
||||
var o int
|
||||
if stack > 4 {
|
||||
osize = 3.5
|
||||
}
|
||||
if b.bottomRow(space) {
|
||||
osize += 1.0
|
||||
}
|
||||
o = int(osize * float64(b.overlapSize))
|
||||
if !b.bottomRow(space) {
|
||||
y += o
|
||||
} else {
|
||||
y = y + (h - o)
|
||||
}
|
||||
|
||||
w, h = b.spaceWidth, b.spaceWidth
|
||||
if space == 0 || space == 25 {
|
||||
w = b.barWidth
|
||||
}
|
||||
|
||||
return x, y, w, h
|
||||
}
|
||||
|
||||
func (b *board) SetState(v []int) {
|
||||
b.moveQueue <- &stateUpdate{-1, -1, v}
|
||||
}
|
||||
|
||||
func (b *board) ProcessState() {
|
||||
v := b.V
|
||||
|
||||
if b.lastDirection != v[fibs.StateDirection] {
|
||||
b.setSpaceRects()
|
||||
}
|
||||
b.lastDirection = v[fibs.StateDirection]
|
||||
|
||||
b.Sprites = &Sprites{}
|
||||
b.spaces = make([][]*Sprite, 26)
|
||||
for space := 0; space < 26; space++ {
|
||||
spaceValue := v[fibs.StateBoardSpace0+space]
|
||||
if spaceValue == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
white := spaceValue > 0
|
||||
// TODO reverse bar spaces - always?
|
||||
// TODO take direction into account
|
||||
|
||||
abs := spaceValue
|
||||
if abs < 0 {
|
||||
abs *= -1
|
||||
}
|
||||
|
||||
for i := 0; i < abs; i++ {
|
||||
s := b.newSprite(white)
|
||||
b.spaces[space] = append(b.spaces[space], s)
|
||||
b.Sprites.sprites = append(b.Sprites.sprites, s)
|
||||
}
|
||||
}
|
||||
b.Sprites.num = len(b.Sprites.sprites)
|
||||
|
||||
b.positionCheckers()
|
||||
}
|
||||
|
||||
func (b *board) _movePiece(sprite *Sprite, from int, to int, speed int) {
|
||||
moveSize := 1
|
||||
moveDelay := time.Duration(2/speed) * time.Millisecond
|
||||
|
||||
stackTo := len(b.spaces[to])
|
||||
if stackTo == 1 && sprite.colorWhite != b.spaces[to][0].colorWhite {
|
||||
stackTo = 0 // Hit
|
||||
}
|
||||
x, y, _, _ := b.stackSpaceRect(to, stackTo)
|
||||
x, y = b.offsetPosition(x, y)
|
||||
|
||||
if sprite.x != x {
|
||||
// Center
|
||||
cy := (b.h / 2) - (b.spaceWidth / 2)
|
||||
for {
|
||||
if sprite.y == cy {
|
||||
break
|
||||
}
|
||||
if sprite.y < cy {
|
||||
sprite.y += moveSize
|
||||
if sprite.y > cy {
|
||||
sprite.y = cy
|
||||
}
|
||||
} else if sprite.y > cy {
|
||||
sprite.y -= moveSize
|
||||
if sprite.y < cy {
|
||||
sprite.y = cy
|
||||
}
|
||||
}
|
||||
time.Sleep(moveDelay)
|
||||
}
|
||||
for {
|
||||
if sprite.x == x {
|
||||
break
|
||||
}
|
||||
if sprite.x < x {
|
||||
sprite.x += moveSize
|
||||
if sprite.x > x {
|
||||
sprite.x = x
|
||||
}
|
||||
} else if sprite.x > x {
|
||||
sprite.x -= moveSize
|
||||
if sprite.x < x {
|
||||
sprite.x = x
|
||||
}
|
||||
}
|
||||
time.Sleep(moveDelay / 2)
|
||||
}
|
||||
}
|
||||
for {
|
||||
if sprite.x == x && sprite.y == y {
|
||||
break
|
||||
}
|
||||
if sprite.x < x {
|
||||
sprite.x += moveSize
|
||||
if sprite.x > x {
|
||||
sprite.x = x
|
||||
}
|
||||
} else if sprite.x > x {
|
||||
sprite.x -= moveSize
|
||||
if sprite.x < x {
|
||||
sprite.x = x
|
||||
}
|
||||
}
|
||||
if sprite.y < y {
|
||||
sprite.y += moveSize
|
||||
if sprite.y > y {
|
||||
sprite.y = y
|
||||
}
|
||||
} else if sprite.y > y {
|
||||
sprite.y -= moveSize
|
||||
if sprite.y < y {
|
||||
sprite.y = y
|
||||
}
|
||||
}
|
||||
time.Sleep(moveDelay)
|
||||
}
|
||||
|
||||
// TODO do not add bear off pieces
|
||||
b.spaces[to] = append(b.spaces[to], sprite)
|
||||
for i, s := range b.spaces[from] {
|
||||
if s == sprite {
|
||||
b.spaces[from] = append(b.spaces[from][:i], b.spaces[from][i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
b.moving = nil
|
||||
}
|
||||
|
||||
func (b *board) handlePieceMoves() {
|
||||
for u := range b.moveQueue {
|
||||
if u.from == -1 || u.to == -1 {
|
||||
b.V = u.v
|
||||
b.ProcessState()
|
||||
continue
|
||||
}
|
||||
|
||||
from, to := u.from, u.to
|
||||
|
||||
pieces := b.spaces[from]
|
||||
if len(pieces) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sprite := pieces[len(pieces)-1]
|
||||
|
||||
var moveAfter *Sprite
|
||||
if len(b.spaces[to]) == 1 {
|
||||
if sprite.colorWhite != b.spaces[to][0].colorWhite {
|
||||
moveAfter = b.spaces[to][0]
|
||||
}
|
||||
}
|
||||
|
||||
b._movePiece(sprite, from, to, 1)
|
||||
if moveAfter != nil {
|
||||
toBar := 0
|
||||
if b.V[fibs.StateDirection] == 1 {
|
||||
toBar = 25
|
||||
}
|
||||
b._movePiece(moveAfter, to, toBar, 2)
|
||||
}
|
||||
|
||||
b.positionCheckers()
|
||||
}
|
||||
}
|
||||
|
||||
// Do not call directly
|
||||
func (b *board) movePiece(from int, to int) {
|
||||
b.moveQueue <- &stateUpdate{from, to, nil}
|
||||
}
|
||||
|
||||
func (b *board) update() {
|
||||
if b.dragging == nil {
|
||||
// TODO allow grabbing multiple pieces by grabbing further down the stack
|
||||
|
||||
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
|
||||
x, y := ebiten.CursorPosition()
|
||||
|
||||
|
@ -289,20 +679,41 @@ func (b *board) update() {
|
|||
}
|
||||
}
|
||||
|
||||
x, y := ebiten.CursorPosition()
|
||||
if b.dragTouchId != -1 {
|
||||
x, y = ebiten.TouchPosition(b.dragTouchId)
|
||||
}
|
||||
|
||||
var dropped *Sprite
|
||||
if b.dragTouchId == -1 {
|
||||
if inpututil.IsMouseButtonJustReleased(ebiten.MouseButtonLeft) {
|
||||
dropped = b.dragging
|
||||
b.dragging = nil
|
||||
}
|
||||
} else if inpututil.IsTouchJustReleased(b.dragTouchId) {
|
||||
dropped = b.dragging
|
||||
b.dragging = nil
|
||||
}
|
||||
if dropped != nil {
|
||||
// TODO allow dragging anywhere outside of board to bear off
|
||||
// allow dragging on to bar to bear off
|
||||
|
||||
index := b.spaceAt(x, y)
|
||||
if index >= 0 {
|
||||
for space, pieces := range b.spaces {
|
||||
for stackIndex, piece := range pieces {
|
||||
if piece == dropped {
|
||||
b.spaces[space] = append(b.spaces[space][:stackIndex], b.spaces[space][stackIndex+1:]...)
|
||||
b.spaces[index] = append(b.spaces[index], dropped)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
b.positionCheckers()
|
||||
}
|
||||
|
||||
if b.dragging != nil {
|
||||
x, y := ebiten.CursorPosition()
|
||||
if b.dragTouchId != -1 {
|
||||
x, y = ebiten.TouchPosition(b.dragTouchId)
|
||||
}
|
||||
|
||||
sprite := b.dragging
|
||||
sprite.x = x - (sprite.w / 2)
|
||||
sprite.y = y - (sprite.h / 2)
|
||||
|
|
311
game/game.go
311
game/game.go
|
@ -6,22 +6,19 @@ import (
|
|||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
_ "image/png"
|
||||
"log"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2/examples/resources/fonts"
|
||||
"golang.org/x/image/font/opentype"
|
||||
|
||||
"github.com/nfnt/resize"
|
||||
|
||||
// Asset decoding
|
||||
_ "image/png"
|
||||
|
||||
"code.rocketnine.space/tslocum/fibs"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
"github.com/hajimehoshi/ebiten/v2/examples/resources/fonts"
|
||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||
"github.com/nfnt/resize"
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/font/opentype"
|
||||
)
|
||||
|
||||
// Copyright 2020 The Ebiten Authors
|
||||
|
@ -38,8 +35,6 @@ import (
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
const maxAngle = 256
|
||||
|
||||
//go:embed assets
|
||||
var assetsFS embed.FS
|
||||
|
||||
|
@ -53,6 +48,8 @@ var (
|
|||
mplusBigFont font.Face
|
||||
)
|
||||
|
||||
const defaultServerAddress = "fibs.com:4321"
|
||||
|
||||
func init() {
|
||||
loadAssets(0)
|
||||
|
||||
|
@ -108,65 +105,6 @@ func initializeFonts() {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO copied
|
||||
|
||||
func line(x0, y0, x1, y1 float32, clr color.RGBA) ([]ebiten.Vertex, []uint16) {
|
||||
const width = 1
|
||||
|
||||
theta := math.Atan2(float64(y1-y0), float64(x1-x0))
|
||||
theta += math.Pi / 2
|
||||
dx := float32(math.Cos(theta))
|
||||
dy := float32(math.Sin(theta))
|
||||
|
||||
r := float32(clr.R) / 0xff
|
||||
g := float32(clr.G) / 0xff
|
||||
b := float32(clr.B) / 0xff
|
||||
a := float32(clr.A) / 0xff
|
||||
|
||||
return []ebiten.Vertex{
|
||||
{
|
||||
DstX: x0 - width*dx/2,
|
||||
DstY: y0 - width*dy/2,
|
||||
SrcX: 1,
|
||||
SrcY: 1,
|
||||
ColorR: r,
|
||||
ColorG: g,
|
||||
ColorB: b,
|
||||
ColorA: a,
|
||||
},
|
||||
{
|
||||
DstX: x0 + width*dx/2,
|
||||
DstY: y0 + width*dy/2,
|
||||
SrcX: 1,
|
||||
SrcY: 1,
|
||||
ColorR: r,
|
||||
ColorG: g,
|
||||
ColorB: b,
|
||||
ColorA: a,
|
||||
},
|
||||
{
|
||||
DstX: x1 - width*dx/2,
|
||||
DstY: y1 - width*dy/2,
|
||||
SrcX: 1,
|
||||
SrcY: 1,
|
||||
ColorR: r,
|
||||
ColorG: g,
|
||||
ColorB: b,
|
||||
ColorA: a,
|
||||
},
|
||||
{
|
||||
DstX: x1 + width*dx/2,
|
||||
DstY: y1 + width*dy/2,
|
||||
SrcX: 1,
|
||||
SrcY: 1,
|
||||
ColorR: r,
|
||||
ColorG: g,
|
||||
ColorB: b,
|
||||
ColorA: a,
|
||||
},
|
||||
}, []uint16{0, 1, 2, 1, 2, 3}
|
||||
}
|
||||
|
||||
type Sprite struct {
|
||||
image *ebiten.Image
|
||||
w int
|
||||
|
@ -196,29 +134,105 @@ const (
|
|||
MaxSprites = 50000
|
||||
)
|
||||
|
||||
var spinner = []byte(`-\|/`)
|
||||
|
||||
type Game struct {
|
||||
touchIDs []ebiten.TouchID
|
||||
sprites Sprites
|
||||
op *ebiten.DrawImageOptions
|
||||
board *board
|
||||
Board *board
|
||||
|
||||
screenW, screenH int
|
||||
|
||||
drawBuffer bytes.Buffer
|
||||
|
||||
spinnerIndex int
|
||||
|
||||
ServerAddress string
|
||||
Username string
|
||||
Password string
|
||||
loggedIn bool
|
||||
usernameConfirmed bool
|
||||
|
||||
Watch bool
|
||||
|
||||
Client *fibs.Client
|
||||
|
||||
runeBuffer []rune
|
||||
inputBuffer string
|
||||
|
||||
Debug int
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
go func() {
|
||||
// TODO fetch HTTP request, set debugExtra
|
||||
}()
|
||||
|
||||
return &Game{
|
||||
g := &Game{
|
||||
op: &ebiten.DrawImageOptions{
|
||||
Filter: ebiten.FilterNearest,
|
||||
},
|
||||
board: NewBoard(),
|
||||
Board: NewBoard(),
|
||||
|
||||
runeBuffer: make([]rune, 24),
|
||||
}
|
||||
|
||||
go func() {
|
||||
t := time.NewTicker(time.Second / 4)
|
||||
for range t.C {
|
||||
_ = g.update()
|
||||
}
|
||||
}()
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Game) handleEvents() {
|
||||
for e := range g.Client.Event {
|
||||
switch event := e.(type) {
|
||||
case *fibs.EventMove:
|
||||
g.Board.movePiece(event.From, event.To)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Connect() {
|
||||
g.loggedIn = true
|
||||
|
||||
address := g.ServerAddress
|
||||
if address == "" {
|
||||
address = defaultServerAddress
|
||||
}
|
||||
g.Client = fibs.NewClient(address, g.Username, g.Password)
|
||||
|
||||
go g.handleEvents()
|
||||
|
||||
c := g.Client
|
||||
|
||||
if g.Watch {
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
c.WatchRandomGame()
|
||||
|
||||
go g.renderLoop()
|
||||
}()
|
||||
}
|
||||
|
||||
go func() {
|
||||
err := c.Connect()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (g *Game) renderLoop() {
|
||||
t := time.NewTicker(time.Second)
|
||||
for range t.C {
|
||||
gameBoard := g.Board
|
||||
v := g.Client.Board.GetIntState()
|
||||
gameBoard.SetState(v)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,7 +258,61 @@ func (g *Game) rightTouched() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
// Separate update function for all normal update logic, as Update may only be
|
||||
// called when there is user input when vsync is disabled.
|
||||
func (g *Game) update() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Update() error { // Called by ebiten only when input occurs
|
||||
err := g.update()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !g.loggedIn {
|
||||
f := func() {
|
||||
var clearBuffer bool
|
||||
defer func() {
|
||||
if clearBuffer {
|
||||
g.inputBuffer = ""
|
||||
|
||||
if !g.usernameConfirmed {
|
||||
g.usernameConfirmed = true
|
||||
} else if g.Password != "" {
|
||||
g.Connect()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyBackspace) && len(g.inputBuffer) > 0 {
|
||||
g.inputBuffer = g.inputBuffer[:len(g.inputBuffer)-1]
|
||||
}
|
||||
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyEnter) {
|
||||
clearBuffer = true
|
||||
}
|
||||
|
||||
g.runeBuffer = ebiten.AppendInputChars(g.runeBuffer[:0])
|
||||
if len(g.runeBuffer) > 0 {
|
||||
g.inputBuffer += string(g.runeBuffer)
|
||||
|
||||
if strings.ContainsRune(g.inputBuffer, '\n') {
|
||||
g.inputBuffer = strings.Split(g.inputBuffer, "\n")[0]
|
||||
clearBuffer = true
|
||||
}
|
||||
if !g.usernameConfirmed {
|
||||
g.Username = g.inputBuffer
|
||||
} else {
|
||||
g.Password = g.inputBuffer
|
||||
}
|
||||
log.Println("INPUT BUFFER IS:" + g.inputBuffer)
|
||||
}
|
||||
}
|
||||
|
||||
f()
|
||||
}
|
||||
|
||||
g.touchIDs = ebiten.AppendTouchIDs(g.touchIDs[:0])
|
||||
|
||||
// Decrease the number of the sprites.
|
||||
|
@ -263,7 +331,15 @@ func (g *Game) Update() error {
|
|||
}
|
||||
}
|
||||
|
||||
g.board.update()
|
||||
if inpututil.IsKeyJustPressed(ebiten.KeyD) {
|
||||
g.Debug++
|
||||
if g.Debug == 3 {
|
||||
g.Debug = 0
|
||||
}
|
||||
g.Board.debug = g.Debug
|
||||
}
|
||||
|
||||
g.Board.update()
|
||||
|
||||
//g.sprites.Update()
|
||||
return nil
|
||||
|
@ -272,44 +348,73 @@ func (g *Game) Update() error {
|
|||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.Fill(color.RGBA{0, 102, 51, 255})
|
||||
|
||||
g.board.draw(screen)
|
||||
// Log in screen
|
||||
if !g.loggedIn {
|
||||
const welcomeText = `Please enter your FIBS username and password.
|
||||
If you do not have a FIBS account yet, visit
|
||||
http://www.fibs.com/help.html#register`
|
||||
debugBox := image.NewRGBA(image.Rect(0, 0, g.screenW, g.screenH))
|
||||
debugImg := ebiten.NewImageFromImage(debugBox)
|
||||
|
||||
debugBox := image.NewRGBA(image.Rect(10, 20, 200, 200))
|
||||
debugImg := ebiten.NewImageFromImage(debugBox)
|
||||
if !g.usernameConfirmed {
|
||||
ebitenutil.DebugPrint(debugImg, welcomeText+fmt.Sprintf("\n\nUsername: %s", g.Username))
|
||||
} else {
|
||||
ebitenutil.DebugPrint(debugImg, welcomeText+fmt.Sprintf("\n\nPassword: %s", strings.Repeat("*", len(g.Password))))
|
||||
}
|
||||
|
||||
g.drawBuffer.Reset()
|
||||
|
||||
g.drawBuffer.Write([]byte(fmt.Sprintf("FPS %0.0f\nTPS %0.0f", ebiten.CurrentFPS(), ebiten.CurrentTPS())))
|
||||
|
||||
scaleFactor := ebiten.DeviceScaleFactor()
|
||||
if scaleFactor != 1.0 {
|
||||
g.drawBuffer.WriteRune('\n')
|
||||
g.drawBuffer.Write([]byte(fmt.Sprintf("SCA %0.1f", scaleFactor)))
|
||||
g.resetImageOptions()
|
||||
g.op.GeoM.Scale(2, 2)
|
||||
screen.DrawImage(debugImg, g.op)
|
||||
return
|
||||
}
|
||||
|
||||
if debugExtra != nil {
|
||||
g.drawBuffer.WriteRune('\n')
|
||||
g.drawBuffer.Write(debugExtra)
|
||||
// Game screen
|
||||
|
||||
g.Board.draw(screen)
|
||||
|
||||
if g.Debug == 1 {
|
||||
debugBox := image.NewRGBA(image.Rect(10, 20, 200, 200))
|
||||
debugImg := ebiten.NewImageFromImage(debugBox)
|
||||
|
||||
g.drawBuffer.Reset()
|
||||
|
||||
g.drawBuffer.Write([]byte(fmt.Sprintf("FPS %0.0f\nTPS %0.0f", ebiten.CurrentFPS(), ebiten.CurrentTPS())))
|
||||
|
||||
/* TODO enable when vsync is able to be turned off
|
||||
g.spinnerIndex++
|
||||
if g.spinnerIndex == 4 {
|
||||
g.spinnerIndex = 0
|
||||
}*/
|
||||
|
||||
scaleFactor := ebiten.DeviceScaleFactor()
|
||||
if scaleFactor != 1.0 {
|
||||
g.drawBuffer.WriteRune('\n')
|
||||
g.drawBuffer.Write([]byte(fmt.Sprintf("SCA %0.1f", scaleFactor)))
|
||||
}
|
||||
|
||||
if debugExtra != nil {
|
||||
g.drawBuffer.WriteRune('\n')
|
||||
g.drawBuffer.Write(debugExtra)
|
||||
}
|
||||
|
||||
ebitenutil.DebugPrint(debugImg, g.drawBuffer.String())
|
||||
|
||||
g.resetImageOptions()
|
||||
g.op.GeoM.Translate(3, 0)
|
||||
g.op.GeoM.Scale(2, 2)
|
||||
screen.DrawImage(debugImg, g.op)
|
||||
}
|
||||
|
||||
ebitenutil.DebugPrint(debugImg, g.drawBuffer.String())
|
||||
|
||||
g.resetImageOptions()
|
||||
g.op.GeoM.Translate(3, 0)
|
||||
g.op.GeoM.Scale(2, 2)
|
||||
screen.DrawImage(debugImg, g.op)
|
||||
}
|
||||
|
||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
s := ebiten.DeviceScaleFactor()
|
||||
outsideWidth, outsideHeight = int(float64(outsideWidth)*s), int(float64(outsideHeight)*s)
|
||||
if g.screenW == outsideWidth && g.screenH == outsideHeight {
|
||||
return outsideWidth, outsideHeight
|
||||
}
|
||||
|
||||
g.screenW, g.screenH = outsideWidth, outsideHeight
|
||||
|
||||
g.board.setRect(0, 0, g.screenW, g.screenH)
|
||||
|
||||
// TODO use scale factor
|
||||
g.Board.setRect(0, 0, g.screenW, g.screenH)
|
||||
return outsideWidth, outsideHeight
|
||||
}
|
||||
|
||||
|
|
11
go.mod
11
go.mod
|
@ -3,7 +3,8 @@ module code.rocketnine.space/tslocum/boxcars
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.11.0.20210818171906-9f1113b733b9
|
||||
code.rocketnine.space/tslocum/fibs v0.0.0-00010101000000-000000000000
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210825183521-91a72880271d
|
||||
github.com/llgcode/draw2d v0.0.0-20210313082411-577c1ead272a
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
|
||||
|
@ -12,9 +13,13 @@ require (
|
|||
require (
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210727001814-0db043d8d5be // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/reiver/go-oi v1.0.0 // indirect
|
||||
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e // indirect
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
|
||||
golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
)
|
||||
|
||||
replace code.rocketnine.space/tslocum/fibs => /home/trevor/programming/fibs
|
||||
|
|
24
go.sum
24
go.sum
|
@ -4,24 +4,20 @@ github.com/go-gl/glfw v0.0.0-20180426074136-46a8d530c326 h1:QqWaXlVeUGwSH7hO8giZ
|
|||
github.com/go-gl/glfw v0.0.0-20180426074136-46a8d530c326/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210727001814-0db043d8d5be h1:vEIVIuBApEBQTEJt19GfhoU+zFSV+sNTa9E9FdnRYfk=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20210727001814-0db043d8d5be/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY=
|
||||
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.1.3 h1:JefUkL0M4nrdVwVq7MMZxSTh6mSxOylm+C4Anoucbb0=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.1.3/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.11.0.20210818171906-9f1113b733b9 h1:7BPQ3xdKXg80VujVnjcmlDrZnwwV+Pi5OWIW8dBYLpo=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.11.0.20210818171906-9f1113b733b9/go.mod h1:2jj60Rz9WF8YOAJrh9355q9d0yoa9VKqhGxo112+rSU=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210825183521-91a72880271d h1:EMEmUvZhS8hZ4eq1732CWs7aKcSWXhVvcxllfhVZc9Y=
|
||||
github.com/hajimehoshi/ebiten/v2 v2.2.0-alpha.12.0.20210825183521-91a72880271d/go.mod h1:B4Cje+Kb1ZjztrKFPaiMWOGXO3Vp8u+zIBdxkZqkyD4=
|
||||
github.com/hajimehoshi/file2byteslice v0.0.0-20200812174855-0e5e8a80490e/go.mod h1:CqqAHp7Dk/AqQiwuhV1yT2334qbA/tFWQW0MD2dGqUE=
|
||||
github.com/hajimehoshi/go-mp3 v0.3.2/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
|
||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
|
||||
github.com/hajimehoshi/oto/v2 v2.0.0-alpha.2/go.mod h1:rUKQmwMkqmRxe+IAof9+tuYA2ofm8cAWXFmSfzDN8vQ=
|
||||
github.com/jakecoffman/cp v1.1.0/go.mod h1:JjY/Fp6d8E1CHnu74gWNnU0+b9VzEdUVPoJxg2PsTQg=
|
||||
github.com/jfreymuth/oggvorbis v1.0.3/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
||||
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/llgcode/draw2d v0.0.0-20210313082411-577c1ead272a h1:gl2CmDrcVtYJY4YBKfNdpa4Igj3iNIBsaC3m8TQipYw=
|
||||
github.com/llgcode/draw2d v0.0.0-20210313082411-577c1ead272a/go.mod h1:mVa0dA29Db2S4LVqDYLlsePDzRJLDfdhVZiI15uY0FA=
|
||||
github.com/llgcode/ps v0.0.0-20150911083025-f1443b32eedb h1:61ndUreYSlWFeCY44JxDDkngVoI7/1MVhEl98Nm0KOk=
|
||||
|
@ -29,6 +25,10 @@ github.com/llgcode/ps v0.0.0-20150911083025-f1443b32eedb/go.mod h1:1l8ky+Ew27CMX
|
|||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
|
||||
github.com/reiver/go-oi v1.0.0 h1:nvECWD7LF+vOs8leNGV/ww+F2iZKf3EYjYZ527turzM=
|
||||
github.com/reiver/go-oi v1.0.0/go.mod h1:RrDBct90BAhoDTxB1fenZwfykqeGvhI6LsNfStJoEkI=
|
||||
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e h1:quuzZLi72kkJjl+f5AQ93FMcadG19WkS7MO6TXFOSas=
|
||||
github.com/reiver/go-telnet v0.0.0-20180421082511-9ff0b2ab096e/go.mod h1:+5vNVvEWwEIx86DB9Ke/+a5wBI464eDRo3eF0LcfpWg=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
@ -40,7 +40,6 @@ golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86h
|
|||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs=
|
||||
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
|
@ -62,13 +61,15 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55 h1:rw6UNGRMfarCepjI8qOepea/SXwIBVfTKjztZ5gBbq4=
|
||||
golang.org/x/sys v0.0.0-20210820121016-41cdb8703e55/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
@ -76,4 +77,3 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
|
|
44
main.go
44
main.go
|
@ -1,7 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"code.rocketnine.space/tslocum/boxcars/game"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
|
@ -19,6 +23,10 @@ func main() {
|
|||
ebiten.SetMaxTPS(60) // TODO allow users to set custom value
|
||||
ebiten.SetRunnableOnUnfocused(true) // Note - this currently does nothing in ebiten
|
||||
|
||||
// TODO set up system to call scheduleframe automatically
|
||||
//ebiten.SetFPSMode(ebiten.FPSModeVsyncOffMinimum)
|
||||
// TODO breaks justpressedkey
|
||||
|
||||
//ebiten.SetWindowClosingHandled(true) TODO implement
|
||||
|
||||
fullscreenWidth, fullscreenHeight := ebiten.ScreenSizeInFullscreen()
|
||||
|
@ -26,7 +34,41 @@ func main() {
|
|||
ebiten.SetFullscreen(true)
|
||||
}
|
||||
|
||||
if err := ebiten.RunGame(game.NewGame()); err != nil {
|
||||
g := game.NewGame()
|
||||
|
||||
flag.StringVar(&g.Username, "username", "", "Username")
|
||||
flag.StringVar(&g.Password, "password", "", "Password")
|
||||
flag.StringVar(&g.ServerAddress, "address", "fibs.com:4321", "Server address")
|
||||
flag.BoolVar(&g.Watch, "watch", false, "Watch random game")
|
||||
flag.Parse()
|
||||
|
||||
// Auto-connect
|
||||
if g.Username != "" && g.Password != "" {
|
||||
g.Connect()
|
||||
}
|
||||
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
// TODO temporary
|
||||
if string(scanner.Bytes()) == "/board" {
|
||||
g.Client.Out <- []byte("set boardstyle 2")
|
||||
time.Sleep(time.Second / 2)
|
||||
g.Client.Out <- []byte("board")
|
||||
time.Sleep(time.Second / 2)
|
||||
g.Client.Out <- []byte("set boardstyle 3")
|
||||
continue
|
||||
}
|
||||
|
||||
g.Client.Out <- append(scanner.Bytes())
|
||||
}
|
||||
|
||||
if scanner.Err() != nil {
|
||||
// TODO
|
||||
}
|
||||
}()
|
||||
|
||||
if err := ebiten.RunGame(g); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue