Browse Source

Update Guidebook for v0.8.0

master
Noah Petherbridge 3 years ago
parent
commit
63f069bf8e
  1. 122
      docs/changes.md
  2. 10
      docs/custom-doodads/edit-external.md
  3. 79
      docs/custom-doodads/edit-in-game.md
  4. 51
      docs/custom-doodads/index.md
  5. 253
      docs/custom-doodads/scripts.md
  6. 14
      docs/custom-levels/index.md
  7. 137
      docs/doodads.md
  8. 16
      docs/hacking.md
  9. BIN
      docs/images/doodad-editor.png
  10. BIN
      docs/images/doodad-properties.png
  11. BIN
      docs/images/doodad-tags.png
  12. BIN
      docs/images/doodads.png
  13. BIN
      docs/images/doodads/anvil.png
  14. BIN
      docs/images/doodads/checkpoint-flag.png
  15. BIN
      docs/images/doodads/electric-trapdoor.gif
  16. BIN
      docs/images/doodads/thief.gif
  17. BIN
      docs/images/generic-script.png
  18. BIN
      docs/images/main-menu.png
  19. 2
      docs/index.md
  20. 31
      docs/linked-doodads.md

122
docs/changes.md

@ -1,5 +1,127 @@
# Changes # Changes
## v0.8.0 (September 4, 2021)
This release brings some new features, new doodads, and new levels.
New features:
* **Checkpoints** for gameplay will ease the pain of dying to fire
pixels or Anvils by teleporting you back to the checkpoint instead
of resetting the whole level.
* The **Doodad Properties** window while editing a doodad grants access
to many features which were previously only available via the
`doodad` tool, such as:
* Edit metadata like the Title and Author of your doodad
* Set the default hitbox of your doodad.
* Attach, open, and delete the JavaScript for your doodad
* Manage tags (key/value store) on your doodads: how you can
communicate settings to the JavaScript which can receive the
tags via `Self.GetTag("name")`
* Some **Generic Doodad Scripts** are built in. Using only the in-game
tools, it is possible to create custom doodads which have some basic
in-game logic and you don't need to write any code. The generic
scripts include:
* Generic Solid: the hitbox is solid
* Generic Fire: its hitbox harms the player
* Generic Anvil: harmless, deadly when falling
* Generic Collectible Item: it goes in your inventory
* **All Characters are Playable!** Use the Link Tool to connect your
Start Flag with another doodad on your level, and you will play
**as** that doodad when the level starts. The Creature doodads are
all intended to be fully functional; playing as buttons and doors
leads to strange results.
New doodads have been added:
* The **Anvil** is a heavy metal object which is affected by gravity.
It is harmless to collision, but if the anvil is in freefall, it
will destroy every mobile doodad that it touches, and is deadly
to the player character.
* The **Electric Trapdoor** is a trapdoor that opens and closes when
powered by a button or switch. It is a horizontal version of the
Electric Door.
* The **Thief** is a new character which will steal items from the
player or other mobile doodads. The Thief is able to pick up items
and unlock doors and he walks back and forth like the Azulians.
* The **Blue Azulian** is now selectable from the Doodads menu. It
behaves like the Red Azulian but moves at half the speed. The
Azulians can pick up items and open doors.
* The **Checkpoint Flag** will remember the player's spot in the level.
Dying to fire pixels or Anvils no longer forces a restart of the
level - you can resume from your last checkpoint, or the Start Flag
by default.
New levels have been added:
* **Castle.level:** introduces the new Thief character. Castle-themed
level showing off various new doodads.
* **Thief 1.level:** a level where you play as the Thief! You need to
steal Small Keys from dozens of Azulians and even steal items back
from another Thief who has already stolen some of the keys.
Some doodads have changed behavior:
* The **Bird** can no longer pick up items, unless controlled by
the player character.
* The **Anvil** and **Box** will reset to their original locations
if they receive a power signal from a linked button or switch.
The user interface has been improved:
* **Tabbed windows!** The Doodad Dropper window of the level editor
and the Settings window use new, tabbed interfaces.
* **Doodad Categories:** the Doodad Dropper's tabs are divided into
a few major categories.
1. Objects: Anvil, Box, Crumbly Floor, and Flags
2. Doors: Doors, Trapdoors, and Keys
3. Gizmos: Buttons, Switches, Electric Doors, etc.
4. Creatures: Bird, Azulians, Thief
5. All: a classic view paging over all doodads (and doodads
not fitting any of the above categories).
New functions are available in the JavaScript API for custom doodads:
* FailLevel(message string): global function that kills the player
with a custom death message.
* SetCheckpoint(Point): set the player respawn location
* Self.MoveTo(Point(x, y int))
* Self.IsPlayer() bool
* Self.SetInventory(bool): turn on or off inventory. Keys and other
items will now only give themselves to mobile doodads which have
inventory.
* Self.HasInventory() bool
* Self.AddItem(filename string, quantity int) - zero quantity for
permanent items like the colored keys.
* Self.RemoveItem(filename string, quantity int)
* Self.HasItem(filename string)
* Self.Inventory() map[string]int
* Self.Hitbox() - also see Self.Hitbox.IsEmpty()
The Events.OnLeave() callback now receives a CollideEvent argument,
like OnCollide, instead of the useless actor ID string. Notable
properties on the CollideEvent will be the .Actor which is leaving
and Settled=true.
Other miscellaneous changes:
* The **Link Tool** can now un-link two doodads by clicking on
them again.
* Actor UUIDs in your levels will now be Type 1 UUIDs (time-based)
instead of random. This will ensure each newly added doodad gets
a larger ID than the previous one, so in cases of draw order
conflicts or that sort of thing, the winner can be picked
deterministically (most recently added renders on top).
* A **death barrier** will prevent Boy from falling forever on unbounded
maps should he somehow fall off the level. The death barrier is a
Y value 1,000 pixels below the lowest pixel on your map.
* Mobile doodads no longer "moonwalk" when they change directions.
* A new color is added to all default palettes: "hint" (pink) for
writing hint notes.
* A maximum scroll speed on the "follow the player character" logic
makes for cooler animations when the character teleports around.
* Levels and Doodads are now sorted on the Open menu.
## v0.7.2 (July 19 2021) ## v0.7.2 (July 19 2021)
This release brings some new features and some new content. This release brings some new features and some new content.

10
docs/custom-doodads/edit-external.md

@ -1,4 +1,4 @@
# Drawing Doodads in an External Program
# External Editors for Doodads
Doodad sprites can be drawn using any image editor and saved as .png files Doodad sprites can be drawn using any image editor and saved as .png files
(with transparency). You can then create a doodad file from your series of (with transparency). You can then create a doodad file from your series of
@ -18,3 +18,11 @@ doodad convert [options] <inputs.png> <output.doodad>
# Example: # Example:
doodad convert door-closed.png door-open.png door.doodad doodad convert door-closed.png door-open.png door.doodad
``` ```
The `doodad` tool can also be used to attach a JavaScript to your doodad,
modify its tags, and other things. See [`doodad` tool](../doodad-tool.md).
## Example Doodads
There are some fully working example doodads you can check out at
<https://code.sketchymaze.com/declassified/doodads>.

79
docs/custom-doodads/edit-in-game.md

@ -4,12 +4,80 @@ Sketchy Maze has support for drawing your custom doodad sprites in-game,
although for now you may find it more comfortable to use an although for now you may find it more comfortable to use an
[external image editor](edit-external.md) instead. [external image editor](edit-external.md) instead.
![Screenshot of the Doodad editor](../images/doodad-editor.png)
To start a new doodad, open the game and enter the level editor. Select the To start a new doodad, open the game and enter the level editor. Select the
"File -> New Doodad" menu at the top of the screen. You will be prompted for "File -> New Doodad" menu at the top of the screen. You will be prompted for
the square dimensions of your doodad (i.e. `100` for a 100x100 sprite) and the square dimensions of your doodad (i.e. `100` for a 100x100 sprite) and
you can begin editing. you can begin editing.
![Screenshot of the Doodad editor](../images/doodad-editor.png)
## Doodad Properties
The "Doodad -> Doodad Properties" menu brings up the properties window for
the doodad you're editing:
![Doodad Properties](../images/doodad-properties.png)
This window has many useful features which (prior to v0.8.0) used to only be
available on the [`doodad` tool](../doodad-tool.md):
* Metadata: you can modify the Title, Author and Hitbox fields.
* Doodad Script: you can view, upload and delete a JavaScript source for
your doodad.
* Generic Scripts: some built-in scripts to easily make useful doodads
without needing to write _any_ code!
* Tags: manage the key/value tag store on the doodad. Tags hold configuration
data that the JavaScript sometimes wants, or some tags have special meaning
to the game such as "category" (see below).
## Generic Doodad Scripts
![Generic Scripts](../images/generic-script.png)
The game includes a few "generic" scripts that you can _easily_ attach to
your doodad. From the Doodad Properties window, click into the select box
and choose from the built-in scripts. A confirmation window will explain
the script and if you want to attach it to your doodad.
### Generic Solid
The Hitbox of your doodad will behave as a solid object in-game. Mobile
doodads can walk on top of it.
### Generic Fire
The Hitbox of your doodad acts just like fire pixels: it will "burn" mobile
doodads and it will harm the player character, failing the level.
"Watch out for (doodad title)!"
### Generic Anvil
Draw your own version of the Anvil! Your doodad does not have a solid hitbox,
and is perfectly harmless, except it falls with gravity and becomes deadly
while falling. It destroys any mobile doodad that it falls on and, if it's
the player character, fails the level.
### Generic Collectible Item
Your doodad will behave similarly to the Keys and can be "picked up" by the
player or other doodad with an inventory. Its sprite will appear in the
Inventory HUD in-game. Be careful on your sprite size, the inventory HUD
grows to accommodate the largest item sprite size!
## Setting the Category Tag
In the Level Editor, the Doodad Dropper window shows a categorical tab frame
with options like "Objects, Gizmos, Doors, Creatures, All"
Your custom doodads will only appear in the "All" tab by default. To put your
doodad into one of the official category tabs, add a tag named "category"
holding one of these values: objects, gizmos, doors, or creatures (all
lowercase).
![Doodad Tags](../images/doodad-tags.png)
You may comma separate multiple categories. Unrecognized categories are
ignored - your doodad always appears on the All tab regardless.
## Layers ## Layers
@ -17,7 +85,7 @@ A key difference between Levels and Doodads are that Doodad drawings can have
multiple **layers**. For doodads these are used to store multiple frames of multiple **layers**. For doodads these are used to store multiple frames of
animation or different states, such as an opened vs. closed door. animation or different states, such as an opened vs. closed door.
Clicking the **Lyr.** button on the left toolbar or the "Tools -> Layers"
Clicking the **Lyr.** button on the left toolbar or the "Doodad -> Layers"
menu will open the Layers window where you can switch your editor between menu will open the Layers window where you can switch your editor between
layers, add and rename them. Layers can be toggled by the doodad's layers, add and rename them. Layers can be toggled by the doodad's
[JavaScript code](scripts.md) by index number or by name, so giving each layer [JavaScript code](scripts.md) by index number or by name, so giving each layer
@ -26,10 +94,3 @@ a descriptive name is useful.
Doodads saved in-game go in your [user config directory](../profile-directory.md) Doodads saved in-game go in your [user config directory](../profile-directory.md)
on your system. on your system.
## Future Planned Features
Creating doodads in-game is intended to be a fully supported feature. The
following features are planned to be supported:
* Implement some features only available on the `doodad` tool using in-game
UI, such as attaching JavaScripts to the doodad.

51
docs/custom-doodads/index.md

@ -13,6 +13,33 @@ image editor. Then, you can program their behavior using JavaScript to make them
* Program its Behavior * Program its Behavior
* [JavaScript](scripts.md) * [JavaScript](scripts.md)
## In-game Doodad Editor
The in-game level editor can be used to create custom doodads. As of
Sketchy Maze v0.8.0, doodads can be authored entirely in-game without
needing to use the `doodad` command-line tool.
![Screenshot of the Doodad editor](../images/doodad-editor.png)
See [Drawing Doodads](edit-in-game.md) for details.
## Using external editors
You may find it more comfortable to draw your doodads in an external
image editor. All of the game's built-in doodads were drawn in The GIMP.
The `doodad` command-line tool that ships with the game is able to convert
a series of PNG images into a doodad, attach a JavaScript, set tags, and
so on.
See [External Editors for Doodads](edit-external.md)
## Example Doodads
There are some example custom doodads you can check out at
<https://code.sketchymaze.com/declassified/doodads>. There you will find
example custom doodads to make your own player characters, Warp Doors,
and more.
## Naming Convention ## Naming Convention
It is strongly encouraged that you name your custom doodad files with a It is strongly encouraged that you name your custom doodad files with a
@ -30,6 +57,30 @@ than yourself.
Future versions of the game will likely prevent saving a new doodad with Future versions of the game will likely prevent saving a new doodad with
the same filename of a built-in one. the same filename of a built-in one.
## Categories
The in-game Doodad Dropper window of the level editor shows a categorical
view of doodads: Objects, Doors, Gizmos, Creatures, and All.
Categories are managed by setting custom tags on your .doodad file, which
can be done by the [doodad tool](../doodad-tool.md) like so:
```bash
doodad edit-doodad --tag "category=objects" example.doodad
```
The "category" tag should hold a lowercase value. Only supported categories
are recognized, which include: objects, doors, gizmos, creatures.
A doodad can appear under multiple categories by joining them with a comma:
```bash
doodad edit-doodad --tag "category=doors,gizmos" example.doodad
```
Every doodad also appears in the "All" tab. In the future, custom tags will
be editable using in-game UI when creating a custom doodad.
## Profile Directory ## Profile Directory
Custom doodads and levels will go in your [Profile Directory](../profile-directory.md), Custom doodads and levels will go in your [Profile Directory](../profile-directory.md),

253
docs/custom-doodads/scripts.md

@ -1,6 +1,6 @@
# Doodad Scripts # Doodad Scripts
Doodads are programmed using JavaScript which gives them their behavior
Doodads are programmed using (ES5) JavaScript which gives them their behavior
and ability to interact with the player and other doodads. and ability to interact with the player and other doodads.
Doodad scripts are run during "Play Mode" when a level _containing_ the doodad Doodad scripts are run during "Play Mode" when a level _containing_ the doodad
@ -58,9 +58,14 @@ function main() {
} }
``` ```
# Installing a Doodad Script
## Installing a Doodad Script
Use the command-line `doodad` tool to attach a script to your doodad file:
Scripts can be attached to your doodad either in-game (using the Doodad
Properties window in the editor) or by using the command-line `doodad` program.
![In-game Script UI](../images/doodad-properties.png)
Using the command-line [`doodad` tool](../doodad-tool.md):
```bash ```bash
# Attach the JavaScript at "script.js" to the doodad file "filename.doodad" # Attach the JavaScript at "script.js" to the doodad file "filename.doodad"
@ -71,7 +76,9 @@ doodad install-script script.js filename.doodad
doodad show --script filename.doodad doodad show --script filename.doodad
``` ```
# Testing Your Script
## Testing Your Script
The best way to test your doodad script is to use it in a level! The best way to test your doodad script is to use it in a level!
@ -80,13 +87,68 @@ like `console.log()` in your script to help debug issues. Drag your custom
doodad into a level and playtest it! Your script's main() function is called doodad into a level and playtest it! Your script's main() function is called
when the level instance of your doodad is initialized. when the level instance of your doodad is initialized.
# JavaScript API
## JavaScript API
The following global variables are available to all Doodad scripts. The following global variables are available to all Doodad scripts.
## Self
### Global Functions
Some useful globally available functions:
#### EndLevel()
This ends the current level, i.e. to be used by the goal flag.
#### FailLevel(message string)
Trigger a failure condition in the level. For example, a hazardous doodad
can cause a death message as though the player had touched a "fire" pixel
on the level.
#### SetCheckpoint(Point)
Set the respawn point for the player character. Usually, this will be
relative to a checkpoint flag's location on the level.
```javascript
Events.OnCollide(function(e) {
if (e.Settled && e.Actor.IsPlayer()) {
SetCheckpoint(Self.Position());
}
})
```
#### Flash(message string, args...)
Flash a message on screen to the user.
Flashed messages appear at the bottom of the screen and fade out after a few
moments. If multiple messages are flashed at the same time, they stack from the
bottom of the window with the newest message on bottom.
Don't abuse this feature as spamming it may annoy the player.
#### GetTick() uint64
Returns the current game tick. This value started at zero when the game was
launched and increments every frame while running.
#### time.Now() time.Time
This exposes the Go standard library function `time.Now()` that returns the
current date and time as a Go time.Time value.
#### time.Add(t time.Time, milliseconds int64) time.Time
Add a number of milliseconds to a Go Time value.
--------
### Self
Self holds data about the current doodad instance loaded inside of a level. Self holds data about the current doodad instance loaded inside of a level.
Many of these are available on other actors that collide with your doodad
in the OnCollide handler, at event.Actor.
**String attributes:** **String attributes:**
@ -95,12 +157,20 @@ Self holds data about the current doodad instance loaded inside of a level.
Methods are below. Methods are below.
### Self.ID() string
#### Self.ID() string
Returns the "actor ID" of the doodad instance loaded inside of a level. This Returns the "actor ID" of the doodad instance loaded inside of a level. This
is usually a random UUID string that was saved with the level data. is usually a random UUID string that was saved with the level data.
### Self.GetTag(string name) string
#### Self.IsPlayer() bool
**New in v0.8.0**
Check if the doodad is the player character. Some enemy creature doodads check
this so as to disable their normal A.I. movement pattern and allow player
controls to set its animations.
#### Self.GetTag(string name) string
Return a "tag" that was saved with the doodad's file data. Return a "tag" that was saved with the doodad's file data.
@ -124,7 +194,7 @@ doodad edit-doodad -t 'color=' filename.doodad
This is useful for a set of multiple doodads to share the same script but This is useful for a set of multiple doodads to share the same script but
have different behavior depending on how each is tagged. have different behavior depending on how each is tagged.
### Self.Position() Point
#### Self.Position() Point
Returns the doodad's current position in the level. Returns the doodad's current position in the level.
@ -135,7 +205,16 @@ var p = Self.Position()
console.log("I am at %d,%d", p.X, p.Y) console.log("I am at %d,%d", p.X, p.Y)
``` ```
### Self.SetHitbox(x, y, w, h int)
#### Self.MoveTo(Point)
Teleport the current doodad to an exact point on the level.
```javascript
// Teleport to origin.
Self.MoveTo(Point(0, 0))
```
#### Self.SetHitbox(x, y, w, h int)
Configure the "solid hitbox" of this doodad. Configure the "solid hitbox" of this doodad.
@ -174,7 +253,30 @@ function main() {
} }
``` ```
### Self.SetVelocity(Velocity)
#### Self.Hitbox() Rect
**New in v0.8.0**
Return the current hitbox of your doodad. If you did not call Self.SetHitbox()
yourself, then this will return the hitbox that was configured on the Doodad's
Properties.
Check Self.Hitbox().IsZero() to see whether the doodad has a hitbox configured
at all (having a value of 0,0,0,0). For example, the generic doodad scripts
run checks like this:
```javascript
function main() {
// If the doodad does not have a hitbox set, default it to
// the full square canvas size of this doodad.
if (Self.Hitbox().IsZero()) {
var size = Self.Size();
Self.SetHitbox(0, 0, size, size);
}
}
```
#### Self.SetVelocity(Velocity)
Set the doodad's velocity. Velocity is a type that can be created with the Set the doodad's velocity. Velocity is a type that can be created with the
Velocity() constructor, which takes an X and Y value: Velocity() constructor, which takes an X and Y value:
@ -186,7 +288,7 @@ Self.SetVelocity( Velocity(3.2, 7.0) );
A positive X velocity propels the doodad to the right. A positive Y velocity A positive X velocity propels the doodad to the right. A positive Y velocity
propels the doodad downward. propels the doodad downward.
### Self.SetMobile(bool)
#### Self.SetMobile(bool)
Call `SetMobile(true)` if the doodad will move on its own. Call `SetMobile(true)` if the doodad will move on its own.
@ -202,7 +304,7 @@ Position).
Self.SetMobile(true); Self.SetMobile(true);
``` ```
### Self.SetGravity(bool)
#### Self.SetGravity(bool)
Set whether gravity applies to this doodad. By default doodads are stationary Set whether gravity applies to this doodad. By default doodads are stationary
and do not fall downwards. The player character and some mobile enemies that and do not fall downwards. The player character and some mobile enemies that
@ -210,9 +312,44 @@ want to be affected by gravity should opt in to this.
```javascript ```javascript
Self.SetGravity(true); Self.SetGravity(true);
// HasGravity to check.
console.log(Self.HasGravity()); // true
```
#### Self.SetInventory(bool)
Set whether this doodad has an inventory and can carry items. Doodads without
inventories can not pick up keys and other items.
```javascript
Self.SetInventory(true);
Self.GetInventory(); // true
``` ```
### Self.ShowLayer(index int)
#### Self.AddItem(filename string, quantity int)
Add an item to the current doodad's inventory. The filename is the name of the
item to add, such as "key-blue.doodad"
If the quantity is zero, the item goes in as a "key item" which does not show
a quantity in your inventory. The four colored keys are examples of this, as
compared to the Small Key which has a quantity.
#### Self.RemoveItem(filename string, quantity int)
Remove items from the current doodad's inventory.
#### Self.HasItem(filename string) bool
Tests if the item is in the inventory.
#### Self.Inventory() map[string]int
Returns the doodad's full inventory data, an object that maps filename strings
to quantity integers.
#### Self.ShowLayer(index int)
Switch the active layer of the doodad to the layer at this index. Switch the active layer of the doodad to the layer at this index.
@ -224,7 +361,7 @@ Self.ShowLayer(0); // 0 is the first and default layer
Self.ShowLayer(1); // show the second layer instead Self.ShowLayer(1); // show the second layer instead
``` ```
### Self.ShowLayerNamed(name string)
#### Self.ShowLayerNamed(name string)
Switch the active layer by name instead of index. Switch the active layer by name instead of index.
@ -241,7 +378,7 @@ order of file names passed in, with 0 being the first file:
doodad convert door.png open-1.png open-2.png open-3.png my-door.doodad doodad convert door.png open-1.png open-2.png open-3.png my-door.doodad
``` ```
### Self.AddAnimation(name string, interval int, layers list)
#### Self.AddAnimation(name string, interval int, layers list)
Register a named animation for your doodad. `interval` is the time in Register a named animation for your doodad. `interval` is the time in
milliseconds before going to the next frame. `layers` is an array of layer milliseconds before going to the next frame. `layers` is an array of layer
@ -260,7 +397,7 @@ Self.AddAnimation("open", 100, ["open-1", "open-2", "open-3"]);
Self.AddAnimation("close", 100, [3, 2, 1]); Self.AddAnimation("close", 100, [3, 2, 1]);
``` ```
### Self.PlayAnimation(name string, callback func())
#### Self.PlayAnimation(name string, callback func())
This starts playing the named animation. The callback function will be called This starts playing the named animation. The callback function will be called
when the animation has completed. when the animation has completed.
@ -274,11 +411,11 @@ Self.PlayAnimation("open", function() {
}); });
``` ```
### Self.IsAnimating() bool
#### Self.IsAnimating() bool
Returns true if an animation is currently being played. Returns true if an animation is currently being played.
### Self.StopAnimation()
#### Self.StopAnimation()
Stops any currently playing animation. Stops any currently playing animation.
@ -292,7 +429,7 @@ Stops any currently playing animation.
* Self.Doodad().GameVersion: the version of {{ app_name }} that was used * Self.Doodad().GameVersion: the version of {{ app_name }} that was used
when the doodad was created. when the doodad was created.
### Self.Destroy()
#### Self.Destroy()
This destroys the current instance of the doodad as it appears in a level. This destroys the current instance of the doodad as it appears in a level.
@ -302,7 +439,7 @@ doodad instance should be destroyed and removed from the active level.
----- -----
## Console Logging
### Console Logging
Like in node.js and the web browser, `console.log` and friends are available Like in node.js and the web browser, `console.log` and friends are available
for logging from a doodad script. Logs are emitted to the same place as the for logging from a doodad script. Logs are emitted to the same place as the
@ -318,12 +455,12 @@ console.error("Error-level messages");
----- -----
## Timers and Intervals
### Timers and Intervals
Like in a web browser, functions such as setTimeout and setInterval are Like in a web browser, functions such as setTimeout and setInterval are
supported in doodad scripts. supported in doodad scripts.
### setTimeout(function, milliseconds int) int
#### setTimeout(function, milliseconds int) int
setTimeout calls your function after the specified number of milliseconds. setTimeout calls your function after the specified number of milliseconds.
@ -332,7 +469,7 @@ setTimeout calls your function after the specified number of milliseconds.
Returns an integer "timeout ID" that you'll need if you want to cancel the Returns an integer "timeout ID" that you'll need if you want to cancel the
timeout with clearTimeout. timeout with clearTimeout.
### setInterval(function, milliseconds int) int
#### setInterval(function, milliseconds int) int
setInterval calls your function repeatedly after every specified number of setInterval calls your function repeatedly after every specified number of
milliseconds. milliseconds.
@ -340,76 +477,42 @@ milliseconds.
Returns an integer "interval ID" that you'll need if you want to cancel the Returns an integer "interval ID" that you'll need if you want to cancel the
interval with clearInterval. interval with clearInterval.
### clearTimeout(id int)
#### clearTimeout(id int)
Cancels the timeout with the given ID. Cancels the timeout with the given ID.
### clearInterval(id int)
#### clearInterval(id int)
Cancels the interval with the given ID. Cancels the interval with the given ID.
----- -----
## Type Constructors
### Type Constructors
Some methods may need data of certain native types that aren't available in Some methods may need data of certain native types that aren't available in
JavaScript. These global functions will initialize data of the correct types: JavaScript. These global functions will initialize data of the correct types:
### RGBA(red, green, blue, alpha uint8)
#### RGBA(red, green, blue, alpha uint8)
Creates a Color type from red, green, blue and alpha values (integers between Creates a Color type from red, green, blue and alpha values (integers between
0 and 255). 0 and 255).
### Point(x, y int)
#### Point(x, y int)
Creates a Point object with X and Y coordinates. Creates a Point object with X and Y coordinates.
### Vector(x, y float64)
#### Vector(x, y float64)
Creates a Vector object with X and Y dimensions. Creates a Vector object with X and Y dimensions.
----- -----
## Global Functions
Some useful globally available functions:
### EndLevel()
This ends the current level, i.e. to be used by the goal flag.
### Flash(message string, args...)
Flash a message on screen to the user.
Flashed messages appear at the bottom of the screen and fade out after a few
moments. If multiple messages are flashed at the same time, they stack from the
bottom of the window with the newest message on bottom.
Don't abuse this feature as spamming it may annoy the player.
### GetTick() uint64
Returns the current game tick. This value started at zero when the game was
launched and increments every frame while running.
### time.Now() time.Time
This exposes the Go standard library function `time.Now()` that returns the
current date and time as a Go time.Time value.
### time.Add(t time.Time, milliseconds int64) time.Time
Add a number of milliseconds to a Go Time value.
--------
## Event Handlers
### Event Handlers
Doodad scripts can respond to certain events using functions on the global Doodad scripts can respond to certain events using functions on the global
`Events` variable. `Events` variable.
### Events.OnCollide( func(event) )
#### Events.OnCollide( func(event) )
OnCollide is called when another actor is colliding with your doodad's sprite OnCollide is called when another actor is colliding with your doodad's sprite
box. The function is given a CollideEvent object which has the following box. The function is given a CollideEvent object which has the following
@ -429,12 +532,15 @@ attributes:
has special behavior when touched (i.e. a button that presses in), you should has special behavior when touched (i.e. a button that presses in), you should
wait until Settled=true before running your handler for that. wait until Settled=true before running your handler for that.
### Events.OnLeave( func(event) )
#### Events.OnLeave( func(event) )
Called when an actor that _was_ colliding with your doodad is no longer Called when an actor that _was_ colliding with your doodad is no longer
colliding (or has left your doodad's sprite box). colliding (or has left your doodad's sprite box).
### Events.RunKeypress( func(event) )
The event argument is the same as OnCollide, with the Actor available
and Settled=true (others left as default zero values).
#### Events.RunKeypress( func(event) )
Handle a keypress. `event` is an `event.State` from the render engine. Handle a keypress. `event` is an `event.State` from the render engine.
@ -442,7 +548,7 @@ TODO: document that.
----- -----
## Pub/Sub Communication
### Pub/Sub Communication
Doodads in a level are able to send and receive messages to other doodads, Doodads in a level are able to send and receive messages to other doodads,
either those that they are **linked** to or those that listen on a more either those that they are **linked** to or those that listen on a more
@ -460,7 +566,7 @@ Doodads communicate in a "publisher/subscriber" model: one doodad publishes an
event with a name and data, and other doodads subscribe to the named event to event with a name and data, and other doodads subscribe to the named event to
receive that data. receive that data.
### Official, Standard Pub/Sub Messages
#### Official, Standard Pub/Sub Messages
The following message names and data types are used by the game's default The following message names and data types are used by the game's default
doodads. You're free to use these in your own custom doodads. doodads. You're free to use these in your own custom doodads.
@ -473,10 +579,11 @@ their custom event names.
|------|-----------|--------------| |------|-----------|--------------|
| power | boolean | Communicates a "powered" (true) or "not powered" state, as in a Button to an Electric Door. | | power | boolean | Communicates a "powered" (true) or "not powered" state, as in a Button to an Electric Door. |
| broadcast:state-change | boolean | An "ON/OFF" button was hit and all state blocks should flip. | | broadcast:state-change | boolean | An "ON/OFF" button was hit and all state blocks should flip. |
| broadcast:checkpoint | string | A checkpoint flag was reached. Value is the actor ID of the checkpoint flag. |
| sticky:down | boolean | A sticky button is pressed Down. If linked to other normal buttons, it tells them to press down as well. Sends a `false` when the Sticky Button itself pops back up. | | sticky:down | boolean | A sticky button is pressed Down. If linked to other normal buttons, it tells them to press down as well. Sends a `false` when the Sticky Button itself pops back up. |
| switch:toggle | boolean | A switch has been toggled from on to off. | | switch:toggle | boolean | A switch has been toggled from on to off. |
### Message.Publish(name string, data...)
#### Message.Publish(name string, data...)
Publish a named message to all of your **linked** doodads. Publish a named message to all of your **linked** doodads.
@ -498,7 +605,7 @@ function main() {
} }
``` ```
### Message.Subscribe(name string, function)
#### Message.Subscribe(name string, function)
Subscribe to a named message from any **linked** doodads. Subscribe to a named message from any **linked** doodads.
@ -526,7 +633,7 @@ function main() {
} }
``` ```
### Message.Broadcast(name string, data...)
#### Message.Broadcast(name string, data...)
This publishes a named message to **every** doodad in the level, whether it This publishes a named message to **every** doodad in the level, whether it
was linked to the broadcaster or not. was linked to the broadcaster or not.

14
docs/custom-levels/index.md

@ -79,18 +79,21 @@ with. The available options as of **version 0.6.0** are:
2. **decoration**: light grey 2. **decoration**: light grey
3. **fire**: red, fire 3. **fire**: red, fire
4. **water**: blue, water 4. **water**: blue, water
5. **hint**: pink
* **Colored Pencil:** a new palette with some more varied default colors. * **Colored Pencil:** a new palette with some more varied default colors.
1. **grass**: green, solid geometry 1. **grass**: green, solid geometry
2. **dirt**: brown, solid 2. **dirt**: brown, solid
3. **stone**: dark grey, solid 3. **stone**: dark grey, solid
4. **fire**: red, fire 4. **fire**: red, fire
5. **water**: light blue (#0099FF), water 5. **water**: light blue (#0099FF), water
6. **hint**: pink
* **Blueprint:** the classic palette for levels with the Blueprint wallpaper: * **Blueprint:** the classic palette for levels with the Blueprint wallpaper:
1. **solid**: white, solid 1. **solid**: white, solid
2. **decoration:** light grey 2. **decoration:** light grey
3. **fire**: light red (#FF5000), fire 3. **fire**: light red (#FF5000), fire
4. **water**: light blue (#0099FF), water 4. **water**: light blue (#0099FF), water
5. **electric**: yellow, solid 5. **electric**: yellow, solid
6. **hint**: pink
In earlier alpha versions of the game, the Blueprint palette was chosen by In earlier alpha versions of the game, the Blueprint palette was chosen by
default when the level starts out with the Blueprint wallpaper, which has a default when the level starts out with the Blueprint wallpaper, which has a
@ -210,8 +213,8 @@ and a magenta box appears around it. Click on it, and then click on the other
doodad to pair it to. A glowing magenta line will connect the two doodads doodad to pair it to. A glowing magenta line will connect the two doodads
together from then on, showing their connection. together from then on, showing their connection.
> **Note:** there seems to be no way to un-link two doodads once linked,
> deleting one from your level and placing a new one will break the links.
To disconnect a link between two doodads, click on the two of them again with
the Link Tool - or delete and replace one of them.
Linked doodads are able to send small messages to their linked partners when Linked doodads are able to send small messages to their linked partners when
events happen to _them_. For example, when the player character steps on a button events happen to _them_. For example, when the player character steps on a button
@ -316,10 +319,13 @@ Its options include:
* Undo (Ctrl-Z) * Undo (Ctrl-Z)
* Redo (Ctrl-Y) * Redo (Ctrl-Y)
* Settings * Settings
* **Level**
* Page settings (to change the level type or wallpaper)
* **Level** _(only when editing a level)_
* Level Properties
* Attached files * Attached files
* Playtest (P) * Playtest (P)
* **Doodad** _(only when editing a doodad)_
* Doodad Properties
* Layers
* **Tools** * **Tools**
* Debug overlay (F3) * Debug overlay (F3)
* Command shell (Enter) * Command shell (Enter)

137
docs/doodads.md

@ -14,17 +14,22 @@ linked together in your levels.
* [Objects](#objects) * [Objects](#objects)
* [Start Flag](#start-flag) - Spawn point of a level * [Start Flag](#start-flag) - Spawn point of a level
* [Checkpoint Flag](#checkpoint-flag) - **NEW in v0.8.0**
* [Exit Flag](#exit-flag) - Goal of a level * [Exit Flag](#exit-flag) - Goal of a level
* [Box](#bog)
* [Anvil](#anvil) - **NEW in v0.8.0**
* [Box](#box)
* [Creatures](#creatures) * [Creatures](#creatures)
* [Boy](#boy) - The player character * [Boy](#boy) - The player character
* [Red Bird](#red-bird) * [Red Bird](#red-bird)
* [Red Azulian (test mob)](#red-azulian-test-mob)
* [Azulians](#azulians)
* [Thief](#thief) - **NEW in v0.8.0**
* [Doors & Trapdoors](#doors-trapdoors) * [Doors & Trapdoors](#doors-trapdoors)
* [Colored Locked Doors & Keys](#colored-locked-doors-keys) * [Colored Locked Doors & Keys](#colored-locked-doors-keys)
* [Small Key Doors](#small-key-doors) * [Small Key Doors](#small-key-doors)
* [Warp Doors](#warp-doors) * [Warp Doors](#warp-doors)
* [Trapdoors](#trapdoors) * [Trapdoors](#trapdoors)
* [Electric Door](#electric-door)
* [Electric Trapdoor](#electric-trapdoor)
* [Crumbly Floor](#crumbly-floor) * [Crumbly Floor](#crumbly-floor)
* [Objects](#objects) * [Objects](#objects)
* [Box](#box) * [Box](#box)
@ -32,7 +37,6 @@ linked together in your levels.
* [Buttons](#buttons) * [Buttons](#buttons)
* [Sticky Button](#sticky-button) * [Sticky Button](#sticky-button)
* [Switches](#switches) * [Switches](#switches)
* [Electric Door](#electric-door)
* [Boolean State Doodads](#boolean-state-doodads) * [Boolean State Doodads](#boolean-state-doodads)
* [State Button](#state-button) * [State Button](#state-button)
* [State Blocks](#state-blocks) * [State Blocks](#state-blocks)
@ -50,12 +54,32 @@ The **Start Flag** sets the player spawn point in your level. There should be
only one start flag per level. only one start flag per level.
Multiple Start Flags in one level is considered to be an error; a warning is Multiple Start Flags in one level is considered to be an error; a warning is
flashed on-screen and the player will spawn at one of the flags at random.
flashed on-screen and the player will spawn at the "first" start flag it found.
A level without a Start Flag will spawn the player at the 0,0 coordinate at A level without a Start Flag will spawn the player at the 0,0 coordinate at
the top-left corner of the level, and flash an error about the missing Start the top-left corner of the level, and flash an error about the missing Start
Flag. Flag.
If the Start Flag is [linked](linked-doodads.md#start-flag) to another doodad
in your level, then that doodad will be used for the player character. For example,
linking a Start Flag to a Thief will use the Thief as the player character
for that level instead of the default character, [Boy](#boy).
### Checkpoint Flag
![Checkpoint Flag](images/doodads/checkpoint-flag.png)
The **Checkpoint Flag** records the player's position in the level each time
he reaches a checkpoint. Should they die during the level, the option to
"Retry from checkpoint" will teleport the player back to that location and
continue gameplay without resetting the level -- so you keep any keys you
have, unlocked doors remain unlocked, etc.
The default checkpoint location is at the Start Flag, and crossing Checkpoint
Flags updates it to the last flag touched. When a second checkpoint is touched,
the previous checkpoint flags are reset and the player's spawn point is the
checkpoint they most recently touched.
### Exit Flag ### Exit Flag
![Exit Flag](images/doodads/exit-flag.png) ![Exit Flag](images/doodads/exit-flag.png)
@ -63,6 +87,22 @@ Flag.
The **Exit Flag** sets a goal point for the level. The player must touch this The **Exit Flag** sets a goal point for the level. The player must touch this
flag to win the level. flag to win the level.
### Anvil
![Anvil](images/doodads/anvil.png)
The **Anvil** is a "harmless" object that becomes dangerous when it is falling.
It has no collision and is affected by gravity; when falling, it is dangerous
to any **mobile** doodad that it encounters, including the player character.
Being hit by it will fail the level with "Watch out for falling anvils!" and
you can retry from your last checkpoint. It destroys other mobile doodads that
it lands on, removing them from the level.
If it receives a **power** signal (from a [linked](linked-doodads.md#buttons)
Button or Switch), the Anvil will reset to its original location on the level,
making "reset buttons" possible for puzzle levels.
### Box ### Box
![Box](images/doodads/box.gif) ![Box](images/doodads/box.gif)
@ -79,6 +119,11 @@ pushing simultaneously. Boxes can be stacked on top of each other, but sometimes
Boy will get "stuck" standing on top of the pile. If this happens, use the Boy will get "stuck" standing on top of the pile. If this happens, use the
[cheat code](hacking.md#cheat-codes) `ghost mode` to get yourself unstuck. [cheat code](hacking.md#cheat-codes) `ghost mode` to get yourself unstuck.
**New in v0.8.0:**
If it receives a **power** signal (from a [linked](linked-doodads.md#buttons)
Button or Switch), the Anvil will reset to its original location on the level,
making "reset buttons" possible for puzzle levels.
--- ---
# Creatures # Creatures
@ -113,19 +158,55 @@ ride more reliably.
Currently, however, the bird is harmless and does not dive bomb the player. Currently, however, the bird is harmless and does not dive bomb the player.
### Red Azulian (Test Mob)
**New in v0.8.0:** the Bird no longer can pick up items such as keys, unless
controlled by the player character.
### Azulians
![Red Azulian](images/doodads/red-azulian.gif) ![Red Azulian](images/doodads/red-azulian.gif)
The red Azulian is a test mobile character. Not really an enemy, as he doesn't
care about the player.
The **Red Azulian** was the first test mobile character, and the
**Blue Azulian** was originally the player character in very early builds of
the game.
The Azulians' A.I., when placed in your level, is that they walk right and
left across the ground, changing directions when hitting an obstacle. They
can pick up keys, unlock doors, and interact with buttons and switches that
they walk onto - basically all the capabilities as the player character.
The blue Azulian walks half as fast as the red one.
You can play as them in your custom levels by linking a Start Flag to
the Azulian.
### Thief
The Azulian's A.I. just has it run left and right until it meets resistance.
It can pick up keys, activate buttons and switches that it passes by, and can
unlock doors.
![Thief](images/doodads/thief.gif)
This mob will probably go away in future releases of the game and will remain
in the code as a hidden easter egg.
The **Thief** is a mobile character which can steal items from other doodads,
including the player character.
The Thief's A.I. is to walk right and left, she can pick up items, unlock doors,
and activate most devices that it walks onto. When she encounters another
doodad (including the player), the Thief will **steal** any items they are
carrying:
* For items which have no quantity, such as the Blue Key, the Thief will only
steal it if she does not already have one, letting the player keep the
key.
* Items with quantity are always stolen: the Thief will steal all your small
keys.
* The A.I. Thief does **not** steal from other A.I. Thieves.
The player can play **as** the Thief by using the Link Tool and connecting
the Start Flag to a Thief. When controlled by the player character, the Thief
has special abilities compared to most other characters:
* You can steal items from other characters. When you contact another character
such as the Azulians, if they are holding any items, you'll automatically
steal them in the same way the Thief usually steals from you.
* The player character is immune to Thieves which will not steal from Thieves.
* The player character _can_, though, pilfer items that the other Thieves have
collected.
--- ---
@ -203,6 +284,27 @@ as a solid wall. If the door is open you may run in from the wrong side.
Trapdoors come in four variants: downward-facing (default), rightward, leftward Trapdoors come in four variants: downward-facing (default), rightward, leftward
and upwards. and upwards.
### Electric Door
![Electric Door](images/doodads/electric-door.gif)
The sci-fi **Electric Door** can only be opened when it receives a "power" signal
from a linked button or switch. See [Linked Doodads](custom-levels/index.md#link-tool).
When the door receives a "power: on" signal it will open and allow passage to
the player or other mobile doodads. When it receives a "power: off" signal it
will close.
### Electric Trapdoor
![Electric Trapdoor](images/doodads/electric-trapdoor.gif)
The **Electric Trapdoor** requires a power source to open it.
If it receives a power signal from a linked Button or Switch, it will open.
When it loses power, it will close. Switches will always toggle its state
regardless of "power" status.
### Crumbly Floor ### Crumbly Floor
![Crumbly Floor](images/doodads/crumbly-floor.gif) ![Crumbly Floor](images/doodads/crumbly-floor.gif)
@ -266,17 +368,6 @@ same way):
* Side-profile switches to attach to the side of a wall (left and right). * Side-profile switches to attach to the side of a wall (left and right).
* Side-profile floor switch. * Side-profile floor switch.
### Electric Door
![Electric Door](images/doodads/electric-door.gif)
The sci-fi **Electric Door** can only be opened when it receives a "power" signal
from a linked button or switch. See [Linked Doodads](custom-levels/index.md#link-tool).
When the door receives a "power: on" signal it will open and allow passage to
the player or other mobile doodads. When it receives a "power: off" signal it
will close.
--- ---
## Boolean State Doodads ## Boolean State Doodads

16
docs/hacking.md

@ -178,6 +178,22 @@ open the developer console and type:
Removes all keys and items from the player's inventory. Removes all keys and items from the player's inventory.
* `fly like a bird`
Play as the Bird by default on levels that don't specify a character.
* `the cell`
Play as the Blue Azulian by default.
* `play as thief`
Play as the Thief by default.
* `pinocchio`
Play as the Boy (default) as the player character.
## JavaScript Shell ## JavaScript Shell
The developer console also features a JavaScript shell, which exposes The developer console also features a JavaScript shell, which exposes

BIN
docs/images/doodad-editor.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/images/doodad-properties.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
docs/images/doodad-tags.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/images/doodads.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 75 KiB

BIN
docs/images/doodads/anvil.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 B

BIN
docs/images/doodads/checkpoint-flag.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
docs/images/doodads/electric-trapdoor.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/images/doodads/thief.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
docs/images/generic-script.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/images/main-menu.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 110 KiB

2
docs/index.md

@ -7,7 +7,7 @@ maps on paper. You can draw a level for a 2D platformer game, drag-and-drop
"doodads" such as buttons and doors into your level, play it and share your "doodads" such as buttons and doors into your level, play it and share your
levels with others. levels with others.
**Last Updated:** July 19, 2021 for Sketchy Maze v0.7.2.
**Last Updated:** Sept. 3, 2021 for Sketchy Maze v0.8.0.
## Table of Contents ## Table of Contents

31
docs/linked-doodads.md

@ -20,6 +20,28 @@ Currently, the only way to _unlink_ two doodads is to delete one of them. With t
This section describes how the built-in doodads interact with one another when they're linked, and some example use cases. Custom doodads made by users should follow similar patterns; check the [PubSub event types](custom-doodads/scripts.md#official-standard-pub-sub-messages) used by built-in doodads, or invent your own custom event types! This section describes how the built-in doodads interact with one another when they're linked, and some example use cases. Custom doodads made by users should follow similar patterns; check the [PubSub event types](custom-doodads/scripts.md#official-standard-pub-sub-messages) used by built-in doodads, or invent your own custom event types!
### Start Flag
Link it with **any one doodad** and the that doodad will be the player
character for this level.
It is considered an error to link more than one doodad to the Start Flag.
It is undefined behavior which doodad "wins" in that case.
Upon level start, all actors linked to the Start Flag are destroyed.
### Anvil
If the Anvil receives **power** from any linked Button or Switch, it will teleport
back to its original starting location on the level. With this, players can make
a "Reset Button" for puzzle levels.
### Box
If the Box receives **power** from any linked Button or Switch, it will teleport
back to its original starting location on the level. With this, players can make
a "Reset Button" for puzzle levels.
### Buttons ### Buttons
Quick reference: Quick reference:
@ -81,6 +103,15 @@ The technicals:
* If the sender is saying **power** (false), the door will close. * If the sender is saying **power** (false), the door will close.
* If the sender is a Switch, this message is ignored in favor of the toggle behavior. * If the sender is a Switch, this message is ignored in favor of the toggle behavior.
### Electric Trapdoor
The Electric Trapdoor is basically a horizontal version of the
[Electric Door](#electric-door).
* Opens when it receives power from a Button, closes when power is removed.
* Always toggles state when powered from a Switch regardless of the Switch's
actual power status.
### Warp Doors ### Warp Doors
Warp Doors let the player fast travel across the map by sending them to a linked Warp Door. Warp Doors let the player fast travel across the map by sending them to a linked Warp Door.

Loading…
Cancel
Save