mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-03 23:26:41 -05:00
Adding input system, mouse cursor scene, interactive component
* added `d2common/d2input`, copied input vector logic from hellspawner * added an `InteractiveComponent` which contains input vector, enable flag, and callback function * Added an InputSystem which handles input logic and iterates over entities with interactive components * added a mouse cursor scene for rendering the mouse cursor * made the trademark sprite disappear when left mouse is clicked * various other small bugfixes in scene systems
This commit is contained in:
parent
3f5d2c0938
commit
e6d418fdb2
93
d2common/d2input/input_vector.go
Normal file
93
d2common/d2input/input_vector.go
Normal file
@ -0,0 +1,93 @@
|
||||
package d2input
|
||||
|
||||
import "github.com/gravestench/akara"
|
||||
|
||||
func NewInputVector() *InputVector {
|
||||
v := &InputVector{
|
||||
KeyVector: akara.NewBitSet(),
|
||||
ModifierVector: akara.NewBitSet(),
|
||||
MouseButtonVector: akara.NewBitSet(),
|
||||
}
|
||||
|
||||
return v.Clear()
|
||||
}
|
||||
|
||||
type InputVector struct {
|
||||
KeyVector *akara.BitSet
|
||||
ModifierVector *akara.BitSet
|
||||
MouseButtonVector *akara.BitSet
|
||||
}
|
||||
|
||||
func (iv *InputVector) SetKey(key Key) *InputVector {
|
||||
return iv.SetKeys([]Key{key})
|
||||
}
|
||||
|
||||
func (iv *InputVector) SetKeys(keys []Key) *InputVector {
|
||||
if len(keys) == 0 {
|
||||
return iv
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
iv.KeyVector.Set(int(key), true)
|
||||
}
|
||||
|
||||
return iv
|
||||
}
|
||||
|
||||
func (iv *InputVector) SetModifier(mod Modifier) *InputVector {
|
||||
return iv.SetModifiers([]Modifier{mod})
|
||||
}
|
||||
|
||||
func (iv *InputVector) SetModifiers(mods []Modifier) *InputVector {
|
||||
if len(mods) == 0 {
|
||||
return iv
|
||||
}
|
||||
|
||||
for _, key := range mods {
|
||||
iv.ModifierVector.Set(int(key), true)
|
||||
}
|
||||
|
||||
return iv
|
||||
}
|
||||
|
||||
func (iv *InputVector) SetMouseButton(button MouseButton) *InputVector {
|
||||
return iv.SetMouseButtons([]MouseButton{button})
|
||||
}
|
||||
|
||||
func (iv *InputVector) SetMouseButtons(buttons []MouseButton) *InputVector {
|
||||
if len(buttons) == 0 {
|
||||
return iv
|
||||
}
|
||||
|
||||
for _, key := range buttons {
|
||||
iv.MouseButtonVector.Set(int(key), true)
|
||||
}
|
||||
|
||||
return iv
|
||||
}
|
||||
|
||||
func (iv *InputVector) Contains(other *InputVector) bool {
|
||||
keys := iv.KeyVector.ContainsAll(other.KeyVector)
|
||||
buttons := iv.MouseButtonVector.ContainsAll(other.MouseButtonVector)
|
||||
|
||||
// We do Equals here, because we dont want CTRL+X and CTRL+ALT+X to fire at the same time
|
||||
mods := iv.ModifierVector.Equals(other.ModifierVector)
|
||||
|
||||
return keys && mods && buttons
|
||||
}
|
||||
|
||||
func (iv *InputVector) Intersects(other *InputVector) bool {
|
||||
keys := iv.KeyVector.Intersects(other.KeyVector)
|
||||
mods := iv.ModifierVector.Intersects(other.ModifierVector)
|
||||
buttons := iv.MouseButtonVector.Intersects(other.MouseButtonVector)
|
||||
|
||||
return keys || mods || buttons
|
||||
}
|
||||
|
||||
func (iv *InputVector) Clear() *InputVector {
|
||||
iv.KeyVector.Clear()
|
||||
iv.ModifierVector.Clear()
|
||||
iv.MouseButtonVector.Clear()
|
||||
|
||||
return iv
|
||||
}
|
105
d2common/d2input/keys.go
Normal file
105
d2common/d2input/keys.go
Normal file
@ -0,0 +1,105 @@
|
||||
package d2input
|
||||
|
||||
import "github.com/hajimehoshi/ebiten/v2"
|
||||
|
||||
type Key = int
|
||||
|
||||
const (
|
||||
Key0 = Key(ebiten.Key0)
|
||||
Key1 = Key(ebiten.Key1)
|
||||
Key2 = Key(ebiten.Key2)
|
||||
Key3 = Key(ebiten.Key3)
|
||||
Key4 = Key(ebiten.Key4)
|
||||
Key5 = Key(ebiten.Key5)
|
||||
Key6 = Key(ebiten.Key6)
|
||||
Key7 = Key(ebiten.Key7)
|
||||
Key8 = Key(ebiten.Key8)
|
||||
Key9 = Key(ebiten.Key9)
|
||||
KeyA = Key(ebiten.KeyA)
|
||||
KeyB = Key(ebiten.KeyB)
|
||||
KeyC = Key(ebiten.KeyC)
|
||||
KeyD = Key(ebiten.KeyD)
|
||||
KeyE = Key(ebiten.KeyE)
|
||||
KeyF = Key(ebiten.KeyF)
|
||||
KeyG = Key(ebiten.KeyG)
|
||||
KeyH = Key(ebiten.KeyH)
|
||||
KeyI = Key(ebiten.KeyI)
|
||||
KeyJ = Key(ebiten.KeyJ)
|
||||
KeyK = Key(ebiten.KeyK)
|
||||
KeyL = Key(ebiten.KeyL)
|
||||
KeyM = Key(ebiten.KeyM)
|
||||
KeyN = Key(ebiten.KeyN)
|
||||
KeyO = Key(ebiten.KeyO)
|
||||
KeyP = Key(ebiten.KeyP)
|
||||
KeyQ = Key(ebiten.KeyQ)
|
||||
KeyR = Key(ebiten.KeyR)
|
||||
KeyS = Key(ebiten.KeyS)
|
||||
KeyT = Key(ebiten.KeyT)
|
||||
KeyU = Key(ebiten.KeyU)
|
||||
KeyV = Key(ebiten.KeyV)
|
||||
KeyW = Key(ebiten.KeyW)
|
||||
KeyX = Key(ebiten.KeyX)
|
||||
KeyY = Key(ebiten.KeyY)
|
||||
KeyZ = Key(ebiten.KeyZ)
|
||||
KeyApostrophe = Key(ebiten.KeyApostrophe)
|
||||
KeyBackslash = Key(ebiten.KeyBackslash)
|
||||
KeyBackspace = Key(ebiten.KeyBackspace)
|
||||
KeyCapsLock = Key(ebiten.KeyCapsLock)
|
||||
KeyComma = Key(ebiten.KeyComma)
|
||||
KeyDelete = Key(ebiten.KeyDelete)
|
||||
KeyDown = Key(ebiten.KeyDown)
|
||||
KeyEnd = Key(ebiten.KeyEnd)
|
||||
KeyEnter = Key(ebiten.KeyEnter)
|
||||
KeyEqual = Key(ebiten.KeyEqual)
|
||||
KeyEscape = Key(ebiten.KeyEscape)
|
||||
KeyF1 = Key(ebiten.KeyF1)
|
||||
KeyF2 = Key(ebiten.KeyF2)
|
||||
KeyF3 = Key(ebiten.KeyF3)
|
||||
KeyF4 = Key(ebiten.KeyF4)
|
||||
KeyF5 = Key(ebiten.KeyF5)
|
||||
KeyF6 = Key(ebiten.KeyF6)
|
||||
KeyF7 = Key(ebiten.KeyF7)
|
||||
KeyF8 = Key(ebiten.KeyF8)
|
||||
KeyF9 = Key(ebiten.KeyF9)
|
||||
KeyF10 = Key(ebiten.KeyF10)
|
||||
KeyF11 = Key(ebiten.KeyF11)
|
||||
KeyF12 = Key(ebiten.KeyF12)
|
||||
KeyGraveAccent = Key(ebiten.KeyGraveAccent)
|
||||
KeyHome = Key(ebiten.KeyHome)
|
||||
KeyInsert = Key(ebiten.KeyInsert)
|
||||
KeyKP0 = Key(ebiten.KeyKP0)
|
||||
KeyKP1 = Key(ebiten.KeyKP1)
|
||||
KeyKP2 = Key(ebiten.KeyKP2)
|
||||
KeyKP3 = Key(ebiten.KeyKP3)
|
||||
KeyKP4 = Key(ebiten.KeyKP4)
|
||||
KeyKP5 = Key(ebiten.KeyKP5)
|
||||
KeyKP6 = Key(ebiten.KeyKP6)
|
||||
KeyKP7 = Key(ebiten.KeyKP7)
|
||||
KeyKP8 = Key(ebiten.KeyKP8)
|
||||
KeyKP9 = Key(ebiten.KeyKP9)
|
||||
KeyKPAdd = Key(ebiten.KeyKPAdd)
|
||||
KeyKPDecimal = Key(ebiten.KeyKPDecimal)
|
||||
KeyKPDivide = Key(ebiten.KeyKPDivide)
|
||||
KeyKPEnter = Key(ebiten.KeyKPEnter)
|
||||
KeyKPEqual = Key(ebiten.KeyKPEqual)
|
||||
KeyKPMultiply = Key(ebiten.KeyKPMultiply)
|
||||
KeyKPSubtract = Key(ebiten.KeyKPSubtract)
|
||||
KeyLeft = Key(ebiten.KeyLeft)
|
||||
KeyLeftBracket = Key(ebiten.KeyLeftBracket)
|
||||
KeyMenu = Key(ebiten.KeyMenu)
|
||||
KeyMinus = Key(ebiten.KeyMinus)
|
||||
KeyNumLock = Key(ebiten.KeyNumLock)
|
||||
KeyPageDown = Key(ebiten.KeyPageDown)
|
||||
KeyPageUp = Key(ebiten.KeyPageUp)
|
||||
KeyPause = Key(ebiten.KeyPause)
|
||||
KeyPeriod = Key(ebiten.KeyPeriod)
|
||||
KeyPrintScreen = Key(ebiten.KeyPrintScreen)
|
||||
KeyRight = Key(ebiten.KeyRight)
|
||||
KeyRightBracket = Key(ebiten.KeyRightBracket)
|
||||
KeyScrollLock = Key(ebiten.KeyScrollLock)
|
||||
KeySemicolon = Key(ebiten.KeySemicolon)
|
||||
KeySlash = Key(ebiten.KeySlash)
|
||||
KeySpace = Key(ebiten.KeySpace)
|
||||
KeyTab = Key(ebiten.KeyTab)
|
||||
KeyUp = Key(ebiten.KeyUp)
|
||||
)
|
11
d2common/d2input/modifiers.go
Normal file
11
d2common/d2input/modifiers.go
Normal file
@ -0,0 +1,11 @@
|
||||
package d2input
|
||||
|
||||
import "github.com/hajimehoshi/ebiten/v2"
|
||||
|
||||
type Modifier = int
|
||||
|
||||
const (
|
||||
ModAlt = Modifier(ebiten.KeyAlt)
|
||||
ModControl = Modifier(ebiten.KeyControl)
|
||||
ModShift = Modifier(ebiten.KeyShift)
|
||||
)
|
11
d2common/d2input/mouse_buttons.go
Normal file
11
d2common/d2input/mouse_buttons.go
Normal file
@ -0,0 +1,11 @@
|
||||
package d2input
|
||||
|
||||
import "github.com/hajimehoshi/ebiten/v2"
|
||||
|
||||
type MouseButton = int
|
||||
|
||||
const (
|
||||
MouseButtonLeft = MouseButton(ebiten.MouseButtonLeft)
|
||||
MouseButtonRight = MouseButton(ebiten.MouseButtonRight)
|
||||
MouseButtonMiddle = MouseButton(ebiten.MouseButtonMiddle)
|
||||
)
|
51
d2core/d2components/interactive.go
Normal file
51
d2core/d2components/interactive.go
Normal file
@ -0,0 +1,51 @@
|
||||
package d2components
|
||||
|
||||
import (
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2input"
|
||||
)
|
||||
|
||||
// static check that Interactive implements Component
|
||||
var _ akara.Component = &Interactive{}
|
||||
|
||||
func noop() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Interactive is used to flag file entities with a file type
|
||||
type Interactive struct {
|
||||
Enabled bool
|
||||
*d2input.InputVector
|
||||
Callback func() (preventPropagation bool)
|
||||
}
|
||||
|
||||
// New returns a Interactive component. By default, it contains a nil instance.
|
||||
func (*Interactive) New() akara.Component {
|
||||
return &Interactive{
|
||||
Enabled: true,
|
||||
InputVector: d2input.NewInputVector(),
|
||||
Callback: noop,
|
||||
}
|
||||
}
|
||||
|
||||
// InteractiveFactory is a wrapper for the generic component factory that returns Interactive component instances.
|
||||
// This can be embedded inside of a system to give them the methods for adding, retrieving, and removing a Interactive.
|
||||
type InteractiveFactory struct {
|
||||
Interactive *akara.ComponentFactory
|
||||
}
|
||||
|
||||
// AddInteractive adds a Interactive component to the given entity and returns it
|
||||
func (m *InteractiveFactory) AddInteractive(id akara.EID) *Interactive {
|
||||
return m.Interactive.Add(id).(*Interactive)
|
||||
}
|
||||
|
||||
// GetInteractive returns the Interactive component for the given entity, and a bool for whether or not it exists
|
||||
func (m *InteractiveFactory) GetInteractive(id akara.EID) (*Interactive, bool) {
|
||||
component, found := m.Interactive.Get(id)
|
||||
if !found {
|
||||
return nil, found
|
||||
}
|
||||
|
||||
return component.(*Interactive), found
|
||||
}
|
@ -46,6 +46,9 @@ func (m *GameClientBootstrapSystem) injectSystems() {
|
||||
m.Info("injecting render system")
|
||||
m.AddSystem(&RenderSystem{})
|
||||
|
||||
m.Info("injecting input system")
|
||||
m.AddSystem(&InputSystem{})
|
||||
|
||||
m.Info("injecting update counter system")
|
||||
m.AddSystem(&UpdateCounter{})
|
||||
|
||||
@ -54,6 +57,9 @@ func (m *GameClientBootstrapSystem) injectSystems() {
|
||||
|
||||
m.Info("injecting main menu scene")
|
||||
m.AddSystem(NewMainMenuScene())
|
||||
|
||||
m.Info("injecting mouse cursor scene")
|
||||
m.AddSystem(NewMouseCursorScene())
|
||||
}
|
||||
|
||||
// Update does nothing, but exists to satisfy the `akara.System` interface
|
||||
|
151
d2core/d2systems/input_system.go
Normal file
151
d2core/d2systems/input_system.go
Normal file
@ -0,0 +1,151 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2input"
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2components"
|
||||
"github.com/gravestench/akara"
|
||||
)
|
||||
|
||||
const (
|
||||
logPrefixInputSystem = "Input System"
|
||||
)
|
||||
|
||||
// static check that InputSystem implements the System interface
|
||||
var _ akara.System = &InputSystem{}
|
||||
|
||||
// InputSystem is responsible for handling interactive entities
|
||||
type InputSystem struct {
|
||||
akara.BaseSubscriberSystem
|
||||
*d2util.Logger
|
||||
renderer d2interface.Renderer
|
||||
configs *akara.Subscription
|
||||
interactives *akara.Subscription
|
||||
d2components.GameConfigFactory
|
||||
d2components.InteractiveFactory
|
||||
inputState *d2input.InputVector
|
||||
}
|
||||
|
||||
// Init initializes the system with the given world, injecting the necessary components
|
||||
func (m *InputSystem) Init(world *akara.World) {
|
||||
m.World = world
|
||||
|
||||
m.setupLogger()
|
||||
|
||||
m.Info("initializing ...")
|
||||
|
||||
m.setupFactories()
|
||||
m.setupSubscriptions()
|
||||
|
||||
m.inputState = d2input.NewInputVector()
|
||||
}
|
||||
|
||||
func (m *InputSystem) setupLogger() {
|
||||
m.Logger = d2util.NewLogger()
|
||||
m.SetPrefix(logPrefixInputSystem)
|
||||
}
|
||||
|
||||
func (m *InputSystem) setupFactories() {
|
||||
m.Info("setting up component factories")
|
||||
|
||||
gameConfigID := m.RegisterComponent(&d2components.GameConfig{})
|
||||
interactiveID := m.RegisterComponent(&d2components.Interactive{})
|
||||
|
||||
m.GameConfig = m.GetComponentFactory(gameConfigID)
|
||||
m.Interactive = m.GetComponentFactory(interactiveID)
|
||||
}
|
||||
|
||||
func (m *InputSystem) setupSubscriptions() {
|
||||
m.Info("setting up component subscriptions")
|
||||
|
||||
interactives := m.NewComponentFilter().
|
||||
Require(&d2components.Interactive{}).
|
||||
Build()
|
||||
|
||||
gameConfigs := m.NewComponentFilter().
|
||||
Require(&d2components.GameConfig{}).
|
||||
Build()
|
||||
|
||||
m.interactives = m.AddSubscription(interactives)
|
||||
m.configs = m.AddSubscription(gameConfigs)
|
||||
}
|
||||
|
||||
// Update will iterate over interactive entities
|
||||
func (m *InputSystem) Update() {
|
||||
m.updateInputState()
|
||||
|
||||
for _, id := range m.interactives.GetEntities() {
|
||||
preventPropagation := m.applyInputState(id)
|
||||
if preventPropagation {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *InputSystem) updateInputState() {
|
||||
var keysToCheck = []d2input.Key{
|
||||
d2input.Key0, d2input.Key1, d2input.Key2, d2input.Key3, d2input.Key4, d2input.Key5, d2input.Key6,
|
||||
d2input.Key7, d2input.Key8, d2input.Key9, d2input.KeyA, d2input.KeyB, d2input.KeyC, d2input.KeyD,
|
||||
d2input.KeyE, d2input.KeyF, d2input.KeyG, d2input.KeyH, d2input.KeyI, d2input.KeyJ, d2input.KeyK,
|
||||
d2input.KeyL, d2input.KeyM, d2input.KeyN, d2input.KeyO, d2input.KeyP, d2input.KeyQ, d2input.KeyR,
|
||||
d2input.KeyS, d2input.KeyT, d2input.KeyU, d2input.KeyV, d2input.KeyW, d2input.KeyX, d2input.KeyY,
|
||||
d2input.KeyZ, d2input.KeyApostrophe, d2input.KeyBackslash, d2input.KeyBackspace,
|
||||
d2input.KeyCapsLock, d2input.KeyComma, d2input.KeyDelete, d2input.KeyDown,
|
||||
d2input.KeyEnd, d2input.KeyEnter, d2input.KeyEqual, d2input.KeyEscape,
|
||||
d2input.KeyF1, d2input.KeyF2, d2input.KeyF3, d2input.KeyF4, d2input.KeyF5, d2input.KeyF6,
|
||||
d2input.KeyF7, d2input.KeyF8, d2input.KeyF9, d2input.KeyF10, d2input.KeyF11, d2input.KeyF12,
|
||||
d2input.KeyGraveAccent, d2input.KeyHome, d2input.KeyInsert, d2input.KeyKP0,
|
||||
d2input.KeyKP1, d2input.KeyKP2, d2input.KeyKP3, d2input.KeyKP4, d2input.KeyKP5,
|
||||
d2input.KeyKP6, d2input.KeyKP7, d2input.KeyKP8, d2input.KeyKP9,
|
||||
d2input.KeyKPAdd, d2input.KeyKPDecimal, d2input.KeyKPDivide, d2input.KeyKPEnter,
|
||||
d2input.KeyKPEqual, d2input.KeyKPMultiply, d2input.KeyKPSubtract, d2input.KeyLeft,
|
||||
d2input.KeyLeftBracket, d2input.KeyMenu, d2input.KeyMinus, d2input.KeyNumLock,
|
||||
d2input.KeyPageDown, d2input.KeyPageUp, d2input.KeyPause, d2input.KeyPeriod,
|
||||
d2input.KeyPrintScreen, d2input.KeyRight, d2input.KeyRightBracket,
|
||||
d2input.KeyScrollLock, d2input.KeySemicolon, d2input.KeySlash,
|
||||
d2input.KeySpace, d2input.KeyTab, d2input.KeyUp,
|
||||
}
|
||||
|
||||
var modifiersToCheck = []d2input.Modifier{
|
||||
d2input.ModAlt, d2input.ModControl, d2input.ModShift,
|
||||
}
|
||||
|
||||
var buttonsToCheck = []d2input.MouseButton{
|
||||
d2input.MouseButtonLeft, d2input.MouseButtonMiddle, d2input.MouseButtonRight,
|
||||
}
|
||||
|
||||
for _, key := range keysToCheck {
|
||||
truth := ebiten.IsKeyPressed(ebiten.Key(key))
|
||||
m.inputState.KeyVector.Set(key, truth)
|
||||
}
|
||||
|
||||
for _, mod := range modifiersToCheck {
|
||||
truth := ebiten.IsKeyPressed(ebiten.Key(mod))
|
||||
m.inputState.ModifierVector.Set(mod, truth)
|
||||
}
|
||||
|
||||
for _, btn := range buttonsToCheck {
|
||||
truth := ebiten.IsMouseButtonPressed(ebiten.MouseButton(btn))
|
||||
m.inputState.MouseButtonVector.Set(btn, truth)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *InputSystem) applyInputState(id akara.EID) (preventPropagation bool) {
|
||||
v, found := m.GetInteractive(id)
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
|
||||
if !v.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
if m.inputState.Contains(v.InputVector) {
|
||||
return v.Callback()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@ -37,6 +37,7 @@ var _ akara.System = &BaseScene{}
|
||||
|
||||
type baseSystems struct {
|
||||
*RenderSystem
|
||||
*InputSystem
|
||||
*GameObjectFactory
|
||||
}
|
||||
|
||||
@ -58,8 +59,10 @@ type BaseScene struct {
|
||||
d2components.ViewportFactory
|
||||
d2components.MainViewportFactory
|
||||
d2components.ViewportFilterFactory
|
||||
d2components.PriorityFactory
|
||||
d2components.CameraFactory
|
||||
d2components.RenderableFactory
|
||||
d2components.InteractiveFactory
|
||||
d2components.PositionFactory
|
||||
d2components.ScaleFactory
|
||||
d2components.AnimationFactory
|
||||
@ -82,6 +85,7 @@ func (s *BaseScene) Init(world *akara.World) {
|
||||
s.World = world
|
||||
|
||||
if s.World == nil {
|
||||
s.SetActive(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -99,12 +103,17 @@ func (s *BaseScene) boot() {
|
||||
s.Add.SetPrefix(fmt.Sprintf("%s -> %s", s.key, "Object Factory"))
|
||||
|
||||
for idx := range s.Systems {
|
||||
if rendersys, ok := s.Systems[idx].(*RenderSystem); ok {
|
||||
if rendersys, ok := s.Systems[idx].(*RenderSystem); ok && s.systems.RenderSystem == nil {
|
||||
s.systems.RenderSystem = rendersys
|
||||
continue
|
||||
}
|
||||
|
||||
if objFactory, ok := s.Systems[idx].(*GameObjectFactory); ok {
|
||||
if inputSys, ok := s.Systems[idx].(*InputSystem); ok && s.systems.InputSystem == nil {
|
||||
s.systems.InputSystem = inputSys
|
||||
continue
|
||||
}
|
||||
|
||||
if objFactory, ok := s.Systems[idx].(*GameObjectFactory); ok && s.systems.GameObjectFactory == nil {
|
||||
s.systems.GameObjectFactory = objFactory
|
||||
continue
|
||||
}
|
||||
@ -120,6 +129,13 @@ func (s *BaseScene) boot() {
|
||||
return
|
||||
}
|
||||
|
||||
if s.systems.InputSystem == nil {
|
||||
s.Info("waiting for input system")
|
||||
return
|
||||
}
|
||||
|
||||
s.systems.InputSystem.renderer = s.systems.RenderSystem.renderer
|
||||
|
||||
if s.systems.GameObjectFactory == nil {
|
||||
s.Info("waiting for game object factory ...")
|
||||
return
|
||||
@ -140,7 +156,9 @@ func (s *BaseScene) setupFactories() {
|
||||
viewportID := s.RegisterComponent(&d2components.Viewport{})
|
||||
viewportFilterID := s.RegisterComponent(&d2components.ViewportFilter{})
|
||||
cameraID := s.RegisterComponent(&d2components.Camera{})
|
||||
priorityID := s.RegisterComponent(&d2components.Priority{})
|
||||
renderableID := s.RegisterComponent(&d2components.Renderable{})
|
||||
interactiveID := s.RegisterComponent(&d2components.Interactive{})
|
||||
positionID := s.RegisterComponent(&d2components.Position{})
|
||||
scaleID := s.RegisterComponent(&d2components.Scale{})
|
||||
animationID := s.RegisterComponent(&d2components.Animation{})
|
||||
@ -151,7 +169,9 @@ func (s *BaseScene) setupFactories() {
|
||||
s.Viewport = s.GetComponentFactory(viewportID)
|
||||
s.ViewportFilter = s.GetComponentFactory(viewportFilterID)
|
||||
s.Camera = s.GetComponentFactory(cameraID)
|
||||
s.Priority = s.GetComponentFactory(priorityID)
|
||||
s.Renderable = s.GetComponentFactory(renderableID)
|
||||
s.Interactive = s.GetComponentFactory(interactiveID)
|
||||
s.Position = s.GetComponentFactory(positionID)
|
||||
s.Scale = s.GetComponentFactory(scaleID)
|
||||
s.Animation = s.GetComponentFactory(animationID)
|
||||
@ -163,13 +183,11 @@ func (s *BaseScene) createDefaultViewport() {
|
||||
s.Info("creating default viewport")
|
||||
viewportID := s.NewEntity()
|
||||
s.AddViewport(viewportID)
|
||||
s.AddPriority(viewportID)
|
||||
|
||||
camera := s.AddCamera(viewportID)
|
||||
camera.Width = 800
|
||||
camera.Height = 600
|
||||
camera.Zoom = 1
|
||||
|
||||
sfc := s.systems.renderer.NewSurface(camera.Width, camera.Height)
|
||||
sfc := s.systems.RenderSystem.renderer.NewSurface(camera.Width, camera.Height)
|
||||
|
||||
sfc.Clear(color.Transparent)
|
||||
|
||||
@ -266,9 +284,11 @@ func (s *BaseScene) renderViewport(idx int, objects []akara.EID) {
|
||||
}
|
||||
|
||||
if sfc.Surface == nil {
|
||||
sfc.Surface = s.systems.renderer.NewSurface(camera.Width, camera.Height)
|
||||
sfc.Surface = s.systems.RenderSystem.renderer.NewSurface(camera.Width, camera.Height)
|
||||
}
|
||||
|
||||
sfc.Clear(color.Transparent)
|
||||
|
||||
cx, cy := int(camera.X()), int(camera.Y())
|
||||
|
||||
sfc.Surface.PushTranslation(cx, cy) // negative because we're offsetting everything that gets rendered
|
||||
@ -298,6 +318,11 @@ func (s *BaseScene) renderObject(target d2interface.Surface, id akara.EID) {
|
||||
scale = s.AddScale(id)
|
||||
}
|
||||
|
||||
alpha, found := s.GetAlpha(id)
|
||||
if !found {
|
||||
alpha = s.AddAlpha(id)
|
||||
}
|
||||
|
||||
x, y := int(position.X()), int(position.Y())
|
||||
|
||||
target.PushTranslation(x, y)
|
||||
@ -306,6 +331,9 @@ func (s *BaseScene) renderObject(target d2interface.Surface, id akara.EID) {
|
||||
target.PushScale(scale.X(), scale.Y())
|
||||
defer target.Pop()
|
||||
|
||||
target.PushColor(color.Alpha{A: uint8(alpha.Alpha * 255)})
|
||||
defer target.Pop()
|
||||
|
||||
segment, found := s.systems.SpriteFactory.GetSegmentedSprite(id)
|
||||
if found {
|
||||
animation, found := s.GetAnimation(id)
|
||||
@ -352,10 +380,10 @@ type sceneObjectFactory struct {
|
||||
}
|
||||
|
||||
func (s *sceneObjectFactory) addBasicComponenets(id akara.EID) {
|
||||
_ = s.AddScale(id)
|
||||
_ = s.AddOrigin(id)
|
||||
_ = s.AddPosition(id)
|
||||
_ = s.AddScale(id)
|
||||
_ = s.AddAlpha(id)
|
||||
_ = s.AddOrigin(id)
|
||||
}
|
||||
|
||||
func (s *sceneObjectFactory) Sprite(x, y float64, imgPath, palPath string) akara.EID {
|
||||
|
@ -72,6 +72,7 @@ func (s *LoadingScene) Init(world *akara.World) {
|
||||
|
||||
func (s *LoadingScene) boot() {
|
||||
if !s.BaseScene.booted {
|
||||
s.BaseScene.boot()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2input"
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
@ -28,7 +29,11 @@ var _ d2interface.Scene = &MainMenuScene{}
|
||||
// or start the map engine test.
|
||||
type MainMenuScene struct {
|
||||
*BaseScene
|
||||
booted bool
|
||||
booted bool
|
||||
sprites struct {
|
||||
trademark akara.EID
|
||||
mainBackground akara.EID
|
||||
}
|
||||
}
|
||||
|
||||
// Init the main menu scene
|
||||
@ -43,16 +48,20 @@ func (s *MainMenuScene) boot() {
|
||||
return
|
||||
}
|
||||
|
||||
s.createTrademarkScreen()
|
||||
s.createButtons()
|
||||
s.createBackground()
|
||||
s.createButtons()
|
||||
s.createTrademarkScreen()
|
||||
|
||||
s.booted = true
|
||||
}
|
||||
|
||||
func (s *MainMenuScene) createBackground() {
|
||||
s.Info("creating background")
|
||||
s.Add.SegmentedSprite(0, 0, d2resource.GameSelectScreen, d2resource.PaletteSky, 4, 3, 0)
|
||||
|
||||
imgPath := d2resource.GameSelectScreen
|
||||
palPath := d2resource.PaletteSky
|
||||
|
||||
s.sprites.mainBackground = s.Add.SegmentedSprite(0, 0, imgPath, palPath, 4, 3, 0)
|
||||
}
|
||||
|
||||
func (s *MainMenuScene) createButtons() {
|
||||
@ -61,7 +70,26 @@ func (s *MainMenuScene) createButtons() {
|
||||
|
||||
func (s *MainMenuScene) createTrademarkScreen() {
|
||||
s.Info("creating trademark screen")
|
||||
s.Add.SegmentedSprite(0, 0, d2resource.TrademarkScreen, d2resource.PaletteSky, 4, 3, 0)
|
||||
|
||||
imgPath := d2resource.TrademarkScreen
|
||||
palPath := d2resource.PaletteSky
|
||||
|
||||
s.sprites.trademark = s.Add.SegmentedSprite(0, 0, imgPath, palPath, 4, 3, 0)
|
||||
|
||||
interactive := s.AddInteractive(s.sprites.trademark)
|
||||
|
||||
interactive.InputVector.SetMouseButton(d2input.MouseButtonLeft)
|
||||
|
||||
interactive.Callback = func() bool {
|
||||
s.Info("hiding trademark sprite")
|
||||
|
||||
alpha, _ := s.GetAlpha(s.sprites.trademark)
|
||||
alpha.Alpha = 0
|
||||
|
||||
interactive.Enabled = false
|
||||
|
||||
return true // prevent propagation
|
||||
}
|
||||
}
|
||||
|
||||
// Update the main menu scene
|
||||
|
83
d2core/d2systems/scene_mouse_cursor.go
Normal file
83
d2core/d2systems/scene_mouse_cursor.go
Normal file
@ -0,0 +1,83 @@
|
||||
package d2systems
|
||||
|
||||
import (
|
||||
"github.com/gravestench/akara"
|
||||
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
|
||||
)
|
||||
|
||||
const (
|
||||
sceneKeyMouseCursor = "Mouse Cursor"
|
||||
)
|
||||
|
||||
// NewMouseCursorScene creates a new main menu scene. This is the first screen that the user
|
||||
// will see when launching the game.
|
||||
func NewMouseCursorScene() *MouseCursorScene {
|
||||
scene := &MouseCursorScene{
|
||||
BaseScene: NewBaseScene(sceneKeyMouseCursor),
|
||||
}
|
||||
|
||||
return scene
|
||||
}
|
||||
|
||||
// static check that MouseCursorScene implements the scene interface
|
||||
var _ d2interface.Scene = &MouseCursorScene{}
|
||||
|
||||
// MouseCursorScene represents the game's main menu, where users can select single or multi player,
|
||||
// or start the map engine test.
|
||||
type MouseCursorScene struct {
|
||||
*BaseScene
|
||||
booted bool
|
||||
cursor akara.EID
|
||||
}
|
||||
|
||||
// Init the main menu scene
|
||||
func (s *MouseCursorScene) Init(world *akara.World) {
|
||||
s.World = world
|
||||
|
||||
s.Info("initializing ...")
|
||||
}
|
||||
|
||||
func (s *MouseCursorScene) boot() {
|
||||
if !s.BaseScene.booted {
|
||||
s.BaseScene.boot()
|
||||
return
|
||||
}
|
||||
|
||||
s.createMouseCursor()
|
||||
|
||||
s.booted = true
|
||||
}
|
||||
|
||||
func (s *MouseCursorScene) createMouseCursor() {
|
||||
s.Info("creating mouse cursor")
|
||||
s.cursor = s.Add.Sprite(0, 0, d2resource.CursorDefault, d2resource.PaletteUnits)
|
||||
}
|
||||
|
||||
// Update the main menu scene
|
||||
func (s *MouseCursorScene) Update() {
|
||||
if s.Paused() {
|
||||
return
|
||||
}
|
||||
|
||||
if !s.booted {
|
||||
s.boot()
|
||||
return
|
||||
}
|
||||
|
||||
s.updateCursorPosition()
|
||||
|
||||
s.BaseScene.Update()
|
||||
}
|
||||
|
||||
func (s *MouseCursorScene) updateCursorPosition() {
|
||||
spritePosition, found := s.GetPosition(s.cursor)
|
||||
if !found {
|
||||
return
|
||||
}
|
||||
|
||||
cx, cy := s.systems.InputSystem.renderer.GetCursorPos()
|
||||
|
||||
spritePosition.Set(float64(cx), float64(cy))
|
||||
}
|
4
go.sum
4
go.sum
@ -19,10 +19,6 @@ github.com/gofrs/flock v0.8.0 h1:MSdYClljsF3PbENUUEx85nkWfJSGfzYI9yEBZOJz6CY=
|
||||
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gravestench/akara v0.0.0-20201119221449-924b47999403 h1:hoCEhoSD+4Hvg3xdbfbVleJXhyHqP/1jUa1QqexE1UQ=
|
||||
github.com/gravestench/akara v0.0.0-20201119221449-924b47999403/go.mod h1:fTeda1SogMg5Lkd4lXMEd/Pk/a5/gQuLGaAI2rn1PBQ=
|
||||
github.com/gravestench/akara v0.0.0-20201122210148-a1ee8ea83994 h1:Wp+4kZ0Pkap2ueAkTrE22rk++3VZE8TsU1bewpnzmsM=
|
||||
github.com/gravestench/akara v0.0.0-20201122210148-a1ee8ea83994/go.mod h1:fTeda1SogMg5Lkd4lXMEd/Pk/a5/gQuLGaAI2rn1PBQ=
|
||||
github.com/gravestench/akara v0.0.0-20201128054238-892de9d70d6b h1:Ngfdn7O3wXQBzbOLsL6vQ9G4F7utUiKjQqKnwHbY5uI=
|
||||
github.com/gravestench/akara v0.0.0-20201128054238-892de9d70d6b/go.mod h1:fTeda1SogMg5Lkd4lXMEd/Pk/a5/gQuLGaAI2rn1PBQ=
|
||||
github.com/hajimehoshi/bitmapfont/v2 v2.1.0/go.mod h1:2BnYrkTQGThpr/CY6LorYtt/zEPNzvE/ND69CRTaHMs=
|
||||
|
Loading…
Reference in New Issue
Block a user