Updated README & added credits.
This commit is contained in:
parent
c82ce53433
commit
6f9191cbf9
28
README.md
28
README.md
@ -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
|
||||||
|
|
||||||
|
@ -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},
|
||||||
|
@ -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
185
cmd/tins2021/credits.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
@ -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 {
|
||||||
|
@ -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`),
|
||||||
|
Loading…
Reference in New Issue
Block a user