mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-11 19:48:54 +01:00
doc: Update
This commit is contained in:
parent
db74b4c34c
commit
989aef8e2b
@ -46,6 +46,10 @@ import (
|
||||
const (
|
||||
screenWidth = 320
|
||||
screenHeight = 240
|
||||
|
||||
// This sample rate doesn't match with wav/ogg's sample rate,
|
||||
// but decoders adjust them.
|
||||
sampleRate = 48000
|
||||
)
|
||||
|
||||
var (
|
||||
@ -54,39 +58,59 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
playerBarImage, err = ebiten.NewImage(300, 4, ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := playerBarImage.Fill(&color.RGBA{0x80, 0x80, 0x80, 0xff}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
playerBarImage, _ = ebiten.NewImage(300, 4, ebiten.FilterNearest)
|
||||
playerBarImage.Fill(&color.RGBA{0x80, 0x80, 0x80, 0xff})
|
||||
|
||||
playerCurrentImage, err = ebiten.NewImage(4, 10, ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
playerCurrentImage, _ = ebiten.NewImage(4, 10, ebiten.FilterNearest)
|
||||
playerCurrentImage.Fill(&color.RGBA{0xff, 0xff, 0xff, 0xff})
|
||||
}
|
||||
|
||||
type Input struct {
|
||||
mouseButtonStates map[ebiten.MouseButton]int
|
||||
keyStates map[ebiten.Key]int
|
||||
}
|
||||
|
||||
func (i *Input) update() {
|
||||
for _, key := range []ebiten.Key{ebiten.KeyP, ebiten.KeyS, ebiten.KeyX, ebiten.KeyZ} {
|
||||
if !ebiten.IsKeyPressed(key) {
|
||||
i.keyStates[key] = 0
|
||||
} else {
|
||||
i.keyStates[key]++
|
||||
}
|
||||
}
|
||||
if err := playerCurrentImage.Fill(&color.RGBA{0xff, 0xff, 0xff, 0xff}); err != nil {
|
||||
log.Fatal(err)
|
||||
if !ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
i.mouseButtonStates[ebiten.MouseButtonLeft] = 0
|
||||
} else {
|
||||
i.mouseButtonStates[ebiten.MouseButtonLeft]++
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Input) isKeyTriggered(key ebiten.Key) bool {
|
||||
return i.keyStates[key] == 1
|
||||
}
|
||||
|
||||
func (i *Input) isKeyPressed(key ebiten.Key) bool {
|
||||
return i.keyStates[key] > 0
|
||||
}
|
||||
|
||||
func (i *Input) isMouseButtonTriggered(mouseButton ebiten.MouseButton) bool {
|
||||
return i.mouseButtonStates[mouseButton] == 1
|
||||
}
|
||||
|
||||
type Player struct {
|
||||
audioPlayer *audio.Player
|
||||
total time.Duration
|
||||
seekedCh chan error
|
||||
input *Input
|
||||
audioContext *audio.Context
|
||||
audioPlayer *audio.Player
|
||||
total time.Duration
|
||||
seekedCh chan error
|
||||
seBytes []uint8
|
||||
seCh chan []uint8
|
||||
volume128 int
|
||||
previousPos time.Duration
|
||||
}
|
||||
|
||||
var (
|
||||
audioContext *audio.Context
|
||||
musicPlayer *Player
|
||||
seBytes []byte
|
||||
musicCh = make(chan *Player)
|
||||
seCh = make(chan []byte)
|
||||
mouseButtonState = map[ebiten.MouseButton]int{}
|
||||
keyState = map[ebiten.Key]int{}
|
||||
volume128 = 128
|
||||
musicPlayer *Player
|
||||
)
|
||||
|
||||
func playerBarRect() (x, y, w, h int) {
|
||||
@ -96,77 +120,122 @@ func playerBarRect() (x, y, w, h int) {
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Player) updateSE() error {
|
||||
if seBytes == nil {
|
||||
return nil
|
||||
}
|
||||
if !ebiten.IsKeyPressed(ebiten.KeyP) {
|
||||
keyState[ebiten.KeyP] = 0
|
||||
return nil
|
||||
}
|
||||
keyState[ebiten.KeyP]++
|
||||
if keyState[ebiten.KeyP] != 1 {
|
||||
return nil
|
||||
}
|
||||
sePlayer, err := audio.NewPlayerFromBytes(audioContext, seBytes)
|
||||
func NewPlayer(audioContext *audio.Context) (*Player, error) {
|
||||
const bytesPerSample = 4 // TODO: This should be defined in audio package
|
||||
wavF, err := ebitenutil.OpenFile("_resources/audio/jab.wav")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
oggF, err := ebitenutil.OpenFile("_resources/audio/ragtime.ogg")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := vorbis.Decode(audioContext, oggF)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p, err := audio.NewPlayer(audioContext, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
player := &Player{
|
||||
input: &Input{
|
||||
mouseButtonStates: map[ebiten.MouseButton]int{},
|
||||
keyStates: map[ebiten.Key]int{},
|
||||
},
|
||||
audioContext: audioContext,
|
||||
audioPlayer: p,
|
||||
total: time.Second * time.Duration(s.Size()) / bytesPerSample / sampleRate,
|
||||
volume128: 128,
|
||||
seCh: make(chan []uint8),
|
||||
}
|
||||
player.audioPlayer.Play()
|
||||
go func() {
|
||||
s, err := wav.Decode(audioContext, wavF)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
b, err := ioutil.ReadAll(s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
player.seCh <- b
|
||||
}()
|
||||
return player, nil
|
||||
}
|
||||
|
||||
func (p *Player) update() error {
|
||||
p.input.update()
|
||||
select {
|
||||
case p.seBytes = <-p.seCh:
|
||||
close(p.seCh)
|
||||
p.seCh = nil
|
||||
case err := <-p.seekedCh:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
close(p.seekedCh)
|
||||
p.seekedCh = nil
|
||||
default:
|
||||
}
|
||||
p.updateBar()
|
||||
p.updatePlayPause()
|
||||
p.updateSE()
|
||||
p.updateVolume()
|
||||
if err := p.audioContext.Update(); err != nil {
|
||||
return err
|
||||
}
|
||||
return sePlayer.Play()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Player) updateSE() {
|
||||
if p.seBytes == nil {
|
||||
return
|
||||
}
|
||||
if !p.input.isKeyTriggered(ebiten.KeyP) {
|
||||
return
|
||||
}
|
||||
sePlayer, _ := audio.NewPlayerFromBytes(p.audioContext, p.seBytes)
|
||||
sePlayer.Play()
|
||||
}
|
||||
|
||||
func (p *Player) updateVolume() {
|
||||
if p.audioPlayer == nil {
|
||||
return
|
||||
if p.input.isKeyPressed(ebiten.KeyZ) {
|
||||
p.volume128--
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyZ) {
|
||||
volume128--
|
||||
if p.input.isKeyPressed(ebiten.KeyX) {
|
||||
p.volume128++
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyX) {
|
||||
volume128++
|
||||
if p.volume128 < 0 {
|
||||
p.volume128 = 0
|
||||
}
|
||||
if volume128 < 0 {
|
||||
volume128 = 0
|
||||
if 128 < p.volume128 {
|
||||
p.volume128 = 128
|
||||
}
|
||||
if 128 < volume128 {
|
||||
volume128 = 128
|
||||
}
|
||||
p.audioPlayer.SetVolume(float64(volume128) / 128)
|
||||
p.audioPlayer.SetVolume(float64(p.volume128) / 128)
|
||||
}
|
||||
|
||||
func (p *Player) updatePlayPause() error {
|
||||
if p.audioPlayer == nil {
|
||||
return nil
|
||||
}
|
||||
if !ebiten.IsKeyPressed(ebiten.KeyS) {
|
||||
keyState[ebiten.KeyS] = 0
|
||||
return nil
|
||||
}
|
||||
keyState[ebiten.KeyS]++
|
||||
if keyState[ebiten.KeyS] != 1 {
|
||||
return nil
|
||||
func (p *Player) updatePlayPause() {
|
||||
if !p.input.isKeyTriggered(ebiten.KeyS) {
|
||||
return
|
||||
}
|
||||
if p.audioPlayer.IsPlaying() {
|
||||
return p.audioPlayer.Pause()
|
||||
p.audioPlayer.Pause()
|
||||
return
|
||||
}
|
||||
return p.audioPlayer.Play()
|
||||
p.audioPlayer.Play()
|
||||
}
|
||||
|
||||
func (p *Player) updateBar() {
|
||||
if p.audioPlayer == nil {
|
||||
return
|
||||
}
|
||||
if p.seekedCh != nil {
|
||||
return
|
||||
}
|
||||
if !ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
mouseButtonState[ebiten.MouseButtonLeft] = 0
|
||||
return
|
||||
}
|
||||
mouseButtonState[ebiten.MouseButtonLeft]++
|
||||
if mouseButtonState[ebiten.MouseButtonLeft] != 1 {
|
||||
if !p.input.isMouseButtonTriggered(ebiten.MouseButtonLeft) {
|
||||
return
|
||||
}
|
||||
// Start seeking.
|
||||
x, y := ebiten.CursorPosition()
|
||||
bx, by, bw, bh := playerBarRect()
|
||||
const padding = 4
|
||||
@ -179,7 +248,6 @@ func (p *Player) updateBar() {
|
||||
pos := time.Duration(x-bx) * p.total / time.Duration(bw)
|
||||
p.seekedCh = make(chan error, 1)
|
||||
go func() {
|
||||
// This can't be done parallely! !?!?
|
||||
p.seekedCh <- p.audioPlayer.Seek(pos)
|
||||
}()
|
||||
}
|
||||
@ -188,133 +256,60 @@ func (p *Player) close() error {
|
||||
return p.audioPlayer.Close()
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
if musicPlayer == nil {
|
||||
select {
|
||||
case musicPlayer = <-musicCh:
|
||||
default:
|
||||
}
|
||||
}
|
||||
if seBytes == nil {
|
||||
select {
|
||||
case seBytes = <-seCh:
|
||||
default:
|
||||
}
|
||||
}
|
||||
if musicPlayer != nil {
|
||||
musicPlayer.updateBar()
|
||||
if err := musicPlayer.updatePlayPause(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := musicPlayer.updateSE(); err != nil {
|
||||
return err
|
||||
}
|
||||
musicPlayer.updateVolume()
|
||||
}
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
func (p *Player) draw(screen *ebiten.Image) {
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
x, y, w, h := playerBarRect()
|
||||
op.GeoM.Translate(float64(x), float64(y))
|
||||
screen.DrawImage(playerBarImage, op)
|
||||
currentTimeStr := "00:00"
|
||||
if musicPlayer != nil {
|
||||
c := musicPlayer.audioPlayer.Current()
|
||||
c := p.audioPlayer.Current()
|
||||
prev := p.previousPos
|
||||
p.previousPos = c
|
||||
|
||||
// Current Time
|
||||
m := (c / time.Minute) % 100
|
||||
s := (c / time.Second) % 60
|
||||
currentTimeStr = fmt.Sprintf("%02d:%02d", m, s)
|
||||
// Current Time
|
||||
m := (c / time.Minute) % 100
|
||||
s := (c / time.Second) % 60
|
||||
currentTimeStr = fmt.Sprintf("%02d:%02d", m, s)
|
||||
|
||||
// Bar
|
||||
cw, ch := playerCurrentImage.Size()
|
||||
cx := int(time.Duration(w)*c/musicPlayer.total) + x - cw/2
|
||||
cy := y - (ch-h)/2
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(cx), float64(cy))
|
||||
screen.DrawImage(playerCurrentImage, op)
|
||||
}
|
||||
// Bar
|
||||
cw, ch := playerCurrentImage.Size()
|
||||
cx := int(time.Duration(w)*c/p.total) + x - cw/2
|
||||
cy := y - (ch-h)/2
|
||||
op = &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(cx), float64(cy))
|
||||
screen.DrawImage(playerCurrentImage, op)
|
||||
|
||||
msg := fmt.Sprintf(`FPS: %0.2f
|
||||
Press S to toggle Play/Pause
|
||||
Press P to play SE
|
||||
Press Z or X to change volume of the music
|
||||
%s`, ebiten.CurrentFPS(), currentTimeStr)
|
||||
if musicPlayer == nil {
|
||||
msg += "\nNow Loading..."
|
||||
} else if musicPlayer.seekedCh != nil {
|
||||
select {
|
||||
case err := <-musicPlayer.seekedCh:
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
close(musicPlayer.seekedCh)
|
||||
musicPlayer.seekedCh = nil
|
||||
default:
|
||||
msg += "\nSeeking..."
|
||||
}
|
||||
if p.audioPlayer.IsPlaying() && prev == c {
|
||||
msg += "\nLoading..."
|
||||
}
|
||||
ebitenutil.DebugPrint(screen, msg)
|
||||
if err := audioContext.Update(); err != nil {
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
if err := musicPlayer.update(); err != nil {
|
||||
return err
|
||||
}
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
musicPlayer.draw(screen)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
wavF, err := ebitenutil.OpenFile("_resources/audio/jab.wav")
|
||||
audioContext, err := audio.NewContext(sampleRate)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
oggF, err := ebitenutil.OpenFile("_resources/audio/game.ogg")
|
||||
musicPlayer, err = NewPlayer(audioContext)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// This sample rate doesn't match with wav/ogg's sample rate,
|
||||
// but decoders adjust them.
|
||||
const sampleRate = 48000
|
||||
const bytesPerSample = 4 // TODO: This should be defined in audio package
|
||||
audioContext, err = audio.NewContext(sampleRate)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
go func() {
|
||||
s, err := wav.Decode(audioContext, wavF)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
b, err := ioutil.ReadAll(s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
seCh <- b
|
||||
close(seCh)
|
||||
}()
|
||||
go func() {
|
||||
s, err := vorbis.Decode(audioContext, oggF)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
p, err := audio.NewPlayer(audioContext, s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
musicCh <- &Player{
|
||||
audioPlayer: p,
|
||||
total: time.Second * time.Duration(s.Size()) / bytesPerSample / sampleRate,
|
||||
}
|
||||
close(musicCh)
|
||||
// TODO: Is this goroutine-safe?
|
||||
if err := p.Play(); err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Audio (Ebiten Demo)"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ func main() {
|
||||
}
|
||||
groundImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
|
||||
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "infinite scroll"); err != nil {
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Infinite Scroll (Ebiten Demo)"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"image"
|
||||
"log"
|
||||
"math/rand"
|
||||
"time"
|
||||
@ -38,20 +37,18 @@ import (
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
var (
|
||||
randSource = rand.NewSource(time.Now().UnixNano())
|
||||
rnd = rand.New(randSource)
|
||||
)
|
||||
|
||||
// World represents the game state
|
||||
type World struct {
|
||||
area [][]bool
|
||||
rnd *rand.Rand
|
||||
}
|
||||
|
||||
// NewWorld creates a new world
|
||||
func NewWorld(width, height int) *World {
|
||||
world := World{}
|
||||
world.area = makeArea(width, height)
|
||||
world := World{
|
||||
area: makeArea(width, height),
|
||||
rnd: rand.New(rand.NewSource(time.Now().UnixNano())),
|
||||
}
|
||||
return &world
|
||||
}
|
||||
|
||||
@ -59,10 +56,9 @@ func NewWorld(width, height int) *World {
|
||||
func (w *World) RandomSeed(limit int) {
|
||||
height := len(w.area)
|
||||
width := len(w.area[0])
|
||||
|
||||
for i := 0; i < limit; i++ {
|
||||
x := rnd.Intn(width)
|
||||
y := rnd.Intn(height)
|
||||
x := w.rnd.Intn(width)
|
||||
y := w.rnd.Intn(height)
|
||||
w.area[y][x] = true
|
||||
}
|
||||
}
|
||||
@ -71,9 +67,7 @@ func (w *World) RandomSeed(limit int) {
|
||||
func (w *World) Progress() {
|
||||
height := len(w.area)
|
||||
width := len(w.area[0])
|
||||
|
||||
next := makeArea(width, height)
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
|
||||
@ -105,23 +99,22 @@ func (w *World) Progress() {
|
||||
}
|
||||
|
||||
// DrawImage paints current game state
|
||||
func (w *World) DrawImage(img *image.RGBA) {
|
||||
func (w *World) DrawImage(pix []uint8) {
|
||||
height := len(w.area)
|
||||
width := len(w.area[0])
|
||||
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
pos := 4*y*width + 4*x
|
||||
if w.area[y][x] {
|
||||
img.Pix[pos] = 0xff
|
||||
img.Pix[pos+1] = 0xff
|
||||
img.Pix[pos+2] = 0xff
|
||||
img.Pix[pos+3] = 0xff
|
||||
pix[pos] = 0xff
|
||||
pix[pos+1] = 0xff
|
||||
pix[pos+2] = 0xff
|
||||
pix[pos+3] = 0xff
|
||||
} else {
|
||||
img.Pix[pos] = 0
|
||||
img.Pix[pos+1] = 0
|
||||
img.Pix[pos+2] = 0
|
||||
img.Pix[pos+3] = 0
|
||||
pix[pos] = 0
|
||||
pix[pos+1] = 0
|
||||
pix[pos+2] = 0
|
||||
pix[pos+3] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -131,27 +124,22 @@ func (w *World) DrawImage(img *image.RGBA) {
|
||||
func neighbourCount(a [][]bool, x, y int) int {
|
||||
height := len(a)
|
||||
width := len(a[0])
|
||||
|
||||
lowX := 0
|
||||
if x > 0 {
|
||||
lowX = x - 1
|
||||
}
|
||||
|
||||
lowY := 0
|
||||
if y > 0 {
|
||||
lowY = y - 1
|
||||
}
|
||||
|
||||
highX := width - 1
|
||||
if x < width-1 {
|
||||
highX = x + 1
|
||||
}
|
||||
|
||||
highY := height - 1
|
||||
if y < height-1 {
|
||||
highY = y + 1
|
||||
}
|
||||
|
||||
near := 0
|
||||
for pY := lowY; pY <= highY; pY++ {
|
||||
for pX := lowX; pX <= highX; pX++ {
|
||||
@ -178,8 +166,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
world *World
|
||||
noiseImage *image.RGBA
|
||||
world = NewWorld(screenWidth, screenHeight)
|
||||
pixels = make([]uint8, screenWidth*screenHeight*4)
|
||||
)
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
@ -187,20 +175,14 @@ func update(screen *ebiten.Image) error {
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
world.DrawImage(noiseImage)
|
||||
screen.ReplacePixels(noiseImage.Pix)
|
||||
world.DrawImage(pixels)
|
||||
screen.ReplacePixels(pixels)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
population := int((screenWidth * screenHeight) / 10)
|
||||
scale := 2.0
|
||||
|
||||
world = NewWorld(screenWidth, screenHeight)
|
||||
world.RandomSeed(population)
|
||||
|
||||
noiseImage = image.NewRGBA(image.Rect(0, 0, screenWidth, screenHeight))
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, scale, "Game of Life (Ebiten Demo)"); err != nil {
|
||||
world.RandomSeed(int((screenWidth * screenHeight) / 10))
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2.0, "Game of Life (Ebiten Demo)"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func paint(screen *ebiten.Image, x, y int) {
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(x), float64(y))
|
||||
op.ColorM.Scale(1.0, 0.50, 0.125, 1.0)
|
||||
theta := 2.0 * math.Pi * float64(count%60) / ebiten.FPS
|
||||
theta := 2.0 * math.Pi * float64(count%ebiten.FPS) / ebiten.FPS
|
||||
op.ColorM.RotateHue(theta)
|
||||
canvasImage.DrawImage(brushImage, op)
|
||||
}
|
||||
|
@ -94,20 +94,15 @@ func toBytes(l, r []int16) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
func addNote(freq float64, vol float64) error {
|
||||
func addNote(freq float64, vol float64) {
|
||||
// TODO: Call Close method of *audio.Player.
|
||||
// However, this works without Close because Close is automatically called when GC
|
||||
// collects a *audio.Player object.
|
||||
f := int(freq)
|
||||
if n, ok := noteCache[f]; ok {
|
||||
p, err := audio.NewPlayerFromBytes(audioContext, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.Play(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
p, _ := audio.NewPlayerFromBytes(audioContext, n)
|
||||
p.Play()
|
||||
return
|
||||
}
|
||||
length := len(pcm) * baseFreq / f
|
||||
l := make([]int16, length)
|
||||
@ -123,14 +118,9 @@ func addNote(freq float64, vol float64) error {
|
||||
}
|
||||
n := toBytes(l, r)
|
||||
noteCache[f] = n
|
||||
p, err := audio.NewPlayerFromBytes(audioContext, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.Play(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
p, _ := audio.NewPlayerFromBytes(audioContext, n)
|
||||
p.Play()
|
||||
return
|
||||
}
|
||||
|
||||
var keys = []ebiten.Key{
|
||||
@ -216,9 +206,10 @@ func update(screen *ebiten.Image) error {
|
||||
if keyStates[key] != 1 {
|
||||
continue
|
||||
}
|
||||
if err := addNote(220*math.Exp2(float64(i-1)/12.0), 1.0); err != nil {
|
||||
return err
|
||||
}
|
||||
addNote(220*math.Exp2(float64(i-1)/12.0), 1.0)
|
||||
}
|
||||
if err := audioContext.Update(); err != nil {
|
||||
return err
|
||||
}
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
@ -227,10 +218,6 @@ func update(screen *ebiten.Image) error {
|
||||
screen.DrawImage(imagePiano, nil)
|
||||
|
||||
ebitenutil.DebugPrint(screen, fmt.Sprintf("FPS: %0.2f", ebiten.CurrentFPS()))
|
||||
|
||||
if err := audioContext.Update(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
<main><div class="container">
|
||||
<h1>Ebiten</h1>
|
||||
<p class="lead">A simple 2D game library in Go</p>
|
||||
<p>Stable version: v1.4.0-rc1 / Development version: v1.5.0-alpha</p>
|
||||
<p>Stable version: v1.5.0 / Development version: v1.6.0-alpha</p>
|
||||
|
||||
<h2 id="platforms">Platforms</h2>
|
||||
<dl class="dl-horizontal">
|
||||
|
Loading…
Reference in New Issue
Block a user