* Remove several unused functions in doodad.Drawing (velocity, acceleration,
grounded, etc.) - uix.Actor is where these are actually managed.
* In the JavaScript API, setTimeout() and setInterval() will translate the
milliseconds from wallclock time into a fixed number of game ticks to match
the target frame rate for better deterministic timing.
Made some fixes to touchscreen control detection:
* TouchScreenMode is activated on the first SDL2 FingerDown
* TouchScreenMode deactivates after the last finger is removed, and a
mouse event happens at least 5 ticks later.
* Touchscreen mode used to be detected based on SDL2 GetNumTouchDevices
but on a Macbook, the trackpad registers as a touch device - worse,
GetNumTouchDevices will only start returning 1 the first time some
devices are touched.
* The result was that on macOS the custom mouse cursor was drawn by
default, but on the first trackpad touch, would disappear in favor of
assuming the game is running on a touch screen device (which is not
the case).
* New method: the render engine has an IsFingerDown boolean which will
be true as long as at least one finger has registered a FingerDown
event, but not yet a FingerUp event.
* So as long as one finger is down, the mouse cursor can disappear and
then it comes back on release. This isn't perfectly ideal for pure
touch devices (ideally the cursor remains hidden until a mouse
movement without touch occurs).
Add the ability for the free version of the game to allow loading levels that
use embedded custom doodads if those levels are signed.
* Uses the same signing keys as the JWT token for license registrations.
* Levels and Levelpacks can both be signed. So individual levels with embedded
doodads can work in free versions of the game.
* Levelpacks now support embedded doodads properly: the individual levels in
the pack don't need to embed a custom doodad, but if the doodad exists in
the levelpack's doodads/ folder it will load from there instead - for full
versions of the game OR when the levelpack is signed.
Signatures are computed by getting a listing of embedded assets inside the
zipfile (the assets/ folder in levels, and the doodads/ + levels/ folders
in levelpacks). Thus for individual signed levels, the level geometry and
metadata may be changed without breaking the signature but if custom doodads
are changed the signature will break.
The doodle-admin command adds subcommands to `sign-level` and `verify-level`
to manage signatures on levels and levelpacks.
When using the `doodad levelpack create` command, any custom doodads the
levels mention that are found in your profile directory get embedded into
the zipfile by default (with --doodads custom).
Convert the Chunker size to a uint8 so chunk sizes are limited to 255px. This
means that inside of a chunk, uint8's can track the relative pixel coordinates
and result in a great memory savings since all of these uint8's are currently
64-bits wide apiece.
WIP on rectangular shaped doodads:
* You can create such a doodad in the editor and draw it normally.
* It doesn't draw the right size when dragged into your level however:
- In uix.Actor.Size() it gets a rect of the doodad's square Chunker size,
instead of getting the proper doodad.Size rect.
- If you give it the doodad.Size rect, it draws the Canvas size correctly
instead of a square - the full drawing appears and in gameplay its hitbox
(assuming the same large rectangle size) works correctly in-game.
- But, the doodad has scrolling issues when it gets to the top or left edge
of the screen! This old gnarly bug has come back. For some reason square
canvas doodads draw correctly but rectangular ones have the drawing scroll
just a bit - how far it scrolls is proportional to how big the doodad is,
with the Start Flag only scrolling a few pixels before it stops.
* Added a Cheats Menu UI accessible from the Settings window's "Experimental"
tab and from there you can enable the Cheats Menu from the "Help" screen of
the gameplay mode.
* Commonly used cheats all have corresponding buttons to click on, especially
helpful for touchscreen devices like the Pinephone where keyboard input
doesn't always work reliably.
* The buttons in the Cheats Menu just automate entry of the cheat commands.
* `boolProp` command has a new `flip` option to toggle their value (e.g.
`boolProp show-hidden-doodads flip`)
* Add an exception catcher that pops open a UI window showing errors that
occur in doodad scripts during gameplay.
* Shows a preview of the header of the error (character wrapped) with a
Copy button to copy the full raw text to clipboard for inspection.
* Buttons to dismiss the modal once or stop any further errors from
opening during this gameplay session (until next restart).
* Add developer shell commands to test the exception catcher:
- 'throw <message>' to throw a custom message.
- 'throw2' to stress test a "long" message.
- 'throw3' to throw a realistic message copied from an actual error.
* Scripting engine: console.log() and friends will now insert the script
VM's name in front of its messages (the filename + actor ID).
The gamepad mouse cursor has become THE mouse cursor. It is always visible and your
real cursor is hidden, and this way the game can swap out other cursors for certain
scenarios:
* The Pencil Tool in the editor will use a pencil cursor over the level canvas.
* The Flood Tool has a custom Flood cursor so you don't forget it's selected!
Other improvements:
* The Palette buttons in the editor now render using their swatch's pattern
instead of only using its color.
* If you have an ultra HD monitor and open a Bounded level in the editor which
is too small to fill your screen, the editor canvas limits its size to fit
the level (preferable over showing parts of the level you can't actually play
as it's out of bounds).
* The "brush size" box is only drawn around the cursor when a relevant tool is
selected (Pencil, Line, Rect, Ellipse, Eraser)
Added a new level property: Difficulty
* An enum ranging from -1, 0, 1 (Peaceful, Normal, Hard)
* Default difficulty is Normal; pre-existing levels are Normal by
default per the zero value.
Doodad scripts can read the difficulty via the new global variable
`Level.Difficulty` and some doodads have been updated:
* Azulians: on Peaceful they ignore all player characters, and on Hard
they are in "hunt mode": infinite aggro radius and they're aggressive
to all characters.
* Bird: on Peaceful they will not dive and attack any player character.
Other spit and polish:
* New Level/Level Properties UI reworked into a magicform.
* New "PromptPre(question, answer, func)" function for prompting the
user with the developer shell, but pre-filling in an answer for them
to either post or edit.
* magicform has a PromptUser field option for simple Text/Int fields
which present as buttons, so magicform can prompt and update the
variable itself.
* Don't show the _autosave.doodad in the Doodad Dropper window.
* Loadscreen: put the progress bar between the Title and Subtitle so it
looks good even on mobile landscape orientation (narrow height)
* Bugfixes around window OnResize events: the loadscreen handles
resizing correctly now and the Level Editor (or w/e) will also be the
right size if you resized the window during loading.
* When playing as the Bird, the dive attack is able to destroy other
mobile doodads such as Azulians and Thieves.
* The Box has been made invulnerable so it can't be destroyed by Anvils
or player-controlled Birds.
* Bugfixes with pop-up modals:
* The quit game confirm modal doesn't appear if another modal is
already active on screen.
* The Escape key can dismiss Alert and Confirm modals.
* Add "Level" menu items to Play Mode to restart the level or retry from
the last checkpoint (in case of softlocks, etc.)
Adds support for Xbox and Nintendo style game controllers. The gamepad
controls are documented on the README and in the game's Settings window.
The buttons are not customizable yet, except that the player can choose
between two button styles:
* X Style (default): "A" button is on the bottom and "B" on the right.
* N Style: swaps the A/B and the X/Y buttons to use a Nintendo-style
layout instead of an Xbox-style.
* New doodad: Invisible Warp Door
* All warp doors require the player to be grounded (if affected by
gravity) to open them. No jumping or falling thru and opening
a warp door mid-air!
* Title Screen now randomly selects from a couple of levels.
* Title Screen: if it fails to load a level it sets up a basic
blank level with a wallpaper instead.
* New developer shell command: titlescreen <level>
Opens the MainScene with a custom user level as the background.
* Add Auto-save to the Editor to save your drawing every 5 minutes
* Add a MenuBar to the Play Scene for easier navigation to other
features of the game.
* Doodad JS API: time.Since() now available.
* The "Story Mode" button on the MainScene opens the levelpacks window.
* Levelpacks from all places are shown (built-in and user files), basic
level picker works.
* When playing a level out of a levelpack: the PlayScene gets the file
data from the zipfile and plays it OK.
* When a levelpack level is solved, the "Next Level" button appears on
the success modal and hitting Return will advance to the next level in
the pack. The final level doesn't show this button.
* The user can edit levelpack levels! Clicking the "Edit" button on the
Play Mode moves the loaded level over to the EditScene and the user
could save it to disk or edit/playtest it perfectly OK! The link to
the levelpack is lost upon opening in the editor, so the "Next Level"
victory button doesn't appear.
* The Red Bird now records its original altitude on the level and will
try and return there should it accidentally climb up or down a wall.
Sometimes goes into a wavy pattern surrounding its original altitude.
* Editor UI: in the default (vertical) toolbar, the Palette now has a
two column view to show more color choices on screen at once.
* User setting added: hide the touch control hints.
* The level scroll logic was getting a null pointer crash if you open a
doodad rather than a level file.
* Add a crosshair option to the level editor, configurable in the Game
Settings window.
* The "Giant Screenshot" feature takes a very long time, so it is made
asynchronous. If you try and run a second one while the first is busy,
you get an error flash. You can continue editing the level, even
playtest it, or load a different level, and it will continue crunching
on the Giant Screenshot and flash when it's finished.
* Updated the player physics to use proper Velocity to jump off the
ground rather than the hacky timer-based fixed speed approach.
* FlashError() function to flash "error level" messages to the screen.
They appear in orange text instead of the usual blue, and most error
messages in the game use this now. The dev console "error <msg>"
command can simulate an error message.
* Flashed message fonts are updated. The blue font now uses softer
stroke and shadow colors and the same algorithm applies to the orange
error flashes.
Some other changes to player physics:
* Max velocity, acceleration speed, and gravity have been tweaked.
* Fast turn-around if you are moving right and then need to go left.
Your velocity resets to zero at the transition so you quickly get
going the way you want to go.
Some levels that need a bit of love for the new platforming physics:
* Tutorial 3.level
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.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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.
* 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 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 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.
* 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!)
* 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 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.
* 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.