package main
import (
"fmt"
"github.com/lucasb-eyer/go-colorful"
"math"
"math/rand"
"syscall/js"
)
var (
width float64
height float64
ctx js.Value
)
type Ball struct {
posX float64
posY float64
dirX float64
dirY float64
color colorful.Color
size float64
}
func main() {
doc := js.Global().Get("document")
canvasEl := doc.Call("getElementById", "mycanvas")
width = doc.Get("body").Get("clientWidth").Float()
height = doc.Get("body").Get("clientHeight").Float()
canvasEl.Set("width", width)
canvasEl.Set("height", height)
ctx = canvasEl.Call("getContext", "2d")
done := make(chan struct{}, 0)
bm := BallManager{
speed: 160,
size: 10,
}
bm.SetNBalls(160)
var renderFrame js.Func
var tmark float64
var markCount = 0
var tdiffSum float64
renderFrame = js.FuncOf(func(this js.Value, args []js.Value) interface{} {
now := args[0].Float()
tdiff := now - tmark
tdiffSum += now - tmark
markCount++
if markCount > 10 {
doc.Call("getElementById", "fps").Set("innerHTML", fmt.Sprintf("FPS: %.01f", 1000/(tdiffSum/float64(markCount))))
tdiffSum, markCount = 0, 0
}
tmark = now
curBodyW := doc.Get("body").Get("clientWidth").Float()
curBodyH := doc.Get("body").Get("clientHeight").Float()
if curBodyW != width || curBodyH != height {
width, height = curBodyW, curBodyH
canvasEl.Set("width", width)
canvasEl.Set("height", height)
}
bm.Update(tdiff / 1000)
js.Global().Call("requestAnimationFrame", renderFrame)
return nil
})
defer renderFrame.Release()
js.Global().Call("requestAnimationFrame", renderFrame)
<-done
}
type BallManager struct {
balls []*Ball
speed float64
size int
}
func (bm *BallManager) Update(dtTime float64) {
if bm.balls == nil {
return
}
ctx.Call("clearRect", 0, 0, width, height)
for _, ball := range bm.balls {
if ball.posX < 0 {
ball.posX = 0
ball.dirX *= -1
}
if ball.posX > width {
ball.posX = width
ball.dirX *= -1
}
if ball.posY < 0 {
ball.posY = 0
ball.dirY *= -1
}
if ball.posY > height {
ball.posY = height
ball.dirY *= -1
}
dirX := ball.dirX
dirY := ball.dirY
ctx.Set("globalAlpha", 0.6)
ctx.Call("beginPath")
ctx.Set("fillStyle", ball.color.Hex())
ctx.Call("arc", ball.posX, ball.posY, bm.size, 0, 2*math.Pi)
ctx.Call("fill")
ball.posX += dirX * bm.speed * dtTime
ball.posY += dirY * bm.speed * dtTime
}
}
func (bm *BallManager) SetNBalls(n int) {
bm.balls = make([]*Ball, n)
for i := 0; i < n; i++ {
bm.balls[i] = &Ball{
posX: rand.Float64() * width,
posY: rand.Float64() * height,
dirX: rand.NormFloat64(),
dirY: rand.NormFloat64(),
color: colorful.FastHappyColor(),
size: 10,
}
}
}