Implemented scene events and callback handlers for those events. Manager defaults also added.
This commit is contained in:
@@ -11,13 +11,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
//setup manager
|
||||||
manager := groovy.NewManager()
|
manager := groovy.NewManager()
|
||||||
|
manager.SetDimensions(groovy.Area{Width: 1280, Height: 720})
|
||||||
loadScenes(&manager)
|
|
||||||
|
|
||||||
ebiten.SetWindowSize(manager.Info.Dimension.Width, manager.Info.Dimension.Height)
|
ebiten.SetWindowSize(manager.Info.Dimension.Width, manager.Info.Dimension.Height)
|
||||||
ebiten.SetWindowTitle(manager.Info.Name)
|
ebiten.SetWindowTitle(manager.Info.Name)
|
||||||
|
|
||||||
|
loadScenes(&manager)
|
||||||
|
|
||||||
|
//identification
|
||||||
fmt.Println(manager.Info.Name + ": v" + manager.Info.Version)
|
fmt.Println(manager.Info.Name + ": v" + manager.Info.Version)
|
||||||
|
|
||||||
if err := ebiten.RunGame(&manager); err != nil {
|
if err := ebiten.RunGame(&manager); err != nil {
|
||||||
@@ -28,14 +31,31 @@ func main() {
|
|||||||
|
|
||||||
// Example loading of two scenes
|
// Example loading of two scenes
|
||||||
func loadScenes(m *groovy.Manager) {
|
func loadScenes(m *groovy.Manager) {
|
||||||
|
//call the loaders for each scene
|
||||||
|
loadSplash(m)
|
||||||
|
loadMenu(m)
|
||||||
|
|
||||||
|
//reset the manager to start scene 1
|
||||||
|
m.ResetScenes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates splash screen, sets completion handler
|
||||||
|
func loadSplash(m *groovy.Manager) {
|
||||||
|
//create splash screen and append as first scene in manager
|
||||||
sceneSplash := splashmenu.NewSplash()
|
sceneSplash := splashmenu.NewSplash()
|
||||||
m.AddScene(&sceneSplash)
|
m.AddScene(&sceneSplash)
|
||||||
|
}
|
||||||
sceneMenu := splashmenu.NewMenu()
|
|
||||||
m.AddScene(&sceneMenu)
|
// creates menu screen, populates the options, sets key event handler
|
||||||
|
func loadMenu(m *groovy.Manager) {
|
||||||
//sets current scene to the splash menu
|
//create menu with defined options, append to manager
|
||||||
m.SetCurrentScene(0)
|
sceneMenu := splashmenu.NewMenu()
|
||||||
|
sceneMenu.SetOptions(map[int]splashmenu.MenuOption{
|
||||||
m.SetDimensions(groovy.Area{Width: 1280, Height: 720})
|
1: {Description: "splash", SelectionEvent: groovy.RESET, Mapping: ebiten.Key1},
|
||||||
|
2: {Description: "menu"},
|
||||||
|
3: {Description: "swing"},
|
||||||
|
4: {Description: "exit", SelectionEvent: groovy.ENDGAME, Mapping: ebiten.Key4},
|
||||||
|
})
|
||||||
|
|
||||||
|
m.AddScene(&sceneMenu)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package splashmenu
|
package splashmenu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cosmos/diego/groovy"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
"github.com/hajimehoshi/ebiten/v2/examples/resources/fonts"
|
"github.com/hajimehoshi/ebiten/v2/examples/resources/fonts"
|
||||||
@@ -13,6 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
titleFont font.Face
|
||||||
menuFont font.Face
|
menuFont font.Face
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,8 +26,17 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const dpi = 72
|
const dpi = 72
|
||||||
|
titleFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
|
||||||
|
Size: 16,
|
||||||
|
DPI: dpi,
|
||||||
|
Hinting: font.HintingVertical,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
menuFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
|
menuFont, err = opentype.NewFace(tt, &opentype.FaceOptions{
|
||||||
Size: 12,
|
Size: 10,
|
||||||
DPI: dpi,
|
DPI: dpi,
|
||||||
Hinting: font.HintingVertical,
|
Hinting: font.HintingVertical,
|
||||||
})
|
})
|
||||||
@@ -35,34 +47,61 @@ func init() {
|
|||||||
|
|
||||||
type Menu struct {
|
type Menu struct {
|
||||||
bgcolor color.RGBA
|
bgcolor color.RGBA
|
||||||
completed bool
|
options map[int]MenuOption
|
||||||
|
events map[groovy.SceneEvent]func()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMenu() Menu {
|
func NewMenu() Menu {
|
||||||
return Menu{
|
return Menu{
|
||||||
bgcolor: color.RGBA{0x33, 0x33, 0x99, 0xFF},
|
bgcolor: color.RGBA{0x33, 0x33, 0x99, 0xFF},
|
||||||
completed: false,
|
events: make(map[groovy.SceneEvent]func()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) Draw(screen *ebiten.Image) {
|
func (m *Menu) Draw(screen *ebiten.Image) {
|
||||||
screen.Fill(m.bgcolor)
|
screen.Fill(m.bgcolor)
|
||||||
text.Draw(screen, "menu", menuFont, 40, 40, color.White)
|
text.Draw(screen, "menu", titleFont, 40, 40, color.White)
|
||||||
|
|
||||||
|
m.RenderOptions(screen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Menu) SetEventHandler(event groovy.SceneEvent, f func()) {
|
||||||
|
m.events[event] = f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Menu) SetOptions(options map[int]MenuOption) {
|
||||||
|
m.options = make(map[int]MenuOption)
|
||||||
|
|
||||||
|
for k, v := range options {
|
||||||
|
m.options[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Menu) RenderOptions(screen *ebiten.Image) {
|
||||||
|
|
||||||
|
var offset int = 20
|
||||||
|
|
||||||
|
for k, v := range m.options {
|
||||||
|
m.options[k] = v
|
||||||
|
text.Draw(screen, strconv.Itoa(k)+": "+v.Description, menuFont, 40, 60+offset*k, color.White)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) Update() error {
|
func (m *Menu) Update() error {
|
||||||
|
|
||||||
var keysPressed []ebiten.Key
|
var keysPressed []ebiten.Key
|
||||||
keysPressed = inpututil.AppendPressedKeys(keysPressed[:0])
|
keysPressed = inpututil.AppendPressedKeys(keysPressed[:0])
|
||||||
|
|
||||||
|
for _, o := range m.options {
|
||||||
|
if m.events[o.SelectionEvent] != nil {
|
||||||
for _, k := range keysPressed {
|
for _, k := range keysPressed {
|
||||||
if k == ebiten.KeyEnter {
|
if k == o.Mapping {
|
||||||
m.completed = true
|
m.events[o.SelectionEvent]()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Menu) Completed() bool {
|
|
||||||
return m.completed
|
|
||||||
}
|
|
||||||
|
|||||||
13
examples/splashmenu/scenes/menuoption.go
Normal file
13
examples/splashmenu/scenes/menuoption.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package splashmenu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cosmos/diego/groovy"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MenuOption struct {
|
||||||
|
Description string
|
||||||
|
SelectionEvent groovy.SceneEvent
|
||||||
|
Mapping ebiten.Key
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package splashmenu
|
package splashmenu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cosmos/diego/groovy"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
@@ -34,14 +35,19 @@ func init() {
|
|||||||
|
|
||||||
type Splash struct {
|
type Splash struct {
|
||||||
bgcolor color.RGBA
|
bgcolor color.RGBA
|
||||||
completed bool
|
|
||||||
increment int
|
increment int
|
||||||
|
events map[groovy.SceneEvent]func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSceneEvents implements groovy.Scene.
|
||||||
|
func (*Splash) GetSceneEvents() []groovy.SceneEvent {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSplash() Splash {
|
func NewSplash() Splash {
|
||||||
return Splash{
|
return Splash{
|
||||||
bgcolor: color.RGBA{0xFF, 0xFF, 0xFF, 0xFF},
|
bgcolor: color.RGBA{0xFF, 0xFF, 0xFF, 0xFF},
|
||||||
completed: false,
|
events: make(map[groovy.SceneEvent]func()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,12 +64,12 @@ func (s *Splash) Update() error {
|
|||||||
s.bgcolor.B = (s.bgcolor.B - 2) % 0xFF
|
s.bgcolor.B = (s.bgcolor.B - 2) % 0xFF
|
||||||
|
|
||||||
if s.bgcolor.R == 0x00 {
|
if s.bgcolor.R == 0x00 {
|
||||||
s.completed = true
|
s.events[groovy.COMPLETED]()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Splash) Completed() bool {
|
func (s Splash) SetEventHandler(event groovy.SceneEvent, f func()) {
|
||||||
return s.completed
|
s.events[event] = f
|
||||||
}
|
}
|
||||||
|
|||||||
79
manager.go
79
manager.go
@@ -25,8 +25,10 @@ type GameInfo struct {
|
|||||||
type Manager struct {
|
type Manager struct {
|
||||||
Info GameInfo
|
Info GameInfo
|
||||||
currentScene Scene
|
currentScene Scene
|
||||||
currentSceneId int
|
currentSceneId uint
|
||||||
|
nextSceneId uint
|
||||||
scenes []Scene
|
scenes []Scene
|
||||||
|
EventMap map[SceneEvent]func()
|
||||||
}
|
}
|
||||||
|
|
||||||
// can be used to create default manager instance
|
// can be used to create default manager instance
|
||||||
@@ -37,9 +39,11 @@ func NewManager() Manager {
|
|||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Dimension: Area{
|
Dimension: Area{
|
||||||
Width: defaultWidth,
|
Width: defaultWidth,
|
||||||
Height: defaultHeight},
|
Height: defaultHeight,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
currentSceneId: 0,
|
currentSceneId: 0,
|
||||||
|
nextSceneId: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,30 +54,14 @@ func (m *Manager) Update() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
m.CheckTransitions()
|
|
||||||
m.CheckExit()
|
|
||||||
|
|
||||||
//call the current scene's update method
|
//call the current scene's update method
|
||||||
return m.currentScene.Update()
|
return m.currentScene.Update()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for exit condition
|
func (m *Manager) Quit() {
|
||||||
func (m *Manager) CheckExit() {
|
|
||||||
if m.currentSceneId >= len(m.scenes) {
|
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// check for scene completion and if reached, set up next scene (if available)
|
|
||||||
func (m *Manager) CheckTransitions() {
|
|
||||||
if m.currentScene.Completed() {
|
|
||||||
m.currentSceneId++
|
|
||||||
if m.currentSceneId < len(m.scenes) {
|
|
||||||
m.currentScene = m.scenes[m.currentSceneId]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// calls current scene's draw method if the currentscene is valid
|
// calls current scene's draw method if the currentscene is valid
|
||||||
func (m *Manager) Draw(screen *ebiten.Image) {
|
func (m *Manager) Draw(screen *ebiten.Image) {
|
||||||
@@ -89,18 +77,57 @@ func (m *Manager) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHe
|
|||||||
|
|
||||||
// appends scene to the managed scenes
|
// appends scene to the managed scenes
|
||||||
func (m *Manager) AddScene(s Scene) {
|
func (m *Manager) AddScene(s Scene) {
|
||||||
|
setDefaultHandlers(m, s)
|
||||||
m.scenes = append(m.scenes, s)
|
m.scenes = append(m.scenes, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets the current scene, based on sceneindex
|
// sets the default callback handlers for a given scene within manager
|
||||||
func (m *Manager) SetCurrentScene(sceneId int) {
|
// Default Handling behaviours:
|
||||||
if sceneId >= 0 && sceneId < len(m.scenes) {
|
//
|
||||||
m.currentSceneId = sceneId
|
// reset: sets (scene, nextscene) to {0, 1}
|
||||||
m.currentScene = m.scenes[m.currentSceneId]
|
// scene completion: sets (scene, nextscene) to {nextscene, nextscene+1}
|
||||||
}
|
// end game: shutdown groovy
|
||||||
|
//
|
||||||
|
// note: NOOP and RELOAD are purposefully not mapped; they are scene
|
||||||
|
// specific and should be mapped to by user of groovy
|
||||||
|
func setDefaultHandlers(m *Manager, s Scene) {
|
||||||
|
s.SetEventHandler(RESET, func() { m.ResetScenes() })
|
||||||
|
s.SetEventHandler(COMPLETED, func() { m.TransitionScene() })
|
||||||
|
s.SetEventHandler(ENDGAME, func() { m.Quit() })
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for exit condition
|
// we're going to reset the scene to the first one
|
||||||
|
func (m *Manager) ResetScenes() {
|
||||||
|
m.currentSceneId = 0
|
||||||
|
m.nextSceneId = 1
|
||||||
|
m.SetCurrentScene(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets the current scene, based on sceneindex n
|
||||||
|
// n > scenelist, quit
|
||||||
|
// otherwise, scene = n
|
||||||
|
func (m *Manager) SetCurrentScene(sceneId uint) {
|
||||||
|
if sceneId >= uint(len(m.scenes)) {
|
||||||
|
m.Quit()
|
||||||
|
}
|
||||||
|
m.currentSceneId = sceneId
|
||||||
|
m.currentScene = m.scenes[sceneId]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) TransitionScene() {
|
||||||
|
m.SetCurrentScene(m.nextSceneId)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Manager) SetNextScene(sceneId uint) {
|
||||||
|
m.nextSceneId = sceneId
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets sene dimensions
|
||||||
func (m *Manager) SetDimensions(a Area) {
|
func (m *Manager) SetDimensions(a Area) {
|
||||||
m.Info.Dimension = a
|
m.Info.Dimension = a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// report number of total scenes
|
||||||
|
func (m *Manager) SceneCount() uint {
|
||||||
|
return uint(len(m.scenes))
|
||||||
|
}
|
||||||
|
|||||||
17
scene.go
17
scene.go
@@ -2,8 +2,23 @@ package groovy
|
|||||||
|
|
||||||
import "github.com/hajimehoshi/ebiten/v2"
|
import "github.com/hajimehoshi/ebiten/v2"
|
||||||
|
|
||||||
|
type SceneEvent int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
NOOP SceneEvent = 0
|
||||||
|
RESET SceneEvent = 1 // reset to initial scene
|
||||||
|
RELOAD SceneEvent = 3 // reload current scene
|
||||||
|
COMPLETED SceneEvent = 4 // current scene has completed
|
||||||
|
ENDGAME SceneEvent = 5 // shutdown all scenes
|
||||||
|
)
|
||||||
|
|
||||||
type Scene interface {
|
type Scene interface {
|
||||||
Update() error
|
Update() error
|
||||||
Draw(screen *ebiten.Image)
|
Draw(screen *ebiten.Image)
|
||||||
Completed() bool
|
SetEventHandler(e SceneEvent, f func())
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArgoScale interface {
|
||||||
|
Draw(screen *ebiten.Image)
|
||||||
|
GetSceneEvents() []SceneEvent
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user