Merge branch 'main' of https://github.com/devraza/ambition
This commit is contained in:
commit
950fe47f52
|
@ -3,7 +3,7 @@
|
||||||
# Ambition
|
# Ambition
|
||||||
|
|
||||||
## About
|
## About
|
||||||
Ambtion is a fast-paced, text-based multiplayer role-playing game.
|
Ambition is a fast-paced, text-based multiplayer role-playing game.
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
- [Muhammad Nauman Raza](https://github.com/devraza) - Project Manager/Founder, Producer, and Programmer
|
- [Muhammad Nauman Raza](https://github.com/devraza) - Project Manager/Founder, Producer, and Programmer
|
||||||
|
@ -11,4 +11,4 @@ Ambtion is a fast-paced, text-based multiplayer role-playing game.
|
||||||
- [Adam Khan](https://github.com/NightmaresStuff) - Concept/Game Artist and Level Designer
|
- [Adam Khan](https://github.com/NightmaresStuff) - Concept/Game Artist and Level Designer
|
||||||
|
|
||||||
## License
|
## License
|
||||||
See [LICENSE](LICENSE) for a copy of the Apache License 2.0
|
See the [LICENSE](LICENSE) for a copy of the Apache License 2.0
|
||||||
|
|
13
frontend/assets/fonts/embed.go
Normal file
13
frontend/assets/fonts/embed.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package fonts
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
//go:embed iosevka-bold.ttf
|
||||||
|
IosevkaBold_ttf []byte
|
||||||
|
|
||||||
|
//go:embed iosevka-regular.ttf
|
||||||
|
IosevkaRegular_ttf []byte
|
||||||
|
)
|
BIN
frontend/assets/fonts/iosevka-bold.ttf
Normal file
BIN
frontend/assets/fonts/iosevka-bold.ttf
Normal file
Binary file not shown.
BIN
frontend/assets/fonts/iosevka-regular.ttf
Normal file
BIN
frontend/assets/fonts/iosevka-regular.ttf
Normal file
Binary file not shown.
|
@ -4,7 +4,9 @@ go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ebitenui/ebitenui v0.5.4
|
github.com/ebitenui/ebitenui v0.5.4
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
github.com/hajimehoshi/ebiten/v2 v2.5.5
|
github.com/hajimehoshi/ebiten/v2 v2.5.5
|
||||||
|
golang.org/x/image v0.7.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -12,7 +14,6 @@ require (
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b // indirect
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b // indirect
|
||||||
github.com/jezek/xgb v1.1.0 // indirect
|
github.com/jezek/xgb v1.1.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
|
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect
|
||||||
golang.org/x/image v0.7.0 // indirect
|
|
||||||
golang.org/x/mobile v0.0.0-20230427221453-e8d11dd0ba41 // indirect
|
golang.org/x/mobile v0.0.0-20230427221453-e8d11dd0ba41 // indirect
|
||||||
golang.org/x/sync v0.2.0 // indirect
|
golang.org/x/sync v0.2.0 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.8.0 // indirect
|
||||||
|
|
|
@ -7,6 +7,7 @@ github.com/ebitenui/ebitenui v0.5.4/go.mod h1:2iyyjninLWNQLZ+pdV/eJ9vRnSs+I+HrzE
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b h1:GgabKamyOYguHqHjSkDACcgoPIz3w0Dis/zJ1wyHHHU=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b h1:GgabKamyOYguHqHjSkDACcgoPIz3w0Dis/zJ1wyHHHU=
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20221017161538-93cebf72946b/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/hajimehoshi/bitmapfont/v2 v2.2.3 h1:jmq/TMNj352V062Tr5e3hAoipkoxCbY1JWTzor0zNps=
|
github.com/hajimehoshi/bitmapfont/v2 v2.2.3 h1:jmq/TMNj352V062Tr5e3hAoipkoxCbY1JWTzor0zNps=
|
||||||
github.com/hajimehoshi/ebiten/v2 v2.5.5 h1:TJNoZsYJYUyFucwE56QRSgmZ+/cklUt1YrwpQVC5vjs=
|
github.com/hajimehoshi/ebiten/v2 v2.5.5 h1:TJNoZsYJYUyFucwE56QRSgmZ+/cklUt1YrwpQVC5vjs=
|
||||||
github.com/hajimehoshi/ebiten/v2 v2.5.5/go.mod h1:mnHSOVysTr/nUZrN1lBTRqhK4NG+T9NR3JsJP2rCppk=
|
github.com/hajimehoshi/ebiten/v2 v2.5.5/go.mod h1:mnHSOVysTr/nUZrN1lBTRqhK4NG+T9NR3JsJP2rCppk=
|
||||||
|
|
|
@ -11,18 +11,22 @@ import (
|
||||||
|
|
||||||
// Ebitengine
|
// Ebitengine
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
// "github.com/hajimehoshi/ebiten/v2/ebitenutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Initialise the test player
|
||||||
|
var testPlayer = initPlayer()
|
||||||
|
|
||||||
// Create the `Game` struct
|
// Create the `Game` struct
|
||||||
type Game struct {
|
type Game struct {
|
||||||
ui UI
|
ui UI
|
||||||
activePlayer Player
|
activePlayer Player
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define the window width/height
|
||||||
const (
|
const (
|
||||||
window_width = 640
|
window_width = 1440
|
||||||
window_height = 480
|
window_height = 960
|
||||||
)
|
)
|
||||||
|
|
||||||
// Update implements Game
|
// Update implements Game
|
||||||
|
@ -36,11 +40,6 @@ func (g *Game) Update() error {
|
||||||
func (g *Game) Draw(screen *ebiten.Image) {
|
func (g *Game) Draw(screen *ebiten.Image) {
|
||||||
// Draw the UI onto the screen
|
// Draw the UI onto the screen
|
||||||
g.ui.base.Draw(screen)
|
g.ui.base.Draw(screen)
|
||||||
|
|
||||||
ebitenutil.DebugPrintAt(screen, "health: " + strconv.Itoa(g.activePlayer.health), 0, 0)
|
|
||||||
ebitenutil.DebugPrintAt(screen, "level: " + strconv.Itoa(g.activePlayer.level), 0, 10)
|
|
||||||
ebitenutil.DebugPrintAt(screen, "exp: " + strconv.Itoa(int(g.activePlayer.exp)), 0, 20)
|
|
||||||
ebitenutil.DebugPrintAt(screen, "ambittion: " + strconv.Itoa(int(g.activePlayer.ambition)), 0, 30)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout implements Game
|
// Layout implements Game
|
||||||
|
@ -69,8 +68,8 @@ func main() {
|
||||||
// Initialise the game
|
// Initialise the game
|
||||||
game := Game{
|
game := Game{
|
||||||
// Initialise the UI
|
// Initialise the UI
|
||||||
ui: uiInit(window_width, window_height),
|
|
||||||
activePlayer: testPlayer,
|
activePlayer: testPlayer,
|
||||||
|
ui: uiInit(window_width, window_height),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log and exit on error
|
// Log and exit on error
|
||||||
|
|
|
@ -1,43 +1,79 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import ()
|
||||||
"math/rand"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
// The player struct
|
||||||
type Player struct {
|
type Player struct {
|
||||||
health int
|
health int
|
||||||
level int
|
health_max int
|
||||||
exp float32
|
defence int
|
||||||
ambition float32
|
level int
|
||||||
|
exp float32
|
||||||
|
ambition float32
|
||||||
|
ambition_max float32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(midnadimple): These gates are temporary. We'll decide on real values later
|
// Create the maps for the level/(max) ambition gates
|
||||||
var level_gates = map[int]float32{
|
var level_gates = make(map[int]float32)
|
||||||
1: 100.0,
|
var level_ambition = make(map[int]float32)
|
||||||
2: 150.0,
|
|
||||||
3: 300.0,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(midnadimple): Move player initialization to server upon login
|
// TODO(midnadimple): Move player initialization to server upon login
|
||||||
func initPlayer() Player {
|
func initPlayer() Player {
|
||||||
return Player{
|
return Player{
|
||||||
health: 100,
|
health: 100,
|
||||||
level: 1,
|
health_max: 100,
|
||||||
exp: 0.0,
|
defence: 0,
|
||||||
ambition: (rand.Float32() * 10), // NOTE(midnadimple): In the future this will be affected by player activity
|
level: 1,
|
||||||
|
exp: 0.0,
|
||||||
|
ambition: 0.0, // NOTE(midnadimple): In the future this will be affected by player activity
|
||||||
|
ambition_max: level_ambition[1], // NOTE(midnadimple): In the future this will be affected by player activity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Formula for XP gain - extremely simple
|
||||||
|
func gain(basexp float32, modifier float32) float32 {
|
||||||
|
gain := basexp * modifier
|
||||||
|
return gain
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the player
|
||||||
func (p *Player) update() {
|
func (p *Player) update() {
|
||||||
// TODO(midnadimple): update health upon damage
|
// TODO(midnadimple): update health upon damage
|
||||||
|
|
||||||
|
// Auto-generate the level gates
|
||||||
|
level_gates[1] = 500
|
||||||
|
for i := 0; i <= 1000; i++ {
|
||||||
|
if i >= 2 {
|
||||||
|
switch {
|
||||||
|
case i <= 10:
|
||||||
|
level_gates[i] = level_gates[i-1] * 1.2
|
||||||
|
case (i <= 100) && (i > 10):
|
||||||
|
level_gates[i] = level_gates[i-1] * 1.1
|
||||||
|
case (i <= 1000) && (i > 100):
|
||||||
|
level_gates[i] = level_gates[i-1] * 1.005
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-generate maximum ambition gates
|
||||||
|
level_ambition[1] = 10
|
||||||
|
for i := 0; i <= 1000; i++ {
|
||||||
|
if i >= 2 {
|
||||||
|
switch {
|
||||||
|
case i <= 10:
|
||||||
|
level_ambition[i] = level_ambition[i-1] * 1.1
|
||||||
|
case (i <= 100) && (i > 10):
|
||||||
|
level_ambition[i] = level_ambition[i-1] * 1.05
|
||||||
|
case (i <= 1000) && (i > 100):
|
||||||
|
level_ambition[i] = level_ambition[i-1] * 1.00005
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the XP to 0 and increase both the level and max ambition on level up
|
||||||
if p.exp >= level_gates[p.level] {
|
if p.exp >= level_gates[p.level] {
|
||||||
p.exp = 0.0
|
p.exp = 0.0
|
||||||
p.level += 1
|
p.level += 1
|
||||||
|
p.ambition_max = level_ambition[p.level]
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(midnadimple): This formula for exp gain is pretty simple, maybe devraza can think of
|
|
||||||
// a more practical one
|
|
||||||
p.exp += 10.0 * (1.0/60.0) * p.ambition
|
|
||||||
|
|
||||||
}
|
}
|
374
frontend/ui.go
374
frontend/ui.go
|
@ -5,45 +5,58 @@ import (
|
||||||
img "image"
|
img "image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
|
// Misc.
|
||||||
|
// "fmt"
|
||||||
|
|
||||||
// EbitenUI
|
// EbitenUI
|
||||||
"github.com/ebitenui/ebitenui"
|
"github.com/ebitenui/ebitenui"
|
||||||
"github.com/ebitenui/ebitenui/image"
|
"github.com/ebitenui/ebitenui/image"
|
||||||
"github.com/ebitenui/ebitenui/widget"
|
"github.com/ebitenui/ebitenui/widget"
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
"github.com/devraza/ambition/assets/fonts"
|
||||||
|
"github.com/golang/freetype/truetype"
|
||||||
|
"golang.org/x/image/font"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The UI struct
|
||||||
type UI struct {
|
type UI struct {
|
||||||
base ebitenui.UI
|
base ebitenui.UI
|
||||||
colors map[string]color.RGBA
|
colors map[string]color.RGBA
|
||||||
width, height int
|
width, height int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The `hazakura` colorscheme (default)
|
||||||
|
var hazakura = map[string]color.RGBA{
|
||||||
|
// The monotone colors
|
||||||
|
"dark_black": color.RGBA{0x0f, 0x0f, 0x0d, 0xff},
|
||||||
|
"black": color.RGBA{0x15, 0x15, 0x17, 0xff},
|
||||||
|
"dark_gray": color.RGBA{0x24, 0x24, 0x26, 0xff},
|
||||||
|
"gray": color.RGBA{0x27, 0x27, 0x2b, 0xff},
|
||||||
|
"light_gray": color.RGBA{0x45, 0x44, 0x49, 0xff},
|
||||||
|
"overlay": color.RGBA{0x5c, 0x5c, 0x61, 0xff},
|
||||||
|
"subwhite": color.RGBA{0xd9, 0x0, 0xd7, 0xff},
|
||||||
|
"white": color.RGBA{0xec, 0xe5, 0xea, 0xff},
|
||||||
|
|
||||||
|
// Actual* colors
|
||||||
|
"red": color.RGBA{0xf0, 0x69, 0x69, 0xff},
|
||||||
|
"magenta": color.RGBA{0xe8, 0x87, 0xbb, 0xff},
|
||||||
|
"purple": color.RGBA{0xa2, 0x92, 0xe8, 0xff},
|
||||||
|
"blue": color.RGBA{0x78, 0xb9, 0xc4, 0xff},
|
||||||
|
"cyan": color.RGBA{0x7e, 0xe6, 0xae, 0xff},
|
||||||
|
"green": color.RGBA{0x91, 0xd6, 0x5c, 0xff},
|
||||||
|
"yellow": color.RGBA{0xd9, 0xd5, 0x64, 0xff},
|
||||||
|
}
|
||||||
|
|
||||||
// Function for UI initialization
|
// Function for UI initialization
|
||||||
func uiInit(width, height int) UI {
|
func uiInit(width, height int) UI {
|
||||||
var ui UI
|
var ui UI
|
||||||
// The `hazakura` colorscheme
|
|
||||||
{
|
|
||||||
hazakura := make(map[string]color.RGBA)
|
|
||||||
// The monotone colors
|
|
||||||
hazakura["dark_black"] = color.RGBA{0x0f, 0x0f, 0x0d, 0xff}
|
|
||||||
hazakura["black"] = color.RGBA{0x15, 0x15, 0x17, 0xff}
|
|
||||||
hazakura["dark_gray"] = color.RGBA{0x24, 0x24, 0x26, 0xff}
|
|
||||||
hazakura["gray"] = color.RGBA{0x27, 0x27, 0x2b, 0xff}
|
|
||||||
hazakura["light_gray"] = color.RGBA{0x45, 0x44, 0x49, 0xff}
|
|
||||||
hazakura["overlay"] = color.RGBA{0x5c, 0x5c, 0x61, 0xff}
|
|
||||||
hazakura["highlight"] = color.RGBA{0xd9, 0x0, 0xd7, 0xff}
|
|
||||||
hazakura["subwhite"] = color.RGBA{0xec, 0xe5, 0xea, 0xff}
|
|
||||||
|
|
||||||
// Actual* colors
|
// Define the UI colors
|
||||||
hazakura["red"] = color.RGBA{0xf0, 0x69, 0x69, 0xff}
|
ui.colors = hazakura
|
||||||
hazakura["magenta"] = color.RGBA{0xe8, 0x87, 0xbb, 0xff}
|
|
||||||
hazakura["purple"] = color.RGBA{0xa2, 0x92, 0xe8, 0xff}
|
|
||||||
hazakura["blue"] = color.RGBA{0x78, 0xb9, 0xc4, 0xff}
|
|
||||||
hazakura["cyan"] = color.RGBA{0x7e, 0xe6, 0xae, 0xff}
|
|
||||||
hazakura["green"] = color.RGBA{0x91, 0xd6, 0x5c, 0xff}
|
|
||||||
hazakura["yellow"] = color.RGBA{0xd9, 0xd5, 0x64, 0xff}
|
|
||||||
|
|
||||||
ui.colors = hazakura
|
// Load the images for the button states
|
||||||
}
|
buttonImage, _ := loadButtonImage()
|
||||||
|
|
||||||
// Get the window width/height
|
// Get the window width/height
|
||||||
ui.width = width
|
ui.width = width
|
||||||
|
@ -55,12 +68,136 @@ func uiInit(width, height int) UI {
|
||||||
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["dark_black"])),
|
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["dark_black"])),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Make the different faces
|
||||||
|
headingFace, _ := makeFace(18, fonts.IosevkaBold_ttf)
|
||||||
|
defaultFace, _ := makeFace(14, fonts.IosevkaRegular_ttf)
|
||||||
|
|
||||||
|
// Create the 'Profile' tab
|
||||||
|
tabProfile := widget.NewTabBookTab("Profile",
|
||||||
|
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["gray"])),
|
||||||
|
widget.ContainerOpts.Layout(widget.NewGridLayout(
|
||||||
|
//Define number of columns in the grid
|
||||||
|
widget.GridLayoutOpts.Columns(2),
|
||||||
|
// Specify the Stretch for each row and column.
|
||||||
|
widget.GridLayoutOpts.Stretch([]bool{false, true}, nil),
|
||||||
|
// Define the spacing between items in the grid
|
||||||
|
widget.GridLayoutOpts.Spacing(20, 15),
|
||||||
|
// Define the padding in the grid
|
||||||
|
widget.GridLayoutOpts.Padding(widget.NewInsetsSimple(20)),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
// Add the player stats as content for the 'profile' tab
|
||||||
|
makeStatsBars(tabProfile, ui, defaultFace)
|
||||||
|
|
||||||
|
// Create the 'Inventory' tab
|
||||||
|
tabInventory := widget.NewTabBookTab("Inventory",
|
||||||
|
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["gray"])),
|
||||||
|
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
|
||||||
|
)
|
||||||
|
inventoryButton := widget.NewText(
|
||||||
|
widget.TextOpts.Text("Placeholder", headingFace, ui.colors["white"]),
|
||||||
|
widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter),
|
||||||
|
widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
tabInventory.AddChild(inventoryButton)
|
||||||
|
|
||||||
|
// Create the 'Other' tab
|
||||||
|
tabOther := widget.NewTabBookTab("Other",
|
||||||
|
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["gray"])),
|
||||||
|
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
|
||||||
|
)
|
||||||
|
otherButton := widget.NewText(
|
||||||
|
widget.TextOpts.Text("Placeholder", headingFace, ui.colors["white"]),
|
||||||
|
widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter),
|
||||||
|
widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
tabOther.AddChild(otherButton)
|
||||||
|
|
||||||
|
// Create the tabbook widget
|
||||||
|
leftTabs := widget.NewTabBook(
|
||||||
|
widget.TabBookOpts.TabButtonImage(buttonImage),
|
||||||
|
widget.TabBookOpts.TabButtonText(headingFace, &widget.ButtonTextColor{Idle: color.White}),
|
||||||
|
widget.TabBookOpts.TabButtonSpacing(0),
|
||||||
|
widget.TabBookOpts.ContainerOpts(
|
||||||
|
widget.ContainerOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
StretchHorizontal: true,
|
||||||
|
StretchVertical: true,
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
widget.TabBookOpts.TabButtonOpts(
|
||||||
|
widget.ButtonOpts.TextPadding(widget.NewInsetsSimple(5)),
|
||||||
|
widget.ButtonOpts.WidgetOpts(widget.WidgetOpts.MinSize(int(float32(width)/(3.5*3)), 0)),
|
||||||
|
),
|
||||||
|
widget.TabBookOpts.Tabs(tabProfile, tabInventory, tabOther),
|
||||||
|
)
|
||||||
// Define the left bar container
|
// Define the left bar container
|
||||||
leftBar := widget.NewContainer(
|
leftBar := widget.NewContainer(
|
||||||
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["gray"])),
|
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["gray"])),
|
||||||
|
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
|
||||||
)
|
)
|
||||||
|
// Add the tabbook to the left bar
|
||||||
|
leftBar.AddChild(leftTabs)
|
||||||
|
|
||||||
|
// Define the contents of the chat window
|
||||||
|
chatContainer := widget.NewContainer(
|
||||||
|
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["black"])),
|
||||||
|
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
|
||||||
|
)
|
||||||
|
chatContainer.AddChild(widget.NewText(
|
||||||
|
widget.TextOpts.Text("Placeholder", defaultFace, ui.colors["white"]),
|
||||||
|
widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
})),
|
||||||
|
))
|
||||||
|
// Define the titlebar for the window
|
||||||
|
chatTitleContainer := widget.NewContainer(
|
||||||
|
// Set the background color of the titlebar
|
||||||
|
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["overlay"])),
|
||||||
|
widget.ContainerOpts.Layout(widget.NewAnchorLayout()),
|
||||||
|
)
|
||||||
|
chatTitleContainer.AddChild(widget.NewText(
|
||||||
|
widget.TextOpts.Text("Chat", headingFace, ui.colors["white"]),
|
||||||
|
widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
})),
|
||||||
|
))
|
||||||
|
|
||||||
|
// Define the chat window
|
||||||
|
chat := widget.NewWindow(
|
||||||
|
// Set the contents of the window
|
||||||
|
widget.WindowOpts.Contents(chatContainer),
|
||||||
|
// Set the titlebar for the window
|
||||||
|
widget.WindowOpts.TitleBar(chatTitleContainer, 25),
|
||||||
|
//Set the window above everything else and block input elsewhere
|
||||||
|
widget.WindowOpts.Modal(),
|
||||||
|
// Set how to close the window. CLICK_OUT will close the window when clicking anywhere
|
||||||
|
widget.WindowOpts.CloseMode(widget.CLICK_OUT),
|
||||||
|
// Make the window draggable
|
||||||
|
widget.WindowOpts.Draggable(),
|
||||||
|
// Make the window resizeable
|
||||||
|
widget.WindowOpts.Resizeable(),
|
||||||
|
// Set the minimum size of the window
|
||||||
|
widget.WindowOpts.MinSize(int(float32(width)/3.6), int(float32(height)/3.5)),
|
||||||
|
// Set the maximum size of the window
|
||||||
|
widget.WindowOpts.MaxSize(width/2, height/2),
|
||||||
|
)
|
||||||
|
// Place the window and add the window to the UI
|
||||||
|
showWindow(chat, ui, float32(width)-float32(width)/3.6, float32(height)-float32(height)/3.5)
|
||||||
|
ui.base.AddWindow(chat)
|
||||||
|
|
||||||
// Set the position and size of the left bar
|
// Set the position and size of the left bar
|
||||||
leftBar.SetLocation(img.Rect(0, 0, int(float64(width)/3.5), height))
|
leftBar.SetLocation(img.Rect(0, 0, int(float32(width)/3.5), height))
|
||||||
// Add the left bar to the root container
|
// Add the left bar to the root container
|
||||||
root.AddChild(leftBar)
|
root.AddChild(leftBar)
|
||||||
|
|
||||||
|
@ -68,3 +205,190 @@ func uiInit(width, height int) UI {
|
||||||
|
|
||||||
return ui
|
return ui
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set a window's location and open the window
|
||||||
|
func showWindow(window *widget.Window, ui UI, v float32, h float32) {
|
||||||
|
// Get the preferred size of the content
|
||||||
|
x, y := window.Contents.PreferredSize()
|
||||||
|
// Create a rect with the preferred size of the content
|
||||||
|
r := img.Rect(0, 0, x, y)
|
||||||
|
// Use the Add method to move the window to the specified point
|
||||||
|
r = r.Add(img.Point{int(v), int(h)})
|
||||||
|
// Set the windows location to the rect
|
||||||
|
window.SetLocation(r)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create progressbars for all the player stats
|
||||||
|
func makeStatsBars(parent *widget.TabBookTab, ui UI, face font.Face) {
|
||||||
|
// Health
|
||||||
|
health := widget.NewText(
|
||||||
|
widget.TextOpts.Text("Health", face, ui.colors["white"]),
|
||||||
|
widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.GridLayoutData{
|
||||||
|
HorizontalPosition: widget.GridLayoutPositionStart,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
health_progressbar := widget.NewProgressBar(
|
||||||
|
widget.ProgressBarOpts.WidgetOpts(
|
||||||
|
// Set the required anchor layout data to determine where in the container to place the progressbar
|
||||||
|
widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
}),
|
||||||
|
// Set the minimum size for the progressbar.
|
||||||
|
widget.WidgetOpts.MinSize(200, 20),
|
||||||
|
),
|
||||||
|
widget.ProgressBarOpts.Images(
|
||||||
|
// Set the track colors
|
||||||
|
&widget.ProgressBarImage{
|
||||||
|
Idle: image.NewNineSliceColor(ui.colors["black"]),
|
||||||
|
Hover: image.NewNineSliceColor(ui.colors["black"]),
|
||||||
|
},
|
||||||
|
// Set the progress colors
|
||||||
|
&widget.ProgressBarImage{
|
||||||
|
Idle: image.NewNineSliceColor(ui.colors["red"]),
|
||||||
|
Hover: image.NewNineSliceColor(ui.colors["red"]),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Set the min, max, and current values for each progressbar
|
||||||
|
widget.ProgressBarOpts.Values(0, testPlayer.health, testPlayer.health),
|
||||||
|
)
|
||||||
|
parent.AddChild(health)
|
||||||
|
parent.AddChild(health_progressbar)
|
||||||
|
|
||||||
|
// Defence
|
||||||
|
defence := widget.NewText(
|
||||||
|
widget.TextOpts.Text("Defence", face, ui.colors["white"]),
|
||||||
|
widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.GridLayoutData{
|
||||||
|
HorizontalPosition: widget.GridLayoutPositionStart,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
defence_progressbar := widget.NewProgressBar(
|
||||||
|
widget.ProgressBarOpts.WidgetOpts(
|
||||||
|
// Set the required anchor layout data to determine where in the container to place the progressbar
|
||||||
|
widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
}),
|
||||||
|
// Set the minimum size for the progressbar.
|
||||||
|
widget.WidgetOpts.MinSize(200, 20),
|
||||||
|
),
|
||||||
|
widget.ProgressBarOpts.Images(
|
||||||
|
// Set the track colors
|
||||||
|
&widget.ProgressBarImage{
|
||||||
|
Idle: image.NewNineSliceColor(ui.colors["black"]),
|
||||||
|
Hover: image.NewNineSliceColor(ui.colors["black"]),
|
||||||
|
},
|
||||||
|
// Set the progress colors
|
||||||
|
&widget.ProgressBarImage{
|
||||||
|
Idle: image.NewNineSliceColor(ui.colors["yellow"]),
|
||||||
|
Hover: image.NewNineSliceColor(ui.colors["yellow"]),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Set the min, max, and current values for each progressbar
|
||||||
|
widget.ProgressBarOpts.Values(0, testPlayer.health, testPlayer.health),
|
||||||
|
)
|
||||||
|
parent.AddChild(defence)
|
||||||
|
parent.AddChild(defence_progressbar)
|
||||||
|
|
||||||
|
// XP/Level
|
||||||
|
level := widget.NewText(
|
||||||
|
widget.TextOpts.Text("Level", face, ui.colors["white"]),
|
||||||
|
widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.GridLayoutData{
|
||||||
|
HorizontalPosition: widget.GridLayoutPositionStart,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
level_progressbar := widget.NewProgressBar(
|
||||||
|
widget.ProgressBarOpts.WidgetOpts(
|
||||||
|
// Set the required anchor layout data to determine where in the container to place the progressbar
|
||||||
|
widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
}),
|
||||||
|
// Set the minimum size for the progressbar.
|
||||||
|
widget.WidgetOpts.MinSize(200, 20),
|
||||||
|
),
|
||||||
|
widget.ProgressBarOpts.Images(
|
||||||
|
// Set the track colors
|
||||||
|
&widget.ProgressBarImage{
|
||||||
|
Idle: image.NewNineSliceColor(ui.colors["black"]),
|
||||||
|
Hover: image.NewNineSliceColor(ui.colors["black"]),
|
||||||
|
},
|
||||||
|
// Set the progress colors
|
||||||
|
&widget.ProgressBarImage{
|
||||||
|
Idle: image.NewNineSliceColor(ui.colors["cyan"]),
|
||||||
|
Hover: image.NewNineSliceColor(ui.colors["cyan"]),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Set the min, max, and current values for each progressbar
|
||||||
|
widget.ProgressBarOpts.Values(0, testPlayer.health, testPlayer.health_max),
|
||||||
|
)
|
||||||
|
parent.AddChild(level)
|
||||||
|
parent.AddChild(level_progressbar)
|
||||||
|
|
||||||
|
// Ambition
|
||||||
|
ambition := widget.NewText(
|
||||||
|
widget.TextOpts.Text("Ambition", face, ui.colors["white"]),
|
||||||
|
widget.TextOpts.WidgetOpts(widget.WidgetOpts.LayoutData(widget.GridLayoutData{
|
||||||
|
HorizontalPosition: widget.GridLayoutPositionStart,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
ambition_progressbar := widget.NewProgressBar(
|
||||||
|
widget.ProgressBarOpts.WidgetOpts(
|
||||||
|
// Set the required anchor layout data to determine where in the container to place the progressbar
|
||||||
|
widget.WidgetOpts.LayoutData(widget.AnchorLayoutData{
|
||||||
|
HorizontalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
VerticalPosition: widget.AnchorLayoutPositionCenter,
|
||||||
|
}),
|
||||||
|
// Set the minimum size for the progressbar.
|
||||||
|
widget.WidgetOpts.MinSize(200, 20),
|
||||||
|
),
|
||||||
|
widget.ProgressBarOpts.Images(
|
||||||
|
// Set the track colors
|
||||||
|
&widget.ProgressBarImage{
|
||||||
|
Idle: image.NewNineSliceColor(ui.colors["black"]),
|
||||||
|
Hover: image.NewNineSliceColor(ui.colors["black"]),
|
||||||
|
},
|
||||||
|
// Set the progress colors
|
||||||
|
&widget.ProgressBarImage{
|
||||||
|
Idle: image.NewNineSliceColor(ui.colors["purple"]),
|
||||||
|
Hover: image.NewNineSliceColor(ui.colors["purple"]),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// Set the min, max, and current values for each progressbar
|
||||||
|
widget.ProgressBarOpts.Values(0, testPlayer.health, testPlayer.health),
|
||||||
|
)
|
||||||
|
parent.AddChild(ambition)
|
||||||
|
parent.AddChild(ambition_progressbar)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load a button image
|
||||||
|
func loadButtonImage() (*widget.ButtonImage, error) {
|
||||||
|
idle := image.NewNineSliceColor(hazakura["black"])
|
||||||
|
hover := image.NewNineSliceColor(hazakura["light_gray"])
|
||||||
|
pressed := image.NewNineSliceColor(hazakura["gray"])
|
||||||
|
pressedHover := image.NewNineSliceColor(hazakura["gray"])
|
||||||
|
disabled := image.NewNineSliceColor(hazakura["overlay"])
|
||||||
|
|
||||||
|
return &widget.ButtonImage{
|
||||||
|
Idle: idle,
|
||||||
|
Hover: hover,
|
||||||
|
Pressed: pressed,
|
||||||
|
PressedHover: pressedHover,
|
||||||
|
Disabled: disabled,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to create a face providing font size and file (from assets)
|
||||||
|
func makeFace(size float64, fontfile []byte) (font.Face, error) {
|
||||||
|
ttfFont, err := truetype.Parse(fontfile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return truetype.NewFace(ttfFont, &truetype.Options{
|
||||||
|
Size: size,
|
||||||
|
DPI: 72,
|
||||||
|
Hinting: font.HintingFull,
|
||||||
|
}), nil
|
||||||
|
}
|
||||||
|
|
Reference in a new issue