Ebiten example - infinitescroll

// +build example jsgo

package main

import (
        "bytes"
        "fmt"
        "image"
        _ "image/png"
        "log"

        "github.com/hajimehoshi/ebiten"
        "github.com/hajimehoshi/ebiten/ebitenutil"
        "github.com/hajimehoshi/ebiten/examples/resources/images"
)

const (
        screenWidth  = 320
        screenHeight = 240
)

var (
        bgImage *ebiten.Image
)

func init() {
        // Decode image from a byte slice instead of a file so that
        // this example works in any working directory.
        // If you want to use a file, there are some options:
        // 1) Use os.Open and pass the file to the image decoder.
        //    This is a very regular way, but doesn't work on browsers.
        // 2) Use ebitenutil.OpenFile and pass the file to the image decoder.
        //    This works even on browsers.
        // 3) Use ebitenutil.NewImageFromFile to create an ebiten.Image directly from a file.
        //    This also works on browsers.
        img, _, err := image.Decode(bytes.NewReader(images.Tile_png))
        if err != nil {
                log.Fatal(err)
        }
        bgImage, _ = ebiten.NewImageFromImage(img, ebiten.FilterDefault)
}

var (
        theViewport = &viewport{}
)

type viewport struct {
        x16 int
        y16 int
}

func (p *viewport) Move() {
        w, h := bgImage.Size()
        maxX16 := w * 16
        maxY16 := h * 16

        p.x16 += w / 32
        p.y16 += h / 32
        p.x16 %= maxX16
        p.y16 %= maxY16
}

func (p *viewport) Position() (int, int) {
        return p.x16, p.y16
}

func update(screen *ebiten.Image) error {
        theViewport.Move()

        if ebiten.IsRunningSlowly() {
                return nil
        }

        x16, y16 := theViewport.Position()
        offsetX, offsetY := float64(-x16)/16, float64(-y16)/16

        // Draw bgImage on the screen repeatedly.
        const repeat = 3
        w, h := bgImage.Size()
        for j := 0; j < repeat; j++ {
                for i := 0; i < repeat; i++ {
                        op := &ebiten.DrawImageOptions{}
                        op.GeoM.Translate(float64(w*i), float64(h*j))
                        op.GeoM.Translate(offsetX, offsetY)
                        screen.DrawImage(bgImage, op)
                }
        }

        ebitenutil.DebugPrint(screen, fmt.Sprintf("FPS: %0.2f", ebiten.CurrentFPS()))
        return nil
}

func main() {
        if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Infinite Scroll (Ebiten Demo)"); err != nil {
                log.Fatal(err)
        }
}