func (nm *V23Manager) makeBall(p *model.Player) *model.Ball { dx := rand.Float64() dy := rand.Float64() sign := rand.Float64() if sign >= 0.5 { dx = -dx } mag := math.Sqrt(dx*dx + dy*dy) return model.NewBall(p, model.Vec{config.MagicX, 0}, model.Vec{float32(dx / mag), float32(dy / mag)}) }
func (gn *Engine) createBall() { if gn.chatty { log.Printf("Creating ball.") } gn.balls = append( gn.balls, model.NewBall( gn.nm.Me(), model.Vec{gn.scn.Width() / 2, gn.scn.Height() / 2}, model.Vec{0, 0})) if gn.chatty { log.Printf("Created ball.") } }
func (gn *Engine) Run(a app.App) { if gn.chatty { log.Println("Starting gn Run.") log.Print("runtime.GOOS = ", runtime.GOOS) log.Print("runtime.GOARCH = ", runtime.GOARCH) } // TODO(monopole): Send these into App somehow, so // the select below can be collapse to just a switch // on app events. var chMasterCommand <-chan ifc.MasterCommand var chPauseDuration <-chan float32 var chGravity <-chan float32 var chIncomingBall <-chan *model.Ball var chQuit <-chan bool holdCount := 0 chWaiting, chIsReady := gn.enterWaitState() var sz size.Event for { if false && gn.chatty { log.Printf(" ") log.Printf(" ") log.Printf("Re-entering select.") } select { case ready := <-chIsReady: log.Printf("Got ready signal = %v", ready) if ready { chWaiting, chIsReady = nil, nil relay := gn.nm.GetRelay() chMasterCommand = relay.ChMasterCommand() chPauseDuration = relay.ChPauseDuration() chGravity = relay.ChGravity() chIncomingBall = relay.ChIncomingBall() chQuit = relay.ChQuit() gn.scn.Start() if gn.chatty { log.Printf("Started screen.") } gn.createBall() gn.isAlive = true if gn.chatty { log.Printf("Seem to be alive now.") } a.Send(paint.Event{}) } else { if gn.chatty { log.Printf("Unable to get ready - exiting.") } if gn.stopMeansReallyStop() { return } chWaiting, chIsReady = gn.enterWaitState() } case mc := <-chMasterCommand: switch mc.Name { case "kick": gn.kick() gn.freeze() case "left": gn.left() case "right": gn.right() case "random": gn.random() case "destroy": gn.balls = []*model.Ball{} default: log.Print("Don't understand command %v", mc) } case <-chQuit: gn.stop() if gn.stopMeansReallyStop() { return } chWaiting, chIsReady = gn.enterWaitState() case pd := <-chPauseDuration: gn.pauseDuration = pd case g := <-chGravity: gn.gravity = g case b := <-chIncomingBall: nx := b.GetPos().X if nx == config.MagicX { // Ball came in from center of top nx = gn.scn.Width() / 2.0 } else if nx >= 0 && nx <= fuzzyZero { // Ball came in from left. nx = 0 } else { // Ball came in from right. nx = gn.scn.Width() } // Assume Y component normalized before teleport. ny := b.GetPos().Y * gn.scn.Height() b.SetPos(nx, ny) // TODO: Adjust velocity per refraction-like rules? gn.balls = append(gn.balls, b) case dc := <-gn.nm.ChDoorCommand(): gn.handleDoor(dc) case event := <-a.Events(): switch e := a.Filter(event).(type) { case lifecycle.Event: switch e.Crosses(lifecycle.StageVisible) { case lifecycle.CrossOn: if chWaiting == nil { log.Panic("Lifecycle trouble") return } if err := gn.scn.SetDrawContext(e.DrawContext); err != nil { log.Panic(err) } log.Print("Passing cycleOn") chWaiting <- readyCycleOn log.Print("Passed cycleOn") case lifecycle.CrossOff: gn.scn.Stop() gn.stop() if gn.stopMeansReallyStop() { return } chWaiting, chIsReady = gn.enterWaitState() } case paint.Event: if gn.isAlive { gn.moveBalls() gn.scn.Paint(gn.balls) a.Publish() } a.Send(paint.Event{}) case key.Event: // Aspirationally use keys if gn.chatty { log.Printf("Key event! %T = %v", e.Code, e.Code) } switch e.Code { case key.CodeQ, key.CodeEscape: gn.stop() if gn.stopMeansReallyStop() { return } chWaiting, chIsReady = gn.enterWaitState() } case touch.Event: if gn.chatty { log.Println("Touch event") } switch e.Type { case touch.TypeBegin: holdCount = 1 gn.beginX = e.X gn.beginY = e.Y if e.X < magicButtonSideLength && e.Y < magicButtonSideLength { if gn.chatty { log.Printf("Touched shutdown spot.\n") } gn.stop() if gn.stopMeansReallyStop() { return } chWaiting, chIsReady = gn.enterWaitState() } case touch.TypeMove: holdCount++ case touch.TypeEnd: if gn.chatty { log.Printf("holdcount = %d", holdCount) } if holdCount > 0 && holdCount <= maxHoldCount { // If they hold on too long, ignore it. dx := float64(e.X - gn.beginX) dy := float64(e.Y - gn.beginY) mag := math.Sqrt(dx*dx + dy*dy) if mag >= minDragLength { ndx := float32(dx/mag) * gn.scn.Width() / gn.pauseDuration ndy := float32(dy/mag) * gn.scn.Height() / gn.pauseDuration b := model.NewBall(nil, model.Vec{gn.beginX, gn.beginY}, model.Vec{ndx, ndy}) if gn.chatty { log.Printf("Sending impulse: %s", b.String()) } gn.applyImpulse(b) } else { if gn.chatty { log.Printf("Mag only %.4f", mag) } } } holdCount = 0 } case size.Event: // TODO: Adjust velocity on resizes - balls should take the // same amount of time to traverse the screen regardless of // the size. sz = e gn.scn.ReSize(float32(sz.WidthPx), float32(sz.HeightPx)) gn.resetImpulseLimit() if gn.chatty && debugShowResizes { log.Printf( "Resize new w=%.2f, new h=%.2f, maxDsqImpulse = %f.2", gn.scn.Width(), gn.scn.Height(), gn.maxDistSqForImpulse) } if chWaiting != nil { if gn.chatty { log.Printf("passing readyResize") } chWaiting <- readyResize if gn.chatty { log.Printf("passed readyResize") } } } } } }