199 lines
5.2 KiB
Go
199 lines
5.2 KiB
Go
package main
|
|
|
|
import (
|
|
"image/color"
|
|
"sync"
|
|
"syscall/js"
|
|
"time"
|
|
|
|
"github.com/llgcode/draw2d/draw2dimg"
|
|
"github.com/llgcode/draw2d/draw2dkit"
|
|
"github.com/markfarnan/go-canvas/canvas"
|
|
|
|
"git.jacknet.io/S.D/Chip-8_Go/chip8"
|
|
)
|
|
|
|
var done chan struct{}
|
|
|
|
var cvs *canvas.Canvas2d
|
|
var width, height float64 = 64, 32
|
|
var sizeMultiplier = 8
|
|
var drawBuf = [64 * 32]byte{}
|
|
var drawNeeded = false
|
|
var graphicsLock sync.Mutex
|
|
var keysLock sync.Mutex
|
|
var window, beep js.Value
|
|
var keys [16]byte
|
|
var gameRunning = true
|
|
|
|
var keyMap = map[int]int{
|
|
88: 0, // x
|
|
49: 1, // 1
|
|
50: 2, // 2
|
|
51: 3, // 3
|
|
81: 4, // q
|
|
87: 5, // w
|
|
69: 6, // e
|
|
65: 7, // a
|
|
83: 8, // s
|
|
68: 9, // d
|
|
90: 10, // z
|
|
67: 11, // c
|
|
52: 12, // 4
|
|
82: 13, // r
|
|
70: 14, // f
|
|
86: 15, // v
|
|
}
|
|
|
|
var gameMap = map[string]func() []byte{
|
|
"pong": getPong,
|
|
"spaceinv": getSpaceInvaders,
|
|
"tetris": getTetris,
|
|
}
|
|
|
|
func keyEventHandle(event js.Value) {
|
|
//println(event.Get("type").String())
|
|
//println(event.Get("keyCode").Int())
|
|
elem, ok := keyMap[event.Get("keyCode").Int()]
|
|
if ok {
|
|
keysLock.Lock()
|
|
defer keysLock.Unlock()
|
|
if event.Get("type").String() == "keydown" {
|
|
keys[elem] = 1
|
|
} else if event.Get("type").String() == "keyup" {
|
|
keys[elem] = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
func cpuCycle(cpu *chip8.Chip8, c chan int, i int) {
|
|
cpu.PerformCycle()
|
|
if cpu.DrawIsNeeded() {
|
|
drawNeeded = true
|
|
graphicsLock.Lock()
|
|
drawBuf = cpu.GetGraphicsBuffer()
|
|
graphicsLock.Unlock()
|
|
keysLock.Lock()
|
|
cpu.UpdateKeys(keys)
|
|
keysLock.Unlock()
|
|
}
|
|
if i > 7 {
|
|
cpu.TickTimers()
|
|
//println("here!")
|
|
}
|
|
if cpu.BeepNeeded() {
|
|
go playSound()
|
|
}
|
|
|
|
c <- 1
|
|
}
|
|
|
|
func timeCycle(c chan int) {
|
|
time.Sleep(2000 * time.Microsecond)
|
|
c <- 0
|
|
}
|
|
|
|
func runGame(game []byte) {
|
|
cpu := chip8.NewCHIP8(game)
|
|
i := 0
|
|
for gameRunning {
|
|
c := make(chan int)
|
|
go timeCycle(c)
|
|
i++
|
|
go cpuCycle(cpu, c, i)
|
|
if i > 7 {
|
|
i = 0
|
|
}
|
|
|
|
x, y := <-c, <-c
|
|
if x == 0 {
|
|
println("CPU RUNNING SLOW")
|
|
println(x, y)
|
|
}
|
|
}
|
|
}
|
|
|
|
func changeGame(event js.Value) {
|
|
//println(event.Get("target").Get("value").String())
|
|
println(event.Get("target").Get("value").String())
|
|
elem, ok := gameMap[event.Get("target").Get("value").String()]
|
|
if ok {
|
|
println("change event!!!!")
|
|
gameRunning = false
|
|
time.Sleep(1 * time.Second)
|
|
//println("changing games!!")
|
|
gameRunning = true
|
|
go runGame(elem())
|
|
} else {
|
|
panic("value not found!")
|
|
}
|
|
}
|
|
|
|
func playSound() {
|
|
beep.Call("play")
|
|
//window.Get("navigator").Call("vibrate", 300)
|
|
}
|
|
|
|
func main() {
|
|
println("CHIP8 IS HERE!")
|
|
window = js.Global()
|
|
|
|
beep = window.Get("Audio").New("data:audio/mp3;base64,SUQzBAAAAAAAI1RTU0UAAAAPAAADTGF2ZjU2LjI1LjEwMQAAAAAAAAAAAAAA/+NAwAAAAAAAAAAAAFhpbmcAAAAPAAAAAwAAA3YAlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaWlpaW8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw////////////////////////////////////////////AAAAAExhdmYAAAAAAAAAAAAAAAAAAAAAACQAAAAAAAAAAAN2UrY2LgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP/jYMQAEvgiwl9DAAAAO1ALSi19XgYG7wIAAAJOD5R0HygIAmD5+sEHLB94gBAEP8vKAgGP/BwMf+D4Pgh/DAPg+D5//y4f///8QBhMQBgEAfB8HwfAgIAgAHAGCFAj1fYUCZyIbThYFExkefOCo8Y7JxiQ0mGVaHKwwGCtGCUkY9OCugoFQwDKqmHQiUCxRAKOh4MjJFAnTkq6QqFGavRpYUCmMxpZnGXJa0xiJcTGZb1gJjwOJDJgoUJG5QQuDAsypiumkp5TUjrOobR2liwoGBf/X1nChmipnKVtSmMNQDGitG1fT/JhR+gYdCvy36lTrxCVV8Paaz1otLndT2fZuOMp3VpatmVR3LePP/8bSQpmhQZECqWsFeJxoepX9dbfHS13/////aysppUblm//8t7p2Ez7xKD/42DE4E5z9pr/nNkRw6bhdiCAZVVSktxunhxhH//4xF+bn4//6//3jEvylMM2K9XmWSn3ah1L2MqVIjmNlJtpQux1n3ajA0ZnFSu5EpX////uGatn///////1r/pYabq0mKT//TRyTEFNRTMuOTkuNaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq/+MQxNIAAANIAcAAAKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqg==")
|
|
|
|
window.Call("addEventListener", "keydown", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
|
keyEventHandle(args[0])
|
|
return nil
|
|
}))
|
|
|
|
window.Call("addEventListener", "keyup", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
|
keyEventHandle(args[0])
|
|
return nil
|
|
}))
|
|
|
|
window.Call("addEventListener", "change", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
|
changeGame(args[0])
|
|
return nil
|
|
}))
|
|
|
|
cvs, _ = canvas.NewCanvas2d(false)
|
|
cvs.Create(int(width)*sizeMultiplier, int(height)*sizeMultiplier)
|
|
|
|
height = float64(cvs.Height())
|
|
width = float64(cvs.Width())
|
|
|
|
cvs.Start(60, Render)
|
|
|
|
go runGame(getPong())
|
|
never_returns := make(chan int)
|
|
<-never_returns
|
|
}
|
|
|
|
func Render(gc *draw2dimg.GraphicContext) bool {
|
|
if !drawNeeded {
|
|
return false
|
|
}
|
|
drawNeeded = false
|
|
gc.SetFillColor(color.RGBA{0x00, 0x00, 0x00, 0xff})
|
|
gc.Clear()
|
|
|
|
gc.SetFillColor(color.RGBA{0x00, 0xff, 0x00, 0xff})
|
|
//gc.SetStrokeColor(color.RGBA{0x00, 0xff, 0x00, 0xff})
|
|
|
|
gc.BeginPath()
|
|
//gc.ArcTo(gs.laserX, gs.laserY, gs.laserSize, gs.laserSize, 0, math.Pi*2)
|
|
graphicsLock.Lock()
|
|
defer graphicsLock.Unlock()
|
|
for i, val := range drawBuf {
|
|
if val != 0 {
|
|
x := i % 64
|
|
y := i / 64
|
|
// println("drawing to ", x, y)
|
|
draw2dkit.Rectangle(gc, float64(x*sizeMultiplier), float64(y*sizeMultiplier), float64((x*sizeMultiplier)+sizeMultiplier), float64((y*sizeMultiplier)+sizeMultiplier))
|
|
}
|
|
}
|
|
gc.FillStroke()
|
|
gc.Close()
|
|
//println("drawing")
|
|
return true
|
|
}
|