From 6f794b7bb23ff2568c510d888df64a1009c62bde Mon Sep 17 00:00:00 2001 From: iegod Date: Mon, 11 Nov 2024 09:54:30 -0500 Subject: [PATCH] Brought in screen manager, minor refactor. --- .vscode/launch.json | 15 +++ altar.png => assets/altar.png | Bin fly-eye.png => assets/fly-eye.png | Bin fly-eye2.png => assets/fly-eye2.png | Bin fly-eye3.png => assets/fly-eye3.png | Bin grasstile.png => assets/grasstile.png | Bin hero.png => assets/hero.png | Bin herodeath.png => assets/herodeath.png | Bin assets/imagebank.go | 76 ++++++++++++ shadow.png => assets/shadow.png | Bin weapon.png => assets/weapon.png | Bin explosion.go => elements/explosion.go | 8 +- hero.go => elements/hero.go | 46 +++----- mover.go => elements/mover.go | 68 +++-------- projectile.go => elements/projectile.go | 11 +- coordinates.go => gamedata/coordinates.go | 2 +- gamedata/gameinfo.go | 16 +++ main.go | 25 ++-- screenmanager/manager.go | 136 ++++++++++++++++++++++ game.go => screens/game.go | 115 ++++++++---------- screens/scene.go | 25 ++++ 21 files changed, 373 insertions(+), 170 deletions(-) create mode 100644 .vscode/launch.json rename altar.png => assets/altar.png (100%) rename fly-eye.png => assets/fly-eye.png (100%) rename fly-eye2.png => assets/fly-eye2.png (100%) rename fly-eye3.png => assets/fly-eye3.png (100%) rename grasstile.png => assets/grasstile.png (100%) rename hero.png => assets/hero.png (100%) rename herodeath.png => assets/herodeath.png (100%) create mode 100644 assets/imagebank.go rename shadow.png => assets/shadow.png (100%) rename weapon.png => assets/weapon.png (100%) rename explosion.go => elements/explosion.go (76%) rename hero.go => elements/hero.go (69%) rename mover.go => elements/mover.go (60%) rename projectile.go => elements/projectile.go (65%) rename coordinates.go => gamedata/coordinates.go (75%) create mode 100644 gamedata/gameinfo.go create mode 100644 screenmanager/manager.go rename game.go => screens/game.go (79%) create mode 100644 screens/scene.go diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..c462248 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "survive", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "main.go" + } + ] +} \ No newline at end of file diff --git a/altar.png b/assets/altar.png similarity index 100% rename from altar.png rename to assets/altar.png diff --git a/fly-eye.png b/assets/fly-eye.png similarity index 100% rename from fly-eye.png rename to assets/fly-eye.png diff --git a/fly-eye2.png b/assets/fly-eye2.png similarity index 100% rename from fly-eye2.png rename to assets/fly-eye2.png diff --git a/fly-eye3.png b/assets/fly-eye3.png similarity index 100% rename from fly-eye3.png rename to assets/fly-eye3.png diff --git a/grasstile.png b/assets/grasstile.png similarity index 100% rename from grasstile.png rename to assets/grasstile.png diff --git a/hero.png b/assets/hero.png similarity index 100% rename from hero.png rename to assets/hero.png diff --git a/herodeath.png b/assets/herodeath.png similarity index 100% rename from herodeath.png rename to assets/herodeath.png diff --git a/assets/imagebank.go b/assets/imagebank.go new file mode 100644 index 0000000..072b97e --- /dev/null +++ b/assets/imagebank.go @@ -0,0 +1,76 @@ +package assets + +import ( + "bytes" + "image" + "log" + + _ "embed" + + "github.com/hajimehoshi/ebiten/v2" +) + +type AssetName string + +const ( + FlyEyeNormal AssetName = "FlyEyeNormal" + FlyEyeDamaged AssetName = "FlyEyeDamaged" + FlyEyeDying AssetName = "FlyEyeDying" + FlyEyeShadow AssetName = "FlyEyeShadow" + HeroNormal AssetName = "HeroNormal" + HeroDying AssetName = "HeroDying" + TileSet AssetName = "TileSet" + Altar AssetName = "Altar" + Weapon AssetName = "Weapon" +) + +var ( + ImageBank map[AssetName]*ebiten.Image + + flyeyeImage *ebiten.Image + flyeyeImage2 *ebiten.Image + flyeyeImage3 *ebiten.Image + shadow *ebiten.Image + + //go:embed fly-eye.png + flyeye_img []byte + //go:embed fly-eye2.png + flyeye_img2 []byte + //go:embed fly-eye3.png + flyeye_img3 []byte + //go:embed shadow.png + shadow_img []byte + //go:embed hero.png + hero_img []byte + //go:embed herodeath.png + herodeath_img []byte + //go:embed grasstile.png + tileset_img []byte + //go:embed altar.png + altar_img []byte + //go:embed weapon.png + weapon_img []byte +) + +func LoadImages() { + ImageBank = make(map[AssetName]*ebiten.Image) + + ImageBank[FlyEyeNormal] = LoadImagesFatal(flyeye_img) + ImageBank[FlyEyeDamaged] = LoadImagesFatal(flyeye_img2) + ImageBank[FlyEyeDying] = LoadImagesFatal(flyeye_img3) + ImageBank[FlyEyeShadow] = LoadImagesFatal(shadow_img) + ImageBank[HeroNormal] = LoadImagesFatal(hero_img) + ImageBank[HeroDying] = LoadImagesFatal(herodeath_img) + ImageBank[TileSet] = LoadImagesFatal(tileset_img) + ImageBank[Altar] = LoadImagesFatal(altar_img) + ImageBank[Weapon] = LoadImagesFatal(weapon_img) + +} + +func LoadImagesFatal(b []byte) *ebiten.Image { + img, _, err := image.Decode(bytes.NewReader(b)) + if err != nil { + log.Fatal(err) + } + return ebiten.NewImageFromImage(img) +} diff --git a/shadow.png b/assets/shadow.png similarity index 100% rename from shadow.png rename to assets/shadow.png diff --git a/weapon.png b/assets/weapon.png similarity index 100% rename from weapon.png rename to assets/weapon.png diff --git a/explosion.go b/elements/explosion.go similarity index 76% rename from explosion.go rename to elements/explosion.go index 6d9f101..9ce99cb 100644 --- a/explosion.go +++ b/elements/explosion.go @@ -1,8 +1,10 @@ -package main +package elements + +import "mover/gamedata" type Explosion struct { Radius float64 - Origin Coordinates + Origin gamedata.Coordinates cycle int Active bool } @@ -27,7 +29,7 @@ func (e *Explosion) Update() { } -func (e *Explosion) SetOrigin(origin Coordinates) { +func (e *Explosion) SetOrigin(origin gamedata.Coordinates) { e.Origin = origin } diff --git a/hero.go b/elements/hero.go similarity index 69% rename from hero.go rename to elements/hero.go index 7743cfc..82b1819 100644 --- a/hero.go +++ b/elements/hero.go @@ -1,9 +1,9 @@ -package main +package elements import ( - "bytes" "image" - "log" + "mover/assets" + "mover/gamedata" _ "embed" "image/color" @@ -12,15 +12,9 @@ import ( "github.com/hajimehoshi/ebiten/v2" ) -var ( - heroImage *ebiten.Image - heroDeath *ebiten.Image - - //go:embed hero.png - hero_img []byte - - //go:embed herodeath.png - herodeath_img []byte +const ( + MOVER_WIDTH = 48 + MOVER_HEIGHT = 48 ) const ( @@ -34,28 +28,14 @@ const ( type HeroAction uint -func init() { - img, _, err := image.Decode(bytes.NewReader(hero_img)) - if err != nil { - log.Fatal(err) - } - heroImage = ebiten.NewImageFromImage(img) - - img, _, err = image.Decode(bytes.NewReader(herodeath_img)) - if err != nil { - log.Fatal(err) - } - heroDeath = ebiten.NewImageFromImage(img) -} - type Hero struct { Sprite *ebiten.Image Maks *ebiten.Image MaksDest *ebiten.Image Angle float64 - Pos Coordinates - Origin Coordinates - Lastpos Coordinates + Pos gamedata.Coordinates + Origin gamedata.Coordinates + Lastpos gamedata.Coordinates Action HeroAction cycles int Upgrade bool @@ -93,7 +73,7 @@ func (m *Hero) SetAngle(a float64) { m.Angle = a } -func (m *Hero) SetOrigin(coords Coordinates) { +func (m *Hero) SetOrigin(coords gamedata.Coordinates) { m.Origin = coords m.Pos = coords } @@ -117,16 +97,16 @@ func (m *Hero) Draw() { switch m.Action { case HeroActionDefault: - m.Sprite.DrawImage(heroImage.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op) + m.Sprite.DrawImage(assets.ImageBank[assets.HeroNormal].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op) case HeroActionDying: - m.Sprite.DrawImage(heroDeath.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op) + m.Sprite.DrawImage(assets.ImageBank[assets.HeroDying].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op) if m.dyingcount >= 31 { m.cycles = 0 m.Action++ } case HeroActionExploding: - m.Sprite.DrawImage(heroDeath.SubImage(image.Rect(48*3, 0, 48*4, 48)).(*ebiten.Image), op) + m.Sprite.DrawImage(assets.ImageBank[assets.HeroDying].SubImage(image.Rect(48*3, 0, 48*4, 48)).(*ebiten.Image), op) default: } } diff --git a/mover.go b/elements/mover.go similarity index 60% rename from mover.go rename to elements/mover.go index 6cd9fa2..c0bf275 100644 --- a/mover.go +++ b/elements/mover.go @@ -1,9 +1,9 @@ -package main +package elements import ( - "bytes" "image" - "log" + "mover/assets" + "mover/gamedata" _ "embed" "image/color" @@ -12,22 +12,6 @@ import ( "github.com/hajimehoshi/ebiten/v2" ) -var ( - flyeyeImage *ebiten.Image - flyeyeImage2 *ebiten.Image - flyeyeImage3 *ebiten.Image - shadow *ebiten.Image - - //go:embed fly-eye.png - flyeye_img []byte - //go:embed fly-eye2.png - flyeye_img2 []byte - //go:embed fly-eye3.png - flyeye_img3 []byte - //go:embed shadow.png - shadow_img []byte -) - const ( MoverActionDefault = iota MoverActionDamaged @@ -39,39 +23,13 @@ const ( type MoverAction uint -func init() { - img, _, err := image.Decode(bytes.NewReader(flyeye_img)) - if err != nil { - log.Fatal(err) - } - flyeyeImage = ebiten.NewImageFromImage(img) - - img, _, err = image.Decode(bytes.NewReader(flyeye_img2)) - if err != nil { - log.Fatal(err) - } - flyeyeImage2 = ebiten.NewImageFromImage(img) - - img, _, err = image.Decode(bytes.NewReader(flyeye_img3)) - if err != nil { - log.Fatal(err) - } - flyeyeImage3 = ebiten.NewImageFromImage(img) - - img, _, err = image.Decode(bytes.NewReader(shadow_img)) - if err != nil { - log.Fatal(err) - } - shadow = ebiten.NewImageFromImage(img) -} - type Mover struct { Sprite *ebiten.Image Maks *ebiten.Image MaksDest *ebiten.Image Angle float64 - Pos Coordinates - Origin Coordinates + Pos gamedata.Coordinates + Origin gamedata.Coordinates Action MoverAction cycles int rotating bool @@ -106,7 +64,7 @@ func (m *Mover) SetAngle(a float64) { m.Angle = a } -func (m *Mover) SetOrigin(coords Coordinates) { +func (m *Mover) SetOrigin(coords gamedata.Coordinates) { m.Origin = coords m.Pos = coords } @@ -126,18 +84,18 @@ func (m *Mover) Draw() { case MoverActionDefault: op := &ebiten.DrawImageOptions{} op.GeoM.Translate(14, 40) - m.Sprite.DrawImage(shadow, op) - m.Sprite.DrawImage(flyeyeImage.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) + m.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeShadow], op) + m.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeNormal].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) case MoverActionDamaged: op := &ebiten.DrawImageOptions{} op.GeoM.Translate(14, 40) - m.Sprite.DrawImage(shadow, op) - m.Sprite.DrawImage(flyeyeImage2.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) + m.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeShadow], op) + m.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeDamaged].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) case MoverActionDying: if (m.cycles/5)%2 == 0 { - m.MaksDest.DrawImage(flyeyeImage2.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) + m.MaksDest.DrawImage(assets.ImageBank[assets.FlyEyeDamaged].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) op := &ebiten.DrawImageOptions{} op.GeoM.Reset() op.Blend = ebiten.BlendSourceAtop @@ -145,14 +103,14 @@ func (m *Mover) Draw() { m.Sprite.DrawImage(m.MaksDest, nil) } else { - m.Sprite.DrawImage(flyeyeImage2.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) + m.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeDamaged].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) } if m.dyingcount >= 31 { m.cycles = 0 m.SetHit() } case MoverActionExploding: - m.Sprite.DrawImage(flyeyeImage3.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) + m.Sprite.DrawImage(assets.ImageBank[assets.FlyEyeDying].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), nil) if idx == 3 { m.SetHit() } diff --git a/projectile.go b/elements/projectile.go similarity index 65% rename from projectile.go rename to elements/projectile.go index 4e526d4..6d4f253 100644 --- a/projectile.go +++ b/elements/projectile.go @@ -1,14 +1,17 @@ -package main +package elements -import "math" +import ( + "math" + "mover/gamedata" +) type Projectile struct { - Pos Coordinates + Pos gamedata.Coordinates Velocity float64 a float64 } -func NewProjectile(origin Coordinates, angle, velocity float64) *Projectile { +func NewProjectile(origin gamedata.Coordinates, angle, velocity float64) *Projectile { return &Projectile{ Velocity: velocity, a: angle, diff --git a/coordinates.go b/gamedata/coordinates.go similarity index 75% rename from coordinates.go rename to gamedata/coordinates.go index 2265753..208f25e 100644 --- a/coordinates.go +++ b/gamedata/coordinates.go @@ -1,4 +1,4 @@ -package main +package gamedata type Coordinates struct { X float64 diff --git a/gamedata/gameinfo.go b/gamedata/gameinfo.go new file mode 100644 index 0000000..6c6cf52 --- /dev/null +++ b/gamedata/gameinfo.go @@ -0,0 +1,16 @@ +package gamedata + +type Area struct { + Width int + Height int +} + +func (a *Area) Area() int { + return a.Height * a.Width +} + +type GameInfo struct { + Name string + Version string + Dimensions Area +} diff --git a/main.go b/main.go index b0b54eb..f7fa00d 100644 --- a/main.go +++ b/main.go @@ -1,8 +1,11 @@ package main import ( - "fmt" "log" + "mover/assets" + "mover/gamedata" + "mover/screenmanager" + "mover/screens" "github.com/hajimehoshi/ebiten/v2" ) @@ -13,17 +16,23 @@ const ( ) func main() { - ver := "survive v0.10" - - fmt.Println(ver) - - moverGame := &Game{} + //moverGame := &Game{} + moverGame := screenmanager.NewManager() + moverGame.SetDimensions(gamedata.Area{Width: screenWidth, Height: screenHeight}) ebiten.SetWindowSize(screenWidth*1.5, screenHeight*1.5) - ebiten.SetWindowTitle(ver) + ebiten.SetWindowTitle(moverGame.Info.Name + ": v" + moverGame.Info.Version) - if err := ebiten.RunGame(moverGame); err != nil { + loadScreens(&moverGame) + + if err := ebiten.RunGame(&moverGame); err != nil { log.Fatal(err) } } + +func loadScreens(m *screenmanager.Manager) { + assets.LoadImages() + m.AddScene(&screens.Game{}) + m.ResetScenes() +} diff --git a/screenmanager/manager.go b/screenmanager/manager.go new file mode 100644 index 0000000..d2086ef --- /dev/null +++ b/screenmanager/manager.go @@ -0,0 +1,136 @@ +package screenmanager + +import ( + "mover/gamedata" + "mover/screens" + + "github.com/hajimehoshi/ebiten/v2" +) + +const ( + defaultWidth = 1024 + defaultHeight = 768 +) + +type Manager struct { + Info gamedata.GameInfo + currentScene screens.Screen + currentSceneId uint + nextSceneId uint + screens []screens.Screen + internalerr error +} + +// can be used to create default manager instance +func NewManager() Manager { + return Manager{ + Info: gamedata.GameInfo{ + Name: "survive", + Version: "0.12", + Dimensions: gamedata.Area{ + Width: defaultWidth, + Height: defaultHeight, + }, + }, + currentSceneId: 0, + nextSceneId: 1, + internalerr: nil, + } +} + +// ebitengine update proxy on behalf of current scene +func (m *Manager) Update() error { + if m.currentScene == nil { + return nil + } + + err := m.currentScene.Update() + if err != nil { + return err + } + + return m.internalerr +} + +// shutdown application +func (m *Manager) Quit() { + m.internalerr = ebiten.Termination +} + +// calls current scene's draw method if the currentscene is valid +func (m *Manager) Draw(screen *ebiten.Image) { + if m.currentScene != nil { + m.currentScene.Draw(screen) + } +} + +// ebitengine proxy for layout +func (m *Manager) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) { + return m.Info.Dimensions.Width, m.Info.Dimensions.Height +} + +// appends scene to the managed screens +func (m *Manager) AddScene(s screens.Screen) { + setDefaultHandlers(m, s) + s.SetDimensions(m.Info.Dimensions) + m.screens = append(m.screens, s) +} + +// sets the default callback handlers for a given scene within manager +// Default Handling behaviours: +// +// reset: sets (scene, nextscene) to {0, 1} +// 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 screens.Screen) { + s.SetEventHandler(screens.EventReset, func() { m.ResetScenes() }) + s.SetEventHandler(screens.EventCompleted, func() { m.TransitionScene() }) + s.SetEventHandler(screens.EventEndgame, func() { m.Quit() }) +} + +// 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.screens)) { + m.Quit() + } else { + m.currentSceneId = sceneId + m.currentScene = m.screens[sceneId] + m.nextSceneId = m.currentSceneId + 1 + } +} + +// handle scene transition +func (m *Manager) TransitionScene() { + m.SetCurrentScene(m.nextSceneId) +} + +// set new sceneId as the successor +func (m *Manager) SetNextScene(sceneId uint) { + m.nextSceneId = sceneId +} + +// sets sene dimensions +func (m *Manager) SetDimensions(a gamedata.Area) { + m.Info.Dimensions = a +} + +// report number of total screens +func (m *Manager) SceneCount() uint { + return uint(len(m.screens)) +} + +func (m *Manager) GetScene(sceneId uint) screens.Screen { + return m.screens[sceneId] +} diff --git a/game.go b/screens/game.go similarity index 79% rename from game.go rename to screens/game.go index 4b0b57f..85dc746 100644 --- a/game.go +++ b/screens/game.go @@ -1,14 +1,16 @@ -package main +package screens import ( - "bytes" "fmt" "image" "image/color" "log" "math" "math/rand/v2" + "mover/assets" + "mover/elements" "mover/fonts" + "mover/gamedata" _ "embed" @@ -23,19 +25,6 @@ const ( MOVER_HEIGHT = 48 ) -var ( - weaponImage *ebiten.Image - tilesetImage *ebiten.Image - altarImage *ebiten.Image - - //go:embed grasstile.png - tileset_img []byte - //go:embed altar.png - altar_img []byte - //go:embed weapon.png - weapon_img []byte -) - type Game struct { background *ebiten.Image collisionMask *ebiten.Image @@ -43,20 +32,21 @@ type Game struct { heroCollisionMask *ebiten.Image heroCollisionCpy *ebiten.Image - Pos Coordinates + dimensions gamedata.Area + Pos gamedata.Coordinates Paused bool initialized bool gameover bool reset bool runtime float64 - hero *Hero - projectiles map[int]*Projectile - explosion *Explosion + hero *elements.Hero + projectiles map[int]*elements.Projectile + explosion *elements.Explosion score int counter int timer int - targets []*Mover + targets []*elements.Mover gamepadIDsBuf []ebiten.GamepadID gamepadIDs map[ebiten.GamepadID]struct{} @@ -64,43 +54,23 @@ type Game struct { //pressedButtons map[ebiten.GamepadID][]string } -func init() { - img, _, err := image.Decode(bytes.NewReader(tileset_img)) - if err != nil { - log.Fatal(err) - } - tilesetImage = ebiten.NewImageFromImage(img) - - img, _, err = image.Decode(bytes.NewReader(altar_img)) - if err != nil { - log.Fatal(err) - } - altarImage = ebiten.NewImageFromImage(img) - - img, _, err = image.Decode(bytes.NewReader(weapon_img)) - if err != nil { - log.Fatal(err) - } - weaponImage = ebiten.NewImageFromImage(img) -} - func (g *Game) Initialize() { - origin := Coordinates{X: 640 / 2, Y: 480 / 2} + origin := gamedata.Coordinates{X: 640 / 2, Y: 480 / 2} g.ConstructBackground() - g.hero = NewHero() + g.hero = elements.NewHero() g.hero.SetOrigin(origin) g.hero.ToggleRotate() g.gameover = false - g.collisionMask = ebiten.NewImage(screenWidth, screenHeight) - g.projectileMask = ebiten.NewImage(screenWidth, screenHeight) + g.collisionMask = ebiten.NewImage(g.dimensions.Width, g.dimensions.Height) + g.projectileMask = ebiten.NewImage(g.dimensions.Width, g.dimensions.Height) g.heroCollisionMask = ebiten.NewImage(MOVER_WIDTH, MOVER_HEIGHT) g.heroCollisionCpy = ebiten.NewImage(MOVER_WIDTH, MOVER_HEIGHT) - g.explosion = NewExplosion() + g.explosion = elements.NewExplosion() g.explosion.SetOrigin(origin) g.score = 0 g.reset = false @@ -116,7 +86,7 @@ func (g *Game) Initialize() { g.timer = 0 g.runtime = 0. - g.projectiles = make(map[int]*Projectile) + g.projectiles = make(map[int]*elements.Projectile) g.initialized = true g.reset = false @@ -184,7 +154,7 @@ func (g *Game) Draw(screen *ebiten.Image) { op.GeoM.Translate(0, -16) op.GeoM.Rotate(g.hero.Angle) op.GeoM.Translate(g.hero.Pos.X, g.hero.Pos.Y) - screen.DrawImage(weaponImage, op) + screen.DrawImage(assets.ImageBank[assets.Weapon], op) //secondary/upgraded weapon sprite; in testing proves sort of distracting /* @@ -226,7 +196,7 @@ func (g *Game) Draw(screen *ebiten.Image) { } func (g *Game) Layout(width, height int) (int, int) { - return screenWidth, screenHeight + return g.dimensions.Width, g.dimensions.Height } func (g *Game) CleanupTargets() { @@ -234,7 +204,7 @@ func (g *Game) CleanupTargets() { i := 0 for _, target := range g.targets { //moving valid targets to the front of the slice - if target.Action < MoverActionDead { + if target.Action < elements.MoverActionDead { g.targets[i] = target i++ } @@ -282,7 +252,7 @@ func (g *Game) StepGame() { func (g *Game) SpawnEnemies() { f := 40000 / (g.counter + 1) if g.counter%f == 0 { - g.targets = append(g.targets, NewMover()) + g.targets = append(g.targets, elements.NewMover()) x0 := rand.Float64() * 640 y0 := rand.Float64() * 480 @@ -290,15 +260,15 @@ func (g *Game) SpawnEnemies() { switch quadrant { case 0: - g.targets[len(g.targets)-1].SetOrigin(Coordinates{X: x0, Y: -MOVER_HEIGHT}) + g.targets[len(g.targets)-1].SetOrigin(gamedata.Coordinates{X: x0, Y: -MOVER_HEIGHT}) case 1: - g.targets[len(g.targets)-1].SetOrigin(Coordinates{X: x0, Y: screenHeight + MOVER_HEIGHT}) + g.targets[len(g.targets)-1].SetOrigin(gamedata.Coordinates{X: x0, Y: float64(g.dimensions.Height) + MOVER_HEIGHT}) case 2: - g.targets[len(g.targets)-1].SetOrigin(Coordinates{X: -MOVER_WIDTH, Y: y0}) + g.targets[len(g.targets)-1].SetOrigin(gamedata.Coordinates{X: -MOVER_WIDTH, Y: y0}) case 3: - g.targets[len(g.targets)-1].SetOrigin(Coordinates{X: screenWidth + x0, Y: y0}) + g.targets[len(g.targets)-1].SetOrigin(gamedata.Coordinates{X: float64(g.dimensions.Width) + x0, Y: y0}) default: - g.targets[len(g.targets)-1].SetOrigin(Coordinates{X: x0, Y: y0}) + g.targets[len(g.targets)-1].SetOrigin(gamedata.Coordinates{X: x0, Y: y0}) fmt.Println("WTF " + string(quadrant)) } @@ -319,7 +289,8 @@ func (g *Game) HandlePulseWaveUpdate() { dy := target.Pos.Y - g.hero.Pos.Y r := math.Sqrt(dx*dx + dy*dy) - if r >= g.explosion.Radius-5 && r <= g.explosion.Radius+5 && target.Action <= MoverActionDamaged && !target.Touched { + if r >= g.explosion.Radius-5 && r <= g.explosion.Radius+5 && + target.Action <= elements.MoverActionDamaged && !target.Touched { target.ToggleColor() target.Touched = true //target.SetHit() @@ -344,7 +315,9 @@ func (g *Game) UpdateProjectiles() { //compute projectile collisions for _, target := range g.targets { //first, boundary check - if p.Pos.X >= target.Pos.X-MOVER_WIDTH/2 && p.Pos.X <= target.Pos.X+MOVER_WIDTH/2 && p.Pos.Y >= target.Pos.Y-MOVER_HEIGHT/2 && p.Pos.Y <= target.Pos.Y+MOVER_HEIGHT/2 && target.Action == MoverActionDamaged { + if p.Pos.X >= target.Pos.X-MOVER_WIDTH/2 && p.Pos.X <= target.Pos.X+MOVER_WIDTH/2 && + p.Pos.Y >= target.Pos.Y-MOVER_HEIGHT/2 && p.Pos.Y <= target.Pos.Y+MOVER_HEIGHT/2 && + target.Action == elements.MoverActionDamaged { //fmt.Println("potential collision") //the following computes total collisions in the image using a projectile mask that is a duplicate of what is on screen @@ -359,7 +332,7 @@ func (g *Game) UpdateProjectiles() { g.collisionMask.DrawImage(target.Sprite, op) //var pixels []byte = make([]byte, MOVER_WIDTH*MOVER_HEIGHT*4) - var pixels []byte = make([]byte, screenWidth*screenHeight*4) + var pixels []byte = make([]byte, g.dimensions.Width*g.dimensions.Height*4) g.collisionMask.ReadPixels(pixels) for i := 0; i < len(pixels); i = i + 4 { if pixels[i+3] != 0 { @@ -367,7 +340,7 @@ func (g *Game) UpdateProjectiles() { delete(g.projectiles, k) //target.ToggleColor() target.SetHit() - //target.SetOrigin(Coordinates{X: rand.Float64() * 640, Y: rand.Float64() * 480}) + //target.SetOrigin(gamedata.Coordinates{X: rand.Float64() * 640, Y: rand.Float64() * 480}) target.Hit = true break } @@ -380,7 +353,7 @@ func (g *Game) UpdateProjectiles() { func (g *Game) UpdateTargets() { for _, target := range g.targets { - if !target.Hit && g.hero.Action < HeroActionDying { + if !target.Hit && g.hero.Action < elements.HeroActionDying { dx := g.hero.Pos.X - target.Pos.X dy := g.hero.Pos.Y - target.Pos.Y angle := math.Atan2(dy, dx) @@ -392,7 +365,9 @@ func (g *Game) UpdateTargets() { } //compute collision with hero - if g.hero.Pos.X >= target.Pos.X-MOVER_WIDTH/2 && g.hero.Pos.X <= target.Pos.X+MOVER_WIDTH/2 && g.hero.Pos.Y >= target.Pos.Y-MOVER_HEIGHT/2 && g.hero.Pos.Y <= target.Pos.Y+MOVER_HEIGHT/2 && target.Action < MoverActionDying && g.hero.Action < HeroActionDying { + if g.hero.Pos.X >= target.Pos.X-MOVER_WIDTH/2 && g.hero.Pos.X <= target.Pos.X+MOVER_WIDTH/2 && + g.hero.Pos.Y >= target.Pos.Y-MOVER_HEIGHT/2 && g.hero.Pos.Y <= target.Pos.Y+MOVER_HEIGHT/2 && + target.Action < elements.MoverActionDying && g.hero.Action < elements.HeroActionDying { g.heroCollisionMask.Clear() g.heroCollisionMask.DrawImage(g.hero.Sprite, nil) @@ -428,10 +403,10 @@ func (g *Game) ResetTargetTouches() { func (g *Game) AppendProjectiles() { if g.counter%14 == 0 && ebiten.IsStandardGamepadButtonPressed(0, ebiten.StandardGamepadButtonFrontBottomRight) { - g.projectiles[g.counter] = NewProjectile(Coordinates{X: g.hero.Pos.X, Y: g.hero.Pos.Y}, g.hero.Angle, 5.) + g.projectiles[g.counter] = elements.NewProjectile(gamedata.Coordinates{X: g.hero.Pos.X, Y: g.hero.Pos.Y}, g.hero.Angle, 5.) if g.hero.Upgrade { - g.projectiles[g.counter+1] = NewProjectile(Coordinates{X: g.hero.Pos.X, Y: g.hero.Pos.Y}, g.hero.Angle+math.Pi, 5.) + g.projectiles[g.counter+1] = elements.NewProjectile(gamedata.Coordinates{X: g.hero.Pos.X, Y: g.hero.Pos.Y}, g.hero.Angle+math.Pi, 5.) } } } @@ -487,7 +462,7 @@ func (g *Game) UpdateHeroPosition() { } func (g *Game) ConstructBackground() { - g.background = ebiten.NewImage(screenWidth, screenHeight) + g.background = ebiten.NewImage(g.dimensions.Width, g.dimensions.Height) BLOCK_SIZE := 32 for i := 0; i < 640/16; i++ { @@ -505,7 +480,7 @@ func (g *Game) ConstructBackground() { //translate for grid element we're painting op := &ebiten.DrawImageOptions{} op.GeoM.Translate(float64(i)*16, float64(j)*16) - g.background.DrawImage(tilesetImage.SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op) + g.background.DrawImage(assets.ImageBank[assets.TileSet].SubImage(image.Rect(x0, y0, x1, y1)).(*ebiten.Image), op) } } @@ -514,5 +489,13 @@ func (g *Game) ConstructBackground() { op := &ebiten.DrawImageOptions{} op.GeoM.Translate(ax, ay) - g.background.DrawImage(altarImage, op) + g.background.DrawImage(assets.ImageBank[assets.Altar], op) +} + +func (g *Game) SetDimensions(a gamedata.Area) { + g.dimensions = a +} + +func (g *Game) SetEventHandler(e ScreenManagerEvent, f func()) { + } diff --git a/screens/scene.go b/screens/scene.go new file mode 100644 index 0000000..03f165f --- /dev/null +++ b/screens/scene.go @@ -0,0 +1,25 @@ +package screens + +import ( + "mover/gamedata" + + "github.com/hajimehoshi/ebiten/v2" +) + +type ScreenManagerEvent int + +const ( + EventNoop ScreenManagerEvent = iota + EventReset // reset to initial scene + EventLoad // loading elements + EventReload // reload current scene + EventCompleted // current scene has completed + EventEndgame // shutdown all scenes +) + +type Screen interface { + Update() error + Draw(screen *ebiten.Image) + SetEventHandler(e ScreenManagerEvent, f func()) + SetDimensions(a gamedata.Area) +}