Obsah
1. Programovací jazyk Go a 2D grafika – kostra jednoduché hry
2. Vykreslení jednoduché scény s využitím knihovny go-sdl2
3. Zdrojový kód prvního demonstračního příkladu
4. Rozdělení kódu aplikace do několika funkcí
5. Použití lokálních proměnných, předávání stavu aplikace do volaných funkcí
6. Zdrojový kód třetího demonstračního příkladu
7. Jediná datová struktura obsahující celý stav aplikace
8. Použití rozhraní (interface)
9. Úplný zdrojový kód upraveného příkladu
11. Reakce na událost typu „ukončení aplikace“
12. Reakce na stisk kláves Escape a Q
13. Pohyb spritu pomocí kurzorových kláves
14. Úplný zdrojový kód osmého demonstračního příkladu
15. Vylepšení předchozího příkladu – reakce na stisk i puštění klávesy
16. Úplný zdrojový kód devátého demonstračního příkladu
17. Automaticky se pohybující sprite a klávesnicí ovládaný hráč
18. Úplný zdrojový kód desátého demonstračního příkladu
19. Repositář s demonstračními příklady
1. Programovací jazyk Go a 2D grafika – kostra jednoduché hry
Dnešní článek se bude v některých ohledech odlišovat od článků předchozích. Zatímco v dřívějších částech seriálu o programovacím jazyce Go jsme se snažili popsat co nejvíce funkcionality, dnes budeme na přání několika čtenářů postupovat odlišným – pomalejším – způsobem. Budeme totiž postupně upravovat jeden demonstrační příklad, který nakonec bude existovat v deseti verzích. První verze bude představována jednoduchou nestrukturovanou aplikací, poslední verze již bude sloužit jako poměrně slušně navržená kostra pro primitivní grafickou hříčku (výsledek se snad ani nedá nazývat „hrou“). Současně už nebudeme pro porovnání uvádět i céčkovou variantu příkladu, protože struktura céčkové hry bude od Go varianty v mnoha ohledech odlišná (tyto jazyky jsou i přes zdánlivou podobnost dosti rozdílné).
Obrázek 1: Předlohou nám bude slavná starodávná hra Adventure pro osmibitovou herní konzoli Atari 2600. Zelený čtverec nalevo je hráč, žlutá „kachna“ je ve skutečnosti strašlivý a k tomu ještě hladový drak.
2. Vykreslení jednoduché scény s využitím knihovny go-sdl2
Ukažme si tedy první verzi příkladu. Ta je velmi jednoduchá a plně vychází z demonstračních příkladů, které jsme si popsali minule. Ve zdrojovém kódu se postupně provádí tyto operace:
- Provede se inicializace knihovny SDL funkcí sdl.Init, současně se zaregistruje kód pro ukončení SDL.
- Vytvoří se nové okno funkcí sdl.CreateWindow, opět se zaregistruje kód zavolaný pro uzavření okna.
- Získá se reference na primární kreslicí plochu, a to konkrétně metodouwindow.GetSurface (tato plocha se nijak nemusí uvolňovat).
- Načte se rastrový obrázek globe.png s alfa kanálem.
- Okno, resp. primární kreslicí plocha se vyplní konstantní barvou metodou primarySurface.FillRect.
- Rastrový obrázek se na primární plochu vykreslí metodouimage.Blit.
- Následně se počká na zobrazení okna – toto není striktně nutné v reálné aplikaci/hře se smyčkou událostí, ovšem pro jednoduchý program bez této smyčky je na některých systémech (kombinacích čipsetu a grafické karty) nutné chvíli počkat.
- Vynucení překreslení obsahu celého okna metodouwindow.UpdateSurface.
- Nakonec se po pěti sekundách (sdl.Delay) celá aplikace korektně ukončí.
Dále si povšimněte, že se testují prakticky všechny návratové kódy s chybou. To lze ověřit nástrojem errcheck, s nímž jsme se již v tomto seriálu setkali.
Obrázek 2: Bitmapa s alfa kanálem zobrazená v okně aplikace.
3. Zdrojový kód prvního demonstračního příkladu
Úplný zdrojový kód dnešního prvního demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/test01.go:
package main import ( "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) func main() { if err := sdl.Init(sdl.INIT_VIDEO); err != nil { panic(err) } defer sdl.Quit() window, err := sdl.CreateWindow("SDL2 example #1", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } defer window.Destroy() primarySurface, err := window.GetSurface() if err != nil { panic(err) } image, err := img.Load("globe.png") if err != nil { panic(err) } defer image.Free() primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: width/2 - image.W/2, Y: height/2 - image.H/2, W: 0, H: 0, } err = image.Blit(nil, primarySurface, &dstRect) if err != nil { panic(err) } sdl.Delay(10) window.UpdateSurface() sdl.Delay(5000) }
Obrázek 3: Drak ve hře Adventure právě dohnal hráče…
4. Rozdělení kódu aplikace do několika funkcí
V předchozím zdrojovém kódu byla celá funkcionalita soustředěna v jediné funkci main, což sice zdánlivě nemusí vadit (ostatně příklad je stále velmi krátký), ovšem s rostoucí složitostí nebude tato struktura zdrojového kódu dobře „škálovat“ a po určité době se programátor ve svém kódu doslova ztratí. První varianta úpravy může spočívat v tom, že se stav celé aplikace, což je v této chvíli trojice objektů (datových struktur splňujících určitá rozhraní), uloží do globálních proměnných:
var ( window *sdl.Window primarySurface *sdl.Surface image *sdl.Surface )
Celá aplikace se díky tomu rozdělí do trojice funkcí volaných z funkce main, která je vstupním bodem do celé aplikace:
- Inicializace – initialize
- Finalizace – finalize
- Překreslení obsahu hlavního okna – redraw
Úplný zdrojový kód naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/test02.go:
package main import ( "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) var ( window *sdl.Window primarySurface *sdl.Surface image *sdl.Surface ) func initialize() { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } window, err = sdl.CreateWindow("SDL2 example #2", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } primarySurface, err = window.GetSurface() if err != nil { panic(err) } image, err = img.Load("globe.png") if err != nil { panic(err) } } func finalize() { primarySurface.Free() image.Free() window.Destroy() sdl.Quit() } func redraw() { primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: width/2 - image.W/2, Y: height/2 - image.H/2, W: 0, H: 0, } err := image.Blit(nil, primarySurface, &dstRect) if err != nil { panic(err) } window.UpdateSurface() } func main() { initialize() defer finalize() sdl.Delay(10) redraw() sdl.Delay(5000) }
5. Použití lokálních proměnných, předávání stavu aplikace do volaných funkcí
Předchozí zdrojový kód pravděpodobně nikoho neohromil, protože se v něm pro uložení stavu aplikace používají globální proměnné, což mj. do značné míry ztěžuje ladění a testování aplikace (nehledě na problémy s použitím ukazatelů ve chvíli, kdyby se nějaká část aplikace spustila ve vlastní gorutině).
Větší izolaci jednotlivých funkcí zajistíme použitím parametrů nesoucích informace o stavu aplikace. Tyto parametry jsou předávány do všech funkcí, které s nimi pracují. Vzhledem k tomu, že všechny objekty nesoucí stav aplikace jsou vytvářeny ve funkci initialize, můžeme její hlavičku upravit takto:
func initialize() (*sdl.Window, *sdl.Surface, *sdl.Surface) { ... ... ... }
Všechny ostatní funkce se přímo či nepřímo volají z funkce main:
func main() { window, primarySurface, image := initialize() defer finalize(window, primarySurface, image) sdl.Delay(10) redraw(window, primarySurface, image) sdl.Delay(5000) }
Obrázek 4: Drak právě spapal hráče; nyní zbývá jen stlačení RESETu.
6. Zdrojový kód třetího demonstračního příkladu
Úplný zdrojový kód dnešního třetího demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/test03.go:
package main import ( "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) func initialize() (*sdl.Window, *sdl.Surface, *sdl.Surface) { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } window, err := sdl.CreateWindow("SDL2 example #3", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } primarySurface, err := window.GetSurface() if err != nil { panic(err) } image, err := img.Load("globe.png") if err != nil { panic(err) } return window, primarySurface, image } func finalize(window *sdl.Window, primarySurface *sdl.Surface, image *sdl.Surface) { primarySurface.Free() image.Free() window.Destroy() sdl.Quit() } func redraw(window *sdl.Window, primarySurface *sdl.Surface, image *sdl.Surface) { primarySurface.FillRect(nil, sdl.MapRGB(primarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: width/2 - image.W/2, Y: height/2 - image.H/2, W: 0, H: 0, } err := image.Blit(nil, primarySurface, &dstRect) if err != nil { panic(err) } window.UpdateSurface() } func main() { window, primarySurface, image := initialize() defer finalize(window, primarySurface, image) sdl.Delay(10) redraw(window, primarySurface, image) sdl.Delay(5000) }
7. Jediná datová struktura obsahující celý stav aplikace
Při čtení předchozí varianty zdrojového kódu vás možná napadlo, že se vlastně stále pracuje se stejnými strukturami, resp. ukazateli na ně a že by tedy mohlo být výhodné tyto struktury sloučit do jediného datového typu. To je v jazyce Go snadné, takže si vytvořme nový datový typ pojmenovaný například gameState:
type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface }
Jakmile máme vytvořenou novou strukturu obsahující veškerý stav aplikace, zdrojový kód se může zjednodušit, protože do funkcí budeme předávat jen jediný parametr – ukazatel na danou strukturu (zde viditelnou lokálně v rámci funkce main):
func main() { var state gameState initialize(&state) defer finalize(&state) sdl.Delay(10) redraw(&state) sdl.Delay(5000) }
Opět si ukažme celý zdrojový kód takto upraveného programu:
package main import ( "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface } func initialize(state *gameState) { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } state.Window, err = sdl.CreateWindow("SDL2 example #4", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } state.PrimarySurface, err = state.Window.GetSurface() if err != nil { panic(err) } state.Image, err = img.Load("globe.png") if err != nil { panic(err) } } func finalize(state *gameState) { state.PrimarySurface.Free() state.Image.Free() state.Window.Destroy() sdl.Quit() } func redraw(state *gameState) { state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: width/2 - state.Image.W/2, Y: height/2 - state.Image.H/2, W: 0, H: 0, } err := state.Image.Blit(nil, state.PrimarySurface, &dstRect) if err != nil { panic(err) } state.Window.UpdateSurface() } func main() { var state gameState initialize(&state) defer finalize(&state) sdl.Delay(10) redraw(&state) sdl.Delay(5000) }
8. Použití rozhraní (interface)
Od předchozího zdrojového kódu je již jen krůček k tomu, abychom využili další vlastnost programovacího jazyka Go. Jedná se o možnost vytvářet rozhraní interface a metody (methods) pro konkrétní datový typ. Pokud nějaký datový typ obsahuje všechny metody daného rozhraní, je automaticky toto rozhraní typem uspokojeno (satisfy), takže se v Go nemusí používat obdoba deklarace objekt/typ implements rozhraní. Připomeňme si, že náš datový typ se stavem aplikace vypadá následovně:
type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface }
Dále nadeklarujeme rozhraní, které bude obsahovat pouze hlavičky metod, tj. jejich názvy, případné parametry a návratové hodnoty:
type Game interface { initialize() finalize() redraw() }
Nyní nám již stačí relativně malá úprava – z funkcí initialize atd. vytvoříme metody. Tj. namísto běžné funkce akceptující ukazatel na datovou strukturu:
func initialize(state *gameState) { ... ... ... }
Vytvoříme metodu, jejímž příjemcem (receiver) je daná struktura popř. ukazatel na ni:
func (state *gameState) initialize() { ... ... ... }
Interně se v metodě chováme k příjemci stejně, jakoby se jednalo o parametr.
V příkladu se dále zjednoduší a zpřehlední funkce main, která přestává mít „céčkový“ ráz:
func main() { game := NewGame() game.initialize() defer game.finalize() sdl.Delay(10) game.redraw() sdl.Delay(5000) }
Obrázek 5: Bludiště ve hře Adventure. Vlevo nahoře se nachází hráč (čtverec) nesoucí meč (šipku) :-)
9. Úplný zdrojový kód upraveného příkladu
Ukažme si nyní celý kód příkladu založeného na použití rozhraní:
package main import ( "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) type Game interface { initialize() finalize() redraw() } type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface } func NewGame() gameState { return gameState{ Window: nil, PrimarySurface: nil, Image: nil, } } func (state *gameState) initialize() { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } state.Window, err = sdl.CreateWindow("SDL2 example #5", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } state.PrimarySurface, err = state.Window.GetSurface() if err != nil { panic(err) } state.Image, err = img.Load("globe.png") if err != nil { panic(err) } } func (state *gameState) finalize() { state.PrimarySurface.Free() state.Image.Free() state.Window.Destroy() sdl.Quit() } func (state *gameState) redraw() { state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: width/2 - state.Image.W/2, Y: height/2 - state.Image.H/2, W: 0, H: 0, } err := state.Image.Blit(nil, state.PrimarySurface, &dstRect) if err != nil { panic(err) } state.Window.UpdateSurface() } func main() { game := NewGame() game.initialize() defer game.finalize() sdl.Delay(10) game.redraw() sdl.Delay(5000) }
10. Systém událostí (events)
Velmi důležitým konceptem, s nímž se v knihovně SDL setkáme, je systém událostí (events). Při běhu aplikace totiž dochází ke vzniku událostí, které jsou vyvolány jak samotným systémem (časovač…), tak i uživatelem (stisk klávesy, posun kurzoru myši, …). Na tyto události může aplikace v případě potřeby adekvátně reagovat.
Interně systém událostí pracuje přibližně takto:
- Knihovna SDL si při své inicializaci vytvoří takzvanou frontu událostí
- Po spuštění aplikace se spustí programová smyčka nazvaná většinou event loop, která postupně z fronty událostí vybírá jednotlivé události (samozřejmě jen za předpokladu, že k nim došlo)
- Následně se pro událost získanou z fronty zavolá příslušný programový kód
11. Reakce na událost typu „ukončení aplikace“
Prvním typem události je událost nazvaná QuitEvent. Tato událost vznikne ve chvíli, kdy se uživatel rozhodne aplikaci ukončit, typicky stiskem ikony sloužící pro uzavření okna. Celá smyčka událostí může vypadat následovně:
func (state *gameState) eventLoop() { var event sdl.Event done := false for !done { event = sdl.PollEvent() switch event.(type) { case *sdl.QuitEvent: log.Println("Quitting") done = true } state.redraw() sdl.Delay(20) } }
Smyčka se volá z funkce main:
func main() { game := NewGame() game.initialize() defer game.finalize() sdl.Delay(10) game.eventLoop() }
Úplný zdrojový kód naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/test06.go:
package main import ( "log" "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) type Game interface { initialize() finalize() redraw() eventLoop() } type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface } func NewGame() gameState { return gameState{ Window: nil, PrimarySurface: nil, Image: nil, } } func (state *gameState) initialize() { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } state.Window, err = sdl.CreateWindow("SDL2 example #6", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } state.PrimarySurface, err = state.Window.GetSurface() if err != nil { panic(err) } state.Image, err = img.Load("globe.png") if err != nil { panic(err) } } func (state *gameState) finalize() { state.PrimarySurface.Free() state.Image.Free() state.Window.Destroy() sdl.Quit() } func (state *gameState) redraw() { state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: width/2 - state.Image.W/2, Y: height/2 - state.Image.H/2, W: 0, H: 0, } err := state.Image.Blit(nil, state.PrimarySurface, &dstRect) if err != nil { panic(err) } state.Window.UpdateSurface() } func (state *gameState) eventLoop() { var event sdl.Event done := false for !done { event = sdl.PollEvent() switch event.(type) { case *sdl.QuitEvent: log.Println("Quitting") done = true } state.redraw() sdl.Delay(20) } } func main() { game := NewGame() game.initialize() defer game.finalize() sdl.Delay(10) game.eventLoop() }
12. Reakce na stisk kláves Escape a Q
Snadno můžeme reagovat i na události typu „stisk klávesy“. Jedná se o událost PRESSED, přičemž struktura nesoucí informace o události obsahuje kód stisknuté klávesy. Tento kód lze porovnat s konstantami, které jsou součástí balíčku sdl a ukončit tak aplikaci například při stisku klávesy Escape popř. Q:
switch t := event.(type) { case *sdl.QuitEvent: done = true case *sdl.KeyboardEvent: keyCode := t.Keysym.Sym if t.State == sdl.PRESSED { switch keyCode { case sdl.K_ESCAPE: done = true case sdl.K_q: done = true } } }
Upravená aplikace vypadá následovně:
package main import ( "log" "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) type Game interface { initialize() finalize() redraw() eventLoop() } type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface } func NewGame() gameState { return gameState{ Window: nil, PrimarySurface: nil, Image: nil, } } func (state *gameState) initialize() { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } state.Window, err = sdl.CreateWindow("SDL2 example #7", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } state.PrimarySurface, err = state.Window.GetSurface() if err != nil { panic(err) } state.Image, err = img.Load("globe.png") if err != nil { panic(err) } } func (state *gameState) finalize() { state.PrimarySurface.Free() state.Image.Free() state.Window.Destroy() sdl.Quit() } func (state *gameState) redraw() { state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: width/2 - state.Image.W/2, Y: height/2 - state.Image.H/2, W: 0, H: 0, } err := state.Image.Blit(nil, state.PrimarySurface, &dstRect) if err != nil { panic(err) } state.Window.UpdateSurface() } func (state *gameState) eventLoop() { var event sdl.Event done := false for !done { event = sdl.PollEvent() switch t := event.(type) { case *sdl.QuitEvent: done = true case *sdl.KeyboardEvent: keyCode := t.Keysym.Sym if t.State == sdl.PRESSED { switch keyCode { case sdl.K_ESCAPE: done = true case sdl.K_q: done = true } } } state.redraw() sdl.Delay(20) } log.Println("Quitting") } func main() { game := NewGame() game.initialize() defer game.finalize() sdl.Delay(10) game.eventLoop() }
13. Pohyb spritu pomocí kurzorových kláves
Nyní rozšíříme stav aplikace o souřadnice spritu (obrázku zeměkoule):
type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface X, Y int32 }
Zeměkoulí budeme pohybovat kurzorovými šipkami, což se projeví i v nepatrně odlišném kódu pro vykreslení:
dstRect := sdl.Rect{ X: state.X, Y: state.Y, W: 0, H: 0, } err := state.Image.Blit(nil, state.PrimarySurface, &dstRect) ... ... ...
Teoreticky je možné reagovat na stisk klávesy, například takto:
switch keyCode { case sdl.K_LEFT: state.X -= 2 case sdl.K_RIGHT: state.X += 2 case sdl.K_UP: state.Y -= 2 case sdl.K_DOWN: state.Y += 2 }
Ovšem po spuštění příkladu uvidíte, že se bude projevovat tzv. autorepeat klávesnice a současně nebude pohyb okamžitý.
14. Úplný zdrojový kód osmého demonstračního příkladu
Úplný zdrojový kód osmého demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/test08.go:
package main import ( "log" "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) type Game interface { initialize() finalize() redraw() eventLoop() } type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface X, Y int32 } func NewGame() gameState { return gameState{ Window: nil, PrimarySurface: nil, Image: nil, } } func (state *gameState) initialize() { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } state.Window, err = sdl.CreateWindow("SDL2 example #8", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } state.PrimarySurface, err = state.Window.GetSurface() if err != nil { panic(err) } state.Image, err = img.Load("globe.png") if err != nil { panic(err) } state.X = width/2 - state.Image.W/2 state.Y = height/2 - state.Image.H/2 } func (state *gameState) finalize() { state.PrimarySurface.Free() state.Image.Free() state.Window.Destroy() sdl.Quit() } func (state *gameState) redraw() { state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: state.X, Y: state.Y, W: 0, H: 0, } err := state.Image.Blit(nil, state.PrimarySurface, &dstRect) if err != nil { panic(err) } state.Window.UpdateSurface() } func (state *gameState) eventLoop() { var event sdl.Event done := false for !done { event = sdl.PollEvent() switch t := event.(type) { case *sdl.QuitEvent: done = true case *sdl.KeyboardEvent: keyCode := t.Keysym.Sym if t.State == sdl.PRESSED { switch keyCode { case sdl.K_ESCAPE: done = true case sdl.K_q: done = true case sdl.K_LEFT: state.X -= 2 case sdl.K_RIGHT: state.X += 2 case sdl.K_UP: state.Y -= 2 case sdl.K_DOWN: state.Y += 2 } } } state.redraw() sdl.Delay(20) } log.Println("Quitting") } func main() { game := NewGame() game.initialize() defer game.finalize() sdl.Delay(10) game.eventLoop() }
15. Vylepšení předchozího příkladu – reakce na stisk i puštění klávesy
Z předchozího příkladu bylo patrné, že kvůli autorepeatu není pohyb hráče plynulý. Je tedy nutné použít odlišnou logiku – ta spočívá v tom, že si zapamatujeme jak stisk klávesy, tak i její puštění. Jedná se sice o stejnou událost, ale s jiným typem: PRESSED versus RELEASED:
case sdl.PRESSED: switch keyCode { case sdl.K_LEFT: left = true case sdl.K_RIGHT: right = true case sdl.K_UP: up = true case sdl.K_DOWN: down = true } case sdl.RELEASED: switch keyCode { case sdl.K_LEFT: left = false case sdl.K_RIGHT: right = false case sdl.K_UP: up = false case sdl.K_DOWN: down = false }
16. Úplný zdrojový kód devátého demonstračního příkladu
Úplný zdrojový kód dnešního předposledního demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/test09.go:
package main import ( "log" "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) type Game interface { initialize() finalize() redraw() eventLoop() } type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface X, Y int32 } func NewGame() gameState { return gameState{ Window: nil, PrimarySurface: nil, Image: nil, } } func (state *gameState) initialize() { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } state.Window, err = sdl.CreateWindow("SDL2 example #9", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } state.PrimarySurface, err = state.Window.GetSurface() if err != nil { panic(err) } state.Image, err = img.Load("globe.png") if err != nil { panic(err) } state.X = width/2 - state.Image.W/2 state.Y = height/2 - state.Image.H/2 } func (state *gameState) finalize() { state.PrimarySurface.Free() state.Image.Free() state.Window.Destroy() sdl.Quit() } func (state *gameState) redraw() { state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192)) dstRect := sdl.Rect{ X: state.X, Y: state.Y, W: 0, H: 0, } err := state.Image.Blit(nil, state.PrimarySurface, &dstRect) if err != nil { panic(err) } state.Window.UpdateSurface() } func (state *gameState) eventLoop() { var event sdl.Event done := false left := false right := false up := false down := false for !done { event = sdl.PollEvent() switch t := event.(type) { case *sdl.QuitEvent: done = true case *sdl.KeyboardEvent: keyCode := t.Keysym.Sym switch t.State { case sdl.PRESSED: switch keyCode { case sdl.K_ESCAPE: done = true case sdl.K_q: done = true case sdl.K_LEFT: left = true case sdl.K_RIGHT: right = true case sdl.K_UP: up = true case sdl.K_DOWN: down = true } case sdl.RELEASED: switch keyCode { case sdl.K_LEFT: left = false case sdl.K_RIGHT: right = false case sdl.K_UP: up = false case sdl.K_DOWN: down = false } } } if left { state.X -= 2 } if right { state.X += 2 } if up { state.Y -= 2 } if down { state.Y += 2 } state.redraw() sdl.Delay(20) } log.Println("Quitting") } func main() { game := NewGame() game.initialize() defer game.finalize() sdl.Delay(10) game.eventLoop() }
17. Automaticky se pohybující sprite a klávesnicí ovládaný hráč
Poslední úprava bude spočívat v tom, že necháme zeměkouli (sprite), aby se ve scéně pohybovala automaticky – odrážela se od stěn okna. Ovšem navíc do scény přidáme hráče, který bude – stejně jako ve hře Adventure – realizován pouhým obdélníkem. Celý stavový prostor hry se tedy dále rozšíří:
type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface PlayerX, PlayerY int32 NPCX, NPCY int32 NPCdX, NPCdY int32 }
Samotný pohyb zeměkoule (NPC) může být realizován následovně (konstanty na začátku byly získány v grafickém editoru, protože sprite okolo sebe obsahuje i neviditelné či poloprůhledné okraje):
func moveNPC(state *gameState) { const ( LeftBorder = 5 TopBorder = 5 RightBorder = 10 BottomBorder = 10 ) state.NPCX += state.NPCdX state.NPCY += state.NPCdY if state.NPCX > state.PrimarySurface.W-state.Image.W+RightBorder { state.NPCdX = -state.NPCdX } if state.NPCY > state.PrimarySurface.H-state.Image.H+BottomBorder { state.NPCdY = -state.NPCdY } if state.NPCX < -LeftBorder { state.NPCdX = -state.NPCdX } if state.NPCY < -TopBorder { state.NPCdY = -state.NPCdY } }
Obrázek 6: Fandové hry Adventure (stále existují!) si mohou pořídit tričko s pro tuto hry typickým drakem (který vypadá spíš jako kachna :-)
18. Úplný zdrojový kód desátého demonstračního příkladu
Úplný zdrojový kód desátého a současně i posledního demonstračního příkladu naleznete na adrese https://github.com/tisnik/go-root/blob/master/article63/test10.go:
package main import ( "log" "github.com/veandco/go-sdl2/img" "github.com/veandco/go-sdl2/sdl" ) const ( width = 640 height = 480 ) type Game interface { initialize() finalize() redraw() eventLoop() } type gameState struct { Window *sdl.Window PrimarySurface *sdl.Surface Image *sdl.Surface PlayerX, PlayerY int32 NPCX, NPCY int32 NPCdX, NPCdY int32 } func NewGame() gameState { return gameState{ Window: nil, PrimarySurface: nil, Image: nil, } } func (state *gameState) initialize() { err := sdl.Init(sdl.INIT_VIDEO) if err != nil { panic(err) } state.Window, err = sdl.CreateWindow("SDL2 example #10", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED, width, height, sdl.WINDOW_SHOWN) if err != nil { panic(err) } state.PrimarySurface, err = state.Window.GetSurface() if err != nil { panic(err) } state.Image, err = img.Load("globe.png") if err != nil { panic(err) } state.NPCX = width/2 - state.Image.W/2 state.NPCY = height/2 - state.Image.H/2 state.NPCdX = 1 state.NPCdY = 1 state.PlayerX = 100 state.PlayerY = 100 } func (state *gameState) finalize() { state.PrimarySurface.Free() state.Image.Free() state.Window.Destroy() sdl.Quit() } func moveNPC(state *gameState) { const ( LeftBorder = 5 TopBorder = 5 RightBorder = 10 BottomBorder = 10 ) state.NPCX += state.NPCdX state.NPCY += state.NPCdY if state.NPCX > state.PrimarySurface.W-state.Image.W+RightBorder { state.NPCdX = -state.NPCdX } if state.NPCY > state.PrimarySurface.H-state.Image.H+BottomBorder { state.NPCdY = -state.NPCdY } if state.NPCX < -LeftBorder { state.NPCdX = -state.NPCdX } if state.NPCY < -TopBorder { state.NPCdY = -state.NPCdY } } func (state *gameState) redraw() { state.PrimarySurface.FillRect(nil, sdl.MapRGB(state.PrimarySurface.Format, 192, 255, 192)) playerRect := sdl.Rect{ X: state.PlayerX, Y: state.PlayerY, W: 20, H: 20, } state.PrimarySurface.FillRect(&playerRect, sdl.MapRGB(state.PrimarySurface.Format, 255, 192, 192)) dstRect := sdl.Rect{ X: state.NPCX, Y: state.NPCY, W: 0, H: 0, } err := state.Image.Blit(nil, state.PrimarySurface, &dstRect) if err != nil { panic(err) } state.Window.UpdateSurface() } func (state *gameState) eventLoop() { var event sdl.Event done := false left := false right := false up := false down := false for !done { event = sdl.PollEvent() switch t := event.(type) { case *sdl.QuitEvent: done = true case *sdl.KeyboardEvent: keyCode := t.Keysym.Sym switch t.State { case sdl.PRESSED: switch keyCode { case sdl.K_ESCAPE: done = true case sdl.K_q: done = true case sdl.K_LEFT: left = true case sdl.K_RIGHT: right = true case sdl.K_UP: up = true case sdl.K_DOWN: down = true } case sdl.RELEASED: switch keyCode { case sdl.K_LEFT: left = false case sdl.K_RIGHT: right = false case sdl.K_UP: up = false case sdl.K_DOWN: down = false } } } if left { state.PlayerX -= 2 } if right { state.PlayerX += 2 } if up { state.PlayerY -= 2 } if down { state.PlayerY += 2 } moveNPC(state) state.redraw() sdl.Delay(10) } log.Println("Quitting") } func main() { game := NewGame() game.initialize() defer game.finalize() sdl.Delay(10) game.eventLoop() }
19. Repositář s demonstračními příklady
Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/go-root (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně stovku kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady, které naleznete v následující tabulce:
# | Příklad | Stručný popis | Cesta |
---|---|---|---|
1 | test01.go | vykreslení jednoduché scény s využitím knihovny go-sdl2 | https://github.com/tisnik/go-root/blob/master/article63/test01.go |
2 | test02.go | rozdělení kódu aplikace do několika funkcí | https://github.com/tisnik/go-root/blob/master/article63/test02.go |
3 | test03.go | použití lokálních proměnných, předávání stavu aplikace do volaných funkcí | https://github.com/tisnik/go-root/blob/master/article63/test03.go |
4 | test04.go | jediná datová struktura obsahující celý stav aplikace | https://github.com/tisnik/go-root/blob/master/article63/test04.go |
5 | test05.go | použití rozhraní (interface) | https://github.com/tisnik/go-root/blob/master/article63/test05.go |
6 | test06.go | reakce na událost typu „ukončení aplikace“ | https://github.com/tisnik/go-root/blob/master/article63/test06.go |
7 | test07.go | reakce na stisk kláves Escape a Q | https://github.com/tisnik/go-root/blob/master/article63/test07.go |
8 | test08.go | pohyb spritu pomocí kurzorových kláves | https://github.com/tisnik/go-root/blob/master/article63/test08.go |
9 | test09.go | vylepšení předchozího příkladu – reakce na stisk i puštění klávesy | https://github.com/tisnik/go-root/blob/master/article63/test09.go |
10 | test10.go | automaticky se pohybující sprite a klávesnicí ovládaný hráč | https://github.com/tisnik/go-root/blob/master/article63/test10.go |
20. Odkazy na Internetu
- Adventure for the Atari 2600 Video Game Console by Warren Robinett
http://www.warrenrobinett.com/adventure/index.html - Mapa hry Adventure
http://www.warrenrobinett.com/adventure/adv-map1.gif - Stránky projektu SDL
http://www.libsdl.org/ - Simple DirectMedia Layer (Wikipedia)
https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer - SDL Language Bindings
http://www.libsdl.org/languages.php - SDL version 1.2.15
http://www.libsdl.org/download-1.2.php - SDL version 2.0.1
http://www.libsdl.org/download-2.0.php - Rozhraní go-sdl2
https://github.com/veandco/go-sdl2 - Dokumentace k rozhraní go-sdl2
https://godoc.org/github.com/veandco/go-sdl2 - Dokumentace k balíčku sdl
https://godoc.org/github.com/veandco/go-sdl2/sdl - Dokumentace k balíčku gfx
https://godoc.org/github.com/veandco/go-sdl2/gfx - Cross-platform games development (part 1)
http://renatoc.wait4.org/2010/02/04/cross-platform-games-development-part-1/ - Cross-platform games development (part 2)
http://renatoc.wait4.org/tag/sdljava/ - Go Data Structures: Binary Search Tree
https://flaviocopes.com/golang-data-structure-binary-search-tree/ - Gobs of data
https://blog.golang.org/gobs-of-data - Formát BSON
http://bsonspec.org/ - Golang Guide: A List of Top Golang Frameworks, IDEs & Tools
https://blog.intelligentbee.com/2017/08/14/golang-guide-list-top-golang-frameworks-ides-tools/ - Tvorba univerzálních projevů
http://www.kyblsoft.cz/projevy - Repositář projektu Gift
https://github.com/disintegration/gift - Dokumentace k projektu Gift
https://godoc.org/github.com/disintegration/gift - Online x86 / x64 Assembler and Disassembler
https://defuse.ca/online-x86-assembler.htm#disassembly2 - The Design of the Go Assembler
https://talks.golang.org/2016/asm.slide#1 - A Quick Guide to Go's Assembler
https://golang.org/doc/asm - AssemblyPolicy
https://github.com/golang/go/wiki/AssemblyPolicy - Geohash in Golang Assembly
https://mmcloughlin.com/posts/geohash-assembly - Command objdump
https://golang.org/cmd/objdump/ - Assembly
https://goroutines.com/asm - Go & Assembly
http://www.doxsey.net/blog/go-and-assembly - A Foray Into Go Assembly Programming
https://blog.sgmansfield.com/2017/04/a-foray-into-go-assembly-programming/ - Golang Capturing log.Println And fmt.Println Output
https://medium.com/@hau12a1/golang-capturing-log-println-and-fmt-println-output-770209c791b4 - Stránka projektu plotly
https://plot.ly/ - Plotly JavaScript Open Source Graphing Library
https://plot.ly/javascript/ - Domain coloring
https://en.wikipedia.org/wiki/Domain_coloring - Michael Fogleman's projects
https://www.michaelfogleman.com/projects/tagged/graphics/ - Color Graphs of Complex Functions
https://web.archive.org/web/20120511021419/http://w.american.edu/cas/mathstat/lcrone/ComplexPlot.html - A Gallery of Complex Functions
http://wismuth.com/complex/gallery.html - package glot
https://godoc.org/github.com/Arafatk/glot - Gnuplotting: Output terminals
http://www.gnuplotting.org/output-terminals/ - Introducing Glot the plotting library for Golang
https://medium.com/@Arafat./introducing-glot-the-plotting-library-for-golang-3133399948a1 - Introducing Glot the plotting library for Golang
https://blog.gopheracademy.com/advent-2018/introducing-glot/ - Glot is a plotting library for Golang built on top of gnuplot
https://github.com/Arafatk/glot - Example plots (gonum/plot)
https://github.com/gonum/plot/wiki/Example-plots - A repository for plotting and visualizing data (gonum/plot)
https://github.com/gonum/plot - golang library to make https://chartjs.org/ plots
https://github.com/brentp/go-chartjs - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - The Gonum Numerical Computing Package
https://www.gonum.org/post/introtogonum/ - Gomacro na GitHubu
https://github.com/cosmos72/gomacro - gophernotes – Use Go in Jupyter notebooks and nteract
https://github.com/gopherdata/gophernotes - gonum
https://github.com/gonum - go-gota/gota – DataFrames and data wrangling in Go (Golang)
https://porter.io/github.com/go-gota/gota - A repository for plotting and visualizing data
https://github.com/gonum/plot - Gonum Numerical Packages
https://www.gonum.org/ - Stránky projektu MinIO
https://min.io/ - MinIO Quickstart Guide
https://docs.min.io/docs/minio-quickstart-guide.html - MinIO Go Client API Reference
https://docs.min.io/docs/golang-client-api-reference - MinIO Python Client API Reference
https://docs.min.io/docs/python-client-api-reference.html - Performance at Scale: MinIO Pushes Past 1.4 terabits per second with 256 NVMe Drives
https://blog.min.io/performance-at-scale-minio-pushes-past-1–3-terabits-per-second-with-256-nvme-drives/ - Benchmarking MinIO vs. AWS S3 for Apache Spark
https://blog.min.io/benchmarking-apache-spark-vs-aws-s3/ - MinIO Client Quickstart Guide
https://docs.min.io/docs/minio-client-quickstart-guide.html - Analýza kvality zdrojových kódů Minia
https://goreportcard.com/report/github.com/minio/minio - This is MinIO
https://www.youtube.com/watch?v=vF0lQh0XOCs - Running MinIO Standalone
https://www.youtube.com/watch?v=dIQsPCHvHoM - „Amazon S3 Compatible Storage in Kubernetes“ – Rob Girard, Principal Tech Marketing Engineer, Minio
https://www.youtube.com/watch?v=wlpn8K0jJ4U - Ginkgo
http://onsi.github.io/ginkgo/ - Gomega
https://onsi.github.io/gomega/ - Ginkgo's Preferred Matcher Library na GitHubu
https://github.com/onsi/gomega/ - Provided Matchers
http://onsi.github.io/gomega/#provided-matchers - Dokumentace k balíčku goexpect
https://godoc.org/github.com/google/goexpect - Balíček goexpect
https://github.com/google/goexpect - Balíček go-expect
https://github.com/Netflix/go-expect - Balíček gexpect
https://github.com/ThomasRooney/gexpect - Expect (originál naprogramovaný v TCL)
https://core.tcl-lang.org/expect/index - Expect (Wikipedia)
https://en.wikipedia.org/wiki/Expect - Pexpect
https://pexpect.readthedocs.io/en/stable/ - Golang SSH Client: Multiple Commands, Crypto & Goexpect Examples
http://networkbit.ch/golang-ssh-client/ - goblin na GitHubu
https://github.com/franela/goblin - Mocha framework
https://mochajs.org/ - frisby na GitHubu
https://github.com/verdverm/frisby - package frisby
https://godoc.org/github.com/verdverm/frisby - Frisby alternatives and similar packages (generováno)
https://go.libhunt.com/frisby-alternatives - Cucumber for golang
https://github.com/DATA-DOG/godog - How to Use Godog for Behavior-driven Development in Go
https://semaphoreci.com/community/tutorials/how-to-use-godog-for-behavior-driven-development-in-go - Comparative Analysis Of GoLang Testing Frameworks
https://www.slideshare.net/DushyantBhalgami/comparative-analysis-of-golang-testing-frameworks - A Quick Guide to Testing in Golang
https://caitiem.com/2016/08/18/a-quick-guide-to-testing-in-golang/ - Tom's Obvious, Minimal Language.
https://github.com/toml-lang/toml - xml.org
http://www.xml.org/ - Soubory .properties
https://en.wikipedia.org/wiki/.properties - Soubory INI
https://en.wikipedia.org/wiki/INI_file - JSON to YAML
https://www.json2yaml.com/ - Data Format Converter
https://toolkit.site/format.html - Viper na GitHubu
https://github.com/spf13/viper - GoDotEnv na GitHubu
https://github.com/joho/godotenv - The fantastic ORM library for Golang
http://gorm.io/ - Dokumentace k balíčku gorilla/mux
https://godoc.org/github.com/gorilla/mux - Gorilla web toolkitk
http://www.gorillatoolkit.org/ - Metric types
https://prometheus.io/docs/concepts/metric_types/ - Histograms with Prometheus: A Tale of Woe
http://linuxczar.net/blog/2017/06/15/prometheus-histogram-2/ - Why are Prometheus histograms cumulative?
https://www.robustperception.io/why-are-prometheus-histograms-cumulative - Histograms and summaries
https://prometheus.io/docs/practices/histograms/ - Instrumenting Golang server in 5 min
https://medium.com/@gsisimogang/instrumenting-golang-server-in-5-min-c1c32489add3 - Semantic Import Versioning in Go
https://www.aaronzhuo.com/semantic-import-versioning-in-go/ - Sémantické verzování
https://semver.org/ - Getting started with Go modules
https://medium.com/@fonseka.live/getting-started-with-go-modules-b3dac652066d - Create projects independent of $GOPATH using Go Modules
https://medium.com/mindorks/create-projects-independent-of-gopath-using-go-modules-802260cdfb51o - Anatomy of Modules in Go
https://medium.com/rungo/anatomy-of-modules-in-go-c8274d215c16 - Modules
https://github.com/golang/go/wiki/Modules - Go Modules Tutorial
https://tutorialedge.net/golang/go-modules-tutorial/ - Module support
https://golang.org/cmd/go/#hdr-Module_support - Go Lang: Memory Management and Garbage Collection
https://vikash1976.wordpress.com/2017/03/26/go-lang-memory-management-and-garbage-collection/ - Golang Internals, Part 4: Object Files and Function Metadata
https://blog.altoros.com/golang-part-4-object-files-and-function-metadata.html - What is REPL?
https://pythonprogramminglanguage.com/repl/ - What is a REPL?
https://codewith.mu/en/tutorials/1.0/repl - Programming at the REPL: Introduction
https://clojure.org/guides/repl/introduction - What is REPL? (Quora)
https://www.quora.com/What-is-REPL - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Read-eval-print loop (Wikipedia)
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - Vim as a Go (Golang) IDE using LSP and vim-go
https://octetz.com/posts/vim-as-go-ide - gopls
https://github.com/golang/go/wiki/gopls - IDE Integration Guide
https://github.com/stamblerre/gocode/blob/master/docs/IDE_integration.md - How to instrument Go code with custom expvar metrics
https://sysdig.com/blog/golang-expvar-custom-metrics/ - Golang expvar metricset (Metricbeat Reference)
https://www.elastic.co/guide/en/beats/metricbeat/7.x/metricbeat-metricset-golang-expvar.html - Package expvar
https://golang.org/pkg/expvar/#NewInt - Java Platform Debugger Architecture: Overview
https://docs.oracle.com/en/java/javase/11/docs/specs/jpda/jpda.html - The JVM Tool Interface (JVM TI): How VM Agents Work
https://www.oracle.com/technetwork/articles/javase/index-140680.html - JVM Tool Interface Version 11.0
https://docs.oracle.com/en/java/javase/11/docs/specs/jvmti.html - Creating a Debugging and Profiling Agent with JVMTI
http://www.oracle.com/technetwork/articles/javase/jvmti-136367.html - JVM TI (Wikipedia)
http://en.wikipedia.org/wiki/JVM_TI - IBM JVMTI extensions
http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index.jsp?topic=%2Fcom.ibm.softrt.doc%2Fdiag%2Ftools%2Fjvmti_extensions.html - Go & cgo: integrating existing C code with Go
http://akrennmair.github.io/golang-cgo-slides/#1 - Using cgo to call C code from within Go code
https://wenzr.wordpress.com/2018/06/07/using-cgo-to-call-c-code-from-within-go-code/ - Package trace
https://golang.org/pkg/runtime/trace/ - Introducing HTTP Tracing
https://blog.golang.org/http-tracing - Command trace
https://golang.org/cmd/trace/ - A StreamLike, Immutable, Lazy Loading and smart Golang Library to deal with slices
https://github.com/wesovilabs/koazee - Funkce vyššího řádu v knihovně Underscore
https://www.root.cz/clanky/funkce-vyssiho-radu-v-knihovne-underscore/ - Delve: a debugger for the Go programming language.
https://github.com/go-delve/delve - Příkazy debuggeru Delve
https://github.com/go-delve/delve/tree/master/Documentation/cli - Debuggery a jejich nadstavby v Linuxu
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2. část)
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
http://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Debugging Go Code with GDB
https://golang.org/doc/gdb - Debugging Go (golang) programs with gdb
https://thornydev.blogspot.com/2014/01/debugging-go-golang-programs-with-gdb.html - GDB – Dokumentace
http://sourceware.org/gdb/current/onlinedocs/gdb/ - GDB – Supported Languages
http://sourceware.org/gdb/current/onlinedocs/gdb/Supported-Languages.html#Supported-Languages - GNU Debugger (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Debugger - The LLDB Debugger
http://lldb.llvm.org/ - Debugger (Wikipedia)
https://en.wikipedia.org/wiki/Debugger - 13 Linux Debuggers for C++ Reviewed
http://www.drdobbs.com/testing/13-linux-debuggers-for-c-reviewed/240156817 - Go is on a Trajectory to Become the Next Enterprise Programming Language
https://hackernoon.com/go-is-on-a-trajectory-to-become-the-next-enterprise-programming-language-3b75d70544e - Go Proverbs: Simple, Poetic, Pithy
https://go-proverbs.github.io/ - Handling Sparse Files on Linux
https://www.systutorials.com/136652/handling-sparse-files-on-linux/ - Gzip (Wikipedia)
https://en.wikipedia.org/wiki/Gzip - Deflate
https://en.wikipedia.org/wiki/DEFLATE - 10 tools written in Go that every developer needs to know
https://gustavohenrique.net/en/2019/01/10-tools-written-in-go-that-every-dev-needs-to-know/ - Hexadecimální prohlížeče a editory s textovým uživatelským rozhraním
https://www.root.cz/clanky/hexadecimalni-prohlizece-a-editory-s-textovym-uzivatelskym-rozhranim/ - Hex dump
https://en.wikipedia.org/wiki/Hex_dump - Rozhraní io.ByteReader
https://golang.org/pkg/io/#ByteReader - Rozhraní io.RuneReader
https://golang.org/pkg/io/#RuneReader - Rozhraní io.ByteScanner
https://golang.org/pkg/io/#ByteScanner - Rozhraní io.RuneScanner
https://golang.org/pkg/io/#RuneScanner - Rozhraní io.Closer
https://golang.org/pkg/io/#Closer - Rozhraní io.Reader
https://golang.org/pkg/io/#Reader - Rozhraní io.Writer
https://golang.org/pkg/io/#Writer - Typ Strings.Reader
https://golang.org/pkg/strings/#Reader - VACUUM (SQL)
https://www.sqlite.org/lang_vacuum.html - VACUUM (Postgres)
https://www.postgresql.org/docs/8.4/sql-vacuum.html - go-cron
https://github.com/rk/go-cron - gocron
https://github.com/jasonlvhit/gocron - clockwork
https://github.com/whiteShtef/clockwork - clockwerk
https://github.com/onatm/clockwerk - JobRunner
https://github.com/bamzi/jobrunner - Rethinking Cron
https://adam.herokuapp.com/past/2010/4/13/rethinking_cron/ - In the Beginning was the Command Line
https://web.archive.org/web/20180218045352/http://www.cryptonomicon.com/beginning.html - repl.it (REPL pro různé jazyky)
https://repl.it/languages - GOCUI – Go Console User Interface (celé uživatelské prostředí, nejenom input box)
https://github.com/jroimartin/gocui - Read–eval–print loop
https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop - go-prompt
https://github.com/c-bata/go-prompt - readline
https://github.com/chzyer/readline - A pure golang implementation for GNU-Readline kind library
https://golangexample.com/a-pure-golang-implementation-for-gnu-readline-kind-library/ - go-readline
https://github.com/fiorix/go-readline - 4 Python libraries for building great command-line user interfaces
https://opensource.com/article/17/5/4-practical-python-libraries - prompt_toolkit 2.0.3 na PyPi
https://pypi.org/project/prompt_toolkit/ - python-prompt-toolkit na GitHubu
https://github.com/jonathanslenders/python-prompt-toolkit - The GNU Readline Library
https://tiswww.case.edu/php/chet/readline/rltop.html - GNU Readline (Wikipedia)
https://en.wikipedia.org/wiki/GNU_Readline - readline — GNU readline interface (Python 3.x)
https://docs.python.org/3/library/readline.html - readline — GNU readline interface (Python 2.x)
https://docs.python.org/2/library/readline.html - GNU Readline Library – command line editing
https://tiswww.cwru.edu/php/chet/readline/readline.html - gnureadline 6.3.8 na PyPi
https://pypi.org/project/gnureadline/ - Editline Library (libedit)
http://thrysoee.dk/editline/ - Comparing Python Command-Line Parsing Libraries – Argparse, Docopt, and Click
https://realpython.com/comparing-python-command-line-parsing-libraries-argparse-docopt-click/ - libedit or editline
http://www.cs.utah.edu/~bigler/code/libedit.html - WinEditLine
http://mingweditline.sourceforge.net/ - rlcompleter — Completion function for GNU readline
https://docs.python.org/3/library/rlcompleter.html - rlwrap na GitHubu
https://github.com/hanslub42/rlwrap - rlwrap(1) – Linux man page
https://linux.die.net/man/1/rlwrap - readline(3) – Linux man page
https://linux.die.net/man/3/readline - history(3) – Linux man page
https://linux.die.net/man/3/history - Dokumentace k balíčku oglematchers
https://godoc.org/github.com/jacobsa/oglematchers - Balíček oglematchers
https://github.com/jacobsa/oglematchers - Dokumentace k balíčku ogletest
https://godoc.org/github.com/jacobsa/ogletest - Balíček ogletest
https://github.com/jacobsa/ogletest - Dokumentace k balíčku assert
https://godoc.org/github.com/stretchr/testify/assert - Testify – Thou Shalt Write Tests
https://github.com/stretchr/testify/ - package testing
https://golang.org/pkg/testing/ - Golang basics – writing unit tests
https://blog.alexellis.io/golang-writing-unit-tests/ - An Introduction to Programming in Go / Testing
https://www.golang-book.com/books/intro/12 - An Introduction to Testing in Go
https://tutorialedge.net/golang/intro-testing-in-go/ - Advanced Go Testing Tutorial
https://tutorialedge.net/golang/advanced-go-testing-tutorial/ - GoConvey
http://goconvey.co/ - Testing Techniques
https://talks.golang.org/2014/testing.slide - 5 simple tips and tricks for writing unit tests in #golang
https://medium.com/@matryer/5-simple-tips-and-tricks-for-writing-unit-tests-in-golang-619653f90742 - Afinní transformace
https://cs.wikibooks.org/wiki/Geometrie/Afinn%C3%AD_transformace_sou%C5%99adnic - package gg
https://godoc.org/github.com/fogleman/gg - Generate an animated GIF with Golang
http://tech.nitoyon.com/en/blog/2016/01/07/go-animated-gif-gen/ - Generate an image programmatically with Golang
http://tech.nitoyon.com/en/blog/2015/12/31/go-image-gen/ - The Go image package
https://blog.golang.org/go-image-package - Balíček draw2D: 2D rendering for different output (raster, pdf, svg)
https://github.com/llgcode/draw2d - Draw a rectangle in Golang?
https://stackoverflow.com/questions/28992396/draw-a-rectangle-in-golang - YAML
https://yaml.org/ - edn
https://github.com/edn-format/edn - Smile
https://github.com/FasterXML/smile-format-specification - Protocol-Buffers
https://developers.google.com/protocol-buffers/ - Marshalling (computer science)
https://en.wikipedia.org/wiki/Marshalling_(computer_science) - Unmarshalling
https://en.wikipedia.org/wiki/Unmarshalling - Introducing JSON
http://json.org/ - Package json
https://golang.org/pkg/encoding/json/ - The Go Blog: JSON and Go
https://blog.golang.org/json-and-go - Go by Example: JSON
https://gobyexample.com/json - Writing Web Applications
https://golang.org/doc/articles/wiki/ - Golang Web Apps
https://www.reinbach.com/blog/golang-webapps-1/ - Build web application with Golang
https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang/details - Golang Templates – Golang Web Pages
https://www.youtube.com/watch?v=TkNIETmF-RU - Simple Golang HTTPS/TLS Examples
https://github.com/denji/golang-tls - Playing with images in HTTP response in golang
https://www.sanarias.com/blog/1214PlayingwithimagesinHTTPresponseingolang - MIME Types List
https://www.freeformatter.com/mime-types-list.html - Go Mutex Tutorial
https://tutorialedge.net/golang/go-mutex-tutorial/ - Creating A Simple Web Server With Golang
https://tutorialedge.net/golang/creating-simple-web-server-with-golang/ - Building a Web Server in Go
https://thenewstack.io/building-a-web-server-in-go/ - How big is the pipe buffer?
https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer - How to turn off buffering of stdout in C
https://stackoverflow.com/questions/7876660/how-to-turn-off-buffering-of-stdout-in-c - setbuf(3) – Linux man page
https://linux.die.net/man/3/setbuf - setvbuf(3) – Linux man page (stejný obsah jako předchozí stránka)
https://linux.die.net/man/3/setvbuf - Select waits on a group of channels
https://yourbasic.org/golang/select-explained/ - Rob Pike: Simplicity is Complicated (video)
http://www.golang.to/posts/dotgo-2015-rob-pike-simplicity-is-complicated-youtube-16893 - Algorithms to Go
https://yourbasic.org/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu/ - Využití knihovny Pygments (nejenom) pro obarvení zdrojových kódů: vlastní filtry a lexery
https://www.root.cz/clanky/vyuziti-knihovny-pygments-nejenom-pro-obarveni-zdrojovych-kodu-vlastni-filtry-a-lexery/ - Go Defer Simplified with Practical Visuals
https://blog.learngoprogramming.com/golang-defer-simplified-77d3b2b817ff - 5 More Gotchas of Defer in Go — Part II
https://blog.learngoprogramming.com/5-gotchas-of-defer-in-go-golang-part-ii-cc550f6ad9aa - The Go Blog: Defer, Panic, and Recover
https://blog.golang.org/defer-panic-and-recover - The defer keyword in Swift 2: try/finally done right
https://www.hackingwithswift.com/new-syntax-swift-2-defer - Swift Defer Statement
https://andybargh.com/swift-defer-statement/ - Modulo operation (Wikipedia)
https://en.wikipedia.org/wiki/Modulo_operation - Node.js vs Golang: Battle of the Next-Gen Languages
https://www.hostingadvice.com/blog/nodejs-vs-golang/ - The Go Programming Language (home page)
https://golang.org/ - GoDoc
https://godoc.org/ - Go (programming language), Wikipedia
https://en.wikipedia.org/wiki/Go_(programming_language) - Go Books (kniha o jazyku Go)
https://github.com/dariubs/GoBooks - The Go Programming Language Specification
https://golang.org/ref/spec - Go: the Good, the Bad and the Ugly
https://bluxte.net/musings/2018/04/10/go-good-bad-ugly/ - Package builtin
https://golang.org/pkg/builtin/ - Package fmt
https://golang.org/pkg/fmt/ - The Little Go Book (další kniha)
https://github.com/dariubs/GoBooks - The Go Programming Language by Brian W. Kernighan, Alan A. A. Donovan
https://www.safaribooksonline.com/library/view/the-go-programming/9780134190570/ebook_split010.html - Learning Go
https://www.miek.nl/go/ - Go Bootcamp
http://www.golangbootcamp.com/ - Programming in Go: Creating Applications for the 21st Century (další kniha o jazyku Go)
http://www.informit.com/store/programming-in-go-creating-applications-for-the-21st-9780321774637 - Introducing Go (Build Reliable, Scalable Programs)
http://shop.oreilly.com/product/0636920046516.do - Learning Go Programming
https://www.packtpub.com/application-development/learning-go-programming - The Go Blog
https://blog.golang.org/ - Getting to Go: The Journey of Go's Garbage Collector
https://blog.golang.org/ismmkeynote - Go (programovací jazyk, Wikipedia)
https://cs.wikipedia.org/wiki/Go_(programovac%C3%AD_jazyk) - Rychle, rychleji až úplně nejrychleji s jazykem Go
https://www.root.cz/clanky/rychle-rychleji-az-uplne-nejrychleji-s-jazykem-go/ - Installing Go on the Raspberry Pi
https://dave.cheney.net/2012/09/25/installing-go-on-the-raspberry-pi - How the Go runtime implements maps efficiently (without generics)
https://dave.cheney.net/2018/05/29/how-the-go-runtime-implements-maps-efficiently-without-generics - Niečo málo o Go – Golang (slovensky)
http://golangsk.logdown.com/ - How Many Go Developers Are There?
https://research.swtch.com/gophercount - Most Popular Technologies (Stack Overflow Survery 2018)
https://insights.stackoverflow.com/survey/2018/#most-popular-technologies - Most Popular Technologies (Stack Overflow Survery 2017)
https://insights.stackoverflow.com/survey/2017#technology - JavaScript vs. Golang for IoT: Is Gopher Winning?
https://www.iotforall.com/javascript-vs-golang-iot/ - The Go Programming Language: Release History
https://golang.org/doc/devel/release.html - Go 1.11 Release Notes
https://golang.org/doc/go1.11 - Go 1.10 Release Notes
https://golang.org/doc/go1.10 - Go 1.9 Release Notes (tato verze je stále používána)
https://golang.org/doc/go1.9 - Go 1.8 Release Notes (i tato verze je stále používána)
https://golang.org/doc/go1.8 - Go on Fedora
https://developer.fedoraproject.org/tech/languages/go/go-installation.html - Writing Go programs
https://developer.fedoraproject.org/tech/languages/go/go-programs.html - The GOPATH environment variable
https://tip.golang.org/doc/code.html#GOPATH - Command gofmt
https://tip.golang.org/cmd/gofmt/ - The Go Blog: go fmt your code
https://blog.golang.org/go-fmt-your-code - C? Go? Cgo!
https://blog.golang.org/c-go-cgo - Spaces vs. Tabs: A 20-Year Debate Reignited by Google’s Golang
https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/ - 400,000 GitHub repositories, 1 billion files, 14 terabytes of code: Spaces or Tabs?
https://medium.com/@hoffa/400–000-github-repositories-1-billion-files-14-terabytes-of-code-spaces-or-tabs-7cfe0b5dd7fd - Gofmt No Longer Allows Spaces. Tabs Only
https://news.ycombinator.com/item?id=7914523 - Why does Go „go fmt“ uses tabs instead of whitespaces?
https://www.quora.com/Why-does-Go-go-fmt-uses-tabs-instead-of-whitespaces - Interactive: The Top Programming Languages 2018
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2018 - Go vs. Python
https://www.peterbe.com/plog/govspy - PackageManagementTools
https://github.com/golang/go/wiki/PackageManagementTools - A Tour of Go: Type inference
https://tour.golang.org/basics/14 - Go Slices: usage and internals
https://blog.golang.org/go-slices-usage-and-internals - Go by Example: Slices
https://gobyexample.com/slices - What is the point of slice type in Go?
https://stackoverflow.com/questions/2098874/what-is-the-point-of-slice-type-in-go - The curious case of Golang array and slices
https://medium.com/@hackintoshrao/the-curious-case-of-golang-array-and-slices-2565491d4335 - Introduction to Slices in Golang
https://www.callicoder.com/golang-slices/ - Golang: Understanding ‚null‘ and nil
https://newfivefour.com/golang-null-nil.html - What does nil mean in golang?
https://stackoverflow.com/questions/35983118/what-does-nil-mean-in-golang - nils In Go
https://go101.org/article/nil.html - Go slices are not dynamic arrays
https://appliedgo.net/slices/ - Go-is-no-good (nelze brát doslova)
https://github.com/ksimka/go-is-not-good - Rust vs. Go
https://news.ycombinator.com/item?id=13430108 - Seriál Programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Modern garbage collection: A look at the Go GC strategy
https://blog.plan99.net/modern-garbage-collection-911ef4f8bd8e - Go GC: Prioritizing low latency and simplicity
https://blog.golang.org/go15gc - Is Golang a good language for embedded systems?
https://www.quora.com/Is-Golang-a-good-language-for-embedded-systems - Running GoLang on an STM32 MCU. A quick tutorial.
https://www.mickmake.com/post/running-golang-on-an-mcu-a-quick-tutorial - Go, Robot, Go! Golang Powered Robotics
https://gobot.io/ - Emgo: Bare metal Go (language for programming embedded systems)
https://github.com/ziutek/emgo - UTF-8 history
https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt - Less is exponentially more
https://commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html - Should I Rust, or Should I Go
https://codeburst.io/should-i-rust-or-should-i-go-59a298e00ea9 - Setting up and using gccgo
https://golang.org/doc/install/gccgo - Elastic Tabstops
http://nickgravgaard.com/elastic-tabstops/ - Strings, bytes, runes and characters in Go
https://blog.golang.org/strings - Datový typ
https://cs.wikipedia.org/wiki/Datov%C3%BD_typ - Seriál o programovacím jazyku Rust: Základní (primitivní) datové typy
https://www.root.cz/clanky/programovaci-jazyk-rust-nahrada-c-nebo-slepa-cesta/#k09 - Seriál o programovacím jazyku Rust: Vytvoření „řezu“ z pole
https://www.root.cz/clanky/prace-s-poli-v-programovacim-jazyku-rust/#k06 - Seriál o programovacím jazyku Rust: Řezy (slice) vektoru
https://www.root.cz/clanky/prace-s-vektory-v-programovacim-jazyku-rust/#k05 - Printf Format Strings
https://www.cprogramming.com/tutorial/printf-format-strings.html - Java: String.format
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#format-java.lang.String-java.lang.Object…- - Java: format string syntax
https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#syntax - Selectors
https://golang.org/ref/spec#Selectors - Calling Go code from Python code
http://savorywatt.com/2015/09/18/calling-go-code-from-python-code/ - Go Data Structures: Interfaces
https://research.swtch.com/interfaces - How to use interfaces in Go
http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go - Interfaces in Go (part I)
https://medium.com/golangspec/interfaces-in-go-part-i-4ae53a97479c - Part 21: Goroutines
https://golangbot.com/goroutines/ - Part 22: Channels
https://golangbot.com/channels/ - [Go] Lightweight eventbus with async compatibility for Go
https://github.com/asaskevich/EventBus - What about Trait support in Golang?
https://www.reddit.com/r/golang/comments/8mfykl/what_about_trait_support_in_golang/ - Don't Get Bitten by Pointer vs Non-Pointer Method Receivers in Golang
https://nathanleclaire.com/blog/2014/08/09/dont-get-bitten-by-pointer-vs-non-pointer-method-receivers-in-golang/ - Control Flow
https://en.wikipedia.org/wiki/Control_flow - Structured programming
https://en.wikipedia.org/wiki/Structured_programming - Control Structures
https://www.golang-book.com/books/intro/5 - Control structures – Go if else statement
http://golangtutorials.blogspot.com/2011/06/control-structures-if-else-statement.html - Control structures – Go switch case statement
http://golangtutorials.blogspot.com/2011/06/control-structures-go-switch-case.html - Control structures – Go for loop, break, continue, range
http://golangtutorials.blogspot.com/2011/06/control-structures-go-for-loop-break.html - Goroutine IDs
https://blog.sgmansfield.com/2015/12/goroutine-ids/ - Different ways to pass channels as arguments in function in go (golang)
https://stackoverflow.com/questions/24868859/different-ways-to-pass-channels-as-arguments-in-function-in-go-golang - justforfunc #22: using the Go execution tracer
https://www.youtube.com/watch?v=ySy3sR1LFCQ - Single Function Exit Point
http://wiki.c2.com/?SingleFunctionExitPoint - Entry point
https://en.wikipedia.org/wiki/Entry_point - Why does Go have a GOTO statement?!
https://www.reddit.com/r/golang/comments/kag5q/why_does_go_have_a_goto_statement/ - Effective Go
https://golang.org/doc/effective_go.html - GoClipse: an Eclipse IDE for the Go programming language
http://goclipse.github.io/ - GoClipse Installation
https://github.com/GoClipse/goclipse/blob/latest/documentation/Installation.md#installation - The zero value of a slice is not nil
https://stackoverflow.com/questions/30806931/the-zero-value-of-a-slice-is-not-nil - Go-tcha: When nil != nil
https://dev.to/pauljlucas/go-tcha-when-nil–nil-hic - Nils in Go
https://www.doxsey.net/blog/nils-in-go