Centralized Tick Counter, Fix Actor Dragging Bug
* The game's tick counter was moved from Doodle.ticks to shmem.Tick where it is more easily available from every corner of the code. * Fix a bug in the Level Editor where dragging an already-existing actor from one part of your map to another, would cause it to lose all its data (especially its UUID), breaking links to other doodads. Now the existing Actor catches a ride on the drag object to be reinserted later. * Animate the Link Line visualizers between actors. They now animate a blinking color between magenta and grey-ish.
This commit is contained in:
parent
dc2695cfc9
commit
a504658055
11
TODO.md
11
TODO.md
|
@ -3,8 +3,7 @@
|
|||
## Alpha Launch Minimum Checklist
|
||||
|
||||
- [ ] Open Source Licenses
|
||||
- [ ] Doodad Scripts: an "end level" function for a level goalpost.
|
||||
|
||||
- [x] Doodad Scripts: an "end level" function for a level goalpost.
|
||||
|
||||
**Blocker Bugs:**
|
||||
|
||||
|
@ -16,7 +15,7 @@
|
|||
|
||||
- Doodads Palette:
|
||||
- [ ] Hide some doodads like the player character.
|
||||
- [ ] Pagination or scrolling UI for long lists of doodads.
|
||||
- [x] Pagination or scrolling UI for long lists of doodads.
|
||||
|
||||
**Nice to haves:**
|
||||
|
||||
|
@ -27,8 +26,8 @@
|
|||
- [ ] Single-player "campaign mode" of built-in levels.
|
||||
- campaign.json file format configuring the level order
|
||||
- [ ] Level Editor Improvements
|
||||
- [ ] Undo/Redo Function
|
||||
- [ ] Lines and Boxes
|
||||
- [x] Undo/Redo Function
|
||||
- [x] Lines and Boxes
|
||||
- [ ] Eraser Tool
|
||||
- [ ] Brush size and/or shape
|
||||
- [ ] Doodad CLI Tool Features
|
||||
|
@ -52,7 +51,7 @@
|
|||
- [ ] Doors
|
||||
- [x] Locked Doors and Keys
|
||||
- [x] Electric Doors
|
||||
- [ ] Trapdoors (1 of 4)
|
||||
- [x] Trapdoors (all 4 directions)
|
||||
|
||||
## Doodad Ideas
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ var (
|
|||
Cyan = RGBA(0, 255, 255, 255)
|
||||
DarkCyan = RGBA(0, 153, 153, 255)
|
||||
Yellow = RGBA(255, 255, 0, 255)
|
||||
Orange = RGBA(255, 153, 0, 255)
|
||||
DarkYellow = RGBA(153, 153, 0, 255)
|
||||
Magenta = RGBA(255, 0, 255, 255)
|
||||
Purple = RGBA(153, 0, 153, 255)
|
||||
|
|
|
@ -55,6 +55,11 @@ var (
|
|||
// Color for draggable doodad.
|
||||
DragColor = render.MustHexColor("#0099FF")
|
||||
|
||||
// Link lines drawn between connected doodads.
|
||||
LinkLineColor = render.Magenta
|
||||
LinkLighten = 128
|
||||
LinkAnimSpeed uint64 = 30 // ticks
|
||||
|
||||
PlayButtonFont = render.Text{
|
||||
FontFilename: "DejaVuSans-Bold.ttf",
|
||||
Size: 16,
|
||||
|
|
|
@ -36,7 +36,6 @@ type Doodle struct {
|
|||
|
||||
startTime time.Time
|
||||
running bool
|
||||
ticks uint64
|
||||
width int
|
||||
height int
|
||||
|
||||
|
@ -110,7 +109,7 @@ func (d *Doodle) Run() error {
|
|||
d.Engine.Clear(render.White)
|
||||
|
||||
start := time.Now() // Record how long this frame took.
|
||||
d.ticks++
|
||||
shmem.Tick++
|
||||
|
||||
// Poll for events.
|
||||
ev, err := d.Engine.Poll()
|
||||
|
|
|
@ -45,6 +45,19 @@ func NewStroke(shape Shape, color render.Color) *Stroke {
|
|||
}
|
||||
}
|
||||
|
||||
// Copy returns a duplicate of the Stroke reference.
|
||||
func (s *Stroke) Copy() *Stroke {
|
||||
nextStrokeID++
|
||||
return &Stroke{
|
||||
ID: nextStrokeID,
|
||||
Shape: s.Shape,
|
||||
Color: s.Color,
|
||||
|
||||
Points: []render.Point{},
|
||||
uniqPoint: map[render.Point]interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
// IterPoints returns an iterator of points represented by the stroke.
|
||||
//
|
||||
// For a Line, returns all of the points between PointA and PointB. For freehand,
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"git.kirsle.net/apps/doodle/lib/ui"
|
||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||
"git.kirsle.net/apps/doodle/pkg/branding"
|
||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
||||
"git.kirsle.net/apps/doodle/pkg/enum"
|
||||
"git.kirsle.net/apps/doodle/pkg/level"
|
||||
|
@ -333,12 +332,8 @@ func (u *EditorUI) SetupCanvas(d *Doodle) *uix.Canvas {
|
|||
// A drag event initiated inside the Canvas. This happens in the ActorTool
|
||||
// mode when you click an existing Doodad and it "pops" out of the canvas
|
||||
// and onto the cursor to be repositioned.
|
||||
drawing.OnDragStart = func(filename string) {
|
||||
doodad, err := doodads.LoadFile(filename)
|
||||
if err != nil {
|
||||
log.Error("drawing.OnDragStart: %s", err.Error())
|
||||
}
|
||||
u.startDragActor(doodad)
|
||||
drawing.OnDragStart = func(actor *level.Actor) {
|
||||
u.startDragActor(nil, actor)
|
||||
}
|
||||
|
||||
// A link event to connect two actors together.
|
||||
|
@ -350,7 +345,6 @@ func (u *EditorUI) SetupCanvas(d *Doodle) *uix.Canvas {
|
|||
b.Actor.AddLink(idA)
|
||||
|
||||
// Reset the Link tool.
|
||||
drawing.Tool = drawtool.ActorTool
|
||||
d.Flash("Linked '%s' and '%s' together", a.Doodad.Title, b.Doodad.Title)
|
||||
}
|
||||
|
||||
|
@ -369,15 +363,25 @@ func (u *EditorUI) SetupCanvas(d *Doodle) *uix.Canvas {
|
|||
return
|
||||
}
|
||||
|
||||
size := actor.canvas.Size()
|
||||
u.Scene.Level.Actors.Add(&level.Actor{
|
||||
var (
|
||||
// Uncenter the drawing from the cursor.
|
||||
Point: render.Point{
|
||||
size = actor.canvas.Size()
|
||||
position = render.Point{
|
||||
X: (u.cursor.X - drawing.Scroll.X - (size.W / 2)) - P.X,
|
||||
Y: (u.cursor.Y - drawing.Scroll.Y - (size.H / 2)) - P.Y,
|
||||
},
|
||||
Filename: actor.doodad.Filename,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
// Was it an already existing actor to re-add to the map?
|
||||
if actor.actor != nil {
|
||||
actor.actor.Point = position
|
||||
u.Scene.Level.Actors.Add(actor.actor)
|
||||
} else {
|
||||
u.Scene.Level.Actors.Add(&level.Actor{
|
||||
Point: position,
|
||||
Filename: actor.doodad.Filename,
|
||||
})
|
||||
}
|
||||
|
||||
err := drawing.InstallActors(u.Scene.Level.Actors)
|
||||
if err != nil {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"git.kirsle.net/apps/doodle/lib/ui"
|
||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||
"git.kirsle.net/apps/doodle/pkg/doodads"
|
||||
"git.kirsle.net/apps/doodle/pkg/level"
|
||||
"git.kirsle.net/apps/doodle/pkg/log"
|
||||
"git.kirsle.net/apps/doodle/pkg/uix"
|
||||
)
|
||||
|
@ -18,13 +19,29 @@ import (
|
|||
// DraggableActor is a Doodad being dragged from the Doodad palette.
|
||||
type DraggableActor struct {
|
||||
canvas *uix.Canvas
|
||||
doodad *doodads.Doodad
|
||||
doodad *doodads.Doodad // if a new one from the palette
|
||||
actor *level.Actor // if a level actor
|
||||
}
|
||||
|
||||
// startDragActor begins the drag event for a Doodad onto a level.
|
||||
func (u *EditorUI) startDragActor(doodad *doodads.Doodad) {
|
||||
// actor may be nil (if you drag a new doodad from the palette) or otherwise
|
||||
// is an existing actor from the level.
|
||||
func (u *EditorUI) startDragActor(doodad *doodads.Doodad, actor *level.Actor) {
|
||||
u.Supervisor.DragStart()
|
||||
|
||||
if doodad == nil {
|
||||
if actor != nil {
|
||||
obj, err := doodads.LoadFile(actor.Filename)
|
||||
if err != nil {
|
||||
log.Error("startDragExistingActor: actor doodad name %s not found: %s", actor.Filename, err)
|
||||
return
|
||||
}
|
||||
doodad = obj
|
||||
} else {
|
||||
panic("EditorUI.startDragActor: doodad AND/OR actor is required, but neither were given")
|
||||
}
|
||||
}
|
||||
|
||||
// Create the canvas to render on the mouse cursor.
|
||||
drawing := uix.NewCanvas(doodad.Layers[0].Chunker.Size, false)
|
||||
drawing.LoadDoodad(doodad)
|
||||
|
@ -34,6 +51,7 @@ func (u *EditorUI) startDragActor(doodad *doodads.Doodad) {
|
|||
u.DraggableActor = &DraggableActor{
|
||||
canvas: drawing,
|
||||
doodad: doodad,
|
||||
actor: actor,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +171,7 @@ func (u *EditorUI) setupDoodadFrame(e render.Engine, window *ui.Window) (*ui.Fra
|
|||
// editor_ui.go#SetupCanvas()
|
||||
btn.Handle(ui.MouseDown, func(e render.Point) {
|
||||
log.Warn("MouseDown on doodad %s (%s)", doodad.Filename, doodad.Title)
|
||||
u.startDragActor(doodad)
|
||||
u.startDragActor(doodad, nil)
|
||||
})
|
||||
u.Supervisor.Add(btn)
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"git.kirsle.net/apps/doodle/lib/ui"
|
||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||
"git.kirsle.net/apps/doodle/pkg/log"
|
||||
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
|
@ -146,7 +147,7 @@ func (s *Shell) Write(line string) {
|
|||
s.Output = append(s.Output, line)
|
||||
s.Flashes = append(s.Flashes, Flash{
|
||||
Text: line,
|
||||
Expires: s.parent.ticks + balance.FlashTTL,
|
||||
Expires: shmem.Tick + balance.FlashTTL,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -253,8 +254,8 @@ func (s *Shell) Draw(d *Doodle, ev *events.State) error {
|
|||
}
|
||||
|
||||
// Cursor flip?
|
||||
if d.ticks > s.cursorFlip {
|
||||
s.cursorFlip = d.ticks + s.cursorRate
|
||||
if shmem.Tick > s.cursorFlip {
|
||||
s.cursorFlip = shmem.Tick + s.cursorRate
|
||||
if s.cursor == ' ' {
|
||||
s.cursor = '_'
|
||||
} else {
|
||||
|
@ -329,7 +330,7 @@ func (s *Shell) Draw(d *Doodle, ev *events.State) error {
|
|||
outputY := int32(d.height - (lineHeight * 2) - 16)
|
||||
for i := len(s.Flashes); i > 0; i-- {
|
||||
flash := s.Flashes[i-1]
|
||||
if d.ticks >= flash.Expires {
|
||||
if shmem.Tick >= flash.Expires {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@ import (
|
|||
// Shared globals for easy access throughout the app.
|
||||
// Not an ideal place to keep things but *shrug*
|
||||
var (
|
||||
// Tick is incremented by the main game loop each frame.
|
||||
Tick uint64
|
||||
|
||||
// Current render engine (i.e. SDL2 or HTML5 Canvas)
|
||||
// The level.Chunk.ToBitmap() uses this to cache a texture image.
|
||||
CurrentRenderEngine render.Engine
|
||||
|
|
|
@ -67,7 +67,7 @@ type Canvas struct {
|
|||
// that controls the actors. Upstream should delete them and then reinstall
|
||||
// the actor list from scratch.
|
||||
OnDeleteActors func([]*level.Actor)
|
||||
OnDragStart func(filename string)
|
||||
OnDragStart func(*level.Actor)
|
||||
|
||||
// -- WHEN Canvas.Tool is "Link" --
|
||||
// When the Canvas wants to link two actors together. Arguments are the IDs
|
||||
|
|
|
@ -183,7 +183,7 @@ func (w *Canvas) loopEditable(ev *events.State) error {
|
|||
// Pop this canvas out for the drag/drop.
|
||||
if w.OnDragStart != nil {
|
||||
deleteActors = append(deleteActors, actor.Actor)
|
||||
w.OnDragStart(actor.Actor.Filename)
|
||||
w.OnDragStart(actor.Actor)
|
||||
}
|
||||
break
|
||||
} else if ev.Button2.Read() {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"git.kirsle.net/apps/doodle/pkg/drawtool"
|
||||
"git.kirsle.net/apps/doodle/pkg/level"
|
||||
"git.kirsle.net/apps/doodle/pkg/log"
|
||||
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||
)
|
||||
|
||||
// canvas_strokes.go: functions related to drawtool.Stroke and the Canvas.
|
||||
|
@ -115,6 +116,27 @@ func (w *Canvas) presentActorLinks(e render.Engine) {
|
|||
}
|
||||
}
|
||||
|
||||
// If no links, stop.
|
||||
if len(actorMap) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// The glow colored line. Huge hacky block of code but makes for some
|
||||
// basic visualization for now.
|
||||
var color = balance.LinkLineColor
|
||||
var lightenStep = float64(balance.LinkLighten) / 16
|
||||
var step = shmem.Tick % balance.LinkAnimSpeed
|
||||
if step < 32 {
|
||||
for i := uint64(0); i < step; i++ {
|
||||
color = color.Lighten(int(lightenStep))
|
||||
}
|
||||
if step > 16 {
|
||||
for i := uint64(0); i < step-16; i++ {
|
||||
color = color.Darken(int(lightenStep))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over the linked actors and draw stroke lines.
|
||||
for _, actor := range actorMap {
|
||||
for _, linkID := range actor.Actor.Links {
|
||||
|
@ -130,7 +152,7 @@ func (w *Canvas) presentActorLinks(e render.Engine) {
|
|||
)
|
||||
|
||||
// Draw a line connecting the centers of each actor together.
|
||||
stroke := drawtool.NewStroke(drawtool.Line, render.Magenta)
|
||||
stroke := drawtool.NewStroke(drawtool.Line, color)
|
||||
stroke.PointA = render.Point{
|
||||
X: aP.X + (aS.W / 2),
|
||||
Y: aP.Y + (aS.H / 2),
|
||||
|
@ -141,6 +163,16 @@ func (w *Canvas) presentActorLinks(e render.Engine) {
|
|||
}
|
||||
|
||||
strokes = append(strokes, stroke)
|
||||
|
||||
// Make it double thick.
|
||||
double := stroke.Copy()
|
||||
double.PointA = render.NewPoint(stroke.PointA.X, stroke.PointA.Y+1)
|
||||
double.PointB = render.NewPoint(stroke.PointB.X, stroke.PointB.Y+1)
|
||||
strokes = append(strokes, double)
|
||||
double = stroke.Copy()
|
||||
double.PointA = render.NewPoint(stroke.PointA.X+1, stroke.PointA.Y)
|
||||
double.PointB = render.NewPoint(stroke.PointB.X+1, stroke.PointB.Y)
|
||||
strokes = append(strokes, double)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user