From f325a70da2b592a068bc491b2971fc6f996fbfb9 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Wed, 24 Jan 2018 12:06:12 +0900 Subject: [PATCH] docs: Update --- docs/examples/_resources/fonts/arcade_n.ttf | Bin 0 -> 26500 bytes docs/examples/_resources/fonts/license.md | 26 ++++++ .../_resources/images/keyboard/keyboard.png | Bin 1861 -> 3688 bytes docs/examples/alphablending.html | 4 + docs/examples/audio.html | 84 ++++++++++-------- docs/examples/piano.html | 49 ++++++++-- 6 files changed, 119 insertions(+), 44 deletions(-) create mode 100755 docs/examples/_resources/fonts/arcade_n.ttf diff --git a/docs/examples/_resources/fonts/arcade_n.ttf b/docs/examples/_resources/fonts/arcade_n.ttf new file mode 100755 index 0000000000000000000000000000000000000000..4730e445880b94d8fe957bc1b8d3aee574c8965c GIT binary patch literal 26500 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 U*AK^{w7%Ey^$hfQeJ&>ZKV21=CIA2c diff --git a/docs/examples/alphablending.html b/docs/examples/alphablending.html index e46ee5dd1..1651a25f4 100644 --- a/docs/examples/alphablending.html +++ b/docs/examples/alphablending.html @@ -60,10 +60,14 @@ func update(screen *ebiten.Image) error { case 240 < count: diff = float64(480-count) * 0.2 } + if ebiten.IsRunningSlowly() { return nil } + screen.Fill(color.NRGBA{0x00, 0x00, 0x80, 0xff}) + + // Draw 100 Ebitens op := &ebiten.DrawImageOptions{} op.ColorM.Scale(1.0, 1.0, 1.0, 0.5) for i := 0; i < 10*10; i++ { diff --git a/docs/examples/audio.html b/docs/examples/audio.html index 2fed0115b..1b4201800 100644 --- a/docs/examples/audio.html +++ b/docs/examples/audio.html @@ -62,6 +62,11 @@ var ( playerCurrentColor = color.RGBA{0xff, 0xff, 0xff, 0xff} ) +// Input manages the current input state to detect keys 'just pressed'. +// +// Note: 'just pressed' is a very common idiom. +// There is a plan to create a new package for input utility. +// See https://github.com/hajimehoshi/ebiten/issues/415. type Input struct { mouseButtonStates map[ebiten.MouseButton]int keyStates map[ebiten.Key]int @@ -82,7 +87,7 @@ func (i *Input) update() { } } -func (i *Input) isKeyTriggered(key ebiten.Key) bool { +func (i *Input) isKeyJustPressed(key ebiten.Key) bool { return i.keyStates[key] == 1 } @@ -90,25 +95,22 @@ func (i *Input) isKeyPressed(key ebiten.Key) bool { return i.keyStates[key] > 0 } -func (i *Input) isMouseButtonTriggered(mouseButton ebiten.MouseButton) bool { +func (i *Input) isMouseButtonJustPressed(mouseButton ebiten.MouseButton) bool { return i.mouseButtonStates[mouseButton] == 1 } +// Player represents the current audio state. type Player struct { input *Input audioContext *audio.Context audioPlayer *audio.Player current time.Duration total time.Duration - seBytes []uint8 - seCh chan []uint8 + seBytes []byte + seCh chan []byte volume128 int } -var ( - musicPlayer *Player -) - func playerBarRect() (x, y, w, h int) { w, h = 300, 4 x = (screenWidth - w) / 2 @@ -141,9 +143,9 @@ func NewPlayer(audioContext *audio.Context) (*Player, error) { }, audioContext: audioContext, audioPlayer: p, - total: time.Second * time.Duration(s.Size()) / bytesPerSample / sampleRate, + total: time.Second * time.Duration(s.Length()) / bytesPerSample / sampleRate, volume128: 128, - seCh: make(chan []uint8), + seCh: make(chan []byte), } if player.total == 0 { player.total = 1 @@ -173,32 +175,36 @@ func (p *Player) update() error { p.seCh = nil default: } + if p.audioPlayer.IsPlaying() { p.current = p.audioPlayer.Current() } - p.updateBar() - p.updatePlayPause() - p.updateSE() - p.updateVolume() - if p.input.isKeyTriggered(ebiten.KeyB) { + p.seekBarIfNeeded() + p.switchPlayStateIfNeeded() + p.playSEIfNeeded() + p.updateVolumeIfNeeded() + + if p.input.isKeyJustPressed(ebiten.KeyB) { b := ebiten.IsRunnableInBackground() ebiten.SetRunnableInBackground(!b) } return nil } -func (p *Player) updateSE() { +func (p *Player) playSEIfNeeded() { if p.seBytes == nil { + // Bytes for the SE is not loaded yet. return } - if !p.input.isKeyTriggered(ebiten.KeyP) { + + if !p.input.isKeyJustPressed(ebiten.KeyP) { return } sePlayer, _ := audio.NewPlayerFromBytes(p.audioContext, p.seBytes) sePlayer.Play() } -func (p *Player) updateVolume() { +func (p *Player) updateVolumeIfNeeded() { if p.input.isKeyPressed(ebiten.KeyZ) { p.volume128-- } @@ -214,8 +220,8 @@ func (p *Player) updateVolume() { p.audioPlayer.SetVolume(float64(p.volume128) / 128) } -func (p *Player) updatePlayPause() { - if !p.input.isKeyTriggered(ebiten.KeyS) { +func (p *Player) switchPlayStateIfNeeded() { + if !p.input.isKeyJustPressed(ebiten.KeyS) { return } if p.audioPlayer.IsPlaying() { @@ -225,11 +231,12 @@ func (p *Player) updatePlayPause() { p.audioPlayer.Play() } -func (p *Player) updateBar() { - if !p.input.isMouseButtonTriggered(ebiten.MouseButtonLeft) { +func (p *Player) seekBarIfNeeded() { + if !p.input.isMouseButtonJustPressed(ebiten.MouseButtonLeft) { return } - // Start seeking. + + // Calculate the next seeking position from the current cursor position. x, y := ebiten.CursorPosition() bx, by, bw, bh := playerBarRect() const padding = 4 @@ -249,40 +256,45 @@ func (p *Player) close() error { } func (p *Player) draw(screen *ebiten.Image) { - // Bar + // Draw the bar. x, y, w, h := playerBarRect() ebitenutil.DrawRect(screen, float64(x), float64(y), float64(w), float64(h), playerBarColor) - currentTimeStr := "00:00" - - // Current Time + // Draw the cursor on the bar. c := p.current - m := (c / time.Minute) % 100 - s := (c / time.Second) % 60 - currentTimeStr = fmt.Sprintf("%02d:%02d", m, s) - - // Cursor cw, ch := 4, 10 cx := int(time.Duration(w)*c/p.total) + x - cw/2 cy := y - (ch-h)/2 ebitenutil.DrawRect(screen, float64(cx), float64(cy), float64(cw), float64(ch), playerCurrentColor) + // Compose the curren time text. + m := (c / time.Minute) % 100 + s := (c / time.Second) % 60 + currentTimeStr := fmt.Sprintf("%02d:%02d", m, s) + + // Draw the debug message. 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 Press B to switch the run-in-background state -%s`, ebiten.CurrentFPS(), currentTimeStr) +Current Time: %s`, ebiten.CurrentFPS(), currentTimeStr) ebitenutil.DebugPrint(screen, msg) } +var ( + musicPlayer *Player +) + func update(screen *ebiten.Image) error { if err := musicPlayer.update(); err != nil { return err } + if ebiten.IsRunningSlowly() { return nil } + musicPlayer.draw(screen) return nil } @@ -300,10 +312,8 @@ func main() { if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Audio (Ebiten Demo)"); err != nil { log.Fatal(err) } - if musicPlayer != nil { - if err := musicPlayer.close(); err != nil { - log.Fatal(err) - } + if err := musicPlayer.close(); err != nil { + log.Fatal(err) } } diff --git a/docs/examples/piano.html b/docs/examples/piano.html index 29d4dd131..a89f34387 100644 --- a/docs/examples/piano.html +++ b/docs/examples/piano.html @@ -34,15 +34,52 @@ package main import ( "fmt" "image/color" + "io/ioutil" "log" "math" + "github.com/golang/freetype/truetype" + "golang.org/x/image/font" + "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/audio" "github.com/hajimehoshi/ebiten/ebitenutil" - "github.com/hajimehoshi/ebiten/examples/common" + "github.com/hajimehoshi/ebiten/text" ) +const ( + arcadeFontSize = 8 +) + +var ( + arcadeFont font.Face +) + +func init() { + f, err := ebitenutil.OpenFile(ebitenutil.JoinStringsIntoFilePath("_resources", "fonts", "arcade_n.ttf")) + if err != nil { + log.Fatal(err) + } + defer f.Close() + + b, err := ioutil.ReadAll(f) + if err != nil { + log.Fatal(err) + } + + tt, err := truetype.Parse(b) + if err != nil { + log.Fatal(err) + } + + const dpi = 72 + arcadeFont = truetype.NewFace(tt, &truetype.Options{ + Size: arcadeFontSize, + DPI: dpi, + Hinting: font.HintingFull, + }) +} + const ( screenWidth = 320 screenHeight = 240 @@ -64,15 +101,13 @@ var pcm = make([]float64, 4*sampleRate) const baseFreq = 220 func init() { - s := float64(sampleRate) amp := []float64{1.0, 0.8, 0.6, 0.4, 0.2} x := []float64{4.0, 2.0, 1.0, 0.5, 0.25} for i := 0; i < len(pcm); i++ { v := 0.0 - twoPiF := 2.0 * math.Pi * baseFreq for j := 0; j < len(amp); j++ { - a := amp[j] * math.Exp(-5*float64(i)/(x[j]*s)) - v += a * math.Sin(float64(i)*twoPiF*float64(j+1)/s) + a := amp[j] * math.Exp(-5*float64(i)/(x[j]*sampleRate)) + v += a * math.Sin(2.0*math.Pi*float64(i)*baseFreq*float64(j+1)/sampleRate) } pcm[i] = v / 5.0 } @@ -175,7 +210,7 @@ func init() { x := i*width + 36 height := 112 ebitenutil.DrawRect(imagePiano, float64(x), float64(y), float64(width-1), float64(height), color.White) - common.ArcadeFont.DrawText(imagePiano, k, x+8, y+height-16, 1, color.Black) + text.Draw(imagePiano, k, arcadeFont, x+8, y+height-8, color.Black) } blackKeys := []string{"Q", "W", "", "R", "T", "", "U", "I", "O"} @@ -186,7 +221,7 @@ func init() { x := i*width + 24 height := 64 ebitenutil.DrawRect(imagePiano, float64(x), float64(y), float64(width-1), float64(height), color.Black) - common.ArcadeFont.DrawText(imagePiano, k, x+8, y+height-16, 1, color.White) + text.Draw(imagePiano, k, arcadeFont, x+8, y+height-8, color.White) } }