// browser specific code (keyboard handling and rendering) package main import ( "syscall/js" ) // TODO PRIO2 interface KeyBoard func (t *Tetris) KeyboardHandling() { keydown := js.FuncOf(func(this js.Value, args []js.Value) interface{} { event := args[0] code := event.Get("code").String() switch code { case "ArrowLeft", "KeyJ": t.move(-1, 0, t.rotation) event.Call("preventDefault") break case "ArrowUp", "KeyK": t.move(0, 0, (t.rotation+1)%4) event.Call("preventDefault") break case "ArrowRight", "KeyL": t.move(1, 0, t.rotation) event.Call("preventDefault") break case "Space": t.drop() event.Call("preventDefault") break case "ArrowDown", "KeyI", "KeyM": t.fall() event.Call("preventDefault") break } return nil }) // TODO PRIO3 defer keyDown.Release() (atexit? onerror?) js.Global().Get("window"). Call("addEventListener", "keydown", keydown) } const template = `
Score
0
Lines
0
` type BrowserRenderer struct { bucket, preview js.Value score, lines js.Value } // TODO PRIO3 is it idiomatic to do more than init structures in Go? func NewBrowserRenderer() *BrowserRenderer { r := BrowserRenderer{} document := js.Global().Get("document") section := document.Call("querySelector", "section") section.Set("innerHTML", template) r.bucket = section.Call("querySelector", ".bucket") r.preview = section.Call("querySelector", ".preview") r.score = section.Call("querySelector", ".score") r.lines = section.Call("querySelector", ".lines") // bucket for y := 0; y < HEIGHT; y++ { row := r.bucket.Call("insertRow") for x := 0; x < WIDTH; x++ { row.Call("insertCell") } } // preview for y := 0; y < 4; y++ { row := r.preview.Call("insertRow") for x := 0; x < 4; x++ { row.Call("insertCell") } } return &r } func (r *BrowserRenderer) Draw(x, y int, color string) { // little bit kludgy if x < WIDTH { row := r.bucket.Get("rows").Index(y) cell := row.Get("cells").Index(x) cell.Set("className", color) } else { row := r.preview.Get("rows").Index(y) cell := row.Get("cells").Index(x - WIDTH) cell.Set("className", color) } } func (r *BrowserRenderer) Score(score, lines int) { r.score.Set("textContent", score) r.lines.Set("textContent", lines) } func (r *BrowserRenderer) GameOver() { window := js.Global().Get("window") window.Call("alert", "Game over :-(") }