Two new tools added to the Level Editor:
* Pan Tool: left-click to scroll the level around safely.
* Text Tool: write text onto your level.
Features of the Text Tool:
* Can choose from the game's built-in fonts, size and enter the message
you want to write.
* The mouse cursor previews the text when hovered over the level.
* Click to "stamp" the text onto your level. The currently selected
color swatch will be used to color the text in.
* Adds two new fonts: Azulian.ttf and Rive.ttf that can be selected in
the Text Tool.
Some implementation notes:
* Added package native/engine_sdl.go that handles the lower-level
SDL2_TTF logic to rasterize the text into a black&white image.
* WASM not supported yet (if the game even still built for WASM);
native/engine_wasm.go stubs out the TextToImage() call with a "not
supported" error just in case.
Other changes:
* New Toolbar icons: they are 24x24 instead of 32x32 to make more room
for more tools.
* The toolbar now shows two buttons per row for a more densely packed
layout. For very narrow screen widths (< 600px) the default Vertical
Toolbar layout will use one-button-per-row to not eat too much screen
real estate.
* In the Horizontal Toolbars layout there are 2 buttons per column.
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.
* Clean up unused msgpack code for levels and doodads
* Fix the cosmetic bug where actors in your level would display wrongly
when scrolling off the top/left edges of the screen: they used to
anchor at their own 0,0 coordinate and crop their width/height leading
to a 'scrolling' effect that didn't happen on the right/bottom edges.
The Default handler of the developer command shell now calls out to
RiveScript to match the user's message to a friendly reply. If
RiveScript returns NoReplyMatched then give the "command not found"
error.
* Adds pkg/savegame to store user progress thru Level Packs.
* The savegame.json is mildly tamper resistant by including a checksum
along with the JSON body.
* The checksum combines the JSON string + an app secret (in savegame.go)
+ user specific entropy (stored in their settings.json). If the user
modifies their save file and the checksum becomes invalid the game
will not load the save file, acting like it didn't exist, resetting
all their high scores.
Updates to the Story Mode window:
* On the LevelPacks list: shows e.g. "[completed 0 of 3 levels]" showing
a user's progress thru the level pack.
* Below the levels on the Detail screen:
* Shows an indicator whether the level is completed or not.
* Shows high scores (fastest times beating the level)
* Shows a padlock icon if levels are locked and the player hasn't
reached them yet. Pops up an Alert modal if a locked level is
clicked on.
Scoring is based around your fastest time elapsed to finish the level.
* Perfect Time (gold coin): player has not died during the level.
* Best Time (silver coin): player has continued from a checkpoint.
In-game an elapsed timer is shown in the top left corner along with the
gold or silver coin indicating if your run has been Perfect.
If the user enters any Cheat Codes during gameplay they are not eligible
to win a high score, but the level will still be marked as completed.
The icon next to the in-game timer disappears when a cheat code has been
entered.
* SDL2 builds of the game now set their app window icon.
* Create/Edit Level window is updated to show a tabbed UI to create a
new Level or a new Doodad. The dedicated main menu button to create a
new doodad (which immediately prompted for its size) is replaced by
this new tab's UI.
* Edit Drawing/Play Level window is more responsive to smaller screen
sizes by drawing fewer columns of filenames.
* Bugfix: the Alert and Confirm modals always re-center themselves on
screen, especially to adapt between Portrait or Landscape mode on a
mobile device.
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
* 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.
* 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
* 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.
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.
* 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
* 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.
* 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.
Implement the Wallpaper system into the levels and the concept of
Bounded and Unbounded levels.
The first wallpaper image is notepad.png which looks like standard ruled
notebook paper. On bounded levels, the top/left edges of the page look
as you would expect and the blue lines tile indefinitely in the positive
directions. On unbounded levels, you only get the repeating blue lines
but not the edge pieces.
A wallpaper is just a rectangular image file. The image is divided into
four equal quadrants to be the Corner, Top, Left and Repeat textures for
the wallpaper. The Repeat texture is ALWAYS used and fills all the empty
space behind the drawing. (Doodads draw with blank canvases as before
because only levels have wallpapers!)
Levels have four options of a "Page Type":
- Unbounded (default, infinite space)
- NoNegativeSpace (has a top left edge but can grow infinitely)
- Bounded (has a top left edge and bounded size)
- Bordered (bounded with bordered texture; NOT IMPLEMENTED!)
The scrollable viewport of a Canvas will respect the wallpaper and page
type settings of a Level loaded into it. That is, if the level has a top
left edge (not Unbounded) you can NOT scroll to see negative coordinates
below (0,0) -- and if the level has a max dimension set, you can't
scroll to see pixels outside those dimensions.
The Canvas property NoLimitScroll=true will override the scroll locking
and let you see outside the bounds, for debugging.
- Default map settings for New Level are now:
- Page Type: NoNegativeSpace
- Wallpaper: notepad.png (default)
- MaxWidth: 2550 (8.5" * 300 ppi)
- MaxHeight: 3300 ( 11" * 300 ppi)