* 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.
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.
* 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.
* 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)
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.)
* 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.
* 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.
* 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.
* 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 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.
* 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.
* 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.
* 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.
* 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.
* Add some encoding/decoding functions for binary msgpack format for
levels and doodads. Currently it writes msgpack files that can be
decoded and printed by Python (mp2json.py) but it can't re-read from
the binary format. For now, levels will continue to write in JSON
format.
* Add filesystem abstraction functions to the balance/ package to search
multiple paths to find Levels and Doodads, to make way for
system-level doodads.
* Build the app with -tags="shareware" to compile the free/shareware
build of the game.
* `make build-free` compiles both binaries to the bin/ folder in
shareware mode.
* The constant balance.FreeVersion is true in the shareware build and
all functionality related to the Doodad Editor UI mode is disabled
in this build mode.
* Add the JavaScript system for Doodads to run their scripts in levels,
and wire initial OnCollide() handler support.
* CLI: Add a `doodad install-script` command to the doodad tool.
* Usage: `doodad install-script <index.js> <filename.doodad>`
* Add dev-assets folder for storing source files for the official
default doodads, sprites, levels, etc. and for now add a JavaScript
for the first test doodad.
Fixes:
* Move the call to CollidesWithGrid() inside the Canvas instead of
outside in the PlayScene.movePlayer() so it can apply to all Actors
in motion.
* PlayScene.movePlayer() in turn just sets the player's Velocity so the
Canvas.Loop() can move the actor itself.
* When keeping the player inside the level boundaries: previously it was
assuming the player Position was relative to the window, and was
checking the WorldIndexAt and getting wrong results.
* Canvas scrolling (loopFollowActor): check that the actor is getting
close to the screen edge using the Viewport into the world, NOT the
screen-relative coordinates of the Canvas bounding boxes.