mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08: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"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal"
|
||||
@ -137,6 +138,8 @@ const ebitenKeysTmpl = `{{.License}}
|
||||
package ebiten
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/input"
|
||||
)
|
||||
|
||||
@ -150,6 +153,14 @@ const (
|
||||
{{range $index, $name := .KeyNames}}Key{{$name}} Key = Key(input.Key{{$name}})
|
||||
{{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}}
|
||||
@ -332,10 +343,15 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
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 {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 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.
|
||||
buildTag := ""
|
||||
|
164
keys.go
164
keys.go
@ -17,6 +17,8 @@
|
||||
package ebiten
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/input"
|
||||
)
|
||||
|
||||
@ -107,3 +109,165 @@ const (
|
||||
KeyUp Key = Key(input.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
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/internal/clock"
|
||||
"github.com/hajimehoshi/ebiten/internal/devicescale"
|
||||
"github.com/hajimehoshi/ebiten/internal/png"
|
||||
"github.com/hajimehoshi/ebiten/internal/ui"
|
||||
)
|
||||
|
||||
@ -88,6 +91,68 @@ func run(width, height int, scale float64, title string, g *graphicsContext, mai
|
||||
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.
|
||||
// f is a function which is called at every frame.
|
||||
// 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.
|
||||
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)
|
||||
go func() {
|
||||
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.
|
||||
// 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 {
|
||||
if screenshot {
|
||||
s := &screenshotTaker{f: f}
|
||||
f = s.update
|
||||
}
|
||||
|
||||
ch := make(chan error)
|
||||
go func() {
|
||||
defer close(ch)
|
||||
|
Loading…
Reference in New Issue
Block a user