mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 19:28:57 +01:00
docs: Add example groups
This commit is contained in:
parent
d139b8ad6e
commit
444e5bab84
73
_docs/gen.go
73
_docs/gen.go
@ -176,29 +176,37 @@ func versions() string {
|
||||
return fmt.Sprintf("v%s (dev: v%s)", stableVersion, devVersion)
|
||||
}
|
||||
|
||||
var examples = []example{
|
||||
{"alphablending", 320, 240},
|
||||
{"audio", 320, 240},
|
||||
{"font", 320, 240},
|
||||
{"highdpi", 320, 240},
|
||||
{"hsv", 320, 240},
|
||||
{"hue", 320, 240},
|
||||
{"gamepad", 320, 240},
|
||||
{"infinitescroll", 320, 240},
|
||||
{"keyboard", 320, 240},
|
||||
{"life", 320, 240},
|
||||
{"masking", 320, 240},
|
||||
{"mosaic", 320, 240},
|
||||
{"noise", 320, 240},
|
||||
{"paint", 320, 240},
|
||||
{"perspective", 320, 240},
|
||||
{"piano", 320, 240},
|
||||
{"rotate", 320, 240},
|
||||
{"sprites", 320, 240},
|
||||
{"typewriter", 320, 240},
|
||||
{"2048", 210, 300},
|
||||
{"blocks", 256, 240},
|
||||
}
|
||||
var (
|
||||
graphicsExamples = []example{
|
||||
{"alphablending", 320, 240},
|
||||
{"font", 320, 240},
|
||||
{"highdpi", 320, 240},
|
||||
{"hsv", 320, 240},
|
||||
{"hue", 320, 240},
|
||||
{"infinitescroll", 320, 240},
|
||||
{"life", 320, 240},
|
||||
{"masking", 320, 240},
|
||||
{"mosaic", 320, 240},
|
||||
{"noise", 320, 240},
|
||||
{"paint", 320, 240},
|
||||
{"perspective", 320, 240},
|
||||
{"rotate", 320, 240},
|
||||
{"sprites", 320, 240},
|
||||
}
|
||||
inputExamples = []example{
|
||||
{"gamepad", 320, 240},
|
||||
{"keyboard", 320, 240},
|
||||
{"typewriter", 320, 240},
|
||||
}
|
||||
audioExamples = []example{
|
||||
{"audio", 320, 240},
|
||||
{"piano", 320, 240},
|
||||
}
|
||||
gameExamples = []example{
|
||||
{"2048", 210, 300},
|
||||
{"blocks", 256, 240},
|
||||
}
|
||||
)
|
||||
|
||||
func clear() error {
|
||||
if err := filepath.Walk("public", func(path string, info os.FileInfo, err error) error {
|
||||
@ -253,11 +261,14 @@ func outputMain() error {
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"URL": url,
|
||||
"Copyright": copyright,
|
||||
"StableVersion": stableVersion,
|
||||
"DevVersion": devVersion,
|
||||
"Examples": examples,
|
||||
"URL": url,
|
||||
"Copyright": copyright,
|
||||
"StableVersion": stableVersion,
|
||||
"DevVersion": devVersion,
|
||||
"GraphicsExamples": graphicsExamples,
|
||||
"InputExamples": inputExamples,
|
||||
"AudioExamples": audioExamples,
|
||||
"GameExamples": gameExamples,
|
||||
}
|
||||
return t.Funcs(funcs).Execute(f, data)
|
||||
}
|
||||
@ -355,6 +366,12 @@ func main() {
|
||||
if err := outputExampleResources(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
examples := []example{}
|
||||
examples = append(examples, graphicsExamples...)
|
||||
examples = append(examples, inputExamples...)
|
||||
examples = append(examples, audioExamples...)
|
||||
examples = append(examples, gameExamples...)
|
||||
for _, e := range examples {
|
||||
if err := outputExampleContent(&e); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -60,13 +60,39 @@
|
||||
</dl>
|
||||
|
||||
<h2 id="examples">Examples</h2>
|
||||
<h3>Graphics</h3>
|
||||
<div class="row">
|
||||
{{range .Examples -}}
|
||||
{{range .GraphicsExamples -}}
|
||||
<div class="col-3">
|
||||
<a href="examples/{{.Name}}.html"><img src="images/examples/{{.Name}}.png" width="{{.ThumbWidth}}" height="{{.ThumbHeight}}" alt="Ebiten example: {{.Name}}" class="img-thumbnail"></a>
|
||||
</div>
|
||||
{{- end}}
|
||||
</div>
|
||||
<h3>Input</h3>
|
||||
<div class="row">
|
||||
{{range .InputExamples -}}
|
||||
<div class="col-3">
|
||||
<a href="examples/{{.Name}}.html"><img src="images/examples/{{.Name}}.png" width="{{.ThumbWidth}}" height="{{.ThumbHeight}}" alt="Ebiten example: {{.Name}}" class="img-thumbnail"></a>
|
||||
</div>
|
||||
{{- end}}
|
||||
</div>
|
||||
<h3>Audio</h3>
|
||||
<div class="row">
|
||||
{{range .AudioExamples -}}
|
||||
<div class="col-3">
|
||||
<a href="examples/{{.Name}}.html"><img src="images/examples/{{.Name}}.png" width="{{.ThumbWidth}}" height="{{.ThumbHeight}}" alt="Ebiten example: {{.Name}}" class="img-thumbnail"></a>
|
||||
</div>
|
||||
{{- end}}
|
||||
</div>
|
||||
<h3>Game</h3>
|
||||
<div class="row">
|
||||
{{range .GameExamples -}}
|
||||
<div class="col-3">
|
||||
<a href="examples/{{.Name}}.html"><img src="images/examples/{{.Name}}.png" width="{{.ThumbWidth}}" height="{{.ThumbHeight}}" alt="Ebiten example: {{.Name}}" class="img-thumbnail"></a>
|
||||
</div>
|
||||
{{- end}}
|
||||
</div>
|
||||
|
||||
<p><a href="https://blog.golang.org/go-programming-language-turns-two">The Gopher photographs by Chris Nokleberg</a> are licensed under <a href="https://creativecommons.org/licenses/by/3.0/">the Creative Commons 3.0 Attributions License</a>.</p>
|
||||
|
||||
<h3>Execute the examples</h3>
|
||||
|
@ -62,20 +62,23 @@ func (r *rand) next() uint32 {
|
||||
return r.w
|
||||
}
|
||||
|
||||
var randInstance = &rand{12345678, 4185243, 776511, 45411}
|
||||
var theRand = &rand{12345678, 4185243, 776511, 45411}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
// Generate the noise with random RGB values.
|
||||
const l = screenWidth * screenHeight
|
||||
for i := 0; i < l; i++ {
|
||||
x := randInstance.next()
|
||||
x := theRand.next()
|
||||
noiseImage.Pix[4*i] = uint8(x >> 24)
|
||||
noiseImage.Pix[4*i+1] = uint8(x >> 16)
|
||||
noiseImage.Pix[4*i+2] = uint8(x >> 8)
|
||||
noiseImage.Pix[4*i+3] = 0xff
|
||||
}
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
screen.ReplacePixels(noiseImage.Pix)
|
||||
ebitenutil.DebugPrint(screen, fmt.Sprintf("FPS: %f", ebiten.CurrentFPS()))
|
||||
return nil
|
||||
|
@ -53,46 +53,12 @@ var (
|
||||
canvasImage *ebiten.Image
|
||||
)
|
||||
|
||||
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%ebiten.FPS) / ebiten.FPS
|
||||
op.ColorM.RotateHue(theta)
|
||||
canvasImage.DrawImage(brushImage, op)
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
drawn := false
|
||||
mx, my := ebiten.CursorPosition()
|
||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
paint(screen, mx, my)
|
||||
drawn = true
|
||||
}
|
||||
for _, t := range ebiten.Touches() {
|
||||
x, y := t.Position()
|
||||
paint(screen, x, y)
|
||||
drawn = true
|
||||
}
|
||||
if drawn {
|
||||
count++
|
||||
}
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
screen.DrawImage(canvasImage, nil)
|
||||
|
||||
msg := fmt.Sprintf("(%d, %d)", mx, my)
|
||||
for _, t := range ebiten.Touches() {
|
||||
x, y := t.Position()
|
||||
msg += fmt.Sprintf("\n(%d, %d) touch %d", x, y, t.ID())
|
||||
}
|
||||
ebitenutil.DebugPrint(screen, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
const a0, a1, a2 = 0x40, 0xc0, 0xff
|
||||
func init() {
|
||||
const (
|
||||
a0 = 0x40
|
||||
a1 = 0xc0
|
||||
a2 = 0xff
|
||||
)
|
||||
pixels := []uint8{
|
||||
a0, a1, a1, a0,
|
||||
a1, a2, a2, a1,
|
||||
@ -107,7 +73,55 @@ func main() {
|
||||
|
||||
canvasImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
|
||||
canvasImage.Fill(color.White)
|
||||
}
|
||||
|
||||
// paint draws the brush on the given canvas image at the position (x, y).
|
||||
func paint(canvas *ebiten.Image, x, y int) {
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
op.GeoM.Translate(float64(x), float64(y))
|
||||
// Scale the color and rotate the hue so that colors vary on each frame.
|
||||
op.ColorM.Scale(1.0, 0.50, 0.125, 1.0)
|
||||
theta := 2.0 * math.Pi * float64(count%ebiten.FPS) / ebiten.FPS
|
||||
op.ColorM.RotateHue(theta)
|
||||
canvas.DrawImage(brushImage, op)
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
drawn := false
|
||||
|
||||
// Paint the brush by mouse dragging
|
||||
mx, my := ebiten.CursorPosition()
|
||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
paint(canvasImage, mx, my)
|
||||
drawn = true
|
||||
}
|
||||
|
||||
// Paint the brush by touches
|
||||
for _, t := range ebiten.Touches() {
|
||||
x, y := t.Position()
|
||||
paint(canvasImage, x, y)
|
||||
drawn = true
|
||||
}
|
||||
if drawn {
|
||||
count++
|
||||
}
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
screen.DrawImage(canvasImage, nil)
|
||||
|
||||
msg := fmt.Sprintf("(%d, %d)", mx, my)
|
||||
for _, t := range ebiten.Touches() {
|
||||
x, y := t.Position()
|
||||
msg += fmt.Sprintf("\n(%d, %d) touch %d", x, y, t.ID())
|
||||
}
|
||||
ebitenutil.DebugPrint(screen, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Paint (Ebiten Demo)"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -53,17 +53,25 @@ func update(screen *ebiten.Image) error {
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Split the image into horizontal lines and draw them with different scales.
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
w, h := gophersImage.Size()
|
||||
for i := 0; i < h; i++ {
|
||||
op.GeoM.Reset()
|
||||
width := w + i*3/4
|
||||
x := ((h - i) * 3 / 4) / 2
|
||||
op.GeoM.Scale(float64(width)/float64(w), 1)
|
||||
op.GeoM.Translate(float64(x), float64(i))
|
||||
maxWidth := float64(w) + float64(h)*3/4
|
||||
op.GeoM.Translate(-maxWidth/2, -float64(h)/2)
|
||||
|
||||
// Move the image's center to the upper-left corner.
|
||||
op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
|
||||
|
||||
// Scale each lines and adjust the position.
|
||||
lineW := w + i*3/4
|
||||
x := -float64(lineW) / float64(w) / 2
|
||||
op.GeoM.Scale(float64(lineW)/float64(w), 1)
|
||||
op.GeoM.Translate(x, float64(i))
|
||||
|
||||
// Move the image's center to the screen's center.
|
||||
op.GeoM.Translate(screenWidth/2, screenHeight/2)
|
||||
|
||||
r := image.Rect(0, i, w, i+1)
|
||||
op.SourceRect = &r
|
||||
screen.DrawImage(gophersImage, op)
|
||||
|
@ -47,10 +47,6 @@ import (
|
||||
"github.com/hajimehoshi/ebiten/text"
|
||||
)
|
||||
|
||||
const (
|
||||
arcadeFontSize = 8
|
||||
)
|
||||
|
||||
var (
|
||||
arcadeFont font.Face
|
||||
)
|
||||
@ -72,7 +68,10 @@ func init() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
const dpi = 72
|
||||
const (
|
||||
arcadeFontSize = 8
|
||||
dpi = 72
|
||||
)
|
||||
arcadeFont = truetype.NewFace(tt, &truetype.Options{
|
||||
Size: arcadeFontSize,
|
||||
DPI: dpi,
|
||||
@ -84,6 +83,7 @@ const (
|
||||
screenWidth = 320
|
||||
screenHeight = 240
|
||||
sampleRate = 44100
|
||||
baseFreq = 220
|
||||
)
|
||||
|
||||
var audioContext *audio.Context
|
||||
@ -96,27 +96,21 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
var pcm = make([]float64, 4*sampleRate)
|
||||
|
||||
const baseFreq = 220
|
||||
|
||||
func init() {
|
||||
// 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.
|
||||
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
|
||||
for j := 0; j < len(amp); j++ {
|
||||
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
|
||||
v := 0.0
|
||||
for j := 0; j < len(amp); j++ {
|
||||
// Decay
|
||||
a := amp[j] * math.Exp(-5*float64(i)*freq/baseFreq/(x[j]*sampleRate))
|
||||
v += a * math.Sin(2.0*math.Pi*float64(i)*freq*float64(j+1)/sampleRate)
|
||||
}
|
||||
return v / 5.0
|
||||
}
|
||||
|
||||
var (
|
||||
noteCache = map[int][]byte{}
|
||||
)
|
||||
|
||||
// toBytes returns the 2ch little endian 16bit byte sequence with the given left/right sequence.
|
||||
func toBytes(l, r []int16) []byte {
|
||||
if len(l) != len(r) {
|
||||
panic("len(l) must equal to len(r)")
|
||||
@ -131,62 +125,109 @@ func toBytes(l, r []int16) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
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, _ := audio.NewPlayerFromBytes(audioContext, n)
|
||||
p.Play()
|
||||
return
|
||||
}
|
||||
length := len(pcm) * baseFreq / f
|
||||
l := make([]int16, length)
|
||||
r := make([]int16, length)
|
||||
j := 0
|
||||
jj := 0
|
||||
for i := 0; i < len(l); i++ {
|
||||
p := pcm[j]
|
||||
l[i] = int16(p * vol * math.MaxInt16)
|
||||
r[i] = l[i]
|
||||
jj += f
|
||||
j = jj / baseFreq
|
||||
}
|
||||
n := toBytes(l, r)
|
||||
noteCache[f] = n
|
||||
p, _ := audio.NewPlayerFromBytes(audioContext, n)
|
||||
p.Play()
|
||||
return
|
||||
}
|
||||
|
||||
var keys = []ebiten.Key{
|
||||
ebiten.KeyQ,
|
||||
ebiten.KeyA,
|
||||
ebiten.KeyW,
|
||||
ebiten.KeyS,
|
||||
ebiten.KeyD,
|
||||
ebiten.KeyR,
|
||||
ebiten.KeyF,
|
||||
ebiten.KeyT,
|
||||
ebiten.KeyG,
|
||||
ebiten.KeyH,
|
||||
ebiten.KeyU,
|
||||
ebiten.KeyJ,
|
||||
ebiten.KeyI,
|
||||
ebiten.KeyK,
|
||||
ebiten.KeyO,
|
||||
ebiten.KeyL,
|
||||
}
|
||||
|
||||
var keyStates = map[ebiten.Key]int{}
|
||||
var (
|
||||
pianoNoteSamples = map[int][]byte{}
|
||||
pianoNoteSamplesInited = false
|
||||
pianoNoteSamplesInitCh = make(chan struct{})
|
||||
)
|
||||
|
||||
func init() {
|
||||
for _, key := range keys {
|
||||
keyStates[key] = 0
|
||||
// Initialize piano data.
|
||||
// This takes a little long time (especially on browsers),
|
||||
// so run this asynchronously and notice the progress.
|
||||
go func() {
|
||||
// Create a reference data and use this for other frequency.
|
||||
const refFreq = 110
|
||||
length := 4 * sampleRate * baseFreq / refFreq
|
||||
refData := make([]int16, length)
|
||||
for i := 0; i < length; i++ {
|
||||
refData[i] = int16(pianoAt(i, refFreq) * math.MaxInt16)
|
||||
}
|
||||
|
||||
for i := range keys {
|
||||
freq := baseFreq * math.Exp2(float64(i-1)/12.0)
|
||||
|
||||
// Clculate the wave data for the freq.
|
||||
length := 4 * sampleRate * baseFreq / int(freq)
|
||||
l := make([]int16, length)
|
||||
r := make([]int16, length)
|
||||
for i := 0; i < length; i++ {
|
||||
idx := int(float64(i) * freq / refFreq)
|
||||
if len(refData) <= idx {
|
||||
break
|
||||
}
|
||||
l[i] = refData[idx]
|
||||
}
|
||||
copy(r, l)
|
||||
n := toBytes(l, r)
|
||||
pianoNoteSamples[int(freq)] = n
|
||||
}
|
||||
close(pianoNoteSamplesInitCh)
|
||||
}()
|
||||
}
|
||||
|
||||
// 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.Image
|
||||
)
|
||||
|
||||
func init() {
|
||||
pianoImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
|
||||
|
||||
const (
|
||||
keyWidth = 24
|
||||
y = 48
|
||||
)
|
||||
|
||||
whiteKeys := []string{"A", "S", "D", "F", "G", "H", "J", "K", "L"}
|
||||
for i, k := range whiteKeys {
|
||||
x := i*keyWidth + 36
|
||||
height := 112
|
||||
ebitenutil.DrawRect(pianoImage, float64(x), float64(y), float64(keyWidth-1), float64(height), color.White)
|
||||
text.Draw(pianoImage, k, arcadeFont, x+8, y+height-8, color.Black)
|
||||
}
|
||||
|
||||
blackKeys := []string{"Q", "W", "", "R", "T", "", "U", "I", "O"}
|
||||
for i, k := range blackKeys {
|
||||
if k == "" {
|
||||
continue
|
||||
}
|
||||
x := i*keyWidth + 24
|
||||
height := 64
|
||||
ebitenutil.DrawRect(pianoImage, float64(x), float64(y), float64(keyWidth-1), float64(height), color.Black)
|
||||
text.Draw(pianoImage, k, arcadeFont, x+8, y+height-8, color.White)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
keys = []ebiten.Key{
|
||||
ebiten.KeyQ,
|
||||
ebiten.KeyA,
|
||||
ebiten.KeyW,
|
||||
ebiten.KeyS,
|
||||
ebiten.KeyD,
|
||||
ebiten.KeyR,
|
||||
ebiten.KeyF,
|
||||
ebiten.KeyT,
|
||||
ebiten.KeyG,
|
||||
ebiten.KeyH,
|
||||
ebiten.KeyU,
|
||||
ebiten.KeyJ,
|
||||
ebiten.KeyI,
|
||||
ebiten.KeyK,
|
||||
ebiten.KeyO,
|
||||
ebiten.KeyL,
|
||||
}
|
||||
keyStates = map[ebiten.Key]int{}
|
||||
)
|
||||
|
||||
// updateInput updates the input state.
|
||||
func updateInput() {
|
||||
for _, key := range keys {
|
||||
if !ebiten.IsKeyPressed(key) {
|
||||
@ -197,47 +238,33 @@ func updateInput() {
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
imagePiano *ebiten.Image
|
||||
)
|
||||
|
||||
func init() {
|
||||
imagePiano, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest)
|
||||
whiteKeys := []string{"A", "S", "D", "F", "G", "H", "J", "K", "L"}
|
||||
width := 24
|
||||
y := 48
|
||||
for i, k := range whiteKeys {
|
||||
x := i*width + 36
|
||||
height := 112
|
||||
ebitenutil.DrawRect(imagePiano, float64(x), float64(y), float64(width-1), float64(height), color.White)
|
||||
text.Draw(imagePiano, k, arcadeFont, x+8, y+height-8, color.Black)
|
||||
}
|
||||
|
||||
blackKeys := []string{"Q", "W", "", "R", "T", "", "U", "I", "O"}
|
||||
for i, k := range blackKeys {
|
||||
if k == "" {
|
||||
continue
|
||||
}
|
||||
x := i*width + 24
|
||||
height := 64
|
||||
ebitenutil.DrawRect(imagePiano, float64(x), float64(y), float64(width-1), float64(height), color.Black)
|
||||
text.Draw(imagePiano, k, arcadeFont, x+8, y+height-8, color.White)
|
||||
}
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
updateInput()
|
||||
for i, key := range keys {
|
||||
if keyStates[key] != 1 {
|
||||
continue
|
||||
// The piano data is still being initialized.
|
||||
// Get the progress if available.
|
||||
if !pianoNoteSamplesInited {
|
||||
select {
|
||||
case <-pianoNoteSamplesInitCh:
|
||||
pianoNoteSamplesInited = true
|
||||
default:
|
||||
}
|
||||
addNote(220*math.Exp2(float64(i-1)/12.0), 1.0)
|
||||
}
|
||||
|
||||
if pianoNoteSamplesInited {
|
||||
updateInput()
|
||||
for i, key := range keys {
|
||||
if keyStates[key] != 1 {
|
||||
continue
|
||||
}
|
||||
playNote(baseFreq * math.Exp2(float64(i-1)/12.0))
|
||||
}
|
||||
}
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
screen.Fill(color.RGBA{0x80, 0x80, 0xc0, 0xff})
|
||||
screen.DrawImage(imagePiano, nil)
|
||||
screen.DrawImage(pianoImage, nil)
|
||||
|
||||
ebitenutil.DebugPrint(screen, fmt.Sprintf("FPS: %0.2f", ebiten.CurrentFPS()))
|
||||
return nil
|
||||
|
@ -46,7 +46,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
count int
|
||||
count = 0
|
||||
gophersImage *ebiten.Image
|
||||
)
|
||||
|
||||
@ -57,8 +57,17 @@ func update(screen *ebiten.Image) error {
|
||||
}
|
||||
w, h := gophersImage.Size()
|
||||
op := &ebiten.DrawImageOptions{}
|
||||
|
||||
// Move the image's center to the screen's upper-left corner.
|
||||
// This is a prepartion for rotating. When geometry matrices are applied,
|
||||
// the origin point is the upper-left corner.
|
||||
op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
|
||||
|
||||
// Rotate the image. As a result, the anchor point of this rotate is
|
||||
// the center of the image.
|
||||
op.GeoM.Rotate(float64(count%360) * 2 * math.Pi / 360)
|
||||
|
||||
// Move the image to the screen's center.
|
||||
op.GeoM.Translate(screenWidth/2, screenHeight/2)
|
||||
screen.DrawImage(gophersImage, op)
|
||||
return nil
|
||||
|
@ -104,43 +104,7 @@ var (
|
||||
op = &ebiten.DrawImageOptions{}
|
||||
)
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
if ebiten.IsKeyPressed(ebiten.KeyLeft) {
|
||||
sprites.num -= 20
|
||||
if sprites.num < MinSprites {
|
||||
sprites.num = MinSprites
|
||||
}
|
||||
}
|
||||
if ebiten.IsKeyPressed(ebiten.KeyRight) {
|
||||
sprites.num += 20
|
||||
if MaxSprites < sprites.num {
|
||||
sprites.num = MaxSprites
|
||||
}
|
||||
}
|
||||
sprites.Update()
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
w, h := ebitenImage.Size()
|
||||
for i := 0; i < sprites.num; i++ {
|
||||
s := sprites.sprites[i]
|
||||
op.GeoM.Reset()
|
||||
op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
|
||||
op.GeoM.Rotate(2 * math.Pi * float64(s.angle) / maxAngle)
|
||||
op.GeoM.Translate(float64(w)/2, float64(h)/2)
|
||||
op.GeoM.Translate(float64(s.x), float64(s.y))
|
||||
screen.DrawImage(ebitenImage, op)
|
||||
}
|
||||
msg := fmt.Sprintf(`FPS: %0.2f
|
||||
Num of sprites: %d
|
||||
Press <- or -> to change the number of sprites`, ebiten.CurrentFPS(), sprites.num)
|
||||
ebitenutil.DebugPrint(screen, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
var err error
|
||||
func init() {
|
||||
img, _, err := ebitenutil.NewImageFromFile("_resources/images/ebiten.png", ebiten.FilterNearest)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@ -165,6 +129,55 @@ func main() {
|
||||
angle: a,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
// Decrease the nubmer of the sprites.
|
||||
if ebiten.IsKeyPressed(ebiten.KeyLeft) {
|
||||
sprites.num -= 20
|
||||
if sprites.num < MinSprites {
|
||||
sprites.num = MinSprites
|
||||
}
|
||||
}
|
||||
|
||||
// Increase the nubmer of the sprites.
|
||||
if ebiten.IsKeyPressed(ebiten.KeyRight) {
|
||||
sprites.num += 20
|
||||
if MaxSprites < sprites.num {
|
||||
sprites.num = MaxSprites
|
||||
}
|
||||
}
|
||||
|
||||
sprites.Update()
|
||||
|
||||
if ebiten.IsRunningSlowly() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Draw each sprite.
|
||||
// DrawImage can be called many many times, but in the implementation,
|
||||
// the actual draw call to GPU is very few since these calls satisfy
|
||||
// some conditions e.g. all the rendering sources and targets are same.
|
||||
// For more detail, see:
|
||||
// https://godoc.org/github.com/hajimehoshi/ebiten#Image.DrawImage
|
||||
w, h := ebitenImage.Size()
|
||||
for i := 0; i < sprites.num; i++ {
|
||||
s := sprites.sprites[i]
|
||||
op.GeoM.Reset()
|
||||
op.GeoM.Translate(-float64(w)/2, -float64(h)/2)
|
||||
op.GeoM.Rotate(2 * math.Pi * float64(s.angle) / maxAngle)
|
||||
op.GeoM.Translate(float64(w)/2, float64(h)/2)
|
||||
op.GeoM.Translate(float64(s.x), float64(s.y))
|
||||
screen.DrawImage(ebitenImage, op)
|
||||
}
|
||||
msg := fmt.Sprintf(`FPS: %0.2f
|
||||
Num of sprites: %d
|
||||
Press <- or -> to change the number of sprites`, ebiten.CurrentFPS(), sprites.num)
|
||||
ebitenutil.DebugPrint(screen, msg)
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Sprites (Ebiten Demo)"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
@ -46,14 +46,23 @@ var (
|
||||
)
|
||||
|
||||
func update(screen *ebiten.Image) error {
|
||||
// Add a string from InputChars, that returns string input by users.
|
||||
// Note that InputChars result changes every frame, so you need to call this
|
||||
// every frame.
|
||||
text += string(ebiten.InputChars())
|
||||
|
||||
// Adjust the string to be at most 10 lines.
|
||||
ss := strings.Split(text, "\n")
|
||||
if len(ss) > 10 {
|
||||
text = strings.Join(ss[len(ss)-10:], "\n")
|
||||
}
|
||||
|
||||
// If the enter key is pressed, add a line break.
|
||||
if ebiten.IsKeyPressed(ebiten.KeyEnter) && !strings.HasSuffix(text, "\n") {
|
||||
text += "\n"
|
||||
}
|
||||
|
||||
// If the backspace key is pressed, remove one character.
|
||||
bsPressed := ebiten.IsKeyPressed(ebiten.KeyBackspace)
|
||||
if !bsPrevPressed && bsPressed {
|
||||
if len(text) >= 1 {
|
||||
@ -68,6 +77,7 @@ func update(screen *ebiten.Image) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Blink the cursor.
|
||||
t := text
|
||||
if counter%60 < 30 {
|
||||
t += "_"
|
||||
|
@ -60,11 +60,10 @@
|
||||
</dl>
|
||||
|
||||
<h2 id="examples">Examples</h2>
|
||||
<h3>Graphics</h3>
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<a href="examples/alphablending.html"><img src="images/examples/alphablending.png" width="320" height="240" alt="Ebiten example: alphablending" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/audio.html"><img src="images/examples/audio.png" width="320" height="240" alt="Ebiten example: audio" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/font.html"><img src="images/examples/font.png" width="320" height="240" alt="Ebiten example: font" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
@ -73,12 +72,8 @@
|
||||
<a href="examples/hsv.html"><img src="images/examples/hsv.png" width="320" height="240" alt="Ebiten example: hsv" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/hue.html"><img src="images/examples/hue.png" width="320" height="240" alt="Ebiten example: hue" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/gamepad.html"><img src="images/examples/gamepad.png" width="320" height="240" alt="Ebiten example: gamepad" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/infinitescroll.html"><img src="images/examples/infinitescroll.png" width="320" height="240" alt="Ebiten example: infinitescroll" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/keyboard.html"><img src="images/examples/keyboard.png" width="320" height="240" alt="Ebiten example: keyboard" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/life.html"><img src="images/examples/life.png" width="320" height="240" alt="Ebiten example: life" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
@ -91,20 +86,39 @@
|
||||
<a href="examples/paint.html"><img src="images/examples/paint.png" width="320" height="240" alt="Ebiten example: paint" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/perspective.html"><img src="images/examples/perspective.png" width="320" height="240" alt="Ebiten example: perspective" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/piano.html"><img src="images/examples/piano.png" width="320" height="240" alt="Ebiten example: piano" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/rotate.html"><img src="images/examples/rotate.png" width="320" height="240" alt="Ebiten example: rotate" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/sprites.html"><img src="images/examples/sprites.png" width="320" height="240" alt="Ebiten example: sprites" class="img-thumbnail"></a>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Input</h3>
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<a href="examples/gamepad.html"><img src="images/examples/gamepad.png" width="320" height="240" alt="Ebiten example: gamepad" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/keyboard.html"><img src="images/examples/keyboard.png" width="320" height="240" alt="Ebiten example: keyboard" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/typewriter.html"><img src="images/examples/typewriter.png" width="320" height="240" alt="Ebiten example: typewriter" class="img-thumbnail"></a>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Audio</h3>
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<a href="examples/audio.html"><img src="images/examples/audio.png" width="320" height="240" alt="Ebiten example: audio" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/piano.html"><img src="images/examples/piano.png" width="320" height="240" alt="Ebiten example: piano" class="img-thumbnail"></a>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Game</h3>
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<a href="examples/2048.html"><img src="images/examples/2048.png" width="210" height="300" alt="Ebiten example: 2048" class="img-thumbnail"></a>
|
||||
</div><div class="col-3">
|
||||
<a href="examples/blocks.html"><img src="images/examples/blocks.png" width="256" height="240" alt="Ebiten example: blocks" class="img-thumbnail"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p><a href="https://blog.golang.org/go-programming-language-turns-two">The Gopher photographs by Chris Nokleberg</a> are licensed under <a href="https://creativecommons.org/licenses/by/3.0/">the Creative Commons 3.0 Attributions License</a>.</p>
|
||||
|
||||
<h3>Execute the examples</h3>
|
||||
|
Loading…
Reference in New Issue
Block a user