Implemented scene events and callback handlers for those events. Manager defaults also added.

This commit is contained in:
2023-08-23 01:24:43 -04:00
parent f2b3f371c4
commit 5da470937e
6 changed files with 179 additions and 59 deletions

View File

@@ -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)
} }

View File

@@ -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
}

View 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
}

View File

@@ -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
} }

View File

@@ -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))
}

View File

@@ -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
} }