Skip to content

Commit

Permalink
Server controls game border decoration
Browse files Browse the repository at this point in the history
  • Loading branch information
armsnyder committed Nov 20, 2020
1 parent 3dfa8e2 commit d488cb1
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 170 deletions.
132 changes: 73 additions & 59 deletions pkg/client/scenes/draw_lib.go → pkg/client/draw/draw_lib.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package scenes
package draw

import (
"fmt"
Expand All @@ -14,10 +14,10 @@ const gameBoyWidth, gameBoyHeight = 96, 24
// Margins inside the bordered game window.
const marginX, marginY = 3, 1

// draw is a general function for drawing to the terminal.
// Draw is a general function for drawing to the terminal.
// The text can be a rune, a string, or a multiline string, which will be drawn relative to the
// specified anchor. This function should always be used instead of termbox.SetCell().
func draw(anchor anchor, color color, text interface{}) {
func Draw(anchor Anchor, color Color, text interface{}) {
switch t := text.(type) {
case rune:
positionX, positionY, _, _ := anchor()
Expand All @@ -34,94 +34,94 @@ func draw(anchor anchor, color color, text interface{}) {

for i, row := range rows {
for j, ch := range []rune(row) { // Converting to []rune first gets us tight alignment.
draw(offset(anchor, offsetX+j, offsetY+i), color, ch)
Draw(Offset(anchor, offsetX+j, offsetY+i), color, ch)
}
}

default:
panic(fmt.Errorf("unsupported draw text type %T", text))
panic(fmt.Errorf("unsupported Draw text type %T", text))
}
}

// setCursor uses an anchor to determine the position of the cursor, so it can be used in
// conjunction with draw to place the cursor.
func setCursor(anchor anchor) {
// SetCursor uses an Anchor to determine the position of the cursor, so it can be used in
// conjunction with Draw to place the cursor.
func SetCursor(anchor Anchor) {
x, y, _, _ := anchor()
termbox.SetCursor(x, y-1)
}

// anchor defines a position offset and direction that can be used for drawing.
type anchor func() (positionX, positionY int, drawDirectionX, drawDirectionY float64)
// Anchor defines a position offset and direction that can be used for drawing.
type Anchor func() (positionX, positionY int, drawDirectionX, drawDirectionY float64)

// origin is an anchor on the top-left corner of the terminal window.
func origin() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
// Origin is an Anchor on the top-left corner of the terminal window.
func Origin() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
return 0, 0, 0, 0
}

// topLeft is an anchor on the top-left corner of the game window.
func topLeft() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
// TopLeft is an Anchor on the top-left corner of the game window.
func TopLeft() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
termWidth, termHeight := termbox.Size()
leftX := (termWidth - gameBoyWidth) / 2
topY := (termHeight - gameBoyHeight) / 2
// Add an inner margin while also ensuring the text is always on-screen.
return max(0, leftX+marginX+2), max(0, topY+marginY+1), 0, 0
}

// topRight is an anchor on the top-right corner of the game window.
func topRight() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
// TopRight is an Anchor on the top-right corner of the game window.
func TopRight() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
termWidth, termHeight := termbox.Size()
rightX := (termWidth + gameBoyWidth) / 2
topY := (termHeight - gameBoyHeight) / 2
// Add an inner margin while also ensuring the text is always on-screen.
return min(termWidth, rightX-marginX), max(0, topY+marginY+1), -1, 0
}

// botRight is an anchor on the bottom-right corner of the game window.
func botRight() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
// BotRight is an Anchor on the bottom-right corner of the game window.
func BotRight() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
termWidth, termHeight := termbox.Size()
rightX := (termWidth + gameBoyWidth) / 2
botY := (termHeight + gameBoyHeight) / 2
// Add an inner margin while also ensuring the text is always on-screen.
return min(termWidth, rightX-marginX), min(termHeight, botY-marginY) - 1, -1, 0
}

// center is an anchor in the center-middle of the terminal that draws from the center outward.
func center() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
// Center is an Anchor in the center-middle of the terminal that draws from the center outward.
func Center() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
termWidth, termHeight := termbox.Size()
centerX := termWidth / 2
centerY := termHeight / 2
return centerX, centerY, -0.5, -0.5
}

// centerLeft is an anchor in the center-middle of the terminal that draws toward the left side.
func centerLeft() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
positionX, positionY, _, _ = center()
// CenterLeft is an Anchor in the center-middle of the terminal that draws toward the left side.
func CenterLeft() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
positionX, positionY, _, _ = Center()
return positionX, positionY, -1, -0.5
}

// centerRight is an anchor in the center-middle of the terminal that draws toward the right side.
func centerRight() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
positionX, positionY, _, _ = center()
// CenterRight is an Anchor in the center-middle of the terminal that draws toward the right side.
func CenterRight() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
positionX, positionY, _, _ = Center()
return positionX, positionY, 0, -0.5
}

// centerTop is an anchor in the center-middle of the terminal that draws toward the top.
func centerTop() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
positionX, positionY, _, _ = center()
// CenterTop is an Anchor in the center-middle of the terminal that draws toward the top.
func CenterTop() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
positionX, positionY, _, _ = Center()
return positionX, positionY, -0.5, -1
}

// middleRight is an anchor that is vertically centered and on the right edge of the game window.
func middleRight() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
// MiddleRight is an Anchor that is vertically centered and on the right edge of the game window.
func MiddleRight() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
termWidth, termHeight := termbox.Size()
rightX := (termWidth + gameBoyWidth) / 2
centerY := termHeight / 2
// Add an inner margin while also ensuring the text is always on-screen.
return min(termWidth, rightX-marginX), centerY, -1, 0
}

// offset returns an anchor that is offset from the specified anchor by a specified position.
func offset(anchor anchor, x, y int) anchor {
// Offset returns an Anchor that is cffset from the specified Anchor by a specified position.
func Offset(anchor Anchor, x, y int) Anchor {
return func() (positionX, positionY int, drawDirectionX, drawDirectionY float64) {
positionX, positionY, drawDirectionX, drawDirectionY = anchor()
positionX += x
Expand All @@ -130,60 +130,74 @@ func offset(anchor anchor, x, y int) anchor {
}
}

// color defines foreground and background attributes for drawing.
type color func() (fg, bg termbox.Attribute)
// Color defines foreground and background attributes for drawing.
type Color func() (fg, bg termbox.Attribute)

// normal is the default color.
func normal() (fg, bg termbox.Attribute) {
// Normal is the default Color.
func Normal() (fg, bg termbox.Attribute) {
return termbox.ColorDefault, termbox.ColorDefault
}

// inverted is a color that inverts the text and background color to appear as a highlight.
func inverted() (fg, bg termbox.Attribute) {
// Inverted is a Color that inverts the text and background color to appear as a highlight.
func Inverted() (fg, bg termbox.Attribute) {
return termbox.ColorBlack, termbox.ColorWhite
}

// magenta is a magenta color.
func magenta() (fg, bg termbox.Attribute) {
// Magenta is a magenta Color.
func Magenta() (fg, bg termbox.Attribute) {
return termbox.ColorMagenta, termbox.ColorDefault
}

// green is not a creative color.
func green() (fg, bg termbox.Attribute) {
// Green is not a creative Color.
func Green() (fg, bg termbox.Attribute) {
return termbox.ColorGreen, termbox.ColorDefault
}

func drawGameBoyBorder() {
func Border(decoration string) {
if decoration == "" {
return
}

termWidth, termHeight := termbox.Size()

topY := (termHeight - gameBoyHeight) / 2
bottomY := (termHeight + gameBoyHeight) / 2
leftX := (termWidth - gameBoyWidth) / 2
rightX := (termWidth + gameBoyWidth) / 2

// borderRunes := []rune{'🎃', '🧟', '🔮', '🧛', '🍬', '👻'}
borderRunes := []rune{'🦃', '🍁', '🌽', '🏈', '🥧', '🙏'}
borderRunes := []rune(decoration)

for i := 0; i < gameBoyWidth/2; i++ {
ch := borderRunes[i%len(borderRunes)]
draw(offset(origin, leftX+i*2, topY), normal, ch)
draw(offset(origin, leftX+i*2, bottomY), normal, ch)
Draw(Offset(Origin, leftX+i*2, topY), Normal, ch)
Draw(Offset(Origin, leftX+i*2, bottomY), Normal, ch)
}

for i := 0; i <= gameBoyHeight; i++ {
ch := borderRunes[i%len(borderRunes)]
draw(offset(origin, leftX, topY+i), normal, ch)
draw(offset(origin, rightX, topY+i), normal, ch)
Draw(Offset(Origin, leftX, topY+i), Normal, ch)
Draw(Offset(Origin, rightX, topY+i), Normal, ch)
}
}

func maxLength(ss []string) int {
result := 0
for _, s := range ss {
result = max(result, len(s))
}
return result
}

func drawSplash() {
draw(offset(centerTop, 0, 1), normal, `
_ _ _
___ | |_| |__ ___| | __ _ ___
/ _ \| __| '_ \ / _ \ |/ _`+"`"+` |/ _ \
| (_) | |_| | | | __/ | (_| | (_) |
\___/ \__|_| |_|\___|_|\__, |\___/
|___/
`)
func max(a, b int) int {
if a > b {
return a
}
return b
}

func min(a, b int) int {
if a < b {
return a
}
return b
}
Loading

0 comments on commit d488cb1

Please sign in to comment.