commit d3b15526111748b022e9177b3353529acf23efa4 Author: Noah Petherbridge Date: Sun Aug 15 21:56:55 2021 -0700 Upload some example doodads diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8ef7462 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.doodad \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7e38d10 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# Example Doodads + +This repository includes some example doodads for Sketchy Maze. +You can learn from their scripts or use them as a base for your +own custom doodads. + +All of these doodads are built from PNG images using the +`doodad` program that comes with the game. Check your guidebook +for information where you might find this program. The doodad +files are constructed by the `doodad` tool so it should be +somewhere on your `$PATH`. See the `build.sh` script in each +example for the doodad commands used. + +* [**Playable Character**](character/): making your own character + with animations that follow your keypresses, like the + built-in creatures. +* [**Warp Door**](warp-door/): create your own compatible Warp + Door that you can link to the built-in doors. + +To do: + +* **State Doodads**: create your own "blue" and "orange" boolean + state doodad that follows along with the rest. + +# See Also + +* The [User Guidebook](https://www.sketchymaze.com/guidebook/) of + Sketchy Maze. +* The [Sketchy Maze website](https://www.sketchymaze.com/) diff --git a/character/Makefile b/character/Makefile new file mode 100644 index 0000000..2c685ea --- /dev/null +++ b/character/Makefile @@ -0,0 +1,5 @@ +ALL: build + +.PHONY: build +build: + ./build.sh \ No newline at end of file diff --git a/character/README.md b/character/README.md new file mode 100644 index 0000000..089590c --- /dev/null +++ b/character/README.md @@ -0,0 +1,15 @@ +# Playable Character + +![Example Character](stand-right.png) + +This is an example how to create a custom playable character for your +level. This will create a grayscale copy of the game's default player +character. + +If you Link him to a Start Flag, you will play as him when the level +starts and he faces the direction you're moving and animates and so +on. + +If dropped in your level as an enemy character, his A.I. is to move +right and left, turning around when it meets an obstacle. He is able +to pick up keys, unlock doors, and activate buttons and switches. He does not travel through Warp Doors. diff --git a/character/build.sh b/character/build.sh new file mode 100755 index 0000000..07b97fe --- /dev/null +++ b/character/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# Make it from sprites +doodad convert -t "Example Character" stand-right.png stand-left.png \ + walk-right-1.png walk-right-2.png walk-right-3.png \ + walk-left-1.png walk-left-2.png walk-left-3.png \ + example-character.doodad + +# Attach the script +doodad install-script character.js example-character.doodad + +# Put it in the Creatures category in-game. +doodad edit-doodad --tag "category=creatures" example-character.doodad \ No newline at end of file diff --git a/character/character.js b/character/character.js new file mode 100644 index 0000000..bc3228d --- /dev/null +++ b/character/character.js @@ -0,0 +1,75 @@ +// Playable Character +// +// If not controlled by the player, its AI is to move left and +// right and is able to pick up keys, press buttons and generally +// get up to mischief. +var playerSpeed = 4, + direction = "right"; + +function main() { + Self.SetMobile(true); // Needed to activate most objects + Self.SetInventory(true); // Can pick up keys and items (automatic) + Self.SetGravity(true); // Is pulled down by gravity + Self.SetHitbox(0, 0, 32, 52); + setupAnimations(); + + // Are we the player character? + if (Self.IsPlayer()) { + return playerControls(); + } + return ai() +} + +function setupAnimations() { + Self.AddAnimation("walk-left", 200, ["stand-left", "walk-left-1", "walk-left-2", "walk-left-3", "walk-left-2", "walk-left-1"]); + Self.AddAnimation("walk-right", 200, ["stand-right", "walk-right-1", "walk-right-2", "walk-right-3", "walk-right-2", "walk-right-1"]); +} + +// Player controls +function playerControls() { + Events.OnKeypress(function (ev) { + if (ev.Right) { + if (!Self.IsAnimating()) { + Self.PlayAnimation("walk-right", null); + } + } else if (ev.Left) { + if (!Self.IsAnimating()) { + Self.PlayAnimation("walk-left", null); + } + } else { + Self.StopAnimation(); + } + }) +} + +// AI controls. The AI is very simple: +// walk to the right until you hit an obstacle, +// then walk to the left until you hit an obstacle, +// and repeat. +// It will automatically pickup keys and interact with things +// as it passes because it HasInventory and IsMobile. +function ai() { + // Sample our X position every few frames and detect if we've hit a solid wall. + var sampleTick = 0; + var sampleRate = 5; + var lastSampledX = 0; + + setInterval(function () { + if (sampleTick % sampleRate === 0) { + var curX = Self.Position().X; + var delta = Math.abs(curX - lastSampledX); + if (delta < 5) { + direction = direction === "right" ? "left" : "right"; + } + lastSampledX = curX; + } + sampleTick++; + + var Vx = parseFloat(playerSpeed * (direction === "left" ? -1 : 1)); + Self.SetVelocity(Vector(Vx, 0.0)); + + if (!Self.IsAnimating()) { + Self.PlayAnimation("walk-" + direction, null); + } + }, 100); +} \ No newline at end of file diff --git a/character/stand-left.png b/character/stand-left.png new file mode 100644 index 0000000..6c0c066 Binary files /dev/null and b/character/stand-left.png differ diff --git a/character/stand-right.png b/character/stand-right.png new file mode 100644 index 0000000..bb9f8fa Binary files /dev/null and b/character/stand-right.png differ diff --git a/character/walk-left-1.png b/character/walk-left-1.png new file mode 100644 index 0000000..1db662e Binary files /dev/null and b/character/walk-left-1.png differ diff --git a/character/walk-left-2.png b/character/walk-left-2.png new file mode 100644 index 0000000..79b0c37 Binary files /dev/null and b/character/walk-left-2.png differ diff --git a/character/walk-left-3.png b/character/walk-left-3.png new file mode 100644 index 0000000..c8c88ef Binary files /dev/null and b/character/walk-left-3.png differ diff --git a/character/walk-right-1.png b/character/walk-right-1.png new file mode 100644 index 0000000..2faf867 Binary files /dev/null and b/character/walk-right-1.png differ diff --git a/character/walk-right-2.png b/character/walk-right-2.png new file mode 100644 index 0000000..813a6b2 Binary files /dev/null and b/character/walk-right-2.png differ diff --git a/character/walk-right-3.png b/character/walk-right-3.png new file mode 100644 index 0000000..a3263af Binary files /dev/null and b/character/walk-right-3.png differ diff --git a/warp-door/Makefile b/warp-door/Makefile new file mode 100644 index 0000000..2c685ea --- /dev/null +++ b/warp-door/Makefile @@ -0,0 +1,5 @@ +ALL: build + +.PHONY: build +build: + ./build.sh \ No newline at end of file diff --git a/warp-door/README.md b/warp-door/README.md new file mode 100644 index 0000000..cda7026 --- /dev/null +++ b/warp-door/README.md @@ -0,0 +1,13 @@ +# Warp Door (Grey) + +![Warp Door (Grey)](door-1.png) + +This example contains sprites and JavaScript to make your own +Warp Door which is compatible with the built-in doors. This +doodad will be a greyscale version of the built-in Warp Door. + +The door can be linked to other doors and the player can open +and travel between them. + +**Note:** the title of your doodad must contain the text +"Warp Door" for other doors to recognize your door. \ No newline at end of file diff --git a/warp-door/build.sh b/warp-door/build.sh new file mode 100755 index 0000000..3a5b898 --- /dev/null +++ b/warp-door/build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +doodad convert -t "Warp Door (Grey)" door-1.png door-2.png door-3.png door-4.png example-warp-door.doodad +doodad edit-doodad -q --tag color=none \ + --tag category=doors \ + example-warp-door.doodad +doodad install-script warp-door.js example-warp-door.doodad \ No newline at end of file diff --git a/warp-door/door-1.png b/warp-door/door-1.png new file mode 100644 index 0000000..45177ec Binary files /dev/null and b/warp-door/door-1.png differ diff --git a/warp-door/door-2.png b/warp-door/door-2.png new file mode 100644 index 0000000..b4aee5b Binary files /dev/null and b/warp-door/door-2.png differ diff --git a/warp-door/door-3.png b/warp-door/door-3.png new file mode 100644 index 0000000..75206f8 Binary files /dev/null and b/warp-door/door-3.png differ diff --git a/warp-door/door-4.png b/warp-door/door-4.png new file mode 100644 index 0000000..ee1319d Binary files /dev/null and b/warp-door/door-4.png differ diff --git a/warp-door/warp-door.js b/warp-door/warp-door.js new file mode 100644 index 0000000..a354e77 --- /dev/null +++ b/warp-door/warp-door.js @@ -0,0 +1,79 @@ +// Warp Doors +function main() { + Self.SetHitbox(0, 0, 34, 76); + + var animating = false; + var collide = false; + + // Declare animations and sprite names. + var animSpeed = 100; + var spriteDefault = "door-1"; + Self.AddAnimation("open", animSpeed, ["door-2", "door-3", "door-4"]); + Self.AddAnimation("close", animSpeed, ["door-4", "door-3", "door-2", "door-1"]); + + // Find our linked Warp Door. + var links = Self.GetLinks() + var linkedDoor = null; + for (var i = 0; i < links.length; i++) { + if (links[i].Title.indexOf("Warp Door") > -1) { + linkedDoor = links[i]; + } + } + + // The player Uses the door. + var flashedCooldown = false; // "Locked Door" flashed message. + Events.OnUse(function (e) { + if (animating) { + return; + } + + // Doors without linked exits are not usable. + if (linkedDoor === null) { + if (!flashedCooldown) { + Flash("This door is locked."); + flashedCooldown = true; + setTimeout(function () { + flashedCooldown = false; + }, 1000); + } + return; + } + + // Only players can use doors for now. + if (e.Actor.IsPlayer()) { + + // Freeze the player. + e.Actor.Freeze() + + // Play the open and close animation. + animating = true; + Self.PlayAnimation("open", function () { + e.Actor.Hide() + Self.PlayAnimation("close", function () { + Self.ShowLayerNamed(spriteDefault); + animating = false; + + // Teleport the player to the linked door. Inform the target + // door of the arrival of the player so it doesn't trigger + // to send the player back here again on a loop. + if (linkedDoor !== null) { + Message.Publish("warp-door:incoming", e.Actor); + e.Actor.MoveTo(linkedDoor.Position()); + } + }); + }); + } + }); + + // Respond to incoming warp events. + Message.Subscribe("warp-door:incoming", function (player) { + animating = true; + player.Unfreeze(); + Self.PlayAnimation("open", function () { + player.Show(); + Self.PlayAnimation("close", function () { + animating = false; + }); + }); + }); +}