mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-12 12:08:58 +01:00
docs: Update
This commit is contained in:
parent
80e4ee0998
commit
4f67af726b
@ -82,7 +82,7 @@ func update(screen *ebiten.Image) error {
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
ebitenImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "ebiten.png"), ebiten.FilterNearest)
|
||||
ebitenImage, _, err = ebitenutil.NewImageFromFile("_resources/images/ebiten.png", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -120,11 +120,11 @@ func playerBarRect() (x, y, w, h int) {
|
||||
|
||||
func NewPlayer(audioContext *audio.Context) (*Player, error) {
|
||||
const bytesPerSample = 4 // TODO: This should be defined in audio package
|
||||
wavF, err := ebitenutil.OpenFile(ebitenutil.JoinStringsIntoFilePath("_resources", "audio", "jab.wav"))
|
||||
wavF, err := ebitenutil.OpenFile("_resources/audio/jab.wav")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mp3F, err := ebitenutil.OpenFile(ebitenutil.JoinStringsIntoFilePath("_resources", "audio", "classic.mp3"))
|
||||
mp3F, err := ebitenutil.OpenFile("_resources/audio/classic.mp3")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -45,13 +45,16 @@ import (
|
||||
var (
|
||||
count int
|
||||
highDPIImage *ebiten.Image
|
||||
highDPIImageCh = make(chan *ebiten.Image)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// licensed under Public Domain
|
||||
// Licensed under Public Domain
|
||||
// https://commons.wikimedia.org/wiki/File:As08-16-2593.jpg
|
||||
const url = "https://upload.wikimedia.org/wikipedia/commons/1/1f/As08-16-2593.jpg"
|
||||
|
||||
// Load the image asynchronously.
|
||||
go func() {
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -63,17 +66,35 @@ func init() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
highDPIImage, err = ebiten.NewImageFromImage(img, ebiten.FilterLinear)
|
||||
eimg, err := ebiten.NewImageFromImage(img, ebiten.FilterLinear)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
highDPIImageCh <- eimg
|
||||
close(highDPIImageCh)
|
||||
}()
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
if highDPIImage == nil {
|
||||
// Use select and 'default' clause for non-blocking receiving.
|
||||
select {
|
||||
case img := <-highDPIImageCh:
|
||||
highDPIImage = img
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if highDPIImage == nil {
|
||||
ebitenutil.DebugPrint(screen, "Loading the image...")
|
||||
return nil
|
||||
}
|
||||
|
||||
scale := ebiten.DeviceScaleFactor()
|
||||
sw, sh := screen.Size()
|
||||
|
||||
@ -85,6 +106,7 @@ func update(screen *ebiten.Image) error {
|
||||
|
||||
// The image is just too big. Adjust the scale.
|
||||
op.GeoM.Scale(0.25, 0.25)
|
||||
|
||||
// Scale the image by the device ratio so that the rendering result can be same
|
||||
// on various (diffrent-DPI) environments.
|
||||
op.GeoM.Scale(scale, scale)
|
||||
|
@ -47,15 +47,17 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
hueInt = 0
|
||||
saturationInt = 128
|
||||
valueInt = 128
|
||||
hue128 = 0
|
||||
saturation128 = 128
|
||||
value128 = 128
|
||||
|
||||
inverted = false
|
||||
|
||||
prevPressedI = false
|
||||
gophersImage *ebiten.Image
|
||||
)
|
||||
|
||||
// clamp clamps v to the range [min, max].
|
||||
func clamp(v, min, max int) int {
|
||||
if min > max {
|
||||
panic("min must <= max")
|
||||
@ -70,25 +72,30 @@ func clamp(v, min, max int) int {
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
// Adjust HSV values along with the user's input.
|
||||
if ebiten.IsKeyPressed(ebiten.KeyQ) {
|
||||
hueInt--
|
||||
hue128--
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyW) {
|
||||
hueInt++
|
||||
hue128++
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyA) {
|
||||
saturationInt--
|
||||
saturation128--
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyS) {
|
||||
saturationInt++
|
||||
saturation128++
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyZ) {
|
||||
valueInt--
|
||||
value128--
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyX) {
|
||||
valueInt++
|
||||
value128++
|
||||
}
|
||||
|
||||
hue128 = clamp(hue128, -256, 256)
|
||||
saturation128 = clamp(saturation128, 0, 256)
|
||||
value128 = clamp(value128, 0, 256)
|
||||
|
||||
pressedI := ebiten.IsKeyPressed(ebiten.KeyI)
|
||||
if pressedI && !prevPressedI {
|
||||
inverted = !inverted
|
||||
@ -98,18 +105,19 @@ func update(screen *ebiten.Image) error {
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
hueInt = clamp(hueInt, -256, 256)
|
||||
saturationInt = clamp(saturationInt, 0, 256)
|
||||
valueInt = clamp(valueInt, 0, 256)
|
||||
|
||||
// Center the image on the screen.
|
||||
w, h := gophersImage.Size()
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(screenWidth-w)/2, float64(screenHeight-h)/2)
|
||||
|
||||
hue := float64(hueInt) * 2 * math.Pi / 128
|
||||
saturation := float64(saturationInt) / 128
|
||||
value := float64(valueInt) / 128
|
||||
// Change HSV.
|
||||
hue := float64(hue128) * 2 * math.Pi / 128
|
||||
saturation := float64(saturation128) / 128
|
||||
value := float64(value128) / 128
|
||||
op.ColorM.ChangeHSV(hue, saturation, value)
|
||||
|
||||
// Invert the color.
|
||||
if inverted {
|
||||
op.ColorM.Scale(-1, -1, -1, 1)
|
||||
op.ColorM.Translate(1, 1, 1, 0)
|
||||
@ -117,6 +125,7 @@ func update(screen *ebiten.Image) error {
|
||||
|
||||
screen.DrawImage(gophersImage, op)
|
||||
|
||||
// Draw the text of the current status.
|
||||
msgInverted := "false"
|
||||
if inverted {
|
||||
msgInverted = "true"
|
||||
@ -131,7 +140,7 @@ Inverted: %s [I]`, hue, saturation, value, msgInverted)
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest)
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -52,20 +52,26 @@ var (
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
count++
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Center the image on the screen.
|
||||
w, h := gophersImage.Size()
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(screenWidth-w)/2, float64(screenHeight-h)/2)
|
||||
|
||||
// Rotate the hue.
|
||||
op.ColorM.RotateHue(float64(count%360) * 2 * math.Pi / 360)
|
||||
|
||||
screen.DrawImage(gophersImage, op)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest)
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ import (
|
||||
"fmt"
|
||||
_ "image/png"
|
||||
"log"
|
||||
"math"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/ebitenutil"
|
||||
@ -47,10 +46,19 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
theViewport = &viewport{}
|
||||
bgImage *ebiten.Image
|
||||
repeatedBgImage *ebiten.Image
|
||||
groundImage *ebiten.Image
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
bgImage, _, err = ebitenutil.NewImageFromFile("_resources/images/tile.png", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
theViewport = &viewport{}
|
||||
)
|
||||
|
||||
type viewport struct {
|
||||
@ -58,80 +66,48 @@ type viewport struct {
|
||||
y16 int
|
||||
}
|
||||
|
||||
func round(x float64) float64 {
|
||||
return math.Floor(x + 0.5)
|
||||
}
|
||||
|
||||
func (p *viewport) Move() {
|
||||
w, h := bgImage.Size()
|
||||
mx := w * 16
|
||||
my := h * 16
|
||||
maxX16 := w * 16
|
||||
maxY16 := h * 16
|
||||
|
||||
p.x16 += w / 32
|
||||
p.y16 += h / 32
|
||||
|
||||
for mx <= p.x16 {
|
||||
p.x16 -= mx
|
||||
}
|
||||
for my <= p.y16 {
|
||||
p.y16 -= my
|
||||
}
|
||||
for p.x16 < 0 {
|
||||
p.x16 += mx
|
||||
}
|
||||
for p.y16 < 0 {
|
||||
p.y16 += my
|
||||
}
|
||||
p.x16 %= maxX16
|
||||
p.y16 %= maxY16
|
||||
}
|
||||
|
||||
func (p *viewport) Position() (int, int) {
|
||||
return p.x16, p.y16
|
||||
}
|
||||
|
||||
func updateGroundImage(ground *ebiten.Image) {
|
||||
ground.Clear()
|
||||
x16, y16 := theViewport.Position()
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(-x16)/16, float64(-y16)/16)
|
||||
ground.DrawImage(repeatedBgImage, op)
|
||||
}
|
||||
|
||||
func drawGroundImage(screen *ebiten.Image, ground *ebiten.Image) {
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
screen.DrawImage(ground, op)
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
theViewport.Move()
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
updateGroundImage(groundImage)
|
||||
drawGroundImage(screen, groundImage)
|
||||
|
||||
msg := fmt.Sprintf("FPS: %0.2f", ebiten.CurrentFPS())
|
||||
ebitenutil.DebugPrint(screen, msg)
|
||||
return nil
|
||||
}
|
||||
x16, y16 := theViewport.Position()
|
||||
offsetX, offsetY := float64(-x16)/16, float64(-y16)/16
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
bgImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "tile.png"), ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Draw bgImage on the screen repeatedly.
|
||||
const repeat = 3
|
||||
w, h := bgImage.Size()
|
||||
const repeat = 5
|
||||
repeatedBgImage, _ = ebiten.NewImage(w*repeat, h*repeat, ebiten.FilterNearest)
|
||||
for j := 0; j < repeat; j++ {
|
||||
for i := 0; i < repeat; i++ {
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(w*i), float64(h*j))
|
||||
repeatedBgImage.DrawImage(bgImage, op)
|
||||
op.GeoM.Translate(offsetX, offsetY)
|
||||
screen.DrawImage(bgImage, op)
|
||||
}
|
||||
}
|
||||
groundImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ var keyboardImage *ebiten.Image
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
keyboardImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "keyboard", "keyboard.png"), ebiten.FilterNearest)
|
||||
keyboardImage, _, err = ebitenutil.NewImageFromFile("_resources/images/keyboard/keyboard.png", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -86,15 +86,7 @@ var keyNames = map[ebiten.Key]string{
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
const offsetX, offsetY = 24, 40
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(offsetX, offsetY)
|
||||
op.ColorM.Scale(0.5, 0.5, 0.5, 1)
|
||||
screen.DrawImage(keyboardImage, op)
|
||||
|
||||
// Collect pressed keys' names.
|
||||
pressed := []string{}
|
||||
for i := 0; i <= 9; i++ {
|
||||
if ebiten.IsKeyPressed(ebiten.Key(i) + ebiten.Key0) {
|
||||
@ -102,12 +94,12 @@ func update(screen *ebiten.Image) error {
|
||||
}
|
||||
}
|
||||
for c := 'A'; c <= 'Z'; c++ {
|
||||
if ebiten.IsKeyPressed(ebiten.Key(c) - 'A' + ebiten.KeyA) {
|
||||
if ebiten.IsKeyPressed(ebiten.KeyA + ebiten.Key(c-'A')) {
|
||||
pressed = append(pressed, string(c))
|
||||
}
|
||||
}
|
||||
for i := 1; i <= 12; i++ {
|
||||
if ebiten.IsKeyPressed(ebiten.Key(i) + ebiten.KeyF1 - 1) {
|
||||
if ebiten.IsKeyPressed(ebiten.KeyF1 + ebiten.Key(i-1)) {
|
||||
pressed = append(pressed, "F"+strconv.Itoa(i))
|
||||
}
|
||||
}
|
||||
@ -117,6 +109,22 @@ func update(screen *ebiten.Image) error {
|
||||
}
|
||||
}
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
offsetX = 24
|
||||
offsetY = 40
|
||||
)
|
||||
|
||||
// Draw the base (grayed) keyboard image.
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(offsetX, offsetY)
|
||||
op.ColorM.Scale(0.5, 0.5, 0.5, 1)
|
||||
screen.DrawImage(keyboardImage, op)
|
||||
|
||||
// Draw the highlighted keys.
|
||||
op = &ebiten.DrawImageOptions{}
|
||||
for _, p := range pressed {
|
||||
op.GeoM.Reset()
|
||||
|
@ -39,40 +39,50 @@ import (
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
// World represents the game state
|
||||
// World represents the game state.
|
||||
type World struct {
|
||||
area [][]bool
|
||||
rnd *rand.Rand
|
||||
}
|
||||
|
||||
// NewWorld creates a new world
|
||||
func NewWorld(width, height int) *World {
|
||||
world := World{
|
||||
area: makeArea(width, height),
|
||||
rnd: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
func newArea(width, height int) [][]bool {
|
||||
a := make([][]bool, height)
|
||||
for i := 0; i < height; i++ {
|
||||
a[i] = make([]bool, width)
|
||||
}
|
||||
return &world
|
||||
return a
|
||||
}
|
||||
|
||||
// RandomSeed inits world with a random state
|
||||
func (w *World) RandomSeed(limit int) {
|
||||
// NewWorld creates a new world.
|
||||
func NewWorld(width, height int, maxInitLiveCells int) *World {
|
||||
w := &World{
|
||||
area: newArea(width, height),
|
||||
}
|
||||
w.init(maxInitLiveCells)
|
||||
return w
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
// init inits world with a random state.
|
||||
func (w *World) init(maxLiveCells int) {
|
||||
height := len(w.area)
|
||||
width := len(w.area[0])
|
||||
for i := 0; i < limit; i++ {
|
||||
x := w.rnd.Intn(width)
|
||||
y := w.rnd.Intn(height)
|
||||
for i := 0; i < maxLiveCells; i++ {
|
||||
x := rand.Intn(width)
|
||||
y := rand.Intn(height)
|
||||
w.area[y][x] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Progress game state by one tick
|
||||
func (w *World) Progress() {
|
||||
// Update game state by one tick.
|
||||
func (w *World) Update() {
|
||||
height := len(w.area)
|
||||
width := len(w.area[0])
|
||||
next := makeArea(width, height)
|
||||
next := newArea(width, height)
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
|
||||
pop := neighbourCount(w.area, x, y)
|
||||
switch {
|
||||
case pop < 2:
|
||||
@ -100,66 +110,63 @@ func (w *World) Progress() {
|
||||
w.area = next
|
||||
}
|
||||
|
||||
// DrawImage paints current game state
|
||||
func (w *World) DrawImage(pix []uint8) {
|
||||
// Draw paints current game state.
|
||||
func (w *World) Draw(pix []byte) {
|
||||
height := len(w.area)
|
||||
width := len(w.area[0])
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
pos := 4*y*width + 4*x
|
||||
idx := 4*y*width + 4*x
|
||||
if w.area[y][x] {
|
||||
pix[pos] = 0xff
|
||||
pix[pos+1] = 0xff
|
||||
pix[pos+2] = 0xff
|
||||
pix[pos+3] = 0xff
|
||||
pix[idx] = 0xff
|
||||
pix[idx+1] = 0xff
|
||||
pix[idx+2] = 0xff
|
||||
pix[idx+3] = 0xff
|
||||
} else {
|
||||
pix[pos] = 0
|
||||
pix[pos+1] = 0
|
||||
pix[pos+2] = 0
|
||||
pix[pos+3] = 0
|
||||
pix[idx] = 0
|
||||
pix[idx+1] = 0
|
||||
pix[idx+2] = 0
|
||||
pix[idx+3] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// neighbourCount calculates the Moore neighborhood of x, y
|
||||
func max(a, b int) int {
|
||||
if a < b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// neighbourCount calculates the Moore neighborhood of (x, y).
|
||||
func neighbourCount(a [][]bool, x, y int) int {
|
||||
height := len(a)
|
||||
width := len(a[0])
|
||||
lowX := 0
|
||||
if x > 0 {
|
||||
lowX = x - 1
|
||||
}
|
||||
lowY := 0
|
||||
if y > 0 {
|
||||
lowY = y - 1
|
||||
}
|
||||
highX := width - 1
|
||||
if x < width-1 {
|
||||
highX = x + 1
|
||||
}
|
||||
highY := height - 1
|
||||
if y < height-1 {
|
||||
highY = y + 1
|
||||
}
|
||||
near := 0
|
||||
for pY := lowY; pY <= highY; pY++ {
|
||||
for pX := lowX; pX <= highX; pX++ {
|
||||
if !(pX == x && pY == y) && a[pY][pX] {
|
||||
near++
|
||||
}
|
||||
}
|
||||
}
|
||||
w := len(a[0])
|
||||
h := len(a)
|
||||
minI := max(x-1, 0)
|
||||
minJ := max(y-1, 0)
|
||||
maxI := min(x+1, w-1)
|
||||
maxJ := min(y+1, h-1)
|
||||
|
||||
return near
|
||||
c := 0
|
||||
for j := minJ; j <= maxJ; j++ {
|
||||
for i := minI; i <= maxI; i++ {
|
||||
if i == x && j == y {
|
||||
continue
|
||||
}
|
||||
|
||||
func makeArea(width, height int) [][]bool {
|
||||
area := make([][]bool, height)
|
||||
for i := 0; i < height; i++ {
|
||||
area[i] = make([]bool, width)
|
||||
if a[j][i] {
|
||||
c++
|
||||
}
|
||||
return area
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
const (
|
||||
@ -168,23 +175,24 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
world = NewWorld(screenWidth, screenHeight)
|
||||
pixels = make([]uint8, screenWidth*screenHeight*4)
|
||||
world = NewWorld(screenWidth, screenHeight, int((screenWidth*screenHeight)/10))
|
||||
pixels = make([]byte, screenWidth*screenHeight*4)
|
||||
)
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
world.Progress()
|
||||
world.Update()
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
world.DrawImage(pixels)
|
||||
|
||||
world.Draw(pixels)
|
||||
screen.ReplacePixels(pixels)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
world.RandomSeed(int((screenWidth * screenHeight) / 10))
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2.0, "Game of Life (Ebiten Demo)"); err != nil {
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Game of Life (Ebiten Demo)"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
gophersImage *ebiten.Image
|
||||
fiveyearsImage *ebiten.Image
|
||||
maskImage *ebiten.Image
|
||||
bgImage *ebiten.Image
|
||||
fgImage *ebiten.Image
|
||||
maskedFgImage *ebiten.Image
|
||||
spotLightImage *ebiten.Image
|
||||
spotLightX = 0
|
||||
spotLightY = 0
|
||||
@ -58,6 +58,36 @@ var (
|
||||
spotLightVY = 1
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
bgImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fgImage, _, err = ebitenutil.NewImageFromFile("_resources/images/fiveyears.jpg", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
maskedFgImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
|
||||
|
||||
// Initialize the spot light image.
|
||||
const r = 64
|
||||
alphas := image.Point{r * 2, r * 2}
|
||||
a := image.NewAlpha(image.Rectangle{image.ZP, alphas})
|
||||
for j := 0; j < alphas.Y; j++ {
|
||||
for i := 0; i < alphas.X; i++ {
|
||||
// d is the distance between (i, j) and the (circle) center.
|
||||
d := math.Sqrt(float64((i-r)*(i-r) + (j-r)*(j-r)))
|
||||
// Alphas around the center are 0 and values outside of the circle are 0xff.
|
||||
b := uint8(max(0, min(0xff, int(3*d*0xff/r)-2*0xff)))
|
||||
a.SetAlpha(i, j, color.Alpha{b})
|
||||
}
|
||||
}
|
||||
spotLightImage, _ = ebiten.NewImageFromImage(a, ebiten.FilterNearest)
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
spotLightX += spotLightVX
|
||||
spotLightY += spotLightVY
|
||||
@ -79,22 +109,34 @@ func update(screen *ebiten.Image) error {
|
||||
spotLightY = -spotLightY + 2*maxY
|
||||
spotLightVY = -spotLightVY
|
||||
}
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
maskImage.Clear()
|
||||
|
||||
// Reset the maskedFgImage.
|
||||
maskedFgImage.Fill(color.White)
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.CompositeMode = ebiten.CompositeModeCopy
|
||||
op.GeoM.Translate(float64(spotLightX), float64(spotLightY))
|
||||
maskImage.DrawImage(spotLightImage, op)
|
||||
maskedFgImage.DrawImage(spotLightImage, op)
|
||||
|
||||
// Use 'source-in' composite mode so that the source image (fgImage) is used but the alpha
|
||||
// is determined by the destination image (maskedFgImage).
|
||||
//
|
||||
// The result image is the source image with the destination alpha. In maskedFgImage, alpha
|
||||
// values in the hole is 0 and alpha values in other places are 0xff. As a result, the
|
||||
// maskedFgImage draws the source image with a hole that shape is spotLightImage. Note that
|
||||
// RGB values in the destination image are ignored.
|
||||
//
|
||||
// See also https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin.
|
||||
op = &ebiten.DrawImageOptions{}
|
||||
op.CompositeMode = ebiten.CompositeModeSourceOut
|
||||
maskImage.DrawImage(fiveyearsImage, op)
|
||||
op.CompositeMode = ebiten.CompositeModeSourceIn
|
||||
maskedFgImage.DrawImage(fgImage, op)
|
||||
|
||||
screen.Fill(color.RGBA{0x00, 0x00, 0x80, 0xff})
|
||||
screen.DrawImage(gophersImage, &ebiten.DrawImageOptions{})
|
||||
screen.DrawImage(maskImage, &ebiten.DrawImageOptions{})
|
||||
screen.DrawImage(bgImage, &ebiten.DrawImageOptions{})
|
||||
screen.DrawImage(maskedFgImage, &ebiten.DrawImageOptions{})
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -114,28 +156,6 @@ func min(a, b int) int {
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fiveyearsImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "fiveyears.jpg"), ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
maskImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
|
||||
|
||||
as := image.Point{128, 128}
|
||||
a := image.NewAlpha(image.Rectangle{image.ZP, as})
|
||||
for j := 0; j < as.Y; j++ {
|
||||
for i := 0; i < as.X; i++ {
|
||||
r := as.X / 2
|
||||
d := math.Sqrt(float64((i-r)*(i-r) + (j-r)*(j-r)))
|
||||
b := uint8(max(0, min(0xff, 3*0xff-int(d*3*0xff)/r)))
|
||||
a.SetAlpha(i, j, color.Alpha{b})
|
||||
}
|
||||
}
|
||||
spotLightImage, _ = ebiten.NewImageFromImage(a, ebiten.FilterNearest)
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Masking (Ebiten Demo)"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -51,13 +51,26 @@ var (
|
||||
gophersRenderTarget *ebiten.Image
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shrink the image once.
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Scale(1.0/mosaicRatio, 1.0/mosaicRatio)
|
||||
gophersRenderTarget.DrawImage(gophersImage, op)
|
||||
|
||||
// Enlarge the shrunk image.
|
||||
// The filter is the nearest filter, so the result will be mosaic.
|
||||
op = &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Scale(mosaicRatio, mosaicRatio)
|
||||
screen.DrawImage(gophersRenderTarget, op)
|
||||
@ -65,11 +78,6 @@ func update(screen *ebiten.Image) error {
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
w, h := gophersImage.Size()
|
||||
gophersRenderTarget, _ = ebiten.NewImage(w/mosaicRatio, h/mosaicRatio, ebiten.FilterNearest)
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Mosaic (Ebiten Demo)"); err != nil {
|
||||
|
@ -73,7 +73,7 @@ func update(screen *ebiten.Image) error {
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest)
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
f, err := ebitenutil.OpenFile(ebitenutil.JoinStringsIntoFilePath("_resources", "fonts", "arcade_n.ttf"))
|
||||
f, err := ebitenutil.OpenFile("_resources/fonts/arcade_n.ttf")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ func update(screen *ebiten.Image) error {
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest)
|
||||
gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ Press <- or -> to change the number of sprites`, ebiten.CurrentFPS(), spri
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
img, _, err := ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "ebiten.png"), ebiten.FilterNearest)
|
||||
img, _, err := ebitenutil.NewImageFromFile("_resources/images/ebiten.png", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user