Updated README & added credits.

This commit is contained in:
Sander Schobers 2021-08-09 11:01:29 +02:00
parent c82ce53433
commit 6f9191cbf9
6 changed files with 211 additions and 14 deletions

View File

@ -1,4 +1,4 @@
# TINS 2020 # TINS 2021
## Content ## Content
@ -24,11 +24,14 @@
**Welcome to Qbitter!** **Welcome to Qbitter!**
TODO: description of the game. Qbitter is a game loosly based on a work "LW305 Kringloop" of M.C. Escher where a gnome runs down a stairs and morphs into its 2D abstract shape. The game also lends ideas from _Q*Bert_, a game from the eighties that was itself based on the works of M.C. Escher. In the game you (represented as a gnome) have to collect stars while trying to avoid enemies (hexagons). Every level has increasing difficulty.
**Controls:** **Controls:**
TODO: fill in. W: move up (left) cube
A: move down (left) cube
S: move down (right) cube
D: move up (right) cube
## Additional Rules ## Additional Rules
@ -36,23 +39,28 @@ TODO: fill in.
**genre rule #143** **genre rule #143**
This rule has been omitted by applying the bonus rule. This rule has been omitted (too subjective) by applying the bonus rule. There is two elements that could be considered funny though:
- The gnome (player) is an character that is absurdly placed in this world, both style (hand drawn vs geometric) and color (gray vs colorful) are opposites of each other.
- In the credits my own libraries are blatantly mentioned first (yes I know, it could be considered arrogance or is it humorous as well?).
**artistical rule #60** **artistical rule #147**
The game is based on a work of M.C. Escher "LW305 Kringloop" and it shows in different ways:
The least obvious and not finished within the time contraint: when researching you'll have to dial a phone number like you used to do with an old rotary dial (works by repeating the number on the keyboard an exact number of times). - The isometric cubes of the game try to mimic the style.
- The gnome featured as player is a loose interpretation of the gnome drawn by M.C. Escher.
- Geometric figures are used as game elements (stars, hearts, enemies).
* They are all based on a formula applied on a polar coordinate system (also the heart but this one isn't repeated).
**artistical rule #94** **artistical rule #94**
TODO: describe plug. In the credits some of the libraries I wrote (and used) are promoted (**Developed using** geom, zntg and allg5). To be sure that people notice this I put them on top of the list of credits.
**technical rule #113** **technical rule #113**
The main grid is made of cubes (faux 3D) that are regular hexagons in 2D. The main grid is made of cubes (faux 3D) that are regular hexagons in 2D. Additionaly the enemies of the player are made of wobbly hexagons.
**bonus rule #13** **bonus rule #13**
TODO: describe tests. Some functionality of the root package (tins2021) is unit tested (coverage is at time of writing 17% of the statements). You can find the tests in the files ending on `_test.go` (e.g. `level_test.go`).
### Definition ### Definition

View File

@ -34,7 +34,6 @@ func (a *app) loadFonts(ctx ui.Context, descriptors ...fontDescriptor) error {
const fpsOverlayName = `fps` const fpsOverlayName = `fps`
func (a *app) Init(ctx ui.Context) error { func (a *app) Init(ctx ui.Context) error {
if err := a.loadFonts(ctx, if err := a.loadFonts(ctx,
fontDescriptor{"debug", "fonts/FiraMono-Regular.ttf", 12}, fontDescriptor{"debug", "fonts/FiraMono-Regular.ttf", 12},
fontDescriptor{"default", "fonts/escheresk.ttf", 48}, fontDescriptor{"default", "fonts/escheresk.ttf", 48},

View File

@ -22,7 +22,10 @@ func (app *appContext) show(control ui.Control) {
app.setView(control) app.setView(control)
} }
func (app *appContext) ShowCredits(ctx ui.Context) {} func (app *appContext) ShowCredits(ctx ui.Context) {
app.setView(newCredits(app, ctx))
}
func (app *appContext) ShowInfo(ctx ui.Context) {} func (app *appContext) ShowInfo(ctx ui.Context) {}
func (app *appContext) ShowMainMenu(ctx ui.Context) { func (app *appContext) ShowMainMenu(ctx ui.Context) {

185
cmd/tins2021/credits.go Normal file
View File

@ -0,0 +1,185 @@
package main
import (
"fmt"
"log"
"os/exec"
"runtime"
"strings"
"time"
"opslag.de/schobers/geom"
"opslag.de/schobers/zntg/ui"
)
type credits struct {
ui.ControlBase
app *appContext
content []string
hovering int
offset float32
lastUpdate time.Time
}
func newCredits(app *appContext, ctx ui.Context) *credits {
return &credits{app: app, lastUpdate: time.Now(), content: []string{
"# QBITTER",
"",
"a game by Tharro",
"developed during the TINS 2021 game development competition",
"",
"**Developed using**",
"geom: a Go package for mathematics and geometries",
" - https://opslag.de/schobers/geom",
"zntg: an abstraction for rendering (UIs)",
" - https://opslag.de/schobers/zntg",
"allg5: an Allegro abstraction for Go",
" - https://opslag.de/schobers/allg5",
"",
"**... and also using**",
"Allegro: cross-platform development library",
" - https://liballeg.org",
"SDL: another cross-platform development library",
" - https://libsdl.org",
"go-sdl2: an SDL abstraction for Go",
" - https://github.com/veandco/go-sdl2",
"Fira Mono: monotype font",
"Escheresk: M.C. Escher themed font",
"Escher: M.C. Escher themed font",
"fauxgl: a software renderer for Go",
" - https://github.com/fogleman/fauxgl",
"draw2d: a 2D drawing library for Go",
" - https://github.com/llgcode/draw2d",
"go-colurful: a 2D drawing library for Go",
" - https://github.com/lucasb-eyer/go-colorful",
"resize: an image resizing library for Go",
" - https://github.com/nfnt/resize",
"testify: a testing library for Go",
" - https://github.com/stretchr/testify",
"",
"# THANKS",
"A big thank you to Amarillion for hosting this competition!",
" - https://tins.amarillion.org/2021",
}}
}
func (c *credits) Handle(ctx ui.Context, e ui.Event) bool {
if c.ControlBase.Handle(ctx, e) {
return true
}
ctx.Animate()
switch e := e.(type) {
case *ui.MouseButtonDownEvent:
if c.hovering != -1 {
s := c.content[c.hovering]
if strings.HasPrefix(s, " - https://") {
url := s[3:]
c.openBrowser(url)
}
}
case *ui.KeyDownEvent:
if e.Key == ui.KeyEscape {
c.app.ShowMainMenu(ctx)
return true
}
}
c.hovering = -1
mouse := ctx.MousePosition()
c.enumerateContent(ctx, func(s string, i int, top, height float32, font ui.Font) {
if !strings.HasPrefix(s, " - https://") {
return
}
if mouse.Y >= top && mouse.Y < top+height {
c.hovering = i
}
ctx.Renderer().SetMouseCursor(ui.MouseCursorPointer)
})
now := time.Now()
// if c.hovering == -1 {
delta := now.Sub(c.lastUpdate)
c.offset += float32(delta/time.Millisecond) / float32(20_000)
// }
c.lastUpdate = now
return false
}
func (c *credits) enumerateContent(ctx ui.Context, enum func(s string, i int, top, height float32, font ui.Font)) {
bounds := c.Bounds()
top := (1. - c.offset) * bounds.Max.Y
for i, font := range c.fonts(ctx) {
height := font.Height()
if top+height > 0 && top < bounds.Max.Y {
enum(c.content[i], i, top, height, font)
}
top += height
}
}
func (c *credits) fonts(ctx ui.Context) []ui.Font {
titleFont := ctx.Fonts().Font("title")
captionFont := ctx.Fonts().Font("default")
defaultFont := ctx.Fonts().Font("score")
font := func(s string) ui.Font {
if strings.HasPrefix(s, "# ") {
return titleFont
}
if strings.HasPrefix(s, "**") && strings.HasSuffix(s, "**") {
return captionFont
}
return defaultFont
}
fonts := make([]ui.Font, 0, len(c.content))
for _, line := range c.content {
font := font(line)
fonts = append(fonts, font)
}
return fonts
}
func (c *credits) openBrowser(url string) {
var err error
switch runtime.GOOS {
case "linux":
err = exec.Command("xdg-open", url).Start()
case "windows":
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start()
case "darwin":
err = exec.Command("open", url).Start()
default:
err = fmt.Errorf("unsupported platform")
}
if err != nil {
log.Println(err)
}
}
func (c *credits) Render(ctx ui.Context) {
renderer := ctx.Renderer()
width := c.Bounds().Dx()
defaultColor := ctx.Style().Palette.Text
c.enumerateContent(ctx, func(s string, i int, top, height float32, font ui.Font) {
color := defaultColor
if i == c.hovering {
color = ctx.Style().Palette.Secondary
}
if strings.HasPrefix(s, "# ") {
s = s[2:]
} else if strings.HasPrefix(s, "**") && strings.HasSuffix(s, "**") {
s = s[2 : len(s)-2]
} else if strings.HasPrefix(s, " - https://") {
s = s[3:]
}
textWidth := font.WidthOf(s)
renderer.Text(font, geom.PtF32(.5*(width-textWidth), top), color, s)
})
}

View File

@ -100,6 +100,8 @@ func (r levelController) Handle(ctx ui.Context, e ui.Event) bool {
r.Level.MovePlayer(tins2021.DirectionDownRight) r.Level.MovePlayer(tins2021.DirectionDownRight)
case ui.KeyA: case ui.KeyA:
r.Level.MovePlayer(tins2021.DirectionDownLeft) r.Level.MovePlayer(tins2021.DirectionDownLeft)
case ui.KeyEscape:
r.app.ShowMainMenu(ctx)
} }
} }
for _, animations := range r.Animations { for _, animations := range r.Animations {

View File

@ -82,7 +82,7 @@ func run() error {
Primary: zntg.MustHexColor(tins2021.Orange), Primary: zntg.MustHexColor(tins2021.Orange),
PrimaryDark: zntg.MustHexColor(`#15569F`), PrimaryDark: zntg.MustHexColor(`#15569F`),
PrimaryLight: zntg.MustHexColor(`#ABCAED`), PrimaryLight: zntg.MustHexColor(`#ABCAED`),
Secondary: zntg.MustHexColor(`#4AC69A`), Secondary: zntg.MustHexColor(tins2021.Blue),
SecondaryDark: zntg.MustHexColor(`#0AA36D`), SecondaryDark: zntg.MustHexColor(`#0AA36D`),
SecondaryLight: zntg.MustHexColor(`#A6EED4`), SecondaryLight: zntg.MustHexColor(`#A6EED4`),
Text: zntg.MustHexColor(`#EFEFEF`), Text: zntg.MustHexColor(`#EFEFEF`),