@ -0,0 +1 @@ |
|||||
|
*.doodad |
@ -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/) |
@ -0,0 +1,5 @@ |
|||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
./build.sh |
@ -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. |
@ -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 |
@ -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); |
||||
|
} |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,5 @@ |
|||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
./build.sh |
@ -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. |
@ -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 |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 6.8 KiB |
After Width: | Height: | Size: 6.1 KiB |
@ -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; |
||||
|
}); |
||||
|
}); |
||||
|
}); |
||||
|
} |