mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
parent
c2a5f4ab94
commit
1dc8002689
@ -41,11 +41,8 @@ const (
|
||||
var (
|
||||
skyColor = color.RGBA{0x66, 0xcc, 0xff, 0xff}
|
||||
|
||||
gophersImage *ebiten.Image
|
||||
repeatedGophersImage *ebiten.Image
|
||||
groundImage = ebiten.NewImage(screenWidth*3, screenHeight*2/3+200)
|
||||
perspectiveGroundImage = ebiten.NewImage(screenWidth*3, screenHeight)
|
||||
fogImage *ebiten.Image
|
||||
gophersImage *ebiten.Image
|
||||
repeatedGophersImage *ebiten.Image
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -77,23 +74,6 @@ func init() {
|
||||
repeatedGophersImage.DrawImage(gophersImage, op)
|
||||
}
|
||||
}
|
||||
|
||||
const fogHeight = 16
|
||||
w, _ = perspectiveGroundImage.Size()
|
||||
fogRGBA := image.NewRGBA(image.Rect(0, 0, w, fogHeight))
|
||||
for j := 0; j < fogHeight; j++ {
|
||||
a := uint32(float64(fogHeight-1-j) * 0xff / (fogHeight - 1))
|
||||
clr := skyColor
|
||||
r, g, b, oa := uint32(clr.R), uint32(clr.G), uint32(clr.B), uint32(clr.A)
|
||||
clr.R = uint8(r * a / oa)
|
||||
clr.G = uint8(g * a / oa)
|
||||
clr.B = uint8(b * a / oa)
|
||||
clr.A = uint8(a)
|
||||
for i := 0; i < w; i++ {
|
||||
fogRGBA.SetRGBA(i, j, clr)
|
||||
}
|
||||
}
|
||||
fogImage = ebiten.NewImageFromImage(fogRGBA)
|
||||
}
|
||||
|
||||
// player represents the current airship's position.
|
||||
@ -200,9 +180,9 @@ func (g *Game) updateGroundImage(ground *ebiten.Image) {
|
||||
|
||||
// drawGroundImage draws the ground image to the given screen image.
|
||||
func (g *Game) drawGroundImage(screen *ebiten.Image, ground *ebiten.Image) {
|
||||
perspectiveGroundImage.Clear()
|
||||
g.perspectiveGroundImage.Clear()
|
||||
gw, _ := ground.Size()
|
||||
pw, ph := perspectiveGroundImage.Size()
|
||||
pw, ph := g.perspectiveGroundImage.Size()
|
||||
for j := 0; j < ph; j++ {
|
||||
// z is in [2, -1]
|
||||
rate := float64(j) / float64(ph)
|
||||
@ -216,30 +196,55 @@ func (g *Game) drawGroundImage(screen *ebiten.Image, ground *ebiten.Image) {
|
||||
op.GeoM.Scale(1/z, 8) // 8 is an arbitrary number not to make empty lines.
|
||||
op.GeoM.Translate(float64(pw)/2, float64(j)/z)
|
||||
|
||||
perspectiveGroundImage.DrawImage(ground.SubImage(image.Rect(0, j, gw, j+1)).(*ebiten.Image), op)
|
||||
g.perspectiveGroundImage.DrawImage(ground.SubImage(image.Rect(0, j, gw, j+1)).(*ebiten.Image), op)
|
||||
}
|
||||
|
||||
perspectiveGroundImage.DrawImage(fogImage, nil)
|
||||
g.perspectiveGroundImage.DrawImage(g.fogImage, nil)
|
||||
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(-float64(pw)/2, 0)
|
||||
op.GeoM.Rotate(-1 * float64(g.player.lean) / maxLean * math.Pi / 8)
|
||||
op.GeoM.Translate(float64(screenWidth)/2, screenHeight/3)
|
||||
screen.DrawImage(perspectiveGroundImage, op)
|
||||
screen.DrawImage(g.perspectiveGroundImage, op)
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
player *player
|
||||
|
||||
groundImage *ebiten.Image
|
||||
perspectiveGroundImage *ebiten.Image
|
||||
fogImage *ebiten.Image
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
return &Game{
|
||||
g := &Game{
|
||||
player: &player{
|
||||
x16: 16 * 100,
|
||||
y16: 16 * 200,
|
||||
angle: maxAngle * 3 / 4,
|
||||
},
|
||||
groundImage: ebiten.NewImage(screenWidth*3, screenHeight*2/3+200),
|
||||
perspectiveGroundImage: ebiten.NewImage(screenWidth*3, screenHeight),
|
||||
}
|
||||
|
||||
const fogHeight = 16
|
||||
w, _ := g.perspectiveGroundImage.Size()
|
||||
fogRGBA := image.NewRGBA(image.Rect(0, 0, w, fogHeight))
|
||||
for j := 0; j < fogHeight; j++ {
|
||||
a := uint32(float64(fogHeight-1-j) * 0xff / (fogHeight - 1))
|
||||
clr := skyColor
|
||||
r, g, b, oa := uint32(clr.R), uint32(clr.G), uint32(clr.B), uint32(clr.A)
|
||||
clr.R = uint8(r * a / oa)
|
||||
clr.G = uint8(g * a / oa)
|
||||
clr.B = uint8(b * a / oa)
|
||||
clr.A = uint8(a)
|
||||
for i := 0; i < w; i++ {
|
||||
fogRGBA.SetRGBA(i, j, clr)
|
||||
}
|
||||
}
|
||||
g.fogImage = ebiten.NewImageFromImage(fogRGBA)
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -265,8 +270,8 @@ func (g *Game) Update() error {
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
// Draw the ground image.
|
||||
screen.Fill(skyColor)
|
||||
g.updateGroundImage(groundImage)
|
||||
g.drawGroundImage(screen, groundImage)
|
||||
g.updateGroundImage(g.groundImage)
|
||||
g.drawGroundImage(screen, g.groundImage)
|
||||
|
||||
// Draw the message.
|
||||
tutrial := "Space: Move forward\nLeft/Right: Rotate"
|
||||
|
@ -55,9 +55,6 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
playButtonPosition image.Point
|
||||
alertButtonPosition image.Point
|
||||
|
||||
playButtonImage *ebiten.Image
|
||||
pauseButtonImage *ebiten.Image
|
||||
alertButtonImage *ebiten.Image
|
||||
@ -81,15 +78,6 @@ func init() {
|
||||
panic(err)
|
||||
}
|
||||
alertButtonImage = ebiten.NewImageFromImage(img)
|
||||
|
||||
const buttonPadding = 16
|
||||
|
||||
w, _ := playButtonImage.Size()
|
||||
playButtonPosition.X = (screenWidth - w*2 + buttonPadding*1) / 2
|
||||
playButtonPosition.Y = screenHeight - 160
|
||||
|
||||
alertButtonPosition.X = playButtonPosition.X + w + buttonPadding
|
||||
alertButtonPosition.Y = playButtonPosition.Y
|
||||
}
|
||||
|
||||
type musicType int
|
||||
@ -121,6 +109,9 @@ type Player struct {
|
||||
seCh chan []byte
|
||||
volume128 int
|
||||
musicType musicType
|
||||
|
||||
playButtonPosition image.Point
|
||||
alertButtonPosition image.Point
|
||||
}
|
||||
|
||||
func playerBarRect() (x, y, w, h int) {
|
||||
@ -172,6 +163,15 @@ func NewPlayer(game *Game, audioContext *audio.Context, musicType musicType) (*P
|
||||
if player.total == 0 {
|
||||
player.total = 1
|
||||
}
|
||||
|
||||
const buttonPadding = 16
|
||||
w, _ := playButtonImage.Size()
|
||||
player.playButtonPosition.X = (screenWidth - w*2 + buttonPadding*1) / 2
|
||||
player.playButtonPosition.Y = screenHeight - 160
|
||||
|
||||
player.alertButtonPosition.X = player.playButtonPosition.X + w + buttonPadding
|
||||
player.alertButtonPosition.Y = player.playButtonPosition.Y
|
||||
|
||||
player.audioPlayer.Play()
|
||||
go func() {
|
||||
s, err := wav.Decode(audioContext, bytes.NewReader(raudio.Jab_wav))
|
||||
@ -226,8 +226,8 @@ func (p *Player) shouldPlaySE() bool {
|
||||
return true
|
||||
}
|
||||
r := image.Rectangle{
|
||||
Min: alertButtonPosition,
|
||||
Max: alertButtonPosition.Add(image.Pt(alertButtonImage.Size())),
|
||||
Min: p.alertButtonPosition,
|
||||
Max: p.alertButtonPosition.Add(image.Pt(alertButtonImage.Size())),
|
||||
}
|
||||
if image.Pt(ebiten.CursorPosition()).In(r) {
|
||||
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
|
||||
@ -271,8 +271,8 @@ func (p *Player) shouldSwitchPlayStateIfNeeded() bool {
|
||||
return true
|
||||
}
|
||||
r := image.Rectangle{
|
||||
Min: playButtonPosition,
|
||||
Max: playButtonPosition.Add(image.Pt(playButtonImage.Size())),
|
||||
Min: p.playButtonPosition,
|
||||
Max: p.playButtonPosition.Add(image.Pt(playButtonImage.Size())),
|
||||
}
|
||||
if image.Pt(ebiten.CursorPosition()).In(r) {
|
||||
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
|
||||
@ -350,14 +350,14 @@ func (p *Player) draw(screen *ebiten.Image) {
|
||||
|
||||
// Draw buttons
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(playButtonPosition.X), float64(playButtonPosition.Y))
|
||||
op.GeoM.Translate(float64(p.playButtonPosition.X), float64(p.playButtonPosition.Y))
|
||||
if p.audioPlayer.IsPlaying() {
|
||||
screen.DrawImage(pauseButtonImage, op)
|
||||
} else {
|
||||
screen.DrawImage(playButtonImage, op)
|
||||
}
|
||||
op.GeoM.Reset()
|
||||
op.GeoM.Translate(float64(alertButtonPosition.X), float64(alertButtonPosition.Y))
|
||||
op.GeoM.Translate(float64(p.alertButtonPosition.X), float64(p.alertButtonPosition.Y))
|
||||
screen.DrawImage(alertButtonImage, op)
|
||||
|
||||
// Draw the debug message.
|
||||
|
@ -39,10 +39,9 @@ const (
|
||||
loopLengthInSecond = 4
|
||||
)
|
||||
|
||||
var audioContext = audio.NewContext(sampleRate)
|
||||
|
||||
type Game struct {
|
||||
player *audio.Player
|
||||
player *audio.Player
|
||||
audioContext *audio.Context
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -50,9 +49,13 @@ func (g *Game) Update() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if g.audioContext == nil {
|
||||
g.audioContext = audio.NewContext(sampleRate)
|
||||
}
|
||||
|
||||
// Decode an Ogg file.
|
||||
// oggS is a decoded io.ReadCloser and io.Seeker.
|
||||
oggS, err := vorbis.Decode(audioContext, bytes.NewReader(raudio.Ragtime_ogg))
|
||||
oggS, err := vorbis.Decode(g.audioContext, bytes.NewReader(raudio.Ragtime_ogg))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -61,7 +64,7 @@ func (g *Game) Update() error {
|
||||
// s is still an io.ReadCloser and io.Seeker.
|
||||
s := audio.NewInfiniteLoopWithIntro(oggS, introLengthInSecond*4*sampleRate, loopLengthInSecond*4*sampleRate)
|
||||
|
||||
g.player, err = audio.NewPlayer(audioContext, s)
|
||||
g.player, err = audio.NewPlayer(g.audioContext, s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -41,9 +41,7 @@ const (
|
||||
sampleRate = 22050
|
||||
)
|
||||
|
||||
var img *ebiten.Image
|
||||
|
||||
var audioContext = audio.NewContext(sampleRate)
|
||||
var ebitenImage *ebiten.Image
|
||||
|
||||
type Game struct {
|
||||
player *audio.Player
|
||||
@ -57,6 +55,8 @@ type Game struct {
|
||||
|
||||
count int
|
||||
xpos float64
|
||||
|
||||
audioContext *audio.Context
|
||||
}
|
||||
|
||||
func (g *Game) initAudio() {
|
||||
@ -64,9 +64,13 @@ func (g *Game) initAudio() {
|
||||
return
|
||||
}
|
||||
|
||||
if g.audioContext == nil {
|
||||
g.audioContext = audio.NewContext(sampleRate)
|
||||
}
|
||||
|
||||
// Decode an Ogg file.
|
||||
// oggS is a decoded io.ReadCloser and io.Seeker.
|
||||
oggS, err := vorbis.Decode(audioContext, bytes.NewReader(raudio.Ragtime_ogg))
|
||||
oggS, err := vorbis.Decode(g.audioContext, bytes.NewReader(raudio.Ragtime_ogg))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -74,7 +78,7 @@ func (g *Game) initAudio() {
|
||||
// Wrap the raw audio with the StereoPanStream
|
||||
g.panstream = NewStereoPanStreamFromReader(audio.NewInfiniteLoop(oggS, oggS.Length()))
|
||||
|
||||
g.player, err = audio.NewPlayer(audioContext, g.panstream)
|
||||
g.player, err = audio.NewPlayer(g.audioContext, g.panstream)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@ -109,8 +113,8 @@ Panning: %.2f`, ebiten.CurrentTPS(), float64(pos)/float64(time.Second), g.pannin
|
||||
|
||||
// draw image to show where the sound is at related to the screen
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(g.xpos-float64(img.Bounds().Dx()/2), screenHeight/2)
|
||||
screen.DrawImage(img, op)
|
||||
op.GeoM.Translate(g.xpos-float64(ebitenImage.Bounds().Dx()/2), screenHeight/2)
|
||||
screen.DrawImage(ebitenImage, op)
|
||||
}
|
||||
|
||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
@ -127,11 +131,11 @@ func main() {
|
||||
// This works even on browsers.
|
||||
// 3) Use ebitenutil.NewImageFromFile to create an ebiten.Image directly from a file.
|
||||
// This also works on browsers.
|
||||
rawimg, _, err := image.Decode(bytes.NewReader(images.Ebiten_png))
|
||||
img, _, err := image.Decode(bytes.NewReader(images.Ebiten_png))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
img = ebiten.NewImageFromImage(rawimg)
|
||||
ebitenImage = ebiten.NewImageFromImage(img)
|
||||
|
||||
ebiten.SetWindowSize(screenWidth, screenHeight)
|
||||
ebiten.SetWindowTitle("Audio Panning Loop (Ebiten Demo)")
|
||||
|
@ -33,7 +33,6 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
pixels = make([]byte, screenSize*4)
|
||||
firePalette = []color.RGBA{
|
||||
{R: 7, G: 7, B: 7, A: 255}, // 0
|
||||
{R: 31, G: 7, B: 7, A: 255}, // 1
|
||||
@ -76,16 +75,18 @@ var (
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
firePixels []byte
|
||||
pixels []byte
|
||||
indices []byte
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
firePixels := make([]byte, screenSize)
|
||||
indices := make([]byte, screenSize)
|
||||
for i := screenSize - screenWidth; i < screenSize; i++ {
|
||||
firePixels[i] = 36
|
||||
indices[i] = 36
|
||||
}
|
||||
return &Game{
|
||||
firePixels: firePixels,
|
||||
pixels: make([]byte, screenSize*4),
|
||||
indices: indices,
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +106,7 @@ func (g *Game) updateFireIntensityPerPixel(currentPixelIndex int) {
|
||||
}
|
||||
|
||||
d := rand.Intn(3)
|
||||
newI := int(g.firePixels[below]) - d
|
||||
newI := int(g.indices[below]) - d
|
||||
if newI < 0 {
|
||||
newI = 0
|
||||
}
|
||||
@ -113,16 +114,16 @@ func (g *Game) updateFireIntensityPerPixel(currentPixelIndex int) {
|
||||
if currentPixelIndex-d < 0 {
|
||||
return
|
||||
}
|
||||
g.firePixels[currentPixelIndex-d] = byte(newI)
|
||||
g.indices[currentPixelIndex-d] = byte(newI)
|
||||
}
|
||||
|
||||
func (g *Game) renderFire() {
|
||||
for i, v := range g.firePixels {
|
||||
for i, v := range g.indices {
|
||||
p := firePalette[v]
|
||||
pixels[i*4] = p.R
|
||||
pixels[i*4+1] = p.G
|
||||
pixels[i*4+2] = p.B
|
||||
pixels[i*4+3] = p.A
|
||||
g.pixels[i*4] = p.R
|
||||
g.pixels[i*4+1] = p.G
|
||||
g.pixels[i*4+2] = p.B
|
||||
g.pixels[i*4+3] = p.A
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,7 +134,7 @@ func (g *Game) Update() error {
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
g.renderFire()
|
||||
screen.ReplacePixels(pixels)
|
||||
screen.ReplacePixels(g.pixels)
|
||||
}
|
||||
|
||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
|
@ -126,32 +126,6 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
audioContext = audio.NewContext(48000)
|
||||
jumpPlayer *audio.Player
|
||||
hitPlayer *audio.Player
|
||||
)
|
||||
|
||||
func init() {
|
||||
jumpD, err := vorbis.Decode(audioContext, bytes.NewReader(raudio.Jump_ogg))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
jumpPlayer, err = audio.NewPlayer(audioContext, jumpD)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
jabD, err := wav.Decode(audioContext, bytes.NewReader(raudio.Jab_wav))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
hitPlayer, err = audio.NewPlayer(audioContext, jabD)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
@ -179,6 +153,10 @@ type Game struct {
|
||||
|
||||
touchIDs []ebiten.TouchID
|
||||
gamepadIDs []ebiten.GamepadID
|
||||
|
||||
audioContext *audio.Context
|
||||
jumpPlayer *audio.Player
|
||||
hitPlayer *audio.Player
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
@ -196,6 +174,26 @@ func (g *Game) init() {
|
||||
for i := range g.pipeTileYs {
|
||||
g.pipeTileYs[i] = rand.Intn(6) + 2
|
||||
}
|
||||
|
||||
g.audioContext = audio.NewContext(48000)
|
||||
|
||||
jumpD, err := vorbis.Decode(g.audioContext, bytes.NewReader(raudio.Jump_ogg))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
g.jumpPlayer, err = audio.NewPlayer(g.audioContext, jumpD)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
jabD, err := wav.Decode(g.audioContext, bytes.NewReader(raudio.Jab_wav))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
g.hitPlayer, err = audio.NewPlayer(g.audioContext, jabD)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) isKeyJustPressed() bool {
|
||||
@ -246,8 +244,8 @@ func (g *Game) Update() error {
|
||||
g.cameraX += 2
|
||||
if g.isKeyJustPressed() {
|
||||
g.vy16 = -96
|
||||
jumpPlayer.Rewind()
|
||||
jumpPlayer.Play()
|
||||
g.jumpPlayer.Rewind()
|
||||
g.jumpPlayer.Play()
|
||||
}
|
||||
g.y16 += g.vy16
|
||||
|
||||
@ -258,8 +256,8 @@ func (g *Game) Update() error {
|
||||
}
|
||||
|
||||
if g.hit() {
|
||||
hitPlayer.Rewind()
|
||||
hitPlayer.Play()
|
||||
g.hitPlayer.Rewind()
|
||||
g.hitPlayer.Play()
|
||||
g.mode = ModeGameOver
|
||||
g.gameoverCount = 30
|
||||
}
|
||||
|
@ -26,11 +26,16 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||
)
|
||||
|
||||
var (
|
||||
highDPIImageCh = make(chan *ebiten.Image)
|
||||
)
|
||||
type Game struct {
|
||||
highDPIImageCh chan *ebiten.Image
|
||||
highDPIImage *ebiten.Image
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
g := &Game{
|
||||
highDPIImageCh: make(chan *ebiten.Image),
|
||||
}
|
||||
|
||||
func init() {
|
||||
// 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"
|
||||
@ -41,13 +46,11 @@ func init() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
highDPIImageCh <- img
|
||||
close(highDPIImageCh)
|
||||
g.highDPIImageCh <- img
|
||||
close(g.highDPIImageCh)
|
||||
}()
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
highDPIImage *ebiten.Image
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -61,7 +64,7 @@ func (g *Game) Update() error {
|
||||
|
||||
// Use select and 'default' clause for non-blocking receiving.
|
||||
select {
|
||||
case img := <-highDPIImageCh:
|
||||
case img := <-g.highDPIImageCh:
|
||||
g.highDPIImage = img
|
||||
default:
|
||||
}
|
||||
@ -110,7 +113,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
func main() {
|
||||
ebiten.SetWindowSize(640, 480)
|
||||
ebiten.SetWindowTitle("High DPI (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
if err := ebiten.RunGame(NewGame()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -31,11 +31,15 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
offscreen = ebiten.NewImage(screenWidth, screenHeight)
|
||||
offscreenPix []byte
|
||||
palette [maxIt]byte
|
||||
palette [maxIt]byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := range palette {
|
||||
palette[i] = byte(math.Sqrt(float64(i)/float64(len(palette))) * 0x80)
|
||||
}
|
||||
}
|
||||
|
||||
func color(it int) (r, g, b byte) {
|
||||
if it == maxIt {
|
||||
return 0xff, 0xff, 0xff
|
||||
@ -44,7 +48,22 @@ func color(it int) (r, g, b byte) {
|
||||
return c, c, c
|
||||
}
|
||||
|
||||
func updateOffscreen(centerX, centerY, size float64) {
|
||||
type Game struct {
|
||||
offscreen *ebiten.Image
|
||||
offscreenPix []byte
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
g := &Game{
|
||||
offscreen: ebiten.NewImage(screenWidth, screenHeight),
|
||||
offscreenPix: make([]byte, screenWidth*screenHeight*4),
|
||||
}
|
||||
// Now it is not feasible to call updateOffscreen every frame due to performance.
|
||||
g.updateOffscreen(-0.75, 0.25, 2)
|
||||
return g
|
||||
}
|
||||
|
||||
func (gm *Game) updateOffscreen(centerX, centerY, size float64) {
|
||||
for j := 0; j < screenHeight; j++ {
|
||||
for i := 0; i < screenHeight; i++ {
|
||||
x := float64(i)*size/screenWidth - size/2 + centerX
|
||||
@ -60,25 +79,13 @@ func updateOffscreen(centerX, centerY, size float64) {
|
||||
}
|
||||
r, g, b := color(it)
|
||||
p := 4 * (i + j*screenWidth)
|
||||
offscreenPix[p] = r
|
||||
offscreenPix[p+1] = g
|
||||
offscreenPix[p+2] = b
|
||||
offscreenPix[p+3] = 0xff
|
||||
gm.offscreenPix[p] = r
|
||||
gm.offscreenPix[p+1] = g
|
||||
gm.offscreenPix[p+2] = b
|
||||
gm.offscreenPix[p+3] = 0xff
|
||||
}
|
||||
}
|
||||
offscreen.ReplacePixels(offscreenPix)
|
||||
}
|
||||
|
||||
func init() {
|
||||
offscreenPix = make([]byte, screenWidth*screenHeight*4)
|
||||
for i := range palette {
|
||||
palette[i] = byte(math.Sqrt(float64(i)/float64(len(palette))) * 0x80)
|
||||
}
|
||||
// Now it is not feasible to call updateOffscreen every frame due to performance.
|
||||
updateOffscreen(-0.75, 0.25, 2)
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
gm.offscreen.ReplacePixels(gm.offscreenPix)
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -86,7 +93,7 @@ func (g *Game) Update() error {
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.DrawImage(offscreen, nil)
|
||||
screen.DrawImage(g.offscreen, nil)
|
||||
}
|
||||
|
||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
@ -96,7 +103,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
func main() {
|
||||
ebiten.SetWindowSize(screenWidth, screenHeight)
|
||||
ebiten.SetWindowTitle("Mandelbrot (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
if err := ebiten.RunGame(NewGame()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,7 @@ const (
|
||||
const mosaicRatio = 16
|
||||
|
||||
var (
|
||||
gophersImage *ebiten.Image
|
||||
gophersRenderTarget *ebiten.Image
|
||||
gophersImage *ebiten.Image
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -57,6 +56,7 @@ func init() {
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
gophersRenderTarget *ebiten.Image
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -67,13 +67,13 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
// Shrink the image once.
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Scale(1.0/mosaicRatio, 1.0/mosaicRatio)
|
||||
gophersRenderTarget.DrawImage(gophersImage, op)
|
||||
g.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)
|
||||
screen.DrawImage(g.gophersRenderTarget, op)
|
||||
}
|
||||
|
||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
@ -82,10 +82,12 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
|
||||
func main() {
|
||||
w, h := gophersImage.Size()
|
||||
gophersRenderTarget = ebiten.NewImage(w/mosaicRatio, h/mosaicRatio)
|
||||
g := &Game{
|
||||
gophersRenderTarget: ebiten.NewImage(w/mosaicRatio, h/mosaicRatio),
|
||||
}
|
||||
ebiten.SetWindowSize(screenWidth*2, screenHeight*2)
|
||||
ebiten.SetWindowTitle("Mosaic (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
if err := ebiten.RunGame(g); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -63,8 +63,6 @@ func (g *Game) Update() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var offscreen = ebiten.NewImage(320, 240)
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.ReplacePixels(g.noiseImage.Pix)
|
||||
ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS()))
|
||||
|
@ -34,8 +34,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
brushImage *ebiten.Image
|
||||
canvasImage = ebiten.NewImage(screenWidth, screenHeight)
|
||||
brushImage *ebiten.Image
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -55,13 +54,21 @@ func init() {
|
||||
Stride: 4,
|
||||
Rect: image.Rect(0, 0, 4, 4),
|
||||
})
|
||||
|
||||
canvasImage.Fill(color.White)
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
touches []ebiten.TouchID
|
||||
count int
|
||||
|
||||
canvasImage *ebiten.Image
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
g := &Game{
|
||||
canvasImage: ebiten.NewImage(screenWidth, screenHeight),
|
||||
}
|
||||
g.canvasImage.Fill(color.White)
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -70,7 +77,7 @@ func (g *Game) Update() error {
|
||||
// Paint the brush by mouse dragging
|
||||
mx, my := ebiten.CursorPosition()
|
||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
g.paint(canvasImage, mx, my)
|
||||
g.paint(g.canvasImage, mx, my)
|
||||
drawn = true
|
||||
}
|
||||
|
||||
@ -78,7 +85,7 @@ func (g *Game) Update() error {
|
||||
g.touches = ebiten.AppendTouchIDs(g.touches[:0])
|
||||
for _, t := range g.touches {
|
||||
x, y := ebiten.TouchPosition(t)
|
||||
g.paint(canvasImage, x, y)
|
||||
g.paint(g.canvasImage, x, y)
|
||||
drawn = true
|
||||
}
|
||||
if drawn {
|
||||
@ -100,7 +107,7 @@ func (g *Game) paint(canvas *ebiten.Image, x, y int) {
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.DrawImage(canvasImage, nil)
|
||||
screen.DrawImage(g.canvasImage, nil)
|
||||
|
||||
mx, my := ebiten.CursorPosition()
|
||||
msg := fmt.Sprintf("(%d, %d)", mx, my)
|
||||
@ -118,7 +125,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
func main() {
|
||||
ebiten.SetWindowSize(screenWidth, screenHeight)
|
||||
ebiten.SetWindowTitle("Paint (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
if err := ebiten.RunGame(NewGame()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,6 @@ const (
|
||||
sampleRate = 44100
|
||||
)
|
||||
|
||||
var audioContext = audio.NewContext(sampleRate)
|
||||
|
||||
const (
|
||||
freqA = 440.0
|
||||
freqAS = 466.2
|
||||
@ -91,8 +89,22 @@ func toBytes(l, r []int16) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
scoreIndex int
|
||||
frames int
|
||||
currentNote rune
|
||||
|
||||
audioContext *audio.Context
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
return &Game{
|
||||
audioContext: audio.NewContext(sampleRate),
|
||||
}
|
||||
}
|
||||
|
||||
// playNote plays the note at scoreIndex of the score.
|
||||
func playNote(scoreIndex int) rune {
|
||||
func (g *Game) playNote(scoreIndex int) rune {
|
||||
note := score[scoreIndex]
|
||||
|
||||
// If the note is 'rest', play nothing.
|
||||
@ -118,22 +130,16 @@ func playNote(scoreIndex int) rune {
|
||||
square(l, vol, freq, 0.25)
|
||||
square(r, vol, freq, 0.25)
|
||||
|
||||
p := audio.NewPlayerFromBytes(audioContext, toBytes(l, r))
|
||||
p := audio.NewPlayerFromBytes(g.audioContext, toBytes(l, r))
|
||||
p.Play()
|
||||
|
||||
return rune(note)
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
scoreIndex int
|
||||
frames int
|
||||
currentNote rune
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
// Play notes for each half second.
|
||||
if g.frames%30 == 0 && audioContext.IsReady() {
|
||||
g.currentNote = playNote(g.scoreIndex)
|
||||
if g.frames%30 == 0 && g.audioContext.IsReady() {
|
||||
g.currentNote = g.playNote(g.scoreIndex)
|
||||
g.scoreIndex++
|
||||
g.scoreIndex %= len(score)
|
||||
}
|
||||
@ -148,7 +154,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
} else {
|
||||
msg += string(g.currentNote)
|
||||
}
|
||||
if !audioContext.IsReady() {
|
||||
if !g.audioContext.IsReady() {
|
||||
msg += "\n\n(If the audio doesn't start,\n click the screen or press keys)"
|
||||
}
|
||||
ebitenutil.DebugPrint(screen, msg)
|
||||
@ -161,7 +167,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
func main() {
|
||||
ebiten.SetWindowSize(screenWidth, screenHeight)
|
||||
ebiten.SetWindowTitle("PCM (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
if err := ebiten.RunGame(NewGame()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -65,8 +65,6 @@ const (
|
||||
baseFreq = 220
|
||||
)
|
||||
|
||||
var audioContext = audio.NewContext(sampleRate)
|
||||
|
||||
// pianoAt returns an i-th sample of piano with the given frequency.
|
||||
func pianoAt(i int, freq float64) float64 {
|
||||
// Create piano-like waves with multiple sin waves.
|
||||
@ -137,13 +135,6 @@ func init() {
|
||||
}()
|
||||
}
|
||||
|
||||
// playNote plays piano sound with the given frequency.
|
||||
func playNote(freq float64) {
|
||||
f := int(freq)
|
||||
p := audio.NewPlayerFromBytes(audioContext, pianoNoteSamples[f])
|
||||
p.Play()
|
||||
}
|
||||
|
||||
var (
|
||||
pianoImage = ebiten.NewImage(screenWidth, screenHeight)
|
||||
)
|
||||
@ -196,6 +187,13 @@ var (
|
||||
)
|
||||
|
||||
type Game struct {
|
||||
audioContext *audio.Context
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
return &Game{
|
||||
audioContext: audio.NewContext(sampleRate),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -214,12 +212,19 @@ func (g *Game) Update() error {
|
||||
if !inpututil.IsKeyJustPressed(key) {
|
||||
continue
|
||||
}
|
||||
playNote(baseFreq * math.Exp2(float64(i-1)/12.0))
|
||||
g.playNote(baseFreq * math.Exp2(float64(i-1)/12.0))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// playNote plays piano sound with the given frequency.
|
||||
func (g *Game) playNote(freq float64) {
|
||||
f := int(freq)
|
||||
p := audio.NewPlayerFromBytes(g.audioContext, pianoNoteSamples[f])
|
||||
p.Play()
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.Fill(color.RGBA{0x80, 0x80, 0xc0, 0xff})
|
||||
screen.DrawImage(pianoImage, nil)
|
||||
@ -234,7 +239,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
func main() {
|
||||
ebiten.SetWindowSize(screenWidth*2, screenHeight*2)
|
||||
ebiten.SetWindowTitle("Piano (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
if err := ebiten.RunGame(NewGame()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -37,13 +37,18 @@ func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
}
|
||||
|
||||
var offscreen = ebiten.NewImage(screenWidth, screenHeight)
|
||||
|
||||
type Game struct {
|
||||
offscreen *ebiten.Image
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
return &Game{
|
||||
offscreen: ebiten.NewImage(screenWidth, screenHeight),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
w, h := offscreen.Size()
|
||||
w, h := g.offscreen.Size()
|
||||
x := rand.Intn(w)
|
||||
y := rand.Intn(h)
|
||||
c := color.RGBA{
|
||||
@ -52,12 +57,12 @@ func (g *Game) Update() error {
|
||||
byte(rand.Intn(256)),
|
||||
byte(0xff),
|
||||
}
|
||||
offscreen.Set(x, y, c)
|
||||
g.offscreen.Set(x, y, c)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.DrawImage(offscreen, nil)
|
||||
screen.DrawImage(g.offscreen, nil)
|
||||
ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS()))
|
||||
}
|
||||
|
||||
@ -68,7 +73,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
func main() {
|
||||
ebiten.SetWindowSize(screenWidth*2, screenHeight*2)
|
||||
ebiten.SetWindowTitle("Set (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
if err := ebiten.RunGame(NewGame()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,6 @@ const (
|
||||
frequency = 440
|
||||
)
|
||||
|
||||
var audioContext = audio.NewContext(sampleRate)
|
||||
|
||||
// stream is an infinite stream of 440 Hz sine wave.
|
||||
type stream struct {
|
||||
position int64
|
||||
@ -87,15 +85,19 @@ func (s *stream) Close() error {
|
||||
}
|
||||
|
||||
type Game struct {
|
||||
player *audio.Player
|
||||
audioContext *audio.Context
|
||||
player *audio.Player
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
if g.audioContext == nil {
|
||||
g.audioContext = audio.NewContext(sampleRate)
|
||||
}
|
||||
if g.player == nil {
|
||||
// Pass the (infinite) stream to audio.NewPlayer.
|
||||
// After calling Play, the stream never ends as long as the player object lives.
|
||||
var err error
|
||||
g.player, err = audio.NewPlayer(audioContext, &stream{})
|
||||
g.player, err = audio.NewPlayer(g.audioContext, &stream{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -78,10 +78,7 @@ var (
|
||||
},
|
||||
},
|
||||
}
|
||||
selectedPalette = 0
|
||||
colorCycle = 0
|
||||
canvas = ebiten.NewImage(width, height)
|
||||
auto *automaton
|
||||
|
||||
// blocker is an arbitrary color used to prevent the
|
||||
// squirals from leaving the canvas.
|
||||
blocker = color.RGBA{0, 0, 0, 254}
|
||||
@ -130,7 +127,7 @@ type squiral struct {
|
||||
dead bool
|
||||
}
|
||||
|
||||
func (s *squiral) spawn() {
|
||||
func (s *squiral) spawn(game *Game) {
|
||||
s.dead = false
|
||||
|
||||
rx := rand.Intn(width-4) + 2
|
||||
@ -139,7 +136,7 @@ func (s *squiral) spawn() {
|
||||
for dx := -2; dx <= 2; dx++ {
|
||||
for dy := -2; dy <= 2; dy++ {
|
||||
tx, ty := rx+dx, ry+dy
|
||||
if auto.colorMap[tx][ty] != background {
|
||||
if game.auto.colorMap[tx][ty] != background {
|
||||
s.dead = true
|
||||
return
|
||||
}
|
||||
@ -151,13 +148,13 @@ func (s *squiral) spawn() {
|
||||
s.pos.y = ry
|
||||
s.dir = rand.Intn(4)
|
||||
|
||||
colorCycle = (colorCycle + 1) % len(palettes[selectedPalette].colors)
|
||||
s.col = palettes[selectedPalette].colors[colorCycle]
|
||||
game.colorCycle = (game.colorCycle + 1) % len(palettes[game.selectedPalette].colors)
|
||||
s.col = palettes[game.selectedPalette].colors[game.colorCycle]
|
||||
|
||||
s.rot = rand.Intn(2)
|
||||
}
|
||||
|
||||
func (s *squiral) step(debug int) {
|
||||
func (s *squiral) step(game *Game) {
|
||||
if s.dead {
|
||||
return
|
||||
}
|
||||
@ -179,7 +176,7 @@ func (s *squiral) step(debug int) {
|
||||
x: x + off.x,
|
||||
y: y + off.y,
|
||||
}
|
||||
if auto.colorMap[target.x][target.y] == background {
|
||||
if game.auto.colorMap[target.x][target.y] == background {
|
||||
// If the target is free we need to also check the
|
||||
// surrounding cells.
|
||||
|
||||
@ -189,7 +186,7 @@ func (s *squiral) step(debug int) {
|
||||
x: target.x + off.x,
|
||||
y: target.y + off.y,
|
||||
}
|
||||
if auto.colorMap[ntarg.x][ntarg.y] == s.col {
|
||||
if game.auto.colorMap[ntarg.x][ntarg.y] == s.col {
|
||||
// If this has the same color, we cannot go into this direction,
|
||||
// to avoid ugly blocks of equal color.
|
||||
continue // try next direction
|
||||
@ -206,7 +203,7 @@ func (s *squiral) step(debug int) {
|
||||
|
||||
// If one of the outer targets equals the squiral's
|
||||
// color, again continue with next direction.
|
||||
if auto.colorMap[xtarg.x][xtarg.y] == s.col {
|
||||
if game.auto.colorMap[xtarg.x][xtarg.y] == s.col {
|
||||
// If this is not free we cannot go into this direction.
|
||||
set = false
|
||||
break // try next direction
|
||||
@ -217,7 +214,7 @@ func (s *squiral) step(debug int) {
|
||||
|
||||
// If one of the outer targets equals the squiral's
|
||||
// color, again continue with next direction.
|
||||
if auto.colorMap[xtarg.x][xtarg.y] == s.col {
|
||||
if game.auto.colorMap[xtarg.x][xtarg.y] == s.col {
|
||||
// If this is not free we cannot go into this direction.
|
||||
set = false
|
||||
break // try next direction
|
||||
@ -229,7 +226,7 @@ func (s *squiral) step(debug int) {
|
||||
s.dir = dir
|
||||
// 2. set the color of this squiral to its
|
||||
// current position.
|
||||
setpix(s.pos, s.col)
|
||||
game.setpix(s.pos, s.col)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -243,50 +240,60 @@ type automaton struct {
|
||||
colorMap [width][height]color.Color
|
||||
}
|
||||
|
||||
func (au *automaton) init() {
|
||||
func (au *automaton) init(game *Game) {
|
||||
// Init the test grid with color (0,0,0,0) and the borders of
|
||||
// it with color(0,0,0,254) as a blocker color, so the squirals
|
||||
// cannot escape the scene.
|
||||
for x := 0; x < width; x++ {
|
||||
for y := 0; y < height; y++ {
|
||||
if x == 0 || x == width-1 || y == 0 || y == height-1 {
|
||||
auto.colorMap[x][y] = blocker
|
||||
au.colorMap[x][y] = blocker
|
||||
} else {
|
||||
auto.colorMap[x][y] = background
|
||||
au.colorMap[x][y] = background
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < numOfSquirals; i++ {
|
||||
auto.squirals[i].spawn()
|
||||
au.squirals[i].spawn(game)
|
||||
}
|
||||
}
|
||||
|
||||
func (au *automaton) step() {
|
||||
func (a *automaton) step(game *Game) {
|
||||
for i := 0; i < numOfSquirals; i++ {
|
||||
for s := 0; s < au.squirals[i].speed; s++ {
|
||||
au.squirals[i].step(i)
|
||||
if au.squirals[i].dead {
|
||||
au.squirals[i].spawn()
|
||||
for s := 0; s < a.squirals[i].speed; s++ {
|
||||
a.squirals[i].step(game)
|
||||
if a.squirals[i].dead {
|
||||
a.squirals[i].spawn(game)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setpix(xy vec2, col color.Color) {
|
||||
canvas.Set(xy.x, xy.y, col)
|
||||
auto.colorMap[xy.x][xy.y] = col
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
canvas.Fill(background)
|
||||
|
||||
auto = &automaton{}
|
||||
auto.init()
|
||||
}
|
||||
|
||||
type Game struct{}
|
||||
type Game struct {
|
||||
selectedPalette int
|
||||
colorCycle int
|
||||
canvas *ebiten.Image
|
||||
auto automaton
|
||||
}
|
||||
|
||||
func NewGame() *Game {
|
||||
g := &Game{
|
||||
canvas: ebiten.NewImage(width, height),
|
||||
}
|
||||
g.canvas.Fill(background)
|
||||
g.auto.init(g)
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Game) setpix(xy vec2, col color.Color) {
|
||||
g.canvas.Set(xy.x, xy.y, col)
|
||||
g.auto.colorMap[xy.x][xy.y] = col
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
reset := false
|
||||
@ -299,24 +306,24 @@ func (g *Game) Update() error {
|
||||
}
|
||||
reset = true
|
||||
} else if inpututil.IsKeyJustPressed(ebiten.KeyT) {
|
||||
selectedPalette = (selectedPalette + 1) % len(palettes)
|
||||
g.selectedPalette = (g.selectedPalette + 1) % len(palettes)
|
||||
reset = true
|
||||
} else if inpututil.IsKeyJustPressed(ebiten.KeyR) {
|
||||
reset = true
|
||||
}
|
||||
|
||||
if reset {
|
||||
canvas.Fill(background)
|
||||
auto.init()
|
||||
g.canvas.Fill(background)
|
||||
g.auto.init(g)
|
||||
}
|
||||
|
||||
auto.step()
|
||||
g.auto.step(g)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Game) Draw(screen *ebiten.Image) {
|
||||
screen.DrawImage(canvas, nil)
|
||||
screen.DrawImage(g.canvas, nil)
|
||||
ebitenutil.DebugPrintAt(
|
||||
screen,
|
||||
fmt.Sprintf("TPS: %0.2f, FPS: %0.2f", ebiten.CurrentTPS(), ebiten.CurrentFPS()),
|
||||
@ -334,7 +341,7 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
||||
)
|
||||
ebitenutil.DebugPrintAt(
|
||||
screen,
|
||||
fmt.Sprintf("[t]: cycle theme (current: %s)", palettes[selectedPalette].name),
|
||||
fmt.Sprintf("[t]: cycle theme (current: %s)", palettes[g.selectedPalette].name),
|
||||
1, 48,
|
||||
)
|
||||
}
|
||||
@ -347,7 +354,7 @@ func main() {
|
||||
ebiten.SetMaxTPS(250)
|
||||
ebiten.SetWindowSize(width*scale, height*scale)
|
||||
ebiten.SetWindowTitle("Squirals (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
||||
if err := ebiten.RunGame(NewGame()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -454,9 +454,8 @@ type Game struct {
|
||||
textBoxLog *TextBox
|
||||
}
|
||||
|
||||
var g Game
|
||||
|
||||
func init() {
|
||||
func NewGame() *Game {
|
||||
g := &Game{}
|
||||
g.button1 = &Button{
|
||||
Rect: image.Rect(16, 16, 144, 48),
|
||||
Text: "Button 1",
|
||||
@ -489,6 +488,7 @@ func init() {
|
||||
}
|
||||
g.textBoxLog.AppendLine(msg)
|
||||
})
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -514,7 +514,7 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
func main() {
|
||||
ebiten.SetWindowSize(screenWidth, screenHeight)
|
||||
ebiten.SetWindowTitle("UI (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&g); err != nil {
|
||||
if err := ebiten.RunGame(NewGame()); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -40,9 +40,9 @@ type Game struct {
|
||||
audioPlayer *audio.Player
|
||||
}
|
||||
|
||||
var g Game
|
||||
func NewGame() (*Game, error) {
|
||||
g := &Game{}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
// Initialize audio context.
|
||||
g.audioContext = audio.NewContext(sampleRate)
|
||||
@ -64,14 +64,16 @@ func init() {
|
||||
// Decode wav-formatted data and retrieve decoded PCM stream.
|
||||
d, err := wav.Decode(g.audioContext, bytes.NewReader(raudio.Jab_wav))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create an audio.Player that has one stream.
|
||||
g.audioPlayer, err = audio.NewPlayer(g.audioContext, d)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return g, nil
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
@ -97,9 +99,13 @@ func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
g, err := NewGame()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ebiten.SetWindowSize(screenWidth, screenHeight)
|
||||
ebiten.SetWindowTitle("WAV (Ebiten Demo)")
|
||||
if err := ebiten.RunGame(&g); err != nil {
|
||||
if err := ebiten.RunGame(g); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,6 @@ const (
|
||||
|
||||
var (
|
||||
gophersImage *ebiten.Image
|
||||
count = 0
|
||||
)
|
||||
|
||||
func createRandomIconImage() image.Image {
|
||||
@ -92,6 +91,7 @@ func createRandomIconImage() image.Image {
|
||||
}
|
||||
|
||||
type game struct {
|
||||
count int
|
||||
width int
|
||||
height int
|
||||
transparent bool
|
||||
@ -276,7 +276,7 @@ func (g *game) Update() error {
|
||||
ebiten.SetWindowIcon([]image.Image{createRandomIconImage()})
|
||||
}
|
||||
|
||||
count++
|
||||
g.count++
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -285,8 +285,8 @@ func (g *game) Draw(screen *ebiten.Image) {
|
||||
w2, h2 := screen.Size()
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(-w+w2)/2, float64(-h+h2)/2)
|
||||
dx := math.Cos(2*math.Pi*float64(count)/360) * 20
|
||||
dy := math.Sin(2*math.Pi*float64(count)/360) * 20
|
||||
dx := math.Cos(2*math.Pi*float64(g.count)/360) * 20
|
||||
dy := math.Sin(2*math.Pi*float64(g.count)/360) * 20
|
||||
op.GeoM.Translate(dx, dy)
|
||||
screen.DrawImage(gophersImage, op)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user