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