Title Screen: Lazily scroll the demo level

Adds a lazy scroll algorithm that basically:
- Zigzags right/down a certain distance, then up again
- Then enters a bounce phase where it bounces off the level
  boundaries like a screensaver.

Arrow keys can still scroll the level manually, but the
automated scroll takes over otherwise.
This commit is contained in:
Noah 2021-06-08 21:12:30 -07:00
parent bd90393cc3
commit e8388fafad
2 changed files with 69 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package main
import ( import (
"errors" "errors"
"fmt" "fmt"
"math/rand"
"os" "os"
"regexp" "regexp"
"runtime" "runtime"
@ -37,6 +38,9 @@ func init() {
// Use all the CPU cores for collision detection and other load balanced // Use all the CPU cores for collision detection and other load balanced
// goroutine work in the app. // goroutine work in the app.
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
// Seed the random number generator.
rand.Seed(time.Now().UnixNano())
} }
func main() { func main() {

View File

@ -34,6 +34,11 @@ type MainScene struct {
// Update check variables. // Update check variables.
updateButton *ui.Button updateButton *ui.Button
updateInfo updater.VersionInfo updateInfo updater.VersionInfo
// Lazy scroll variables. See LoopLazyScroll().
lazyScrollBounce bool
lazyScrollTrajectory render.Point
lazyScrollLastValue render.Point
} }
// Name of the scene. // Name of the scene.
@ -217,6 +222,9 @@ func (s *MainScene) Loop(d *Doodle, ev *event.State) error {
log.Error("MainScene.Loop: scripting.Loop: %s", err) log.Error("MainScene.Loop: scripting.Loop: %s", err)
} }
// Lazily scroll the canvas around, slowly.
s.LoopLazyScroll()
s.canvas.Loop(ev) s.canvas.Loop(ev)
if ev.WindowResized { if ev.WindowResized {
@ -233,6 +241,63 @@ func (s *MainScene) Loop(d *Doodle, ev *event.State) error {
return nil return nil
} }
// LoopLazyScroll gently scrolls the title screen demo level, called each Loop.
func (s *MainScene) LoopLazyScroll() {
// The v1 basic sauce algorithm:
// 1. We scroll diagonally downwards and rightwards.
// 2. When we scroll downwards far enough, we change direction.
// Make a zigzag pattern.
// 3. When we reach the right bound of the level
// OR some max number of px into an unbounded level:
// enter a simple ball bouncing mode like a screensaver.
var (
zigzagMaxHeight = 512
maxScrollX = zigzagMaxHeight * 2
lastScrollValue = s.lazyScrollLastValue
currentScroll = s.canvas.Scroll
)
// So we have two states:
// - Zigzag state (default)
// - Bounce state (when we hit a wall)
if !s.lazyScrollBounce {
// Zigzag state.
s.lazyScrollTrajectory = render.Point{
X: -1, // down and right
Y: -1,
}
// When we've gone far enough X, it's also far enough Y.
if currentScroll.X < -zigzagMaxHeight {
s.lazyScrollTrajectory.Y = 1 // go back up
}
// Have we gotten stuck in a corner? (ending the zigzag phase, for bounded levels)
if currentScroll.X < 0 && (currentScroll == lastScrollValue) || currentScroll.X < -maxScrollX {
log.Debug("LoopLazyScroll: Ending zigzag phase, enter bounce phase")
s.lazyScrollBounce = true
s.lazyScrollTrajectory = render.Point{
X: -1,
Y: -1,
}
}
} else {
// Lazy bounce algorithm.
if currentScroll.Y == lastScrollValue.Y {
log.Debug("LoopLazyScroll: Hit a floor/ceiling")
s.lazyScrollTrajectory.Y = -s.lazyScrollTrajectory.Y
}
if currentScroll.X == lastScrollValue.X {
log.Debug("LoopLazyScroll: Hit the side of the map!")
s.lazyScrollTrajectory.X = -s.lazyScrollTrajectory.X
}
}
// Check the scroll.
s.lazyScrollLastValue = currentScroll
s.canvas.ScrollBy(s.lazyScrollTrajectory)
}
// Draw the pixels on this frame. // Draw the pixels on this frame.
func (s *MainScene) Draw(d *Doodle) error { func (s *MainScene) Draw(d *Doodle) error {
// Clear the canvas and fill it with white. // Clear the canvas and fill it with white.