2018-07-26 02:38:54 +00:00
|
|
|
package doodle
|
|
|
|
|
|
|
|
import (
|
2019-12-23 02:21:58 +00:00
|
|
|
"git.kirsle.net/go/render"
|
|
|
|
"git.kirsle.net/go/render/event"
|
2019-12-28 00:31:58 +00:00
|
|
|
"git.kirsle.net/go/ui"
|
2019-04-10 00:35:44 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
2019-06-24 00:52:48 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/branding"
|
2019-06-25 21:57:11 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/level"
|
|
|
|
"git.kirsle.net/apps/doodle/pkg/log"
|
2019-06-28 05:54:46 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/scripting"
|
2019-06-25 21:57:11 +00:00
|
|
|
"git.kirsle.net/apps/doodle/pkg/uix"
|
2018-07-26 02:38:54 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// MainScene implements the main menu of Doodle.
|
|
|
|
type MainScene struct {
|
2018-07-26 03:25:02 +00:00
|
|
|
Supervisor *ui.Supervisor
|
2018-08-01 00:18:13 +00:00
|
|
|
frame *ui.Frame
|
2019-06-25 21:57:11 +00:00
|
|
|
|
|
|
|
// Background wallpaper canvas.
|
2019-06-28 05:54:46 +00:00
|
|
|
scripting *scripting.Supervisor
|
|
|
|
canvas *uix.Canvas
|
2018-07-26 02:38:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Name of the scene.
|
|
|
|
func (s *MainScene) Name() string {
|
|
|
|
return "Main"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the scene.
|
|
|
|
func (s *MainScene) Setup(d *Doodle) error {
|
2018-07-26 03:25:02 +00:00
|
|
|
s.Supervisor = ui.NewSupervisor()
|
|
|
|
|
2019-06-28 05:54:46 +00:00
|
|
|
if err := s.SetupDemoLevel(d); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-06-25 21:57:11 +00:00
|
|
|
|
|
|
|
// Main UI button frame.
|
2018-08-02 01:52:52 +00:00
|
|
|
frame := ui.NewFrame("frame")
|
2018-08-01 00:18:13 +00:00
|
|
|
s.frame = frame
|
|
|
|
|
Add Switches, Fire/Water Collision and Play Menu
* New doodads: Switches.
* They come in four varieties: wall switch (background element, with
"ON/OFF" text) and three side-profile switches for the floor, left
or right walls.
* On collision with the player, they flip their state from "OFF" to
"ON" or vice versa. If the player walks away and then collides
again, the switch flips again.
* Can be used to open/close Electric Doors when turned on/off. Their
default state is "off"
* If a switch receives a power signal from another linked switch, it
sets its own state to match. So, two "on/off" switches that are
connected to a door AND to each other will both flip on/off when one
of them flips.
* Update the Level Collision logic to support Decoration, Fire and Water
pixel collisions.
* Previously, ALL pixels in the level were acting as though solid.
* Non-solid pixels don't count for collision detection, but their
attributes (fire and water) are collected and returned.
* Updated the MenuScene to support loading a map file in Play Mode
instead of Edit Mode. Updated the title screen menu to add a button
for playing levels instead of editing them.
* Wrote some documentation.
2019-07-07 01:30:03 +00:00
|
|
|
var buttons = []struct {
|
|
|
|
Name string
|
|
|
|
Func func()
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
Name: "Play a Level",
|
|
|
|
Func: d.GotoPlayMenu,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Create a New Level",
|
|
|
|
Func: d.GotoNewMenu,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Name: "Edit a Level",
|
|
|
|
Func: d.GotoLoadMenu,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, button := range buttons {
|
|
|
|
button := button
|
|
|
|
btn := ui.NewButton(button.Name, ui.NewLabel(ui.Label{
|
|
|
|
Text: button.Name,
|
|
|
|
Font: balance.StatusFont,
|
|
|
|
}))
|
|
|
|
btn.Handle(ui.Click, func(p render.Point) {
|
|
|
|
button.Func()
|
|
|
|
})
|
|
|
|
s.Supervisor.Add(btn)
|
|
|
|
frame.Pack(btn, ui.Pack{
|
|
|
|
Anchor: ui.N,
|
|
|
|
PadY: 8,
|
|
|
|
// Fill: true,
|
|
|
|
FillX: true,
|
|
|
|
})
|
|
|
|
}
|
2018-07-26 03:25:02 +00:00
|
|
|
|
2018-07-26 02:38:54 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-06-28 05:54:46 +00:00
|
|
|
// SetupDemoLevel configures the wallpaper behind the New screen,
|
|
|
|
// which demos a title screen demo level.
|
|
|
|
func (s *MainScene) SetupDemoLevel(d *Doodle) error {
|
|
|
|
// Set up the background wallpaper canvas.
|
|
|
|
s.canvas = uix.NewCanvas(100, false)
|
|
|
|
s.canvas.Scrollable = true
|
|
|
|
s.canvas.Resize(render.Rect{
|
|
|
|
W: int32(d.width),
|
|
|
|
H: int32(d.height),
|
|
|
|
})
|
|
|
|
|
|
|
|
s.scripting = scripting.NewSupervisor()
|
|
|
|
s.canvas.SetScriptSupervisor(s.scripting)
|
|
|
|
|
2019-07-07 03:31:50 +00:00
|
|
|
// Title screen level to load.
|
|
|
|
if lvl, err := level.LoadFile("example1.level"); err == nil {
|
|
|
|
s.canvas.LoadLevel(d.Engine, lvl)
|
|
|
|
s.canvas.InstallActors(lvl.Actors)
|
|
|
|
|
|
|
|
// Load all actor scripts.
|
|
|
|
if err := s.scripting.InstallScripts(lvl); err != nil {
|
|
|
|
log.Error("Error with title screen level scripts: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run all actors scripts main function to start them off.
|
|
|
|
if err := s.canvas.InstallScripts(); err != nil {
|
|
|
|
log.Error("Error running actor main() functions: %s", err)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Error("Error loading title-screen.level: %s", err)
|
2019-06-28 05:54:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-07-26 02:38:54 +00:00
|
|
|
// Loop the editor scene.
|
2019-12-22 22:11:01 +00:00
|
|
|
func (s *MainScene) Loop(d *Doodle, ev *event.State) error {
|
2018-07-26 03:25:02 +00:00
|
|
|
s.Supervisor.Loop(ev)
|
2019-06-25 21:57:11 +00:00
|
|
|
|
2019-06-28 05:54:46 +00:00
|
|
|
if err := s.scripting.Loop(); err != nil {
|
|
|
|
log.Error("MainScene.Loop: scripting.Loop: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
s.canvas.Loop(ev)
|
|
|
|
|
2019-12-22 22:11:01 +00:00
|
|
|
if ev.WindowResized {
|
2019-06-25 21:57:11 +00:00
|
|
|
w, h := d.Engine.WindowSize()
|
|
|
|
d.width = w
|
|
|
|
d.height = h
|
|
|
|
log.Info("Resized to %dx%d", d.width, d.height)
|
|
|
|
s.canvas.Resize(render.Rect{
|
|
|
|
W: int32(d.width),
|
|
|
|
H: int32(d.height),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-07-26 02:38:54 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the pixels on this frame.
|
|
|
|
func (s *MainScene) Draw(d *Doodle) error {
|
|
|
|
// Clear the canvas and fill it with white.
|
|
|
|
d.Engine.Clear(render.White)
|
|
|
|
|
2019-06-25 21:57:11 +00:00
|
|
|
s.canvas.Present(d.Engine, render.Origin)
|
|
|
|
|
2019-06-28 05:54:46 +00:00
|
|
|
// Draw a sheen over the level for clarity.
|
|
|
|
d.Engine.DrawBox(render.RGBA(255, 255, 254, 128), render.Rect{
|
|
|
|
X: 0,
|
|
|
|
Y: 0,
|
|
|
|
W: int32(d.width),
|
|
|
|
H: int32(d.height),
|
|
|
|
})
|
|
|
|
|
2018-08-05 19:54:57 +00:00
|
|
|
label := ui.NewLabel(ui.Label{
|
2019-06-24 00:52:48 +00:00
|
|
|
Text: branding.AppName,
|
2018-08-05 19:54:57 +00:00
|
|
|
Font: render.Text{
|
2019-06-27 01:36:54 +00:00
|
|
|
Size: 46,
|
2018-08-05 19:54:57 +00:00
|
|
|
Color: render.Pink,
|
|
|
|
Stroke: render.SkyBlue,
|
|
|
|
Shadow: render.Black,
|
|
|
|
},
|
2018-07-26 02:38:54 +00:00
|
|
|
})
|
|
|
|
label.Compute(d.Engine)
|
|
|
|
label.MoveTo(render.Point{
|
2018-10-19 20:31:58 +00:00
|
|
|
X: (int32(d.width) / 2) - (label.Size().W / 2),
|
2018-07-26 02:38:54 +00:00
|
|
|
Y: 120,
|
|
|
|
})
|
2018-08-05 19:54:57 +00:00
|
|
|
label.Present(d.Engine, label.Point())
|
2018-07-26 02:38:54 +00:00
|
|
|
|
2018-08-01 00:18:13 +00:00
|
|
|
s.frame.Compute(d.Engine)
|
|
|
|
s.frame.MoveTo(render.Point{
|
2018-10-19 20:31:58 +00:00
|
|
|
X: (int32(d.width) / 2) - (s.frame.Size().W / 2),
|
2019-06-27 01:36:54 +00:00
|
|
|
Y: 260,
|
2018-08-01 00:18:13 +00:00
|
|
|
})
|
2018-08-05 19:54:57 +00:00
|
|
|
s.frame.Present(d.Engine, s.frame.Point())
|
2018-07-26 02:38:54 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy the scene.
|
|
|
|
func (s *MainScene) Destroy() error {
|
|
|
|
return nil
|
|
|
|
}
|