mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 11:18:54 +01:00
Add 'screenshot' feature
If you run your game with environment variable EBITEN_SCREENSHOT_KEY=<keyname>, you can take a game screenshot by pressing the specified key. Fixes #553
This commit is contained in:
parent
4708d4a6f9
commit
888d650872
18
genkeys.go
18
genkeys.go
@ -26,6 +26,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal"
|
"github.com/hajimehoshi/ebiten/internal"
|
||||||
@ -137,6 +138,8 @@ const ebitenKeysTmpl = `{{.License}}
|
|||||||
package ebiten
|
package ebiten
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/input"
|
"github.com/hajimehoshi/ebiten/internal/input"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -150,6 +153,14 @@ const (
|
|||||||
{{range $index, $name := .KeyNames}}Key{{$name}} Key = Key(input.Key{{$name}})
|
{{range $index, $name := .KeyNames}}Key{{$name}} Key = Key(input.Key{{$name}})
|
||||||
{{end}} KeyMax Key = Key{{.LastKeyName}}
|
{{end}} KeyMax Key = Key{{.LastKeyName}}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func keyNameToKey(name string) (Key, bool) {
|
||||||
|
switch strings.ToLower(name) {
|
||||||
|
{{range $name := .KeyNames}}case {{$name | printf "%q" | ToLower}}:
|
||||||
|
return Key{{$name}}, true
|
||||||
|
{{end}}}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const inputKeysTmpl = `{{.License}}
|
const inputKeysTmpl = `{{.License}}
|
||||||
@ -332,10 +343,15 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
tmpl, err := template.New(path).Parse(tmpl)
|
|
||||||
|
funcs := template.FuncMap{
|
||||||
|
"ToLower": strings.ToLower,
|
||||||
|
}
|
||||||
|
tmpl, err := template.New(path).Funcs(funcs).Parse(tmpl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The build tag can't be included in the templates because of `go vet`.
|
// The build tag can't be included in the templates because of `go vet`.
|
||||||
// Pass the build tag and extract this in the template to make `go vet` happy.
|
// Pass the build tag and extract this in the template to make `go vet` happy.
|
||||||
buildTag := ""
|
buildTag := ""
|
||||||
|
164
keys.go
164
keys.go
@ -17,6 +17,8 @@
|
|||||||
package ebiten
|
package ebiten
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/input"
|
"github.com/hajimehoshi/ebiten/internal/input"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -107,3 +109,165 @@ const (
|
|||||||
KeyUp Key = Key(input.KeyUp)
|
KeyUp Key = Key(input.KeyUp)
|
||||||
KeyMax Key = KeyUp
|
KeyMax Key = KeyUp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func keyNameToKey(name string) (Key, bool) {
|
||||||
|
switch strings.ToLower(name) {
|
||||||
|
case "0":
|
||||||
|
return Key0, true
|
||||||
|
case "1":
|
||||||
|
return Key1, true
|
||||||
|
case "2":
|
||||||
|
return Key2, true
|
||||||
|
case "3":
|
||||||
|
return Key3, true
|
||||||
|
case "4":
|
||||||
|
return Key4, true
|
||||||
|
case "5":
|
||||||
|
return Key5, true
|
||||||
|
case "6":
|
||||||
|
return Key6, true
|
||||||
|
case "7":
|
||||||
|
return Key7, true
|
||||||
|
case "8":
|
||||||
|
return Key8, true
|
||||||
|
case "9":
|
||||||
|
return Key9, true
|
||||||
|
case "a":
|
||||||
|
return KeyA, true
|
||||||
|
case "b":
|
||||||
|
return KeyB, true
|
||||||
|
case "c":
|
||||||
|
return KeyC, true
|
||||||
|
case "d":
|
||||||
|
return KeyD, true
|
||||||
|
case "e":
|
||||||
|
return KeyE, true
|
||||||
|
case "f":
|
||||||
|
return KeyF, true
|
||||||
|
case "g":
|
||||||
|
return KeyG, true
|
||||||
|
case "h":
|
||||||
|
return KeyH, true
|
||||||
|
case "i":
|
||||||
|
return KeyI, true
|
||||||
|
case "j":
|
||||||
|
return KeyJ, true
|
||||||
|
case "k":
|
||||||
|
return KeyK, true
|
||||||
|
case "l":
|
||||||
|
return KeyL, true
|
||||||
|
case "m":
|
||||||
|
return KeyM, true
|
||||||
|
case "n":
|
||||||
|
return KeyN, true
|
||||||
|
case "o":
|
||||||
|
return KeyO, true
|
||||||
|
case "p":
|
||||||
|
return KeyP, true
|
||||||
|
case "q":
|
||||||
|
return KeyQ, true
|
||||||
|
case "r":
|
||||||
|
return KeyR, true
|
||||||
|
case "s":
|
||||||
|
return KeyS, true
|
||||||
|
case "t":
|
||||||
|
return KeyT, true
|
||||||
|
case "u":
|
||||||
|
return KeyU, true
|
||||||
|
case "v":
|
||||||
|
return KeyV, true
|
||||||
|
case "w":
|
||||||
|
return KeyW, true
|
||||||
|
case "x":
|
||||||
|
return KeyX, true
|
||||||
|
case "y":
|
||||||
|
return KeyY, true
|
||||||
|
case "z":
|
||||||
|
return KeyZ, true
|
||||||
|
case "alt":
|
||||||
|
return KeyAlt, true
|
||||||
|
case "apostrophe":
|
||||||
|
return KeyApostrophe, true
|
||||||
|
case "backslash":
|
||||||
|
return KeyBackslash, true
|
||||||
|
case "backspace":
|
||||||
|
return KeyBackspace, true
|
||||||
|
case "capslock":
|
||||||
|
return KeyCapsLock, true
|
||||||
|
case "comma":
|
||||||
|
return KeyComma, true
|
||||||
|
case "control":
|
||||||
|
return KeyControl, true
|
||||||
|
case "delete":
|
||||||
|
return KeyDelete, true
|
||||||
|
case "down":
|
||||||
|
return KeyDown, true
|
||||||
|
case "end":
|
||||||
|
return KeyEnd, true
|
||||||
|
case "enter":
|
||||||
|
return KeyEnter, true
|
||||||
|
case "equal":
|
||||||
|
return KeyEqual, true
|
||||||
|
case "escape":
|
||||||
|
return KeyEscape, true
|
||||||
|
case "f1":
|
||||||
|
return KeyF1, true
|
||||||
|
case "f2":
|
||||||
|
return KeyF2, true
|
||||||
|
case "f3":
|
||||||
|
return KeyF3, true
|
||||||
|
case "f4":
|
||||||
|
return KeyF4, true
|
||||||
|
case "f5":
|
||||||
|
return KeyF5, true
|
||||||
|
case "f6":
|
||||||
|
return KeyF6, true
|
||||||
|
case "f7":
|
||||||
|
return KeyF7, true
|
||||||
|
case "f8":
|
||||||
|
return KeyF8, true
|
||||||
|
case "f9":
|
||||||
|
return KeyF9, true
|
||||||
|
case "f10":
|
||||||
|
return KeyF10, true
|
||||||
|
case "f11":
|
||||||
|
return KeyF11, true
|
||||||
|
case "f12":
|
||||||
|
return KeyF12, true
|
||||||
|
case "graveaccent":
|
||||||
|
return KeyGraveAccent, true
|
||||||
|
case "home":
|
||||||
|
return KeyHome, true
|
||||||
|
case "insert":
|
||||||
|
return KeyInsert, true
|
||||||
|
case "left":
|
||||||
|
return KeyLeft, true
|
||||||
|
case "leftbracket":
|
||||||
|
return KeyLeftBracket, true
|
||||||
|
case "minus":
|
||||||
|
return KeyMinus, true
|
||||||
|
case "pagedown":
|
||||||
|
return KeyPageDown, true
|
||||||
|
case "pageup":
|
||||||
|
return KeyPageUp, true
|
||||||
|
case "period":
|
||||||
|
return KeyPeriod, true
|
||||||
|
case "right":
|
||||||
|
return KeyRight, true
|
||||||
|
case "rightbracket":
|
||||||
|
return KeyRightBracket, true
|
||||||
|
case "semicolon":
|
||||||
|
return KeySemicolon, true
|
||||||
|
case "shift":
|
||||||
|
return KeyShift, true
|
||||||
|
case "slash":
|
||||||
|
return KeySlash, true
|
||||||
|
case "space":
|
||||||
|
return KeySpace, true
|
||||||
|
case "tab":
|
||||||
|
return KeyTab, true
|
||||||
|
case "up":
|
||||||
|
return KeyUp, true
|
||||||
|
}
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
75
run.go
75
run.go
@ -15,11 +15,14 @@
|
|||||||
package ebiten
|
package ebiten
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"os"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/clock"
|
"github.com/hajimehoshi/ebiten/internal/clock"
|
||||||
"github.com/hajimehoshi/ebiten/internal/devicescale"
|
"github.com/hajimehoshi/ebiten/internal/devicescale"
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/png"
|
||||||
"github.com/hajimehoshi/ebiten/internal/ui"
|
"github.com/hajimehoshi/ebiten/internal/ui"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -88,6 +91,68 @@ func run(width, height int, scale float64, title string, g *graphicsContext, mai
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var screenshot = false
|
||||||
|
var screenshotKey Key
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
keyname := os.Getenv("EBITEN_SCREENSHOT_KEY")
|
||||||
|
if keyname == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
key, ok := keyNameToKey(keyname)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
screenshot = true
|
||||||
|
screenshotKey = key
|
||||||
|
}
|
||||||
|
|
||||||
|
type screenshotTaker struct {
|
||||||
|
f func(screen *Image) error
|
||||||
|
keyState int
|
||||||
|
needToTake bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *screenshotTaker) update(screen *Image) error {
|
||||||
|
if err := s.f(screen); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !screenshot {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if IsKeyPressed(screenshotKey) {
|
||||||
|
s.keyState++
|
||||||
|
if s.keyState == 1 {
|
||||||
|
s.needToTake = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
s.keyState = 0
|
||||||
|
}
|
||||||
|
if s.needToTake && !IsRunningSlowly() {
|
||||||
|
filename := "screenshot.png"
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
filename = fmt.Sprintf("screenshot%d.png", i)
|
||||||
|
}
|
||||||
|
f, err := os.Create(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if err := png.Encode(f, screen); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
s.needToTake = false
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Run runs the game.
|
// Run runs the game.
|
||||||
// f is a function which is called at every frame.
|
// f is a function which is called at every frame.
|
||||||
// The argument (*Image) is the render target that represents the screen.
|
// The argument (*Image) is the render target that represents the screen.
|
||||||
@ -118,6 +183,11 @@ func run(width, height int, scale float64, title string, g *graphicsContext, mai
|
|||||||
//
|
//
|
||||||
// Don't call Run twice or more in one process.
|
// Don't call Run twice or more in one process.
|
||||||
func Run(f func(*Image) error, width, height int, scale float64, title string) error {
|
func Run(f func(*Image) error, width, height int, scale float64, title string) error {
|
||||||
|
if screenshot {
|
||||||
|
s := &screenshotTaker{f: f}
|
||||||
|
f = s.update
|
||||||
|
}
|
||||||
|
|
||||||
ch := make(chan error)
|
ch := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(ch)
|
defer close(ch)
|
||||||
@ -142,6 +212,11 @@ func Run(f func(*Image) error, width, height int, scale float64, title string) e
|
|||||||
// Ebiten users should NOT call this function.
|
// Ebiten users should NOT call this function.
|
||||||
// Instead, functions in github.com/hajimehoshi/ebiten/mobile package calls this.
|
// Instead, functions in github.com/hajimehoshi/ebiten/mobile package calls this.
|
||||||
func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64, title string) <-chan error {
|
func RunWithoutMainLoop(f func(*Image) error, width, height int, scale float64, title string) <-chan error {
|
||||||
|
if screenshot {
|
||||||
|
s := &screenshotTaker{f: f}
|
||||||
|
f = s.update
|
||||||
|
}
|
||||||
|
|
||||||
ch := make(chan error)
|
ch := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
defer close(ch)
|
defer close(ch)
|
||||||
|
Loading…
Reference in New Issue
Block a user