mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-20 07:27:19 -05:00
More layout cleanup
This commit is contained in:
parent
6562816710
commit
f485f803c8
@ -1,13 +0,0 @@
|
||||
package Common
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
// SceneInterface defines the function necessary for scene management
|
||||
type SceneInterface interface {
|
||||
Load()
|
||||
Unload()
|
||||
Render(screen *ebiten.Image)
|
||||
Update()
|
||||
}
|
114
Engine.go
114
Engine.go
@ -4,19 +4,21 @@ import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Sound"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
"github.com/essial/OpenDiablo2/MPQ"
|
||||
"github.com/essial/OpenDiablo2/Palettes"
|
||||
"github.com/essial/OpenDiablo2/ResourcePaths"
|
||||
"github.com/essial/OpenDiablo2/Scenes"
|
||||
"github.com/essial/OpenDiablo2/UI"
|
||||
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
"github.com/hajimehoshi/ebiten/audio"
|
||||
"github.com/hajimehoshi/ebiten/audio/wav"
|
||||
)
|
||||
|
||||
// EngineConfig defines the configuration for the engine, loaded from config.json
|
||||
@ -30,16 +32,6 @@ type EngineConfig struct {
|
||||
MpqLoadOrder []string
|
||||
}
|
||||
|
||||
// CursorButton represents a mouse button
|
||||
type CursorButton uint8
|
||||
|
||||
const (
|
||||
// CursorButtonLeft represents the left mouse button
|
||||
CursorButtonLeft CursorButton = 1
|
||||
// CursorButtonRight represents the right mouse button
|
||||
CursorButtonRight CursorButton = 2
|
||||
)
|
||||
|
||||
// Engine is the core OpenDiablo2 engine
|
||||
type Engine struct {
|
||||
Settings EngineConfig // Engine configuration settings from json file
|
||||
@ -47,39 +39,31 @@ type Engine struct {
|
||||
Palettes map[Palettes.Palette]Common.Palette // Color palettes
|
||||
SoundEntries map[string]SoundEntry // Sound configurations
|
||||
LoadingSprite *Common.Sprite // The sprite shown when loading stuff
|
||||
CursorX int // X position of the cursor
|
||||
CursorY int // Y position of the cursor
|
||||
CursorButtons CursorButton // The buttons that are currently being pressed
|
||||
LoadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays.
|
||||
CurrentScene Common.SceneInterface // The current scene being rendered
|
||||
loadingProgress float64 // LoadingProcess is a range between 0.0 and 1.0. If set, loading screen displays.
|
||||
stepLoadingSize float64 // The size for each loading step
|
||||
CurrentScene Scenes.Scene // The current scene being rendered
|
||||
UIManager *UI.Manager // The UI manager
|
||||
nextScene Common.SceneInterface // The next scene to be loaded at the end of the game loop
|
||||
audioContext *audio.Context // The Audio context
|
||||
bgmAudio *audio.Player // The audio player
|
||||
SoundManager *Sound.Manager // The sound manager
|
||||
nextScene Scenes.Scene // The next scene to be loaded at the end of the game loop
|
||||
fullscreenKey bool // When true, the fullscreen toggle is still being pressed
|
||||
}
|
||||
|
||||
// CreateEngine creates and instance of the OpenDiablo2 engine
|
||||
func CreateEngine() *Engine {
|
||||
result := &Engine{
|
||||
LoadingProgress: float64(0.0),
|
||||
CurrentScene: nil,
|
||||
nextScene: nil,
|
||||
CurrentScene: nil,
|
||||
nextScene: nil,
|
||||
}
|
||||
result.loadConfigurationFile()
|
||||
result.mapMpqFiles()
|
||||
result.loadPalettes()
|
||||
result.loadSoundEntries()
|
||||
result.SoundManager = Sound.CreateManager(result)
|
||||
result.UIManager = UI.CreateManager(result)
|
||||
audioContext, err := audio.NewContext(22050)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
result.audioContext = audioContext
|
||||
result.LoadingSprite = result.LoadSprite(ResourcePaths.LoadingScreen, Palettes.Loading)
|
||||
loadingSpriteSizeX, loadingSpriteSizeY := result.LoadingSprite.GetSize()
|
||||
result.LoadingSprite.MoveTo(int(400-(loadingSpriteSizeX/2)), int(300+(loadingSpriteSizeY/2)))
|
||||
result.SetNextScene(CreateMainMenu(result))
|
||||
result.SetNextScene(Scenes.CreateMainMenu(result, result.UIManager, result.SoundManager))
|
||||
return result
|
||||
}
|
||||
|
||||
@ -142,7 +126,7 @@ func (v *Engine) LoadFile(fileName string) []byte {
|
||||
|
||||
// IsLoading returns true if the engine is currently in a loading state
|
||||
func (v *Engine) IsLoading() bool {
|
||||
return v.LoadingProgress < 1.0
|
||||
return v.loadingProgress < 1.0
|
||||
}
|
||||
|
||||
func (v *Engine) loadPalettes() {
|
||||
@ -190,12 +174,16 @@ func (v *Engine) updateScene() {
|
||||
v.CurrentScene = v.nextScene
|
||||
v.nextScene = nil
|
||||
v.UIManager.Reset()
|
||||
v.CurrentScene.Load()
|
||||
}
|
||||
|
||||
// CursorButtonPressed determines if the specified button has been pressed
|
||||
func (v *Engine) CursorButtonPressed(button CursorButton) bool {
|
||||
return v.CursorButtons&button > 0
|
||||
thingsToLoad := v.CurrentScene.Load()
|
||||
v.SetLoadingStepSize(1.0 / float64(len(thingsToLoad)))
|
||||
v.ResetLoading()
|
||||
go func() {
|
||||
for _, f := range thingsToLoad {
|
||||
f()
|
||||
v.StepLoading()
|
||||
}
|
||||
v.FinishLoading()
|
||||
}()
|
||||
}
|
||||
|
||||
// Update updates the internal state of the engine
|
||||
@ -217,22 +205,15 @@ func (v *Engine) Update() {
|
||||
if v.IsLoading() {
|
||||
return
|
||||
}
|
||||
v.CursorButtons = 0
|
||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
v.CursorButtons |= CursorButtonLeft
|
||||
}
|
||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonRight) {
|
||||
v.CursorButtons |= CursorButtonRight
|
||||
}
|
||||
|
||||
v.CurrentScene.Update()
|
||||
v.UIManager.Update()
|
||||
}
|
||||
|
||||
// Draw draws the game
|
||||
func (v *Engine) Draw(screen *ebiten.Image) {
|
||||
v.CursorX, v.CursorY = ebiten.CursorPosition()
|
||||
if v.LoadingProgress < 1.0 {
|
||||
v.LoadingSprite.Frame = uint8(Common.Max(0, Common.Min(uint32(len(v.LoadingSprite.Frames)-1), uint32(float64(len(v.LoadingSprite.Frames)-1)*v.LoadingProgress))))
|
||||
if v.loadingProgress < 1.0 {
|
||||
v.LoadingSprite.Frame = uint8(Common.Max(0, Common.Min(uint32(len(v.LoadingSprite.Frames)-1), uint32(float64(len(v.LoadingSprite.Frames)-1)*v.loadingProgress))))
|
||||
v.LoadingSprite.Draw(screen)
|
||||
} else {
|
||||
if v.CurrentScene == nil {
|
||||
@ -244,29 +225,26 @@ func (v *Engine) Draw(screen *ebiten.Image) {
|
||||
}
|
||||
|
||||
// SetNextScene tells the engine what scene to load on the next update cycle
|
||||
func (v *Engine) SetNextScene(nextScene Common.SceneInterface) {
|
||||
func (v *Engine) SetNextScene(nextScene Scenes.Scene) {
|
||||
v.nextScene = nextScene
|
||||
}
|
||||
|
||||
// PlayBGM plays an infinitely looping background track
|
||||
func (v *Engine) PlayBGM(song string) {
|
||||
go func() {
|
||||
if v.bgmAudio != nil {
|
||||
v.bgmAudio.Close()
|
||||
}
|
||||
audioData := v.LoadFile(song)
|
||||
d, err := wav.Decode(v.audioContext, audio.BytesReadSeekCloser(audioData))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
s := audio.NewInfiniteLoop(d, int64(len(audioData)))
|
||||
|
||||
v.bgmAudio, err = audio.NewPlayer(v.audioContext, s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Play the infinite-length stream. This never ends.
|
||||
v.bgmAudio.Rewind()
|
||||
v.bgmAudio.Play()
|
||||
}()
|
||||
// SetLoadingStepSize sets the size of the loading step
|
||||
func (v *Engine) SetLoadingStepSize(size float64) {
|
||||
v.stepLoadingSize = size
|
||||
}
|
||||
|
||||
// ResetLoading resets the loading progress
|
||||
func (v *Engine) ResetLoading() {
|
||||
v.loadingProgress = 0.0
|
||||
}
|
||||
|
||||
// StepLoading increments the loading progress
|
||||
func (v *Engine) StepLoading() {
|
||||
v.loadingProgress = math.Min(1.0, v.loadingProgress+v.stepLoadingSize)
|
||||
}
|
||||
|
||||
// FinishLoading terminates the loading phase
|
||||
func (v *Engine) FinishLoading() {
|
||||
v.loadingProgress = 1.0
|
||||
}
|
||||
|
13
Scenes/Scene.go
Normal file
13
Scenes/Scene.go
Normal file
@ -0,0 +1,13 @@
|
||||
package Scenes
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
// Scene defines the function necessary for scene management
|
||||
type Scene interface {
|
||||
Load() []func()
|
||||
Unload()
|
||||
Render(screen *ebiten.Image)
|
||||
Update()
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package OpenDiablo2
|
||||
package Scenes
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
"github.com/essial/OpenDiablo2/Palettes"
|
||||
"github.com/essial/OpenDiablo2/Sound"
|
||||
"github.com/essial/OpenDiablo2/UI"
|
||||
|
||||
"github.com/essial/OpenDiablo2/ResourcePaths"
|
||||
@ -13,7 +14,9 @@ import (
|
||||
|
||||
// MainMenu represents the main menu
|
||||
type MainMenu struct {
|
||||
engine *Engine
|
||||
uiManager *UI.Manager
|
||||
soundManager *Sound.Manager
|
||||
fileProvider Common.FileProvider
|
||||
trademarkBackground *Common.Sprite
|
||||
background *Common.Sprite
|
||||
diabloLogoLeft *Common.Sprite
|
||||
@ -27,72 +30,63 @@ type MainMenu struct {
|
||||
}
|
||||
|
||||
// CreateMainMenu creates an instance of MainMenu
|
||||
func CreateMainMenu(engine *Engine) *MainMenu {
|
||||
func CreateMainMenu(fileProvider Common.FileProvider, uiManager *UI.Manager, soundManager *Sound.Manager) *MainMenu {
|
||||
result := &MainMenu{
|
||||
engine: engine,
|
||||
fileProvider: fileProvider,
|
||||
uiManager: uiManager,
|
||||
soundManager: soundManager,
|
||||
showTrademarkScreen: true,
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Load is called to load the resources for the main menu
|
||||
func (v *MainMenu) Load() {
|
||||
v.engine.PlayBGM(ResourcePaths.BGMTitle)
|
||||
go func() {
|
||||
loadStep := 1.0 / 8.0
|
||||
v.engine.LoadingProgress = 0
|
||||
{
|
||||
v.copyrightLabel = UI.CreateLabel(v.engine, ResourcePaths.FontFormal12, Palettes.Static)
|
||||
func (v *MainMenu) Load() []func() {
|
||||
v.soundManager.PlayBGM(ResourcePaths.BGMTitle)
|
||||
return []func(){
|
||||
func() {
|
||||
v.copyrightLabel = UI.CreateLabel(v.fileProvider, ResourcePaths.FontFormal12, Palettes.Static)
|
||||
v.copyrightLabel.Alignment = UI.LabelAlignCenter
|
||||
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
|
||||
v.copyrightLabel.ColorMod = color.RGBA{188, 168, 140, 255}
|
||||
v.copyrightLabel.MoveTo(400, 500)
|
||||
v.engine.LoadingProgress += loadStep
|
||||
}
|
||||
{
|
||||
v.copyrightLabel2 = UI.CreateLabel(v.engine, ResourcePaths.FontFormal12, Palettes.Static)
|
||||
},
|
||||
func() {
|
||||
v.copyrightLabel2 = UI.CreateLabel(v.fileProvider, ResourcePaths.FontFormal12, Palettes.Static)
|
||||
v.copyrightLabel2.Alignment = UI.LabelAlignCenter
|
||||
v.copyrightLabel2.SetText("All Rights Reserved.")
|
||||
v.copyrightLabel2.ColorMod = color.RGBA{188, 168, 140, 255}
|
||||
v.copyrightLabel2.MoveTo(400, 525)
|
||||
v.engine.LoadingProgress += loadStep
|
||||
}
|
||||
{
|
||||
v.background = v.engine.LoadSprite(ResourcePaths.GameSelectScreen, Palettes.Sky)
|
||||
},
|
||||
func() {
|
||||
v.background = v.fileProvider.LoadSprite(ResourcePaths.GameSelectScreen, Palettes.Sky)
|
||||
v.background.MoveTo(0, 0)
|
||||
v.engine.LoadingProgress += loadStep
|
||||
}
|
||||
{
|
||||
v.trademarkBackground = v.engine.LoadSprite(ResourcePaths.TrademarkScreen, Palettes.Sky)
|
||||
},
|
||||
func() {
|
||||
v.trademarkBackground = v.fileProvider.LoadSprite(ResourcePaths.TrademarkScreen, Palettes.Sky)
|
||||
v.trademarkBackground.MoveTo(0, 0)
|
||||
v.engine.LoadingProgress += loadStep
|
||||
}
|
||||
{
|
||||
v.diabloLogoLeft = v.engine.LoadSprite(ResourcePaths.Diablo2LogoFireLeft, Palettes.Units)
|
||||
},
|
||||
func() {
|
||||
v.diabloLogoLeft = v.fileProvider.LoadSprite(ResourcePaths.Diablo2LogoFireLeft, Palettes.Units)
|
||||
v.diabloLogoLeft.Blend = true
|
||||
v.diabloLogoLeft.Animate = true
|
||||
v.diabloLogoLeft.MoveTo(400, 120)
|
||||
v.engine.LoadingProgress += loadStep
|
||||
}
|
||||
{
|
||||
v.diabloLogoRight = v.engine.LoadSprite(ResourcePaths.Diablo2LogoFireRight, Palettes.Units)
|
||||
},
|
||||
func() {
|
||||
v.diabloLogoRight = v.fileProvider.LoadSprite(ResourcePaths.Diablo2LogoFireRight, Palettes.Units)
|
||||
v.diabloLogoRight.Blend = true
|
||||
v.diabloLogoRight.Animate = true
|
||||
v.diabloLogoRight.MoveTo(400, 120)
|
||||
v.engine.LoadingProgress += loadStep
|
||||
}
|
||||
{
|
||||
v.diabloLogoLeftBack = v.engine.LoadSprite(ResourcePaths.Diablo2LogoBlackLeft, Palettes.Units)
|
||||
},
|
||||
func() {
|
||||
v.diabloLogoLeftBack = v.fileProvider.LoadSprite(ResourcePaths.Diablo2LogoBlackLeft, Palettes.Units)
|
||||
v.diabloLogoLeftBack.MoveTo(400, 120)
|
||||
v.engine.LoadingProgress += loadStep
|
||||
}
|
||||
{
|
||||
v.diabloLogoRightBack = v.engine.LoadSprite(ResourcePaths.Diablo2LogoBlackRight, Palettes.Units)
|
||||
},
|
||||
func() {
|
||||
v.diabloLogoRightBack = v.fileProvider.LoadSprite(ResourcePaths.Diablo2LogoBlackRight, Palettes.Units)
|
||||
v.diabloLogoRightBack.MoveTo(400, 120)
|
||||
v.engine.LoadingProgress = 1.0
|
||||
}
|
||||
}()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Unload unloads the data for the main menu
|
||||
@ -123,7 +117,7 @@ func (v *MainMenu) Render(screen *ebiten.Image) {
|
||||
// Update runs the update logic on the main menu
|
||||
func (v *MainMenu) Update() {
|
||||
if v.showTrademarkScreen {
|
||||
if v.engine.CursorButtonPressed(CursorButtonLeft) {
|
||||
if v.uiManager.CursorButtonPressed(UI.CursorButtonLeft) {
|
||||
v.leftButtonHeld = true
|
||||
v.showTrademarkScreen = false
|
||||
}
|
52
Sound/AudioProvider.go
Normal file
52
Sound/AudioProvider.go
Normal file
@ -0,0 +1,52 @@
|
||||
package Sound
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
"github.com/hajimehoshi/ebiten/audio"
|
||||
"github.com/hajimehoshi/ebiten/audio/wav"
|
||||
)
|
||||
|
||||
// Manager provides sound
|
||||
type Manager struct {
|
||||
fileProvider Common.FileProvider
|
||||
audioContext *audio.Context // The Audio context
|
||||
bgmAudio *audio.Player // The audio player
|
||||
}
|
||||
|
||||
// CreateManager creates a sound provider
|
||||
func CreateManager(fileProvider Common.FileProvider) *Manager {
|
||||
result := &Manager{
|
||||
fileProvider: fileProvider,
|
||||
}
|
||||
audioContext, err := audio.NewContext(22050)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
result.audioContext = audioContext
|
||||
return result
|
||||
}
|
||||
|
||||
// PlayBGM plays an infinitely looping background track
|
||||
func (v *Manager) PlayBGM(song string) {
|
||||
go func() {
|
||||
if v.bgmAudio != nil {
|
||||
v.bgmAudio.Close()
|
||||
}
|
||||
audioData := v.fileProvider.LoadFile(song)
|
||||
d, err := wav.Decode(v.audioContext, audio.BytesReadSeekCloser(audioData))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
s := audio.NewInfiniteLoop(d, int64(len(audioData)))
|
||||
|
||||
v.bgmAudio, err = audio.NewPlayer(v.audioContext, s)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// Play the infinite-length stream. This never ends.
|
||||
v.bgmAudio.Rewind()
|
||||
v.bgmAudio.Play()
|
||||
}()
|
||||
}
|
@ -7,10 +7,23 @@ import (
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
// CursorButton represents a mouse button
|
||||
type CursorButton uint8
|
||||
|
||||
const (
|
||||
// CursorButtonLeft represents the left mouse button
|
||||
CursorButtonLeft CursorButton = 1
|
||||
// CursorButtonRight represents the right mouse button
|
||||
CursorButtonRight CursorButton = 2
|
||||
)
|
||||
|
||||
// Manager represents the UI manager
|
||||
type Manager struct {
|
||||
widgets []*Widget
|
||||
cursorSprite *Common.Sprite
|
||||
widgets []*Widget
|
||||
cursorSprite *Common.Sprite
|
||||
cursorButtons CursorButton
|
||||
CursorX int
|
||||
CursorY int
|
||||
}
|
||||
|
||||
// CreateManager creates a new instance of a UI manager
|
||||
@ -41,5 +54,17 @@ func (v *Manager) Draw(screen *ebiten.Image) {
|
||||
|
||||
// Update updates all of the UI elements
|
||||
func (v *Manager) Update() {
|
||||
|
||||
v.cursorButtons = 0
|
||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonLeft) {
|
||||
v.cursorButtons |= CursorButtonLeft
|
||||
}
|
||||
if ebiten.IsMouseButtonPressed(ebiten.MouseButtonRight) {
|
||||
v.cursorButtons |= CursorButtonRight
|
||||
}
|
||||
v.CursorX, v.CursorY = ebiten.CursorPosition()
|
||||
}
|
||||
|
||||
// CursorButtonPressed determines if the specified button has been pressed
|
||||
func (v *Manager) CursorButtonPressed(button CursorButton) bool {
|
||||
return v.cursorButtons&button > 0
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user