mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-11-17 18:06:03 -05:00
Added button logic.
This commit is contained in:
parent
b0de898fff
commit
054329cf1f
@ -61,7 +61,7 @@ func CreateSprite(data []byte, palette Palette) *Sprite {
|
||||
result.Frames = make([]*SpriteFrame, totalFrames)
|
||||
for i := uint32(0); i < totalFrames; i++ {
|
||||
dataPointer = framePointers[i]
|
||||
result.Frames[i] = &SpriteFrame{}
|
||||
result.Frames[i] = &SpriteFrame{Loaded: false}
|
||||
result.Frames[i].Flip = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||
dataPointer += 4
|
||||
result.Frames[i].Width = binary.LittleEndian.Uint32(data[dataPointer : dataPointer+4])
|
||||
@ -130,6 +130,9 @@ func CreateSprite(data []byte, palette Palette) *Sprite {
|
||||
// GetSize returns the size of the sprite
|
||||
func (v *Sprite) GetSize() (uint32, uint32) {
|
||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
||||
for frame.Loaded == false {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
return frame.Width, frame.Height
|
||||
}
|
||||
|
||||
@ -148,11 +151,29 @@ func (v *Sprite) updateAnimation() {
|
||||
}
|
||||
}
|
||||
|
||||
// GetFrameSize returns the size of the specific frame
|
||||
func (v *Sprite) GetFrameSize(frame int) (width, height uint32) {
|
||||
for v.Frames[frame].Loaded == false {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
width = v.Frames[frame].Width
|
||||
height = v.Frames[frame].Height
|
||||
return
|
||||
}
|
||||
|
||||
// GetTotalFrames returns the number of frames in this sprite (for all directions)
|
||||
func (v *Sprite) GetTotalFrames() int {
|
||||
return len(v.Frames)
|
||||
}
|
||||
|
||||
// Draw draws the sprite onto the target
|
||||
func (v *Sprite) Draw(target *ebiten.Image) {
|
||||
v.updateAnimation()
|
||||
opts := &ebiten.DrawImageOptions{}
|
||||
frame := v.Frames[uint32(v.Frame)+(uint32(v.Direction)*v.FramesPerDirection)]
|
||||
for frame.Loaded == false {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
opts.GeoM.Translate(
|
||||
float64(int32(v.X)+frame.OffsetX),
|
||||
float64((int32(v.Y) - int32(frame.Height) + frame.OffsetY)),
|
||||
@ -165,9 +186,6 @@ func (v *Sprite) Draw(target *ebiten.Image) {
|
||||
if v.ColorMod != nil {
|
||||
opts.ColorM = ColorToColorM(v.ColorMod)
|
||||
}
|
||||
for frame.Image == nil {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
target.DrawImage(frame.Image, opts)
|
||||
}
|
||||
|
||||
@ -193,7 +211,7 @@ func (v *Sprite) DrawSegments(target *ebiten.Image, xSegments, ySegments, offset
|
||||
if v.ColorMod != nil {
|
||||
opts.ColorM = ColorToColorM(v.ColorMod)
|
||||
}
|
||||
for frame.Image == nil {
|
||||
for frame.Loaded == false {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
target.DrawImage(frame.Image, opts)
|
||||
|
@ -2,6 +2,7 @@ package Scenes
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"os"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
"github.com/essial/OpenDiablo2/Palettes"
|
||||
@ -88,14 +89,19 @@ func (v *MainMenu) Load() []func() {
|
||||
v.diabloLogoRightBack.MoveTo(400, 120)
|
||||
},
|
||||
func() {
|
||||
v.exitDiabloButton = UI.CreateButton(v.fileProvider, "EXIT DIABLO II")
|
||||
v.exitDiabloButton = UI.CreateButton(UI.ButtonTypeWide, v.fileProvider, "EXIT DIABLO II")
|
||||
v.exitDiabloButton.MoveTo(264, 535)
|
||||
v.exitDiabloButton.SetVisible(false)
|
||||
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
|
||||
v.uiManager.AddWidget(v.exitDiabloButton)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (v *MainMenu) onExitButtonClicked() {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Unload unloads the data for the main menu
|
||||
func (v *MainMenu) Unload() {
|
||||
|
||||
|
180
UI/Button.go
180
UI/Button.go
@ -1,6 +1,7 @@
|
||||
package UI
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
|
||||
"github.com/essial/OpenDiablo2/Common"
|
||||
@ -9,44 +10,160 @@ import (
|
||||
"github.com/hajimehoshi/ebiten"
|
||||
)
|
||||
|
||||
// ButtonType defines the type of button
|
||||
type ButtonType int
|
||||
|
||||
const (
|
||||
ButtonTypeWide ButtonType = 1
|
||||
ButtonTypeMedium ButtonType = 2
|
||||
ButtonTypeNarrow ButtonType = 3
|
||||
ButtonTypeCancel ButtonType = 4
|
||||
ButtonTypeTall ButtonType = 5
|
||||
ButtonTypeShort ButtonType = 6
|
||||
|
||||
// Game UI
|
||||
|
||||
ButtonTypeSkill ButtonType = 7
|
||||
ButtonTypeRun ButtonType = 8
|
||||
ButtonTypeMenu ButtonType = 9
|
||||
ButtonTypeGoldCoin ButtonType = 10
|
||||
ButtonTypeClose ButtonType = 11
|
||||
ButtonTypeSecondaryInvHand ButtonType = 12
|
||||
ButtonTypeMinipanelCharacter ButtonType = 13
|
||||
ButtonTypeMinipanelInventory ButtonType = 14
|
||||
ButtonTypeMinipanelSkill ButtonType = 15
|
||||
ButtonTypeMinipanelAutomap ButtonType = 16
|
||||
ButtonTypeMinipanelMessage ButtonType = 17
|
||||
ButtonTypeMinipanelQuest ButtonType = 18
|
||||
ButtonTypeMinipanelMen ButtonType = 19
|
||||
)
|
||||
|
||||
// ButtonLayout defines the type of buttons
|
||||
type ButtonLayout struct {
|
||||
XSegments int //1
|
||||
YSegments int // 1
|
||||
ResourceName string
|
||||
PaletteName Palettes.Palette
|
||||
Toggleable bool // false
|
||||
BaseFrame int // 0
|
||||
DisabledFrame int // -1
|
||||
FontPath string // ResourcePaths.FontExocet10
|
||||
ClickableRect *image.Rectangle // nil
|
||||
AllowFrameChange bool // true
|
||||
}
|
||||
|
||||
// ButtonLayouts define the type of buttons you can have
|
||||
var ButtonLayouts = map[ButtonType]ButtonLayout{
|
||||
ButtonTypeWide: {2, 1, ResourcePaths.WideButtonBlank, Palettes.Units, false, 0, -1, ResourcePaths.FontExocet10, nil, true},
|
||||
ButtonTypeShort: {1, 1, ResourcePaths.ShortButtonBlank, Palettes.Units, false, 0, -1, ResourcePaths.FontExocet8, nil, true},
|
||||
/*
|
||||
{eButtonType.Wide, new ButtonLayout { XSegments = 2, ResourceName = ResourcePaths.WideButtonBlank, PaletteName = Palettes.Units } },
|
||||
{eButtonType.Medium, new ButtonLayout{ ResourceName = ResourcePaths.MediumButtonBlank, PaletteName = Palettes.Units } },
|
||||
{eButtonType.Narrow, new ButtonLayout { ResourceName = ResourcePaths.NarrowButtonBlank, PaletteName = Palettes.Units } },
|
||||
{eButtonType.Tall, new ButtonLayout { ResourceName = ResourcePaths.TallButtonBlank, PaletteName = Palettes.Units } },
|
||||
|
||||
{eButtonType.Cancel, new ButtonLayout { ResourceName = ResourcePaths.CancelButton, PaletteName = Palettes.Units } },
|
||||
// Minipanel
|
||||
{eButtonType.MinipanelCharacter, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = Palettes.Units, BaseFrame = 0 } },
|
||||
{eButtonType.MinipanelInventory, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = Palettes.Units, BaseFrame = 2 } },
|
||||
{eButtonType.MinipanelSkill, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = Palettes.Units, BaseFrame = 4 } },
|
||||
{eButtonType.MinipanelAutomap, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = Palettes.Units, BaseFrame = 8 } },
|
||||
{eButtonType.MinipanelMessage, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = Palettes.Units, BaseFrame = 10 } },
|
||||
{eButtonType.MinipanelQuest, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = Palettes.Units, BaseFrame = 12 } },
|
||||
{eButtonType.MinipanelMenu, new ButtonLayout { ResourceName = ResourcePaths.MinipanelButton, PaletteName = Palettes.Units, BaseFrame = 14 } },
|
||||
|
||||
{eButtonType.SecondaryInvHand, new ButtonLayout { ResourceName = ResourcePaths.InventoryWeaponsTab, PaletteName = Palettes.Units, ClickableRect = new Rectangle(0, 0, 0, 20), AllowFrameChange = false } },
|
||||
{eButtonType.Run, new ButtonLayout { ResourceName = ResourcePaths.RunButton, PaletteName = Palettes.Units, Toggleable = true } },
|
||||
{eButtonType.Menu, new ButtonLayout { ResourceName = ResourcePaths.MenuButton, PaletteName = Palettes.Units, Toggleable = true } },
|
||||
{eButtonType.GoldCoin, new ButtonLayout { ResourceName = ResourcePaths.GoldCoinButton, PaletteName = Palettes.Units } },
|
||||
{eButtonType.Close, new ButtonLayout { ResourceName = ResourcePaths.SquareButton, PaletteName = Palettes.Units, BaseFrame = 10 } },
|
||||
{eButtonType.Skill, new ButtonLayout { ResourceName = ResourcePaths.AddSkillButton, PaletteName = Palettes.Units, DisabledFrame = 2
|
||||
*/
|
||||
}
|
||||
|
||||
// Button defines a standard wide UI button
|
||||
type Button struct {
|
||||
enabled bool
|
||||
x, y int
|
||||
width, height uint32
|
||||
visible bool
|
||||
pressed bool
|
||||
fileProvider Common.FileProvider
|
||||
normalImage *ebiten.Image
|
||||
pressedImage *ebiten.Image
|
||||
enabled bool
|
||||
x, y int
|
||||
width, height uint32
|
||||
visible bool
|
||||
pressed bool
|
||||
toggled bool
|
||||
fileProvider Common.FileProvider
|
||||
normalImage *ebiten.Image
|
||||
pressedImage *ebiten.Image
|
||||
toggledImage *ebiten.Image
|
||||
pressedToggledImage *ebiten.Image
|
||||
disabledImage *ebiten.Image
|
||||
onClick func()
|
||||
}
|
||||
|
||||
// CreateButton creates an instance of Button
|
||||
func CreateButton(fileProvider Common.FileProvider, text string) *Button {
|
||||
func CreateButton(buttonType ButtonType, fileProvider Common.FileProvider, text string) *Button {
|
||||
result := &Button{
|
||||
fileProvider: fileProvider,
|
||||
width: 272,
|
||||
height: 35,
|
||||
width: 0,
|
||||
height: 0,
|
||||
visible: true,
|
||||
enabled: true,
|
||||
pressed: false,
|
||||
}
|
||||
font := GetFont(ResourcePaths.FontExocet10, Palettes.Units, fileProvider)
|
||||
result.normalImage, _ = ebiten.NewImage(272, 35, ebiten.FilterNearest)
|
||||
result.pressedImage, _ = ebiten.NewImage(272, 35, ebiten.FilterNearest)
|
||||
textWidth, textHeight := font.GetTextMetrics(text)
|
||||
textX := (272 / 2) - (textWidth / 2)
|
||||
textY := (35 / 2) - (textHeight / 2) + 5
|
||||
buttonLayout := ButtonLayouts[buttonType]
|
||||
font := GetFont(buttonLayout.FontPath, buttonLayout.PaletteName, fileProvider)
|
||||
buttonSprite := fileProvider.LoadSprite(ResourcePaths.WideButtonBlank, Palettes.Units)
|
||||
totalButtonTypes := buttonSprite.GetTotalFrames() / (buttonLayout.XSegments * buttonLayout.YSegments)
|
||||
for i := 0; i < buttonLayout.XSegments; i++ {
|
||||
w, _ := buttonSprite.GetFrameSize(i)
|
||||
result.width += w
|
||||
}
|
||||
for i := 0; i < buttonLayout.YSegments; i++ {
|
||||
_, h := buttonSprite.GetFrameSize(i * buttonLayout.YSegments)
|
||||
result.height += h
|
||||
}
|
||||
|
||||
result.normalImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
result.pressedImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
|
||||
textWidth, textHeight := font.GetTextMetrics(text)
|
||||
textX := (result.width / 2) - (textWidth / 2)
|
||||
textY := (result.height / 2) - (textHeight / 2) + 5
|
||||
buttonSprite.MoveTo(0, 0)
|
||||
buttonSprite.Blend = true
|
||||
buttonSprite.DrawSegments(result.normalImage, 2, 1, 0)
|
||||
buttonSprite.DrawSegments(result.normalImage, 2, 1, buttonLayout.BaseFrame)
|
||||
font.Draw(int(textX), int(textY), text, color.RGBA{100, 100, 100, 255}, result.normalImage)
|
||||
buttonSprite.DrawSegments(result.pressedImage, 2, 1, 1)
|
||||
font.Draw(int(textX-2), int(textY+2), text, color.Black, result.pressedImage)
|
||||
if buttonLayout.AllowFrameChange {
|
||||
if totalButtonTypes > 1 {
|
||||
buttonSprite.DrawSegments(result.pressedImage, 2, 1, buttonLayout.BaseFrame+1)
|
||||
font.Draw(int(textX-2), int(textY+2), text, color.RGBA{100, 100, 100, 255}, result.pressedImage)
|
||||
}
|
||||
if totalButtonTypes > 2 {
|
||||
buttonSprite.DrawSegments(result.toggledImage, 2, 1, buttonLayout.BaseFrame+2)
|
||||
font.Draw(int(textX), int(textY), text, color.RGBA{100, 100, 100, 255}, result.toggledImage)
|
||||
}
|
||||
if totalButtonTypes > 3 {
|
||||
buttonSprite.DrawSegments(result.pressedToggledImage, 2, 1, buttonLayout.BaseFrame+3)
|
||||
font.Draw(int(textX), int(textY), text, color.RGBA{100, 100, 100, 255}, result.pressedToggledImage)
|
||||
}
|
||||
if buttonLayout.DisabledFrame != -1 {
|
||||
buttonSprite.DrawSegments(result.disabledImage, 2, 1, buttonLayout.DisabledFrame)
|
||||
font.Draw(int(textX), int(textY), text, color.RGBA{100, 100, 100, 255}, result.disabledImage)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// OnActivated defines the callback handler for the activate event
|
||||
func (v *Button) OnActivated(callback func()) {
|
||||
v.onClick = callback
|
||||
}
|
||||
|
||||
// Activate calls the on activated callback handler, if any
|
||||
func (v *Button) Activate() {
|
||||
if v.onClick == nil {
|
||||
return
|
||||
}
|
||||
v.onClick()
|
||||
}
|
||||
|
||||
// Draw renders the button
|
||||
func (v *Button) Draw(target *ebiten.Image) {
|
||||
opts := &ebiten.DrawImageOptions{
|
||||
@ -54,11 +171,18 @@ func (v *Button) Draw(target *ebiten.Image) {
|
||||
Filter: ebiten.FilterNearest,
|
||||
}
|
||||
opts.GeoM.Translate(float64(v.x), float64(v.y))
|
||||
if v.pressed {
|
||||
|
||||
if !v.enabled {
|
||||
target.DrawImage(v.disabledImage, opts)
|
||||
} else if v.toggled && v.pressed {
|
||||
target.DrawImage(v.pressedToggledImage, opts)
|
||||
} else if v.pressed {
|
||||
target.DrawImage(v.pressedImage, opts)
|
||||
return
|
||||
} else if v.toggled {
|
||||
target.DrawImage(v.toggledImage, opts)
|
||||
} else {
|
||||
target.DrawImage(v.normalImage, opts)
|
||||
}
|
||||
target.DrawImage(v.normalImage, opts)
|
||||
}
|
||||
|
||||
// GetEnabled returns the enabled state
|
||||
@ -96,3 +220,13 @@ func (v *Button) GetVisible() bool {
|
||||
func (v *Button) SetVisible(visible bool) {
|
||||
v.visible = visible
|
||||
}
|
||||
|
||||
// GetPressed returns the pressed state of the button
|
||||
func (v *Button) GetPressed() bool {
|
||||
return v.pressed
|
||||
}
|
||||
|
||||
// SetPressed sets the pressed state of the button
|
||||
func (v *Button) SetPressed(pressed bool) {
|
||||
v.pressed = pressed
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ type Manager struct {
|
||||
widgets []Widget
|
||||
cursorSprite *Common.Sprite
|
||||
cursorButtons CursorButton
|
||||
pressedIndex int
|
||||
CursorX int
|
||||
CursorY int
|
||||
}
|
||||
@ -29,6 +30,7 @@ type Manager struct {
|
||||
// CreateManager creates a new instance of a UI manager
|
||||
func CreateManager(provider Common.FileProvider) *Manager {
|
||||
result := &Manager{
|
||||
pressedIndex: -1,
|
||||
widgets: make([]Widget, 0),
|
||||
cursorSprite: provider.LoadSprite(ResourcePaths.CursorDefault, Palettes.Units),
|
||||
}
|
||||
@ -38,6 +40,7 @@ func CreateManager(provider Common.FileProvider) *Manager {
|
||||
// Reset resets the state of the UI manager. Typically called for new scenes
|
||||
func (v *Manager) Reset() {
|
||||
v.widgets = make([]Widget, 0)
|
||||
v.pressedIndex = -1
|
||||
}
|
||||
|
||||
// AddWidget adds a widget to the UI manager
|
||||
@ -69,6 +72,55 @@ func (v *Manager) Update() {
|
||||
v.cursorButtons |= CursorButtonRight
|
||||
}
|
||||
v.CursorX, v.CursorY = ebiten.CursorPosition()
|
||||
if v.CursorButtonPressed(CursorButtonLeft) {
|
||||
found := false
|
||||
for i, widget := range v.widgets {
|
||||
if !widget.GetVisible() || !widget.GetEnabled() {
|
||||
continue
|
||||
}
|
||||
wx, wy := widget.GetLocation()
|
||||
ww, wh := widget.GetSize()
|
||||
if v.CursorX >= wx && v.CursorX <= wx+int(ww) && v.CursorY >= wy && v.CursorY <= wy+int(wh) {
|
||||
widget.SetPressed(true)
|
||||
if v.pressedIndex == -1 {
|
||||
found = true
|
||||
v.pressedIndex = i
|
||||
} else if v.pressedIndex > -1 && v.pressedIndex != i {
|
||||
v.widgets[i].SetPressed(false)
|
||||
} else {
|
||||
v.widgets[i].SetPressed(true)
|
||||
found = true
|
||||
}
|
||||
break
|
||||
} else {
|
||||
widget.SetPressed(false)
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
if v.pressedIndex > -1 {
|
||||
v.widgets[v.pressedIndex].SetPressed(false)
|
||||
} else {
|
||||
v.pressedIndex = -2
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if v.pressedIndex > -1 {
|
||||
widget := v.widgets[v.pressedIndex]
|
||||
wx, wy := widget.GetLocation()
|
||||
ww, wh := widget.GetSize()
|
||||
if v.CursorX >= wx && v.CursorX <= wx+int(ww) && v.CursorY >= wy && v.CursorY <= wy+int(wh) {
|
||||
widget.Activate()
|
||||
}
|
||||
} else {
|
||||
for _, widget := range v.widgets {
|
||||
if !widget.GetVisible() || !widget.GetEnabled() {
|
||||
continue
|
||||
}
|
||||
widget.SetPressed(false)
|
||||
}
|
||||
}
|
||||
v.pressedIndex = -1
|
||||
}
|
||||
}
|
||||
|
||||
// CursorButtonPressed determines if the specified button has been pressed
|
||||
|
@ -9,4 +9,8 @@ type Widget interface {
|
||||
Common.Drawable
|
||||
GetEnabled() bool
|
||||
SetEnabled(enabled bool)
|
||||
SetPressed(pressed bool)
|
||||
GetPressed() bool
|
||||
OnActivated(callback func())
|
||||
Activate()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user