commit 5d6e118bb06e7cc6254ccddc29348a86f979f33d Author: Noah Petherbridge Date: Fri Nov 20 19:09:16 2020 -0800 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45ddf0a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +site/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9bf1800 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +SHELL := /bin/bash + +ALL: build + +# `make serve` to serve the mkdocs site on localhost. +.PHONY: serve +serve: + mkdocs serve + +# `make build` to build the static documentation site. +.PHONY: build +build: + mkdocs build + +# `make clean` cleans everything up. +.PHONY: clean +clean: + rm -rf site diff --git a/README.md b/README.md new file mode 100644 index 0000000..43976d2 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Guidebook + +This is `mkdocs` sources for the user guidebook. + +## Setup + +Install mkdocs, i.e. `dnf install mkdocs` on Fedora and use the Makefile: + +* `make build` renders the website +* `make serve` runs the mkdocs development server +* `make clean` cleans up the rendered website diff --git a/docs/about.md b/docs/about.md new file mode 100644 index 0000000..e501178 --- /dev/null +++ b/docs/about.md @@ -0,0 +1,3 @@ +# About Project: Doodle + +Lorem ipsum. diff --git a/docs/custom-doodads/edit-external.md b/docs/custom-doodads/edit-external.md new file mode 100644 index 0000000..3e253ff --- /dev/null +++ b/docs/custom-doodads/edit-external.md @@ -0,0 +1,20 @@ +# Drawing Doodads in an External Program + +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 +PNG images. + +Most of the built-in doodads that ship with the game were created in this way. + +## Create a Doodad from Images + +Save each frame of your doodad as a separate PNG image and then use the `doodad` +command-line tool to convert them to a `.doodad` file. + +```bash +# Usage: +doodad convert [options] + +# Example: +doodad convert door-closed.png door-open.png door.doodad +``` diff --git a/docs/custom-doodads/edit-in-game.md b/docs/custom-doodads/edit-in-game.md new file mode 100644 index 0000000..f26901e --- /dev/null +++ b/docs/custom-doodads/edit-in-game.md @@ -0,0 +1,27 @@ +# Drawing a Doodad In-Game + +Project: Doodle has some **limited** support to draw your doodad sprites +in-game. Currently you can only draw one frame (image) for the doodad +and save it to disk. + +To start a new doodad, open the game and enter the level editor. + +Select the "New Doodad" button at the top of the screen to start drawing a +new doodad. Choose the size (square) of its sprite when prompted. + +Doodads saved in-game go in your user config directory for the game. On Linux, +this is at ~/.config/doodle. + +If you want to create a doodad with multiple frames (to animate it or have +varying states that change the doodad's appearance in the level), the +`doodad` tool is recommended. See +[drawing images in an external program](edit-external.md). + +## Future Planned Features + +Creating doodads in-game is intended to be a fully supported feature. The +following features are planned to be supported: + +* Support editing multiple frames instead of only the first frame. +* Implement some features only available on the `doodad` tool using in-game + UI, such as attaching JavaScripts to the doodad. diff --git a/docs/custom-doodads/index.md b/docs/custom-doodads/index.md new file mode 100644 index 0000000..67fa6fc --- /dev/null +++ b/docs/custom-doodads/index.md @@ -0,0 +1,43 @@ +# Creating Custom Doodads + +Project: Doodle is designed to be modder friendly and provides tools to help +you create your own custom doodads to use in your levels. + +You can draw the sprites for the doodad either in-game or using an external +image editor. Then, you can program their logic using JavaScript to make them +"do" stuff in-game and interact with the player and other doodads. + +* Drawing your Doodad's Sprites + * [In-Game](edit-in-game.md) + * [In an External Program](edit-external.md) +* Program its Behavior + * [JavaScript](scripts.md) + +## doodad (Command Line Tool) + +Your copy of the game should have shipped with a `doodad` command-line tool +bundled with it. On Windows it's called `doodad.exe` and should be in the same +folder as the game executable. On Mac OS, it is inside the .app bundle. + +The `doodad` tool provides a command-line interface to create and inspect +doodad and level files from the game. You'll need to use this tool, at the very +least, to attach a JavaScript to your doodad to make it "do" stuff in-game. + +You can create a doodad from PNG images on disk, attach or view the JavaScript +source on them, and view/edit metadata. + +```bash +# (the $ represents the shell prompt in a command-line terminal) + +# See metadata about a doodad file. +$ doodad show /path/to/custom.doodad + +# Create a new doodad based on PNG images on disk. +$ doodad convert frame0.png frame1.png frame2.png output.doodad + +# Add and view a custom script attached to the doodad. +$ doodad install-script index.js custom.doodad +$ doodad show --script custom.doodad +``` + +More info on the [`doodad` tool](../doodad-tool.md) here. diff --git a/docs/custom-doodads/scripts.md b/docs/custom-doodads/scripts.md new file mode 100644 index 0000000..7f9a2d8 --- /dev/null +++ b/docs/custom-doodads/scripts.md @@ -0,0 +1,564 @@ +# Doodad Scripts + +Doodads are programmed using JavaScript which gives them their behavior +and ability to interact with the player and other doodads. + +Doodad scripts are run during "Play Mode" when a level _containing_ the doodad +is being played. You can install a JavaScript (.js) file into a doodad using +the command-line `doodad` program. + +An example Doodad script looks like the following: + +```javascript +// main() is called on level initialization for each +// instance ("actor") of the doodad. +function main() { + // Logs go to the game's log file (standard output on Linux/Mac). + console.log("%s initialized!", Self.Title); + + // If our doodad has 'solid' parts that should prohibit movement, + // define the hitbox here. Coordinates are relative so 0,0 is the + // top-left pixel of the doodad's sprite. + Self.SetHitbox(0, 0, 64, 12); + + // Handle a collision when another doodad (or player) has entered + // the space of our doodad. + Events.OnCollide(function(e) { + // The `e` object holds information about the event. + console.log("Actor %s has entered our hitbox!", e.Actor.ID()); + + // InHitbox is `true` if we defined a hitbox for ourselves, and + // the colliding actor is inside of the hitbox we defined. + if (e.InHitbox) { + // To prohibit movement, return false from the OnCollide handler. + // If you don't return false, the actor is allowed to keep on + // moving through. + return false; + } + + // When movement is finalized, OnCollide is called one final time + // with e.Settled=true; it is only then that a doodad should run + // event handlers for a logical collide event. + if (e.Settled) { + // do something + Message.Publish("power", true); + } + }); + + // OnLeave is called when an actor, who was previously colliding with + // us, is no longer doing so. + Events.OnLeave(function(e) { + console.log("Actor %s has stopped colliding!", e.Actor.ID()); + }) +} +``` + +# Installing a Doodad Script + +Use the command-line `doodad` tool to attach a script to your doodad file: + +```bash +# Attach the JavaScript at "script.js" to the doodad file "filename.doodad" +doodad install-script script.js filename.doodad + +# To view the script currently attached to a doodad +# (prints the script to your terminal) +doodad show --script filename.doodad +``` + +# Testing Your Script + +The best way to test your doodad script is to use it in a level! + +Run the game in a console to watch the log output, and you can use functions +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 +when the level instance of your doodad is initialized. + +# JavaScript API + +The following global variables are available to all Doodad scripts. + +## Self + +Self holds data about the current doodad instance loaded inside of a level. + +**String attributes:** + +* Self.Title: the doodad title. +* Self.Filename: the doodad filename (useful for inventory items). + +Methods are below. + +### Self.ID() string + +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. + +### Self.GetTag(string name) string + +Return a "tag" that was saved with the doodad's file data. + +Tags are an arbitrary key/value data store attached to the doodad file. +You can use the `doodad.exe` tool shipped with the game to view and manage tags +on your own custom doodads: + +```bash +# Command-line doodad tool usage: + +# Show information about a doodad, look for the "Tags:" section. +doodad show filename.doodad + +# Set a tag. "-t" for short. +doodad edit-doodad --tag 'color=blue' filename.doodad + +# Set the tag to empty to remove it. +doodad edit-doodad -t 'color=' filename.doodad +``` + +This is useful for a set of multiple doodads to share the same script but +have different behavior depending on how each is tagged. + +### Self.Position() Point + +Returns the doodad's current position in the level. + +Point is an object with .X and .Y integer values. + +```javascript +var p = Self.Position() +console.log("I am at %d,%d", p.X, p.Y) +``` + +### Self.SetHitbox(x, y, w, h int) + +Configure the "solid hitbox" of this doodad. + +The X and Y coordinates are relative to the doodad's sprite: (0,0) is the top +left pixel of the doodad. The W and H are the width and height of the hitbox +starting at those coordinates. + +When another doodad enters the area of your doodad's sprite (for example, the +player character has entered the square shape of your doodad sprite) your script +begins to receive OnCollide events from the approaching actor. + +The OnCollide event tells you if the invading doodad is inside your custom +hitbox which you define here (`InHitbox`) making it easy to make choices based +on that status. + +Here's an example script for a hypothetical "locked door" doodad that acts +solid but only on a thin rectangle in the middle of its sprite: + +```javascript +// Example script for a "locked door" +function main() { + // Suppose the doodad's sprite size is 64x64 pixels square. + // The door is in side profile where the door itself ranges from pixels + // (20, 0) to (24, 64) + Self.SetHitbox(20, 0, 24, 64) + + // OnCollide handlers. + Events.OnCollide(function(e) { + // The convenient e.InHitbox tells you if the colliding actor is + // inside the hitbox we defined. + if (e.InHitbox) { + // Return false to protest the collision (act solid). + return false; + } + }); +} +``` + +### Self.SetVelocity(Velocity) + +Set the doodad's velocity. Velocity is a type that can be created with the +Velocity() constructor, which takes an X and Y value: + +```javascript +Self.SetVelocity( Velocity(3.2, 7.0) ); +``` + +A positive X velocity propels the doodad to the right. A positive Y velocity +propels the doodad downward. + +### Self.SetMobile(bool) + +Call `SetMobile(true)` if the doodad will move on its own. + +This is for mobile doodads such as the player character and enemy mobs. +Stationary doodads like buttons, doors, and trapdoors do not mark themselves +as mobile. + +Mobile doodads incur extra work for the game doing collision checking so only +set this to `true` if your doodad will move (i.e. changes its Velocity or +Position). + +```javascript +Self.SetMobile(true); +``` + +### Self.SetGravity(bool) + +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 +want to be affected by gravity should opt in to this. + +```javascript +Self.SetGravity(true); +``` + +### Self.ShowLayer(index int) + +Switch the active layer of the doodad to the layer at this index. + +A doodad file can contain multiple layers, or images. The first and default +layer is at index zero, the second layer at index 1, and so on. + +```javascript +Self.ShowLayer(0); // 0 is the first and default layer +Self.ShowLayer(1); // show the second layer instead +``` + +### Self.ShowLayerNamed(name string) + +Switch the active layer by name instead of index. + +Each layer has an arbitrary name that it can be addressed by instead of needing +to keep track of the layer index. + +Doodads created by the command-line `doodad` tool will have their layers named +automatically by their file name. The layer **indexes** will retain the same +order of file names passed in, with 0 being the first file: + +```bash +# Doodad tool-created doodads have layers named after their file names. +# example "open-1.png" will be named "open-1" +doodad convert door.png open-1.png open-2.png open-3.png my-door.doodad +``` + +### Self.AddAnimation(name string, interval int, layers list) + +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 +names or indexes to be used for the animation. + +Doodads can animate by having multiple frames (images) in the same file. +Layers are ordered (layer 0 is the first, then increments from there) and +each has a name. This function can take either identifier to specify +which layers are part of the animation. + +```javascript +// Animation named "open" using named layers, 100ms delay between frames. +Self.AddAnimation("open", 100, ["open-1", "open-2", "open-3"]); + +// Animation named "close" using layers by index. +Self.AddAnimation("close", 100, [3, 2, 1]); +``` + +### Self.PlayAnimation(name string, callback func()) + +This starts playing the named animation. The callback function will be called +when the animation has completed. + +```javascript +Self.PlayAnimation("open", function() { + console.log("I've finished opening!"); + + // The callback is optional; use null if you don't need it. + Self.PlayAnimation("close", null); +}); +``` + +### Self.IsAnimating() bool + +Returns true if an animation is currently being played. + +### Self.StopAnimation() + +Stops any currently playing animation. + + +* Self.Doodad(): a pointer to the doodad's file data. + * Self.Doodad().Title: get the title of the doodad file. + * Self.Doodad().Author: the name of the author who wrote the doodad. + * Self.Doodad().Script: the doodad's JavaScript source code. Note that + modifying this won't have any effect in-game, as the script had already + been loaded into the interpreter. + * Self.Doodad().GameVersion: the version of {{ app_name }} that was used + when the doodad was created. + +### Self.Destroy() + +This destroys the current instance of the doodad as it appears in a level. + +For example, a Key destroys itself when it's picked up so that it disappears +from the level and can't be picked up again. Call this function when the +doodad instance should be destroyed and removed from the active level. + +----- + +## Console Logging + +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 +game's logs are. + +```javascript +console.log("Hello world!"); +console.log("Interpolate strings '%s' and numbers '%d'", "string", 123); +console.debug("Debug messages shown when the game is in debug mode"); +console.warn("Warning-level messages"); +console.error("Error-level messages"); +``` + +----- + +## Timers and Intervals + +Like in a web browser, functions such as setTimeout and setInterval are +supported in doodad scripts. + +### setTimeout(function, milliseconds int) int + +setTimeout calls your function after the specified number of milliseconds. + +1000ms are in one second. + +Returns an integer "timeout ID" that you'll need if you want to cancel the +timeout with clearTimeout. + +### setInterval(function, milliseconds int) int + +setInterval calls your function repeatedly after every specified number of +milliseconds. + +Returns an integer "interval ID" that you'll need if you want to cancel the +interval with clearInterval. + +### clearTimeout(id int) + +Cancels the timeout with the given ID. + +### clearInterval(id int) + +Cancels the interval with the given ID. + +----- + +## Type Constructors + +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: + +### RGBA(red, green, blue, alpha uint8) + +Creates a Color type from red, green, blue and alpha values (integers between +0 and 255). + +### Point(x, y int) + +Creates a Point object with X and Y coordinates. + +### Vector(x, y float64) + +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 + +Doodad scripts can respond to certain events using functions on the global +`Events` variable. + +### Events.OnCollide( func(event) ) + +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 +attributes: + +* Actor: the doodad which is colliding with your doodad. +* Overlap (Rect): a rectangle of where the two doodads' boxes are overlapping, + relative to your doodad sprite's box. That is, if the Actor was moving in from + the left side of your doodad, the X value would be zero and W would be the + number of pixels of overlap. +* InHitbox (bool): true if the colliding actor's hitbox is intersecting with + the hitbox you defined with SetHitbox(). +* Settled (bool): This is `false` when the game is trying to move the colliding + doodad and is sussing out whether or not your doodad will act solid and + protest its movement. When the game has settled the location of the colliding + doodad it will call OnCollide a final time with Settled=true. If your doodad + has special behavior when touched (i.e. a button that presses in), you should + wait until Settled=true before running your handler for that. + +### Events.OnLeave( func(event) ) + +Called when an actor that _was_ colliding with your doodad is no longer +colliding (or has left your doodad's sprite box). + +### Events.RunKeypress( func(event) ) + +Handle a keypress. `event` is an `event.State` from the render engine. + +TODO: document that. + +----- + +## Pub/Sub Communication + +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 +'broadcast' frequency. + +> **Linking** is when the level author connected two doodads together with +> the Link Tool. The two doodads' scripts can communicate with each other +> in-game over that link. + +For example, if the level author links a Button to an Electric Door, the button +can send a "power" event to the door so that it can open when a player touches +the button. + +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 +receive that data. + +### Official, Standard Pub/Sub Messages + +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. + +If extending this list with your own custom events, be careful to choose a +unique namespace to prevent collision with other users' custom doodads and +their custom event names. + +| Name | Data Type | Description | +|------|-----------|--------------| +| 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. | + +### Message.Publish(name string, data...) + +Publish a named message to all of your **linked** doodads. + +`data` is a list of arbitrary arguments to send with the message. + +```javascript +// Example button doodad that emits a "power" (bool) state to linked doodads +// that subscribe to this event. +function main() { + // When an actor collides with the button, emit a powered state. + Events.OnCollide(function(e) { + Message.Publish("power", true); + }); + + // When the actor leaves the button, turn off the power. + Events.OnLeave(function(e) { + Message.Publish("power", false); + }) +} +``` + +### Message.Subscribe(name string, function) + +Subscribe to a named message from any **linked** doodads. + +The function receives the data that was passed with the message. Its data type +is arbitrary and will depend on the type of message. + +```javascript +// Example electronic device doodad that responds to power from linked buttons. +function main() { + // Boolean to store if our electric device has juice. + var powered = false; + + // Do something while powered + setInterval(function() { + if (powered) { + console.log("Brmm...") + } + }, 1000); + + // Subscribe to the `power` event by a linked button or other power source. + Message.Subscribe("power", function(boolValue) { + console.log("Powered %s!", boolValue === true ? "on" : "off"); + powered = boolValue; + }); +} +``` + +### Message.Broadcast(name string, data...) + +This publishes a named message to **every** doodad in the level, whether it +was linked to the broadcaster or not. + +For example the "ON/OFF" button globally toggles a boolean state in every +state block that subscribes to the `broadcast:state-change` event. + +If you were to broadcast an event like `power` it would activate every single +power-sensitive doodad on the level. + +```javascript +// Example two-state block that globally receives the state-change broadcast. +function main() { + var myState = false; + Message.Subscribe("broadcast:state-change", function(boolValue) { + // Most two-state blocks just flip their own state, ignoring the + // boolValue passed with this message. + myState = !myState; + }); +} + +// Example ON/OFF block that emits the state-change broadcast. It also +// subscribes to the event to keep its own state in sync with all the other +// ON/OFF blocks on the level when they get hit. +function main() { + var myState = false; + + // Listen for other ON/OFF button activations to keep our state in + // sync with theirs. + Message.Subscribe("broadcast:state-change", function(boolValue) { + myState = boolValue; + }); + + // When collided with, broadcast the state toggle to all state blocks. + Events.OnCollide(function(e) { + if (e.Settled) { + myState = !!myState; + Message.Broadcast("broadcast:state-change", myState); + } + }) +} +``` diff --git a/docs/custom-levels/index.md b/docs/custom-levels/index.md new file mode 100644 index 0000000..cd9369e --- /dev/null +++ b/docs/custom-levels/index.md @@ -0,0 +1,99 @@ +# Creating Custom Levels + +One of the core gameplay features is its Level Editor which lets you draw your +own custom maps to play and share with others. + +From the game's Main Menu, click on the "Create a Level" button to open the +level editor. To edit an existing custom level, click on the "Edit a Level" +button instead. + +## Level Properties + +When creating a new level, you first choose some settings for it. These are +described below: + +### Page Type + +This setting controls the size and boundaries of your level, and control the +appearance of the notebook paper background of your level. + +* **Bounded** is the default. The camera won't scroll past the top-left corner + of the page (0,0), and the level size is capped to 2550x3300, or the + approximate size of an 11:9 standard sheet of notebook paper in pixels. +* **No Negative Space** is like Bounded, but the width and height of the level + have no boundary. Levels can grow "infinitely" to the right and downward + but no negative coordinates past the top or left edge. +* **Unbounded** allows for "infinite" sized maps that give unlimited room to + grow your level. The wallpaper on this level type only uses the "tiling" + pattern, so notebook-themed levels won't show the top/left decorations. + +### Wallpaper + +The wallpaper affects the "theme" of your level. Project: Doodle is themed around +hand-drawn mazes on paper, so the built-in themes look like various kinds of +paper. + +* **Notebook** looks like standard ruled notebook paper. It's a white paper with + blue horizontal lines, a single red vertical line down the left, and a wide + margin on the top and left edges. +* **Legal Pad** looks like ruled yellow legal pad. It's similar to Notebook but + has yellow paper and a second vertical red line down the left. +* **Blueprint** is a dark blueprint paper background with a repeating grid pattern. + Notably, the default Color Palette for this theme is different than normal: + "solid" lines are white instead of black, to show up better against the dark + background. + +The decorations of the wallpaper vary based on the Page Type. For example, the +Notebook and Legal Pad have extra padding on the top of the page and red lines +going down just the left side, and the rest of the level uses the repeating blue +lines pattern. The page types and their effect on the wallpapers are: + +* **Bounded** and **No Negative Space** will show the decorations for the top + and left edges of the page, as these levels are bounded on their top/left + corner. +* **Unbounded** levels only use the repeating tiled pattern across the entire + level, because there is no top-left boundary to anchor those decorations to. + +## Editor Mode Interface + +![Level Editor View](../images/editor-1.png) + +Quick 5-minute tour of what you're looking at: + +* The top of the window has your **Menu Bar**: + * **New Level** opens the "Create a New Level" menu. + * **New Doodad** opens the Doodad Editor for drawing a new custom doodad. + You're prompted for the size of the doodad, which will be its width and + height boundary. For example, a size of "100" means a 100x100 pixel graphic + for your custom doodad. + * **Save** and **Save as...** let you save the current Level or Doodad you're + drawing to disk. "Save" will only ask for the filename once whereas "Save as" + asks every time. + * **Load** opens the "Edit a Level" menu to choose a Level or Doodad to edit. + * **Options** options the Level Options dialog so you can modify the page type + and wallpaper setting. +* The panel on the left side of the window is your **Tool Box**. Clicking these + buttons activates a specific drawing tool or mode: + * **Pencil Tool** lets you click, drag, and draw pixels of your selected + Palette color onto your level freehand. + * **Line Tool** lets you easily draw a straight line between two points. Click + in your level where you want the first point to be, and drag your mouse to + the second point. Release the mouse to commit the line to your drawing. + * **Rectangle Tool** lets you easily draw rectangles on your level. + * **Ellipse Tool** lets you draw circles or elliptical shapes. + * **Doodad Tool** lets you drag doodads such as buttons and doors onto your + level. See the [Doodad Tool](#doodad-tool) below. + * **Link Tool** lets you link doodads together so that they can interact off + each other. For example, a Button connected to an Electric Door will cause + the door to open and close when the button is pressed. See [Link Tool](#link-tool) + below. + * **Eraser Tool** cleans up your mistakes. Click and drag over pixels you've + drawn to delete the pixels from your level. + * **Brush Size:** the "Size:" label shows the brush size of your current drawing + tool. This translates to the line thickness, or how big your pixels are when + drawn into the level. Click the + and - buttons to increase or decrease the + brush size, and draw thicker or thinner lines. +* The panel on the right side of the window is your **Palette** of colors to + draw with. + +![Doodad Toolbar View](../images/editor-2.png) diff --git a/docs/doodad-tool.md b/docs/doodad-tool.md new file mode 100644 index 0000000..02c3ef0 --- /dev/null +++ b/docs/doodad-tool.md @@ -0,0 +1,118 @@ +# Doodad Tool + +The game ships with a command-line program called `doodad` which assists in +creating and managing custom doodads and levels. + +The `doodad` tool can show and set details on .doodad and .level files used by +the game, create new doodads from PNG images and attach custom JavaScript source +to program behavior of doodads. + +## Where to Find It + +The `doodad` tool should be in the same place as the game executable. + +On Windows, the program is called `doodad.exe` and comes in the zip file next +to the game executable, `doodle.exe`. + +On Linux, it will typically be at `/opt/project-doodle/doodad`. + +On Mac OS, it is found inside the .app bundle. + +## Usage + +Run `doodad --help` to get usage information. + +The program includes several sub-commands, such as `doodad convert`. Type a +subcommand and `--help` to get help on that command, for example: + +```bash +doodad convert --help +``` + +# Examples + +Here are some common scenarios and use cases for the doodad tool. + +## Show + +```bash +# Usage: +doodad show [doodad or level filename] +``` + +Shows metadata and details about a level or doodad file. + +Examples: + +```bash +$ doodad show button.doodad +===== Doodad: button.doodad ===== +Headers: + File version: 1 + Game version: 0.0.10-alpha + Doodad title: Button + Author: Noah + Locked: true + Hidden: false + Script size: 473 bytes + +Palette: + - Swatch name: Color<#000000+ff> + Attributes: solid + Color: #000000 + - Swatch name: Color<#666666+ff> + Attributes: none + Color: #666666 + - Swatch name: Color<#999999+ff> + Attributes: fire + Color: #999999 + +Layer 0: button1 +Chunks: + Pixels Per Chunk: 37^2 + Number Generated: 1 + Coordinate Range: (0,0) ... (36,36) + World Dimensions: 36x36 + Use -chunks or -verbose to serialize Chunks + +Layer 1: button2 +Chunks: + Pixels Per Chunk: 37^2 + Number Generated: 1 + Coordinate Range: (0,0) ... (36,36) + World Dimensions: 36x36 + Use -chunks or -verbose to serialize Chunks +``` + +## Convert + +```bash +# Usage: +doodad convert [options] +``` + +### Creating a Doodad from PNG images + +Suppose you have PNG images named "frame0.png" through "frame3.png" and want +to create a doodad from those images. This will convert them to the doodad +file "custom.doodad": + +```bash +# Convert PNG images into a doodad. +doodad convert frame0.png frame1.png frame2.png frame3.png custom.doodad + +# The same, but also attach custom tags with the doodad. +doodad convert --tag color=blue frame{0,1,2,3}.png custom.doodad +``` + +### Convert a level to a PNG image + +```bash +doodad convert my.level output.png +``` + +### Create a level from a PNG image + +```bash +doodad convert level.png output.level +``` diff --git a/docs/images/editor-1.png b/docs/images/editor-1.png new file mode 100644 index 0000000..ff354b8 Binary files /dev/null and b/docs/images/editor-1.png differ diff --git a/docs/images/editor-2.png b/docs/images/editor-2.png new file mode 100644 index 0000000..1c48074 Binary files /dev/null and b/docs/images/editor-2.png differ diff --git a/docs/images/main-menu.png b/docs/images/main-menu.png new file mode 100644 index 0000000..ddd7db1 Binary files /dev/null and b/docs/images/main-menu.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..a09f86a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,15 @@ +# Welcome to Project: Doodle + +![](images/main-menu.png) + +[Project: Doodle](about.md) is a drawing-based maze game themed around hand-drawn +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, and play it. + +## Table of Contents + +* [Creating Custom Levels](custom-levels/) +* [Creating Custom Doodads](custom-doodads/) + * [Draw Sprites In-Game](custom-doodads/edit-in-game.md) + * [Draw Sprites with an External Program](custom-doodads/edit-external.md) + * [Program Them with JavaScript](custom-doodads/scripts.md) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..ddb9696 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,9 @@ +site_name: "Project: Doodle Guidebook" +use_directory_urls: false +nav: + - Home: index.md + - About: about.md + - "Custom Doodads": custom-doodads/index.md +markdown_extensions: + - toc: + permalink: "#"