logo

I code dreams

browser

Download
// 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 = `
    <table class="bucket"></table>

	<table class="preview"></table>

    <dl class="statistics">
     <dt>Score</dt>
     <dd class="score">0</dd>
     <dt>Lines</dt>
     <dd class="lines">0</dd>
    </dl>
`

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 :-(")
}