Add multi-touch gesture support so that the player can scroll the level
in the editor (and title screen) by treating a two finger swipe to be
equivalent to a middle click drag.
Fun quirks found with SDL2's MultiGestureEvent:
* They don't begin sending us the event until motion is detected after
two fingers have touched the screen; not the moment the second finger
touches it.
* It spams us with events when it detects any tiny change and a lot of
cool details like rotate/pinch deltas, but it never tells us when the
multitouch STOPS! The game has to block left clicks while multitouch
happens so the user doesn't draw all over their level, so it needs to
know when touch has ended.
* The workaround is to track the mouse cursor position at the first
touch and each delta thereafter; if the deltas stop changing tick to
tick, unset the "is touching" variable.
In the level editor, the "Play (P)" button has a new feature: Play
From Here. On mouse down you begin dragging a silhouette of Boy or
whoever the default player character is, as if you were dragging a
doodad onto your level.
Drop the silhouette on your level and enter Play Mode from that
location instead of the Start Flag.
Release your cursor over the Play button or press the "P" key to
spawn at the Start Flag as usual.
In the editor, clicking and dragging with the middle mouse button
will scroll the view of the editor in place of the arrow keys.
When entering Play Mode, the original scroll position in the level
editor is remembered for when you come back - no more having to
scroll from 0,0 each time to get back to where you were working!
The game can now be played using only a touch screen! The left
mouse click (Button1) can now move and control the player
character.
* A box in the very middle of the screen is the "Use" button and
a deadzone for directional inputs.
* Anywhere outside the middle and to the left registers a Left
button, to the right a Right button, above the top of the middle
is a Jump button, and below the bottom of the middle is a down
input (for antigravity mode).
* Tight platforming is possible: above and below the middle box,
the left/right split is tight in the middle of the window. You
can get tight jumps if jumping or go below if you don't want to
jump. The left/right deadzone is only over the space of the Use
button.
If the player is idle for a while with no controller inputs, some
hints will fade in about the touch controls.
Note: the ScrollboxOffset to track the player character is changed
to 60,60 from 60,100 so the camera will track tighter to the player
and so the player will mostly be over the Use button on touch
controls as long as he's away from a level boundary.
In the Level Editor, the "Level->New viewport" menu opens a window with
its own view into your level. You can open as many viewports as you
want.
* Mouse over a viewport and the arrow keys scroll that canvas instead of
the main editor canvas!
* You can draw inside the viewports! A selectbox to choose the tool to
draw with. No palette or thickness support yet!
* The actors are installed as-is when the viewport is created and it
doesn't show any changes to actors after. Make a new viewport for a
refreshed view.
* Strokes committed inside the viewport show up in the main editor (and
in other viewports), and vice versa. The viewports accurately track
changes to the level's colors, just not the actors.
* Fun feature to load a DIFFERENT level inside of the viewport! Editing
that level doesn't save changes or anything.
In the Level Editor, the "Level->Giant Screenshot" menu will take a full
scale PNG screenshot of the entire level, with its wallpaper and
doodads, and save it in ~/.config/doodle/screenshots.
It is currently CPU intensive and slow. With future work it should be
made asynchronous. The function is abstracted away nicely so that the
doodad CLI tool may support this as well.
The Checkpoint Region acts as an invisible checkpoint flag, remembering
the player's location should they need to respawn there.
New cheat: `show all actors` during Play Mode will make every hidden
actor visible. Useful to see your technical doodads during gameplay!
Developer shell: `Execute(command string)` is available to the
JavaScript interpreter. It simulates another command being run on the
developer console.
New category for the Doodad Dropper: "Technical"
Technical doodads have a dashed outline and label for now, and they
turn invisible on level start, and are for hidden technical effects on
your level.
The doodads include:
* Goal Region: acts like an invisible Exit Flag (128x128), the level is
won when the player character touches this region.
* Fire Region: acts like a death barrier (128x128), kills the player
when a generic "You have died!" message.
* Power Source: on level start, acts like a switch and emits a
power(true) signal to all linked doodads. Link it to your Electric
Door for it to be open by default in your level!
* Stall Player (250ms): The player is paused for a moment the first time
it touches this region. Useful to work around timing issues, e.g.
help prevent the player from winning a race against another character.
There are some UI improvements to the Doodad Dropper window:
* If the first page of doodads is short, extra spacers are added so the
alignment and size shows correctly.
* Added a 'background pattern' to the window: any unoccupied icon space
has an inset rectangle slot.
* "Last pages" which are short still render weirdly without reserving
the correct height in the TabFrame.
Doodad scripting engine updates:
* Self.Hide() and Self.Show() available.
* Subscribe to "broadcast:ready" to know when the level is ready, so you
can safely Publish messages without deadlocks!
For levels having a top/left scroll boundary, the top/left point takes
higher priority for resolving out-of-bounds scroll ranges instead of the
bottom/right.
This fixes a bug where you Zoom Out of a level far enough that the
entire boundaries of a Bounded level are smaller than the viewport into
the level. It could happen if playing normal levels in Play Mode on a
very high-resolution monitor. Previously, the level would anchor to the
bottom/right corner of your screen.
With the Zoom In/Out Feature this broke the ability to scroll well on
the level; so the easy fix is to put the X>0, Y>0 bounds check after the
above, so the level will hug the top/left corner of the screen which
fixes both problems.
* If you open a wide unbounded level like Castle.level and zoom out and
scroll left (into negative world coordinates), the level chunks
display correctly now.
* Doodad outline while dragging is now sized properly for the zoom level
* Make doodad hitboxes for Actor/Link Tool more accurate while zoomed
* Fix chunks low on the level not loading while zoomed in
* Fix Link lines drawn between doodads while zoomed - they point to the
correct position and their DrawLine calls have been optimized so they
don't lag out the level when lots of them are drawn at once.
* When the Actor Tool or Link Tool is active, mouse-over hitboxes on the
level's actors now works correctly while zoomed and scrolling in the
level.
* Regression: Level chunks don't appear outside a certain range from
origin while zoomed in.
* Regression: Actors don't draw their sprite while zoomed in, but do
when zoomed out.
Improvements to the Zoom feature:
* Actor position and size within your level scales up and down
appropriately. The canvas size of the actor is scaled and its canvas
is told the Zoom number of the parent so it will render its own
graphic scaled correctly too.
Other features:
* "Experimental" tab added to the Settings window as a UI version of the
--experimental CLI option. The option saves persistently to disk.
* The "Replace Palette" experimental feature now works better. Debating
whether it's a useful feature to even have.
Progress on the Zoom feature: when you zoom in and out, you can draw
shapes accurately onto the level. Seems a little buggy if you edit
while scrolling (as in drawing a very long line).
The title screen buttons are now more colorful.
A new property is added to the Doodad struct: Hitbox (Rect).
The uix.Actor for Play Mode will defer to the Doodad.Hitbox until the
JavaScript has manually set its own via Self.SetHitbox(). So in effect,
scripts no longer need to worry about their hitbox! The one assigned to
the Doodad will be the default.
Scripts can check if their hitbox is zero before setting a default:
if (Self.Hitbox().IsZero()) {
var size = Self.Size() // get doodad canvas size
Self.SetHitbox(0, 0, size, size) // the full square
}
The built-in generic doodad scripts have made this change, so that your
simple doodad can have a custom hitbox defined easily using in-game
tools.
Other changes:
* New script: Generic Collectible Item. Selecting it will add a
"quantity" tag to your doodad, to easily configure the script.
* JavaScript API: "Self.Hitbox()" returns your doodad's current hitbox.
You can check "Self.Hitbox.IsZero()" to check if it's empty.
In the Doodad Properties window, instead of browsing to select a .js
file to install your script, a SelectBox of built-in generic scripts are
available. These scripts implement simple behaviors and adapt to the
full canvas size of the doodad.
Built-in scripts so far include:
* generic-anvil.js: behaves just like the Anvil.
* generic-fire.js: the entire canvas hitbox acts like fire pixels,
"burning" mobile doodads and failing the level for the player.
* generic-solid.js: the entire canvas hitbox acts solid
The Doodad Properties window brings many features that used to be
available only in the `doodad` CLI tool into the Doodad Editor.
* In the Doodad Editor there is a new menubar item: "Doodad" which
corresponds to the "Level" menu when you're editing a level.
* The "Doodad" menu has two items:
- "Doodad Properties" (NEW)
- "Layers" (moved here from the Tools menu)
* The Doodad Properties window lets you edit the Title and Author values
of the doodad, as well as modify its Tags and manage its Script.
* Its script can be attached (browse for .js file on disk), its existing
script saved back to disk (dev shell prompt) or deleted altogether
from the doodad.
* You can create, modify, and delete Tags on the doodad.
Other changes:
* In the Level Editor, the "Level->Page Settings" menu is renamed to
"Level->Level Properties" to match with "Doodad->Doodad Properties"
and the pop-up window is retitled accordingly.
* The Exit Flag only exits if the Player touches it - not just any
mobile doodad!
* New Doodad: Checkpoint Flag. They update the player's spawn point
whenever the player passes one. The most recently activated
checkpoint is rendered brighter than the others.
* End Level Modal: the fake alert box window drawn by the Play Mode
is replaced with a fancy modal widget (similar to Alert and Confirm).
It handles level victory or failure conditions and can show or hide
all the buttons as needed.
* Gameplay: There is a "Retry from Checkpoint" option added, which
appears in the level failure modal. It will teleport you back to
the Start Flag or the last Checkpoint Flag you had touched, without
resetting the level -- your keys, unlocked doors, etc. will be
preserved so you can retry.
* Set a maximum speed on the "Camera Follows Actor" logic of 64
pixels per tick. This results in a smoother scrolling transition
when the player jumps to a new location on the map, such as by
a Warp Door.
* Update the default color palettes:
* All: Add a "hint" magenta color.
* Colored Pencil: Add a "darkstone" solid color.
Updates to the Doodads JavaScript API:
* SetCheckpoint(Point(x, y)): set the player character's spawn
position. Giving it Self.Position() is an easy way to set the
player spawn to your doodad's location.
* Added the Death Barrier to Play Mode to catch players from falling off
the map and then falling indefinitely, especially on Unbounded maps.
* The Death Barrier is set 1,000 pixels below the lowest point on your
map. If the player falls here they get a death message: "Watch out for
falling off the map!"
* Added cheat codes to change the default Player Character doodad, as a
way to force play as a different character (for levels which don't
specify a custom character):
* Play as Bird: fly like a bird
* Play as Blue Azulian: the cell
* Play as Thief: play as thief
* Reset to default (Boy): pinocchio
New feature: link a Start Flag to another doodad in your level
and you will play as that doodad instead of Boy. All Creatures
are designed to be playable. Playing as "other" doodads leads
to interesting effects, like not being able to activate buttons,
switches, or warp doors and not having an inventory to pick up
keys. The Anvil is fun: it can destroy other mobile doodads by
jumping on them.
If the actor does not specify that it has gravity, the gameplay
starts in antigravity mode. This will be the vast majority of
non-mobile doodads and the Bird.
Other changes:
* The Blue and Red Azulians now share a doodad script.
* The Azulians AI is still to walk back and forth, pickup keys and
press buttons. The Blue Azulian walks slower than the red one.
* The Blue Azulian is no longer hidden from the doodads list.
* Actor UUID values in levels are now V1 UUIDs (time-ordered).
This will help to reliably resolve conflicts in draw order
of overlapping doodads (newest added to level wins).
* Link Tool: clicking on a pair of already-linked doodads will
now unlink them, so you don't have to delete one to delete
the link.
* Actor Tool: deleting an actor immediately calls PruneLinks()
to clean up any links that the deleted doodad might have.
This commit adds the Thief character with starter graphics
(no animations).
The Thief walks back and forth and will steal items from other
doodads, including the player. For singleton items that have no
quantity, like the Colored Keys, the Thief will only steal one
if he does not already have it. Quantitied items like the
Small Key are always stolen.
Flexibility in the playable character is introduced: Boy,
Azulian, Bird, and Thief all respond to playable controls.
There is not currently a method to enable these apart from
modifying balance.PlayerCharacterDoodad at compile time.
New and Changed Doodads
* Thief: new doodad that walks back and forth and will steal
items from other characters inventory.
* Bird: has no inventory and cannot pick up items, unless player
controlled. Its hitbox has also been fixed so it collides with
floors correctly - not something normally seen in the Bird.
* Boy: opts in to have inventory.
* Keys (all): only gives themselves to actors having inventories.
JavaScript API - New functions available
* Self.IsPlayer() - returns if the current actor IS the player.
* Self.SetInventory(bool) - doodads must opt-in to having an
inventory. Keys should only give themselves to doodads having
an inventory.
* Self.HasInventory() bool
* Self.AddItem(filename, qty)
* Self.RemoveItem(filename, qty)
* Self.HasItem(filename)
* Self.Inventory() - returns map[string]int
* Self.ClearInventory()
* Self.OnLeave(func(e)) now receives a CollideEvent as parameter
instead of the useless actor ID. Notably, e.Actor is the
leaving actor and e.Settled is always true.
Other Changes
* Play Mode: if playing as a character which doesn't obey gravity,
such as the bird, antigravity controls are enabled by default.
If you `import antigravity` you can turn gravity back on.
* Doodad collision scripts are no longer run in parallel
goroutines. It made the Thief's job difficult trying to steal
items in many threads simultaneously!
* The Anvil doodad is affected by gravity and becomes dangerous when
falling. If it lands on the player character, you die! If it lands on
any other mobile doodad, it destroys it! It can land on solid doodads
such as the Electric Trapdoor and the Crumbly Floor. It will activate
a Crumbly Floor if it lands on one, and can activate buttons and
switches that it passes.
* JavaScript API: FailLevel(message) can be called from a doodad to kill
the player character. The Anvil does this if it collides with the
player while it's been falling.
* New doodad: Electric Trapdoor. It is a horizontal version of the
Electric Door. Opens while powered by a button or a switch and closes
when it loses power.
* The Box doodad will reset to its original location if it receives a
power signal from a linked Button or Switch. So for box pushing
puzzles you can add a reset button in case the boxes get stuck.
* Refactored the Doodad build scripts into many Makefiles for easier
iteration (don't need to compile ALL doodads to test one).
Updates to the JavaScript API for doodads:
* Self.MoveTo(Point) is now available to set the actor's position in
world coordinates.
* Install the new ui.TabFrame widget into the Settings and Doodad
Dropper windows to give them properly tabbed interfaces.
* Doodad Dropper's new tabs divide the list of doodads into categories
to make them easier to find.
* The officially defined categories so far are:
- Objects (Start/End Flags and Box)
- Doors (All locked doors and keys, Warp Doors, and Electric Door)
- Gizmos (All buttons, switches, state blocks/doors, Electric Door)
- Creatures (Blue/Red Azulian, Bird, Boy)
* The "All" tab of the Doodad Dropper will show every doodad regardless
of its category or whether it fit one of the official categories.
* How doodads are assigned categories is by a special "category" tag in
their metadata, e.g. "category=doors,gizmos" - multiple supported.
* The loading screen for Edit and Play modes is stable and the risk of
game crash is removed. The root cause was the setupAsync() functions
running on a background goroutine, and running SDL2 draw functions
while NOT on the main thread, which causes problems.
* The fix is all SDL2 Texture draws become lazy loaded: when the main
thread is presenting, any Wallpaper or ui.Image that has no texture
yet gets one created at that time from the cached image.Image.
* All internal game logic then uses image.Image types, to cache bitmaps
of Level Chunks, Wallpaper images, Sprite icons, etc. and the game is
free to prepare these asynchronously; only the main thread ever
Presents and the SDL2 textures initialize on first appearance.
* Several functions had arguments cleaned up: Canvas.LoadLevel() does
not need the render.Engine as (e.g. wallpaper) textures don't render
at that stage.
* pkg/loadscreen implements a global Loading Screen for loading heavy
levels for playing or editing.
* All chunks in a level are pre-rendered to bitmap before gameplay
begins, which reduces stutter as chunks were being lazily rendered on
first appearance before.
* The loading screen can be played with in the developer console:
$ loadscreen.Show()
$ loadscreen.Hide()
Along with ShowWithProgress(), SetProgress(float64) and IsActive()
* Chunker: separate the concerns between Bitmaps an (SDL2) Textures.
* Chunker.Prerender() converts a chunk to a bitmap (a Go image.Image)
and caches it, only re-rendering if marked as dirty.
* Chunker.Texture() will use the pre-cached bitmap if available to
immediately produce the SDL2 texture.
Other miscellaneous changes:
* Added to the Colored Pencil palette: Sandstone
* Added "perlin noise" brush pattern
Note: this commit introduces instability and crashes:
* New `asyncSetup()` functions run on a goroutine, but SDL2 texture
calls must run on the main thread.
* Chunker avoids this by caching bitmaps, not textures.
* Wallpaper though is unstable, sometimes works, sometimes has graphical
glitches, sometimes crashes the game.
* Wallpaper.Load() and the *Texture() functions are where it crashes.
* Levels and Doodad files will be written in gzip-compressed JSON format
* `boolProp compress-drawings false` to disable compression and save as
classic JSON format directly
* The game can still read uncompressed JSON files
The file size savings on some built-in assets:
* Tutorial 2.level: 2.2M -> 414K (82% smaller)
* warp-door-orange.doodad: 105K -> 17K (84% smaller)
* Migrate off go-bindata to embed built-in fonts, levels and doodads in
favor of Go 1.16 native embed functionality.
* `make bindata` prints a deprecation warning to not break older build
scripts
* Removes all references of bindata from the program
* Holding Shift while pressing arrow keys in the editor will scroll by
just 1 pixel per tick to aid in precise debugging with the Zoom In/Out
feature.
* The keybinds used in canvas_editable.go to catch the arrow keys are
updated to use our nice keybind package. As a consequence, the WASD
keys will also scroll the level.
* The "d for Doodads" keybind is renamed "q" so as not to open the
Doodads window whenever scrolling right using the WASD keys.
WorldIndexAt() translates the pixel below the mouse cursor in screen
space (0,0 at top-left corner of the application window) into a world
coordinate in the level shown inside the canvas, taking into account the
canvas's position on the window and the scroll position.
It now translates correctly when zoom In or Out, so the "Abs:" mouse
position level in the status bar shows correctly.
Zoom features that are still jank:
- Scrolling while zoomed in, the chunks to the top/left start unloading
too rapidly and outpacing the scroll, eventually level is invisible
- Drawing and committing pixels to the image while zoomed in/out is
unpredictable where the pixels actually land.
- Actors in the level don't move or zoom at all.
* Got the level chunks AND the wallpaper to both scale UP and DOWN
consistently together.
* Trying to draw new pixels while zoomed in/out ends up offsetting the
pixels by 2X still. Still seems an issue between screen coordinates
and world coordinates. Zoom in 2X and try and draw a line 64px from
the corners of the screen? The committed line appropriately lands at
the 64px coord on the level data but, zoomed in, it appears 2X to the
right on the screen from where I dropped the cursor!
* When zooming OUT, the limit on number of chunks the viewport will try
and render is not increased, leaving dead space in the screen; more
chunks should render when there's room.
* The Windows build of v0.6.0 couldn't load embedded wallpapers such as
legal.png when asked, but could load the hard-coded default.png
* Root cause was the filesystem.FindFile() checking for path separators
in the filepath, and on Win32 this is \ but the internal wallpaper
paths use /
* Instead of a simple "cur. ver != latest ver" check, parse the Major,
Minor and Patch components and do a detailed check.
* So a x.x.1 release could be made for a specific platform that had a
bad build, and it won't mind when it sees the latest version is the
older x.x.0 build that other platforms had working fine.
* The pattern textures for level palettes have been brightened and work
better with bright colors.
* The three default palettes for new levels now have patterns applied to
each of their colors.
* Bugfix around resetting keybind states for Zoom In/Out, Scroll to
Origin and Reset Zoom Level bindings.
* Added a Settings window for game options, such as enabling the
horizontal toolbars in Edit Mode. The Settings window also has a
Controls tab showing the gameplay buttons and keyboard shortcuts.
* The Settings window is available as a button on the home screen OR
from the Edit->Settings menu in the EditScene.
* Bugfix: using WASD to move the player character now works better and
is considered by the game to be identical to the arrow key inputs. Boy
now updates his animation based on these keys, and they register as
boolean on/off keys instead of affected by key-repeat.
* Refactor the boolProps: they are all part of usercfg now, and if you
run e.g. "boolProp show-all-doodads true" and then cause the user
settings to save to disk, that boolProp will be permanently enabled
until turned off again.
* Free (shareware) versions of the game will not be able to Publish
Levels (attach custom doodads to the level file) and they will not be
able to load a level which relies on embedded doodads.
* The UI for the Publish Level window is still available, but clicking
on the confirm button will just open the Register (License) window.
* When loading a level containing embedded doodads: if some can't load
because they're embedded and you're using the free version of the
game, the error message is customized to reflect that.
* New command-line tool: doodle-admin for signing license keys for
users. Includes functions to initialize a keypair, sign license keys
and validate existing keys.
* The Main Menu screen shows a blue "Register Game" button in the bottom
right corner of the screen, for unregistered users only.
* In Edit Mode, there is a "Help -> Register" menu item that opens the
License Window.
* The License UI Window lets the user select the license.key file to
register the game with. If registered, a copy of the key is placed in
Doodle's profile directory and the licensee name/email is shown in the
License UI window.
* Unregistered games will show the word "(shareware)" next to the title
screen version number and Edit Mode status bar.
* No restrictions are yet placed on free versions of the game.
On small screen sizes like the Pinephone, the toolbars in the Level
Editor are best made horizontal across the top and bottom of the screen
leaving more room for the drawing.
Enable it with a boolProp for now, and then reopen the level editor:
boolProp horizontalToolbars true
When launching `doodle -w mobile` it will automatically enable this
option.
* The scrollbox by which the game follows the player character has been
revised, it is now an offset away from the window's center instead of
fixed pixel distances from the window's edges.
* Mobile form-factor (Pinephone) now scrolls OK instead of jerking back
and forth rapidly when moving left.
In the Level Editor, the "Level->Attached files" menu opens the
FileSystem Window, which shows a paginated list of attached files and a
"Delete" button to remove them.
- Custom doodads which also exist locally can be deleted from the
level's filesystem at any time.
- If a custom doodad does NOT exist locally, and one of them is still
placed somewhere within the level, you can not delete it.
- You can't delete the custom wallpaper image IF the level is still
using it. Change to a default wallpaper and then you can delete the
custom wallpaper image.
* The Publisher is all hooked up. No native Save File dialogs yet, so
uses the dev shell Prompt() to ask for output filename.
* Custom-only or builtin doodads too can be stored in the level's file
data, at "assets/doodads/*.doodad"
* When loading the embedded level in the Editor: it gets its custom
doodads out of its file, and you can drag and drop them elsehwere,
link them, Play Mode can use them, etc. but they won't appear in the
Doodad Dropper if they are not installed in your local doodads
directory.
* Fleshed out serialization API for the Doodad files:
- LoadFromEmbeddable() looks to load a doodad from embeddable file
data in addition to the usual places.
- Serialize() returns the doodad in bytes, for easy access to embed
into level data.
- Deserialize() to parse and return from bytes.
* When loading a level that references doodads not found in its embedded
data or the filesystem: an Alert modal appears listing the missing
doodads. The rest of the level loads fine, but the actors referenced
by these doodads don't load.
* File->Publish Level in the Level Editor opens the Publish window,
where you can embed custom doodads into your level and export a
portable .level file you can share with others.
* Currently does not actually export a level file yet.
* The dialog lists all unique doodad names in use in your level, and
designates which are built-ins and which are custom (paginated).
* A checkbox would let the user embed built-in doodads into their level,
as well, locking it in to those versions and not using updated
versions from future game releases.
UI Improvements:
* Added styling for a "Primary" UI button, rendered in deep blue.
* Pop-up modals (Alert, Confirm) color their Ok button as Primary.
* The Enter key pressed during an Alert or Confirm modal will invoke its
default button and close the modal, corresponding to its Primary
button.
* The developer console is now opened with the tilde/grave key ` instead
of the Enter key, so that the Enter key is free to click through
modals.
* In the "Open/Edit Drawing" window, a "Browse..." button is added to
the level and doodad sections, spawning a native File Open dialog to
pick a .level or .doodad outside the config root.
Palette swatches gain a new property: Pattern.
Patterns are grayscale textures that the swatch color will sample
against when drawing pixels to the level, by taking the world coordinate
modulo a value inside the texture.
A few algorithms were tried (Screen, Overlay), this branch lands on one
that tries to cast the color from grayscale which comes out rather dark;
to get a patterned color to look black while still seeing the pattern,
the color needs to be as bright as #777 to get the effect.
Adds a lazy scroll algorithm that basically:
- Zigzags right/down a certain distance, then up again
- Then enters a bounce phase where it bounces off the level
boundaries like a screensaver.
Arrow keys can still scroll the level manually, but the
automated scroll takes over otherwise.
* You can now browse for a custom wallpaper image to use with your
levels. A platform-native file picker dialog is used (no WASM support)
* In the New/Edit Level Properties dialog, the Wallpaper drop-down
includes an option to browse for a custom map.
* When editing an existing level: the wallpaper takes effect immediately
in your level once the file is picked. For NEW levels, the wallpaper
will appear once the "Continue" button is pressed.
* All common image types supported: png, jpeg, gif.
* The wallpaper is embedded in the level using the filepath
"assets/wallpapers/custom.b64img" as a Base64-encoded blob of the
image data.
* The `doodad show` command will list the names and sizes of files
embedded in levels. `doodad show --attachment <name>` will get an
attachment and print it to the console window.
* To extract a wallpaper image from a level:
`doodad show -a assets/wallpapers/custom.b64img | base64 -d > out.png`
* Replace the radio buttons for Page Type and Wallpaper with the new
SelectBox widgets from the UI toolkit.
* Choice of default palette also switched from a MenuButton to
a SelectBox widget.
* Experimental "Browse..." option added to the Wallpaper drop-down when
run in --experimental mode; not yet functional.
* In the "New Level" dialog, a "Palette:" option shows a MenuButton
drop-down with options: Default, Colored Pencil, and Blueprint. These
control the set of colors the new level starts with.
* Actors can now walk up gentle inclines to the left as well as they can
to the right. The bug was introduced as a hack to prevent clipping
thru the left wall of a 90 degree corner, but that problem seems
resolved now.
* The F4 key to draw collision boxes works reliably again: it draws the
player's hitbox in world-space using the canvas.DrawStrokes()
function, rather than in screen-space so it follows the player
reliably.
* The F4 key also draws hitboxes for ALL other actors in the level:
buttons, enemies, doors, etc.
* The level geometry collision function is updated to respect a doodad's
declared Hitbox from their script, which may result in a smaller box
than their raw Canvas size. The result is tighter collision between
doodads, and Boy's sprite is rather narrow for its square Canvas so
collision on rightward geometry is tighter for the player character.
* Collision checks between actors also respect the actor's declared
hitboxes now, allowing for Boy to get even closer to a locked door
before being blocked.
New doodad interactions:
* Sticky Buttons will emit a "sticky:down" event to linked doodads, with
a boolean value showing the Sticky Button's state.
* Normal Buttons will listen for "sticky:down" -- when a linked Sticky
Button is pressed, the normal Button presses in as well, and stays
pressed while the sticky:down signal is true.
* When the Sticky Button is released (e.g. because it received power
from another doodad), any linked buttons which were sticky:down
release as well.
* Switch doodads emit a new "switch:toggle" event JUST BEFORE sending
the "power" event. Sensitive Doodads can listen for switches in
particular this way.
* The Electric Door listens for switch:toggle; if a Switch is activated,
the Electric Door always flips its current state (open to close, or
vice versa) and ignores the immediately following power event. This
allows doors to toggle on/off regardless of sync with a Switch.
Other changes:
* When the player character dies by fire, instead of the message saying
"Watch out for fire!" it will use the name of the fire swatch that
hurt the player. This way levels could make it say "Watch out for
spikes!" or "lava" or whatever they want. The "Fire" attribute now
just means "instantly kills the player."
* Level Editor: You can now edit the Title and Author name of your level
in the Page Settings window.
* Bugfix: only the player character ends the game by dying in fire.
Other mobile doodads just turn dark but don't end the game.
* Increase the size of Trapdoor doodad sprites by 150% as they were a
bit small for the player character.
* Rename the game from "Project: Doodle" to "Sketchy Maze"
* The crumbly floor doodad was made 50% larger.
* New doodad: Small Key and Small Key Door. These work like the colored
doors and locks except each Small Key is consumed when it unlocks a
door. The door's appearance is of iron bars.
* The inventory HUD displays a small quantity label in the lower-right
corner of items that have a quantity, such as the Small Key. This is
done as a Canvas.CornerLabel string attribute on uix.Canvas.
* The "give all keys" cheat adds 99 Small Keys to your inventory.
* The "Use Key" (Q or Spacebar) now activates the Warp Door instead of a
collision event doing so.
* Warp Doors are now functional: the player opens a door, disappears,
the door closes; player is teleported to the linked door which opens,
appears the player and closes.
* If the player exits thru a Blue or Orange door which is disabled
(dotted outline), the door still opens and drops the player off but
returns to a Disabled state, acting as a one-way door.
* Clean up several debug log lines from Doodle and doodad scripts.
* The blue and orange ON/OFF state blocks have all been increased in
size to better match the player character (42x42 up from 33x33)
* Added a new mob: the Red Bird. It flies back and forth while
maintaining its altitude, similar to the Red Azulian. Planned AI
behavior is to divebomb the player when it gets close. Dive sprites
are included but not yet hooked up in JavaScript.
* Warp Doors! (WIP). They have a golden "W" on them and come in three
varieties: Brown, Blue and Orange. The blue and orange ones are
sensitive to the State Block and will become dotted outlines when
inactive (and can not be entered in this state). The door opens for
the player character, makes him disappear, then closes again. The plan
is it will then warp you to the location of a linked Warp Door
elsewhere on the level, but for now it will just make the player
re-appear after completing the Close Door animation.
* Added Feature Flag support, run doodle with --experimental to enable
all flags. Eraser Tool is behind a feature flag now.
* + and - on the top row of keyboard keys will zoom the drawing in and
out in Edit Mode. The wallpaper zooms nicely enough, but level
chunkers need work.
* A View menu is added with Zoom in/out, reset zoom, and scroll to
origin options. The whole menu is behind the Zoom feature flag.
* Update README with lots of details for fun debug mode options to play
around with.
* pkg/keybinds holds central functions to check global keybinds, like
DebugOverlay (F3), Undo (Ctrl-Z), GotoPlay/GotoEdit (p/e), etc.
* The Tools menu in the editor mode lists out more options to select
various drawing tools (line, pencil, etc.) - and showing the hotkey
for each tool.
* When editing a doodad in the Editor Mode, the toolbar has a "Lyr."
button that opens the Layers window.
* The Layers window allows switching the active doodad layer that you
are drawing on, as well as create and rename layers.
* With this feature, Doodads may be fully drawn in-game, including
adding alternate named layers for animations and multiple-state
doodads.
* Update the Pager component to have a configurable MaxPageButtons.
Controls that have more pages than this limit will stop having buttons
drawn after the limit. The "Forward" and "Next" buttons can still
navigate into the extra pages.
* Refactored and centralized the various popup windows in Editor Mode
into editor_ui_popups.go; the SetupPopups() and various methods such
as ShowPaletteWindow() and ShowDoodadDropper() make management of
popups simple for the editor_ui!
* The Menu Bar in Editor Mode now has context-specific tools in the
Tools menu: the Doodad Dropper for levels and Layers for doodads.
* Bugfix the Palette Editor window to work equally between Levels and
Doodads, by only having it care about the Palette and not the Level
that owns it.
* Adds global modal support in the pkg/modal/ package. It has easy
Alert() and Confirm() methods to prompt the user before calling a
callback function on affirmative response.
* Modals have global app state: they're processed in the main loop in
pkg/doodle.go similar to the global command shell.
* When a modal is active, a semitransparent black frame covers the
screen (gameplay loop paused, last game frame rendered below) and the
modal window appears on top.
* The developer console retains higher priority than the modal system
and always renders on top.
* Editor Mode: track when the level pixels have been modified, and
confirm the user about unsaved changes when they attempt to close the
level (New, Open, Close, etc.)
* Global: the Escape key no longer immediately shuts down the game, but
will confirm the user's intent via a modal.
* File->Quit in the Editor Mode also invokes the confirm shutdown modal.
* Added initial walking sprites for the player character, "Boy."
* Player doodad filename and title screen level are now configurable in
the balance/numbers.go package.
* Add sound effect and music support to Doodle.
* Fix WASM build to use the 'null' sound driver for now.
* Add a Settings button to the main menu; UI for it is WIP.
* Start the program window maximized with the `-w maximized` CLI option.
* Move the Doodad Palette off the right-side dock of the Editor Scene and
into its own pop-up window: the DoodadDropper.
* Shrink the width of the Color Palette panel and show only the colors in
the buttons. The name of the swatch is available in the mouse-over tooltip.
* Added an "Edit" button to the Color Palette. It opens a Palette Editor
window where you can rename, change colors and attributes of existing colors
OR insert new colors into your palette. (Deleting colors not yet supported).
* level.Chunker gets a Redraw method: invalidates all cached textures of all
chunks forcing the level to redraw itself, possibly with an updated palette.
* Integrate the new ui.MenuBar into the Editor Scene.
* File: New Level/Doodad, Save [as], Open, Close, Exit
* Edit: Undo, Redo, Level options
* Level: Playtest
* Tools: Debug overlay, Command shell
* Help: User Manual, About
* Add an About dialog accessible from the Help menu.
Adds support for sound effects in Doodle and configures some for various
doodads to start out with:
* Buttons and Switches: "Clicked down" and "clicked up" sounds.
* Colored Doors: an "unlocked" sound and a "door opened" sound.
* Electric Door: sci-fi sounds when opening and closing.
* Keys: sound effect for collecting keys.
JavaScript API for Doodads adds a global function `Sound.Play(filename)`
to play sounds. All sounds in the `rtp/sfx/` folder are pre-loaded on
startup for efficient use in the app. Otherwise sounds are lazy-loaded
on first playback.
* Tightens up the surface area of API methods available to the
JavaScript VMs for doodads. Variables and functions are carefully
passed in one-by-one so the doodad script can only access intended
functions and not snoop on undocumented APIs.
* Wrote tons of user documentation for Doodad Scripts: documented the
full surface area of the exposed JavaScript API now that the surface
area is known and limited.
* Early WIP code for the Campaign JSON
There was a clipping bug where the player could sometimes clip thru a
left-side wall, if the left wall and floor made a 90 degree bend and the
player was holding the Left key while jumping slightly into the wall.
A band-aid that seems to work involved two steps:
1. When capping their leftward movement, add a "+ 1" to the cap.
2. At the start of the point loop, enforce the left cap like we do the
ceiling cap.
This seems to patch the problem, BUT it breaks the ability to walk up
slopes while moving left. Right-facing slopes can be climbed fine still.
Note: the original bug never was a problem against right walls, only
left ones, but the true root cause was not identified. See TODO comments
in collide_level.go.
* With the Window Manager update you can open the Level Settings window
while editing a level, to change its wallpaper or page type. But you
could "draw" in the level "through" the opened window. This bug is now
fixed: if the cursor is on top of a managed UI window, the Canvas loop
is not called.
* Take advantage of the new Window Manager feature of the UI toolkit.
* Move the MenuScene's "New Level" and "Play/Edit Level" windows into
stand-alone functions in new pkg/windows/ package. The 'windows'
package is isolated from the rest of Doodle and communicates using
config variables and callback functions to avoid circular dependency.
* MenuScene calls the window constructors from the new package.
* Add an "Options" button to the Menu Bar in the Editor Scene, which
opens the "New Level" window to allow changing the wallpaper or
bounding type of the level currently being edited.
* Move the cheat codes into their own file, cheats.go
* Player character now experiences acceleration and friction when
walking around the map!
* Actor position and movement had to be converted from int's
(render.Point) to float64's to support fine-grained acceleration
steps.
* Added "physics" package and physics.Vector to be a float64 counterpart
for render.Point. Vector is used for uix.Actor.Position() for the sake
of movement math. Vector is flattened back to a render.Point for
collision purposes, since the levels and hitboxes are pixel-bound.
* Refactor the uix.Actor to no longer extend the doodads.Drawing (so it
can have a Position that's a Vector instead of a Point). This broke
some code that expected `.Doodad` to directly reference the
Drawing.Doodad: now you had to refer to it as `a.Drawing.Doodad` which
was ugly. Added convenience method .Doodad() for a shortcut.
* Moved functions like GetBoundingRect() from doodads package to
collision, where it uses its own slimmer Actor interface for just the
relevant methods it needs.
* Added an inventory system for actors as a replacement to the arbitrary
key/value data store. Colored keys now add themselves to the player's
inventory, and colored doors check the inventory.
* Inventory is a map[string]int between doodad filenames
(red-key.doodad) and quantity (0 for key items/unlimited qty).
* API methods to add and remove inventory.
* Items HUD appears in Play Mode in lower-left corner showing doodad
sprites of all the items in the Player's inventory.
* Revamped the sprites for the four colored locked doors. They now have
a side-view profile perspective rather than a front view.
* Doors open facing the left or the right based on what direction the
colliding actor approached it from.
* Update code for recent changes in UI toolkit around event handlers for
buttons.
* Add tooltips to various buttons in the Editor Mode. The left toolbar
shows the names of each tool, the Doodad Palette shows the title of
each doodad and the Color Palette shows the swatch attributes (solid,
fire, water, etc.)
* The `doodad edit-doodad` command now allows setting custom key/value
tags in doodad files, for extra data storage useful to their scripts.
* Colored keys and doors now store a `color` tag with the appropriate
color so that their scripts don't have to parse their Title to find
that information.
* Trapdoors now store a `direction` tag to hold the direction the door
is facing.
* Recent collision update caused a regression where the player would get
"stuck" while standing on top of a solid doodad, unable to walk left
or right.
* When deciding if the actor is on top of a doodad, use the doodad's
Hitbox (if available) instead of the bounding box. This fixes the
upside-down trapdoor acting solid when landed on from the top, since
its Hitbox Y coordinate is not the same as the top of its sprite.
* Cheats: when using the noclip cheat in Play Mode, you can hold down
the Shift key while moving to only move one pixel at a time.
* Fix the level collision bug that allowed clipping thru a ceiling while
climbing up a wall.
* Fix the scrolling behavior to keep the character on-screen no matter
how fast the character is moving, especially downwards.
* Increase player speed and gravity.
* New cheat: "ghost mode" disables clipping for the player character.
* Mark an actor as "grounded" if they fall and are stopped by the lower
level border, so they may jump again.
* Two-state Buttons now also subscribe to the state change message, so
other on/off buttons in the same level update to match the state of
the button that was hit.
* Add lock mutexes around the scripting engine to protect from
concurrent event handlers.
Add new doodads:
* Start Flag: place this in a level to set the spawn point of the player
character. If no flag is found, the player spawns at 0,0 in the top
corner of the map. Only use one Start Flag per level, otherwise the
player will randomly spawn at one of them.
* Crumbly Floor: a solid floor that begins to shake and then fall apart
after a moment when a mobile character steps on it. The floor respawns
after 5 seconds.
* State Blocks: blue and orange blocks that toggle between solid and
pass-thru whenever a State Button is activated.
* State Button: a solid "ON/OFF" block that toggles State Blocks back
and forth when touched. Only activates if touched on the side or bottom;
acts as a solid floor when walked on from the top.
New features for doodad scripts:
* Actor scripts: call SetMobile(true) to mark an actor as a mobile mob
(i.e. player character or enemy). Other doodads can check if the actor
colliding with them IsMobile so they don't activate if placed too close
to other (non-mobile) doodads in a level. The Blue and Red Azulians
are the only mobile characters so far.
* Message.Broadcast allows sending a pub/sub message out to ALL doodads
in the level, instead of only to linked doodads as Message.Publish does.
This is used for the State Blocks to globally communicate on/off status
without needing to link them all together manually.
* New logger module supports js/wasm build by skipping the dependency on
ssh/terminal (which detected interactive consoles, not applicable to
JS). In WASM the logs go to the browser console and ANSI color codes
not needed.
* Discovered a bug where if you hit the Undo key to erase pixels and an
entire chunk became empty by it, the chunk would have rendering errors
and show as a solid black square instead of the level wallpaper
showing through.
* Chunks that have no pixels in them are culled from the chunker
immediately when you call a Delete() operation.
* The level file saver also calls a maintenance function to prune all
empty chunks upon saving the file. So existing levels with broken
chunks need only be re-saved to fix them.
* Improve the collision detection algorithm so that Actor OnCollide
scripts get called more often WHILE an actor is moving, to prevent a
fast-moving actor from zipping right through the "solid" hitbox and
not giving the subject actor time to protest the movement.
* It's implemented by adding a `Settled` boolean to the OnCollide event
object. When the game is testing out movement, Settled=false to give
the actor a chance to say "I'm solid!" and have the moving party be
stopped early.
* After all this is done, for any pair of actors still with overlapping
hitboxes, OnCollide is called one last time with Settled=true. This is
when the actor should run its actions (like publishing messages to
other actors, changing state as in a trapdoor, etc.)
* The new collision detection algorithm works as follows:
* Stage 1 is the same as before, all mobile actors are moved and
tested against level geometry. They record their Original and New
position during this phase.
* Stage 2 is where we re-run that movement but ping actors being
intersected each step of the way. We trace the steps between
Original and New position, test OnCollide handler, and if it returns
false we move the mobile actor to the Last Good Position along the
trace.
* Stage 3 we run the final OnCollide(Settled=true) to let actors run
actions they wanted to for their collide handler, WITHOUT spamming
those actions during Stage 2.
* This should now allow for tweaking of gravity speed and player speed
without breaking all actor collision checking.
* Add initial Ellipse Tool to the Editor Mode. Currently there's
something wrong with the algorithm and the ellipses have a sort of
'lemon shape' to them.
* Refactor the IterLine/IterLine2 functions to be more consistent.
IterLine used to be the raw algorithm that took a bunch of coordinate
numbers and IterLine2 took two render.Point's and was the main one
used throughout the app. Now, IterLine takes the two Points and the
raw algorithm function removed.
* Implement Brush Sizes for drawtool.Stroke and add a UI to the tools panel
to control the brush size.
* Brush sizes: 1, 2, 4, 8, 16, 24, 32, 48, 64
* Add the Eraser Tool to editor mode. It uses a default brush size of 16
and a max size of 32 due to some performance issues.
* The Undo/Redo system now remembers the original color of pixels when
you change them, so that Undo will set them back how they were instead
of deleting the pixel entirely. Due to performance issues, this only
happens when your Brush Size is 0 (drawing single-pixel shapes).
* UI: Add an IntVariable option to ui.Label to bind showing the value of
an int reference.
Aforementioned performance issues:
* When we try to remember whole rects of pixels for drawing thick
shapes, it requires a ton of scanning for each step of the shape. Even
de-duplicating pixel checks, tons of extra reads are constantly
checked.
* The Eraser is the only tool that absolutely needs to be able to
remember wiped pixels AND have large brush sizes. The performance
sucks and lags a bit if you erase a lot all at once, but it's a
trade-off for now.
* So pixels aren't remembered when drawing lines in your level with
thick brushes, so the Undo action will simply delete your pixels and not
reset them. Only the Eraser can bring back pixels.
* Update the Makefile to choose MacOS friendly `date` formats.
* Build the Windows doodle.exe binary as a GUI application to skip the
console window.
* Added Mac OS build instructions.
* The `doodad` CLI tool got a lot of new commands:
* `doodad show` to verbosely print details about Levels and Doodads.
* `edit-level` and `edit-doodad` to update details about Levels and
Doodads, such as their Title, Author, page type and size, etc.
* Doodads gain a `Hidden bool` that hides them from the palette in
Editor Mode. The player character (Blue Azulian) is Hidden.
* Add some boolProps to the balance/ package and made a dynamic system
to easily configure these with the in-game dev console.
* Command: `boolProp list` returns available balance.boolProps
* `boolProp <name>` returns the current value.
* `boolProp <name> <true or false>` sets the value.
* The new boolProps are:
* showAllDoodads: enable Hidden doodads on the palette UI (NOTE:
reload the editor to take effect)
* writeLockOverride: edit files that are write locked anyway
* prettyJSON: pretty-format the JSON files saved by the game.
* Touching "fire" pixels in a level will pop up the End Level alert box
saying you've died by fire and can restart the level.
* Update level.WriteFile() to prune broken links between actors before
save. So when a linked actor is deleted, the leftover link data is
cleaned up.
* Slight optimization in Canvas.drawStrokes: if either end of the stroke
is not within view of the screen, don't show the stroke.
* 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.
* 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.
* Add the other trapdoor directions: Left, Right and Up.
* UI: Show a color square in each Palette Swatch button in Edit Mode.
* Instead of just the label like "solid", "fire", "decoration" it also
shows a square box colored as the swatch color. The label and box
are left-aligned in the button.
* Minor Play Mode physics update:
* The player jump is now limited: they may only continue to move
upwards for 20 ticks, after which they must touch ground before
jumping again.
* Remove the "press Down to move down" button. Only gravity moves you
down.
* Fix a crash in the Editor Mode when you dragged doodads on top of each
other. Source of bug was the loopActorCollision() function, which only
should be useful to Play Mode, and it expected the scripting engine to
be attached to the Canvas. In EditorMode there is no scripting engine.
* Rudimentary scrolling shows a Left and Right button at the top of the
Doodad Palette if your window is deemed not tall enough to contain all
of the doodads.
* A "progress bar" is shown between the buttons indicating the
percentage of your scroll down the doodad list. When you're able to
see the final row of doodads, the progress bar is at 100%.
* Toolbar has icon buttons for the Pencil Tool, Line Tool, Rect Tool,
Actor Tool and Link Tool.
* Remove the tab buttons from the top of the Palette window. The palette
tab is now toggled between Swatches and Doodads by the tool selected
on the tool bar, instead of the tab buttons setting the tool.
* Remove the "Link Doodads" button from the Doodad Palette. The Link
Tool has its own dedicated toolbar button with the others.
* Add support for the LineTool and RectTool while in the EditorMode to
easily draw straight lines and rectangle outlines.
* Key bindings were added to toggle tools in lieu of a proper UI to
select the tool from a toolbar.
* "F" for Pencil (Freehand) Tool (since "P" is for "Playtest")
* "L" for Line Tool
* "R" for Rectangle Tool
* If the current edit tool is Actor or Link, use the new drawtool.Stroke
object to draw visual lines connecting every pair of linked actors in
the level. The lines are hidden during normal editing and gameplay and
only appear when you're possibly manipulating your actors and links.
* Add new pkg/drawtool with utilities to abstract away drawing actions
into Strokes and track undo/redo History for them.
* The freehand Pencil tool in EditorMode has been refactored to create a
Stroke of Shape=Freehand and queue up its world pixels there instead
of directly modifying the level chunker in real time. When the mouse
button is released, the freehand Stroke is committed to the level
chunker and added to the UndoHistory.
* UndoHistory is (temporarily) stored with the level.Level so it can
survive trips to PlayScene and back, but is not stored as JSON on
disk.
* Ctrl-Z and Ctrl-Y in EditorMode for undo and redo, respectively.
* Add a Level Exit doodad, which for now is a little blue flag on a pole
that reads "END"
* JavaScript API: global function EndLevel() will end the level. The
exit doodad calls this when touched by the player.
* Add a "Level Completed" alert box UI to PlayScene with dynamic button
layouts.
* The alert box pops up when a doodad calls EndLevel() and contains
action buttons what to do next.
* "Play Again" restarts the current level again.
* "Edit Level" if you came from the EditorScene; otherwise this button
is not visible.
* "Next Level" is a to-be-implemented button to advance in the single
player story mode. Only shows up when PlayScene.HasNext=true.
* "Exit to Menu" is always visible and closes out to the MainScene.
* Load SDL2 fonts from go-bindata storage so we don't have to ship
external font files on disk.
* Dedupe names of doodads so we don't show double on the front-end
(go-bindata bundled doodads + those on local filesystem)
* Use go-bindata for accessing wallpaper images.
* Better flashed messages walking you through the Link Tool.
* Stylize the title screen (MainScene) by rendering a live example level
as the background wallpaper, with mobile doodads in motion.
* In WASM build, user levels and doodads are written to localStorage
using their userdir path as keys (".config/levels/test.level")
* LoadFile() and WriteFile() for both Levels and Doodads interact with
the localStorage for WASM build instead of filesystem for desktop.
* userdir.ListLevels() and ListDoodads() for WASM scan the localStorage
keys for file names.
* userdir.ResolvePath() now works for WASM (previously was dummied out),
checks for the file in localStorage.
* Use `go-bindata` to embed built-in doodads and levels directly into
the Doodle binary. `make bindata` produces the bindata source file.
* Add `FromJSON()` method to Levels and Doodads to load objects from
JSON strings in memory (for bindata built-ins or WASM ajax requests)
* Update file loading functions to check the embedded bindata files.
* pkg/config.go#EditFile:
* Supports editing a level from bindata (TODO: remove this support)
* If the "assets/levels/%(simple-name.level)" exists in bindata,
edits that drawing.
* No such support for editing built-in doodads.
* WASM has no filesystem access to edit files except built-in
levels (yet)
* pkg/doodads#ListDoodads:
* Prepends built-in doodads from bindata to the returned list.
* WASM: no filesystem access so gets only the built-ins.
* pkg/doodads#LoadFile:
* Checks built-in bindata store first for doodad files.
* WASM: tries an HTTP request if not found in bindata but can go no
further if not found (no filesystem access)
* pkg/filesystem#FindFile:
* This function finds a level/doodad by checking all the places.
* If the level or doodad exists in bindata built-in, always returns
its system path like "assets/doodads/test.doodad"
* WASM: always returns the built-in candidate path even if not found
in bindata so that ajax GET can be attempted.
* pkg/level#ListSystemLevels:
* New function that lists the system level files, similar to the
equivalent doodads function.
* Prepends the bindata built-in level files.
* WASM: only returns the built-ins (no filesystem support)
* Desktop: also lists and returns the assets/levels/ directory.
* pkg/level#LoadFile:
* Like the doodads.LoadFile, tries from built-in bindata first, then
ajax request (WASM) before accessing the filesystem (desktop)
* Menu Scene: TODO, list the built-in levels in the Load Level menu.
This feature will soon go away when WASM gets its own storage for user
levels (localStorage instead of filesystem)
Since SDL2 is using in-memory bitmaps the same as Canvas engine, the
function names of the render.Engine interface have been cleaned up:
* NewTexture(filename, image) -> StoreTexture(name, image)
Create a new cached texture with a given name.
* NewBitmap(filename) -> LoadTexture(name)
Recall a stored texture with a given name.
* level.Chunk.ToBitmap uses simpler names for the textures instead of
userdir.CacheFilename file-like paths.
* Refactor texture caching in render.Engine:
* New interface method: NewTexture(filename string, image.Image)
* WASM immediately encodes the image to PNG and generates a JavaScript
`Image()` object to load it with a data URI and keep it in memory.
* SDL2 saves the bitmap to disk as it did before.
* WASM: deprecate the sessionStorage for holding image data. Session
storage methods panic if called. The image data is directly kept in
Go memory as a js.Value holding an Image().
* Shared Memory workaround: the level.Chunk.ToBitmap() function is where
chunk textures get cached, but it had no access to the render.Engine
used in the game. The `pkg/shmem` package holds global pointers to
common structures like the CurrentRenderEngine as a work-around.
* Also shmem.Flash() so Doodle can make its d.Flash() function
globally available, any sub-package can now flash text to the screen
regardless of source code location.
* JavaScript API for Doodads now has a global Flash() function
available.
* WASM: Handle window resize so Doodle can recompute its dimensions
instead of scaling/shrinking the view.
* Add RGBA color blending support in WASM build.
* Initial texture caching API for Canvas renderer engine. The WASM build
writes the chunk caches as a "data:image/png" base64 URL on the
browser's sessionStorage, for access to copy into the Canvas.
* Separated the ClickEvent from the MouseEvent (motion) in the WASM
event queue system, to allow clicking and dragging.
* Added the EscapeKey handler, which will abruptly terminate the WASM
application, same as it kills the window in the desktop build.
* Optimization fix: I discovered that if the user clicks and holds over
a single pixel when drawing a level, repeated Set() operations were
firing meaning multiple cache invalidations. Not noticeable on PC but
on WebAssembly it crippled the browser. Now if the cursor isn't moving
it doesn't do anything.
* Refactor the event system in the WASM render engine to serialize the
async JavaScript events into a channel, so that queued events are read
off serially in the main loop similar to SDL. This fixes keyboard
input issues, altho if you type really fast some input keys get lost.
* Initial WebAssembly build target for Doodle in the wasm/ folder.
* Add a new render.Engine implementation, lib/render/canvas that uses
the HTML 5 Canvas API instead of SDL2 for the WebAssembly target.
* Ported the basic DrawLine(), DrawBox() etc. functions from SDL2 to
Canvas context2d API.
* Fonts are handled with CSS embedded fonts named after the font
filename and defined in wasm/index.html
* `make wasm` builds the WASM program, and `make wasm-serve` runs a dev
Go server that hosts the WASM file for development. The server also
watches the dev tree for *.go files and rebuilds the WASM binary
automatically on change.
* This build "basically" runs the game. UI and fonts all work and mouse
movements and clicks are detected. No wallpaper support yet or texture
caching (which will crash the game as soon as you click and draw a
pixel in your map!)
* Instead of needing to press the "P" and "E" keys to toggle from edit
mode to play mode (and back again), respectively, the UI now draws a
"Play (P)" or "Edit (E)" button on the bottom right corner of the
level canvas. Clicking it will toggle the mode.
* Fix the EditorUI not showing the correct palette baked into the level
and only showing the default. This was tricky because the palette UI
can only be configured at setup time but not updated later.
* Add a new default palette for the Blueprint theme. Blueprint has a
dark background, so the palette colors should be bright. This palette
is chosen when you start a map with the blueprint wallpaper.
* Add a background Canvas to the MenuScene. In the "New Level" screen,
the background canvas will update to show the wallpaper settings
you've chosen as a preview of the level theme you're about to create.
* To the MenuScene add the "Load Drawing" window UI.
* Displays the user's Levels and Doodads using rows of buttons, 4
buttons per row. Clicking the button loads the EditorScene with that
filename.
* Free Version does not display the Doodads label or button on this
menu screen.
* Debug mode: no longer enables the DebugOverlay (F3) by default, but
does now insert the current FPS counter into the window title bar.
* ui.Frame: set a default "mostly transparent" BG color so the frame
background doesn't render as white.
* Add the MenuScene which will house the game's main menus.
* The "New Level" menu is first to be added.
* UI lets you pick Page Type and Wallpaper using radio buttons.
* Page Type: Unbounded, Bounded (default), No Negative Space, Bordered
* Fix bugs in uix.Canvas to fully support all these page types.
* Implement the pub/sub message passing system that lets the JavaScript
VM of one actor (say, a Button) send messages to other linked actors
in the level (say, an Electric Door)
* Buttons now emit a "power(true)" message while pressed and
"power(false)" when released. Sticky Buttons do not release and so do
not send the power(false) message.
* Electric Doors listen for the "power" event and open or close
themselves based on the boolean value received.
* If a Sticky Button receives power and is currently pressed down, it
will pop back up (reset to "off" position) and notify its linked
actors that they have lost power too. So if a Sticky Button held an
Electric Door open, and another Button powers the Sticky Button, it
would pop back up and also close the Electric Door.
* On the Doodads tab is the Link button to enter the Link Tool.
* Click Link, then click the 1st doodad on the level, then click the 2nd
doodad to complete the link.
* The actors struct in the Level holds the link IDs for each actor.
* Implement the handler code for `return false` when actors are
colliding with each other and wish to act like solid walls.
* The locked doors will `return false` when they're closed and the
colliding actor does not have the matching key.
* Add arbitrary key/value storage to Actors. The colored keys will set
an actor value "key:%TITLE%" on the one who touched the key before
destroying itself. The colored doors check that key when touched to
decide whether to open.
* The trapdoor now only opens if you're touching it from the top (your
overlap box Y value is 0), but if you touch it from below and the door
is closed, it acts like a solid object.
* Events.OnCollide now receives a CollideEvent object, which makes
available the .Actor who collided and the .Overlap rect which is
zero-relative to the target actor. Doodad scripts can use the .Overlap
to see WHERE in their own box the other actor has intruded.
* Update the LockedDoor and ElectricDoor doodads to detect when the
player has entered their inner rect (since their doors are narrower
than their doodad size)
* Update the Button doodads to only press in when the player actually
touches them (because their sizes are shorter than their doodad
height)
* Update the Trapdoor to only trigger its animation when the board
along its top has been touched, not when the empty space below was
touched from the bottom.
* Events.OnLeave now implemented and fires when an actor who was
previously intersecting your doodad has left.
* The engine detects when an event JS callback returns false.
Eventually, the OnCollide can return false to signify the collision is
not accepted and the actor should be bumped away as if they hit solid
geometry.
* Add sync.WaitGroup to some parts of the level collision detection
function and Canvas.Loop() to speed up the frame rate by load
balancing some work in parallel across multiple cores.
* Improves FPS from 30 to 55+ even for busy scenes with lots of mobile
enemies walking around.
* Before the level collision optimization, framerate would sometimes dip
to 30 FPS simply to move the player character on a completely blank
map!
* Add a Red Azulian as a test for mobile enemies.
* Its A.I. has it walk back and forth, changing directions when it
comes up against an obstacle for a few moments.
* It plays walking animations and can trigger collision events with
other Doodads, such as the Electric Door and Trapdoor.
* Move Gravity responsibility to the doodad scripts themselves.
* Call `Self.SetGravity(true)` to opt the Doodad in to gravity.
* The canvas.Loop() adds gravity to any doodad that has it enabled.
* Add animation support for Doodad actors (Play Mode) into the core
engine, so that the Doodad script can register named animations and
play them without managing all the details themselves.
* Doodad API functions on Self: AddAnimation, PlayAnimation,
StopAnimation, IsAnimating
* CLI: the `doodad convert` command will name each layer after the
filename used as the input image.
* CLI: fix the `doodad convert` command creating duplicate Palette
colors when converting a series of input images into a Doodad.