Add status text and input buffers

This commit is contained in:
Trevor Slocum 2021-10-15 11:14:40 -07:00
parent ff6e3e5147
commit 08bb73626b
7 changed files with 130 additions and 28 deletions

View File

@ -15,5 +15,6 @@ func parseFlags(g *game.Game) {
flag.StringVar(&g.ServerAddress, "address", "fibs.com:4321", "Server address")
flag.BoolVar(&g.Watch, "watch", false, "Watch random game")
flag.BoolVar(&g.TV, "tv", false, "Watch random games continuously")
flag.IntVar(&g.Debug, "debug", 0, "Print debug information")
flag.Parse()
}

View File

@ -25,20 +25,6 @@ import (
"golang.org/x/image/font/opentype"
)
// Copyright 2020 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:embed assets
var assetsFS embed.FS
@ -51,6 +37,7 @@ var (
imgCheckerBlack *ebiten.Image
mplusNormalFont font.Face
monoFont font.Face
mplusBigFont font.Face
)
@ -108,6 +95,19 @@ func initializeFonts() {
if err != nil {
log.Fatal(err)
}
tt, err = opentype.Parse(fonts.PressStart2P_ttf)
if err != nil {
log.Fatal(err)
}
monoFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
Size: 12,
DPI: dpi,
Hinting: font.HintingNone,
})
if err != nil {
log.Fatal(err)
}
}
type Sprite struct {
@ -173,8 +173,6 @@ type Game struct {
}
func NewGame() *Game {
fibs.Debug = 1 // TODO
g := &Game{
op: &ebiten.DrawImageOptions{
Filter: ebiten.FilterNearest,
@ -191,6 +189,10 @@ func NewGame() *Game {
}
g.keyboard.SetKeys(kibodo.KeysQWERTY)
msgHandler := NewMessageHandler(g)
fibs.StatusWriter = msgHandler
fibs.GameWriter = msgHandler
// TODO
go func() {
/*
@ -381,6 +383,8 @@ func (g *Game) Update() error { // Called by ebiten only when input occurs
viewBoard = !viewBoard
}
g.buffers.update()
if !viewBoard {
g.lobby.update()
} else {
@ -483,11 +487,11 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
var bw, bh int
if g.buffers.w == 0 && g.buffers.h == 0 {
// Set initial buffer position.
bx = g.screenW / 2
bx = 0
by = g.screenH / 2
// Set initial buffer size.
bw = g.screenW / 2
bh = g.screenH / 4
bw = g.screenW
bh = g.screenH / 2
} else {
// Scale existing buffer size
bx, by = bx*(outsideWidth/g.screenW), by*(outsideHeight/g.screenH)
@ -549,3 +553,20 @@ func (g *Game) Exit() {
g.Board.drawFrame <- false
os.Exit(0)
}
type messageHandler struct {
g *Game
}
func NewMessageHandler(g *Game) *messageHandler {
return &messageHandler{
g: g,
}
}
func (m messageHandler) Write(p []byte) (n int, err error) {
log.Println(string(p))
m.g.buffers.buffers[0].Write(p)
return len(p), nil
}

View File

@ -7,10 +7,9 @@ import (
"sort"
"strings"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"code.rocketnine.space/tslocum/fibs"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/hajimehoshi/ebiten/v2/text"
)
@ -78,7 +77,7 @@ func (l *lobby) setWhoInfo(who []*fibs.WhoInfo) {
sort.Slice(l.who, func(i, j int) bool {
if (l.who[i].Opponent != "") != (l.who[j].Opponent != "") {
return l.who[i].Opponent != ""
return l.who[j].Opponent != ""
}
if l.who[i].Ready != l.who[j].Ready {
return l.who[i].Ready

View File

@ -1,8 +1,12 @@
package game
import (
"image"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/inpututil"
"github.com/hajimehoshi/ebiten/v2/text"
"golang.org/x/exp/shiny/materialdesign/colornames"
)
const (
@ -11,7 +15,7 @@ const (
WindowMaximized
)
const windowStartingAlpha = 0.8
const windowStartingAlpha = 0.9
type tabbedBuffers struct {
buffers []*textBuffer
@ -35,12 +39,19 @@ type tabbedBuffers struct {
}
func newTabbedBuffers() *tabbedBuffers {
return &tabbedBuffers{
tab := &tabbedBuffers{
state: windowNormal,
unfocusedAlpha: windowStartingAlpha,
buffer: ebiten.NewImage(1, 1),
op: &ebiten.DrawImageOptions{},
}
b := &textBuffer{
tab: tab,
}
tab.buffers = []*textBuffer{b}
return tab
}
func (t *tabbedBuffers) setRect(x, y, w, h int) {
@ -57,14 +68,46 @@ func (t *tabbedBuffers) setRect(x, y, w, h int) {
}
func (t *tabbedBuffers) drawBuffer() {
t.buffer.Fill(frameColor)
t.buffer.Fill(borderColor)
sub := t.buffer.SubImage(image.Rect(1, 1, t.w-1, t.h-1)).(*ebiten.Image)
sub.Fill(frameColor)
b := t.buffers[0]
l := len(b.content)
lineHeight := 16
showLines := t.h / lineHeight
if showLines > 1 {
showLines--
}
if showLines > 1 {
showLines--
}
if l < showLines {
showLines = l
}
for i := 0; i < showLines; i++ {
line := string(b.content[l-showLines+i])
bounds := text.BoundString(monoFont, line)
_ = bounds
text.Draw(t.buffer, line, monoFont, 0, (lineHeight * (i + 1)), colornames.White)
}
text.Draw(t.buffer, "Say: Input buffer test", monoFont, 0, t.h-lineHeight, colornames.White)
}
func (t *tabbedBuffers) draw(target *ebiten.Image) {
if t.buffer == nil {
return
}
return // This feature is not yet finished.
if t.state == windowMinimized {
return
}
if t.bufferDirty {
t.drawBuffer()
@ -90,6 +133,17 @@ func (t *tabbedBuffers) click(x, y int) {
func (t *tabbedBuffers) update() {
// TODO accept keyboard input
if inpututil.IsKeyJustPressed(ebiten.KeyEnter) {
if t.state == windowMinimized {
t.state = windowNormal
} else {
t.state = windowMinimized
}
t.bufferDirty = true
}
// Enter brings up keyboard and hides it when there is no input
// TODO switch tabs
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {

View File

@ -1,5 +1,28 @@
package game
import "github.com/hajimehoshi/ebiten/v2"
type textBuffer struct {
content []byte
// Content of buffer separated by newlines.
content [][]byte
// Content as it appears on the screen.
contentWrapped []byte
offset int
tab *tabbedBuffers
}
func (b *textBuffer) Write(p []byte) {
b.content = append(b.content, p)
b.wrapContent()
b.tab.bufferDirty = true
ebiten.ScheduleFrame()
}
func (b *textBuffer) wrapContent() {
// TODO
}

2
go.mod
View File

@ -8,6 +8,7 @@ require (
github.com/hajimehoshi/ebiten/v2 v2.2.0
github.com/llgcode/draw2d v0.0.0-20210904075650-80aa0a2a901d
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
golang.org/x/exp v0.0.0-20211012155715-ffe10e552389
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
)
@ -20,7 +21,6 @@ require (
github.com/modern-go/reflect2 v1.0.1 // 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-20211012155715-ffe10e552389 // indirect
golang.org/x/mobile v0.0.0-20210924032853-1c027f395ef7 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c // indirect

View File

@ -7,6 +7,8 @@ import (
"os/signal"
"syscall"
"code.rocketnine.space/tslocum/fibs"
"code.rocketnine.space/tslocum/boxcars/game"
"github.com/hajimehoshi/ebiten/v2"
)
@ -36,6 +38,8 @@ func main() {
parseFlags(g)
fibs.Debug = g.Debug
if AutoWatch {
g.Watch = true
}