@ -0,0 +1 @@ |
|||||
|
*.doodad |
@ -0,0 +1,4 @@ |
|||||
|
# Sketchy Maze Assets |
||||
|
|
||||
|
All assets in this repository are copyright (C) 2021 Noah Petherbridge. |
||||
|
All rights reserved. |
@ -0,0 +1,17 @@ |
|||||
|
# Sketchy Maze Assets |
||||
|
|
||||
|
This repo contains the game's built-in artwork (doodads and levels). The |
||||
|
assets here are licensed separately from the game's source code. |
||||
|
|
||||
|
The contents of this repository is copyright (C) 2021 Noah Petherbridge. |
||||
|
All rights reserved. Not for redistribution outside of official builds of |
||||
|
Sketchy Maze. |
||||
|
|
||||
|
## Doodads |
||||
|
|
||||
|
The doodads are in source form (png's and scripts) and need compiling. |
||||
|
They'll write and copy their outputs to "./assets/doodads" relative to |
||||
|
the root of this git repo. |
||||
|
|
||||
|
Make sure the `doodad` program is on your $PATH and the build.sh script |
||||
|
will compile all the doodads. |
@ -0,0 +1,22 @@ |
|||||
|
SHELL = /bin/bash |
||||
|
|
||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
doodad convert -t "Blue Azulian" blu-front.png blu-back.png \
|
||||
|
blu-wr{1,2,3,4}.png blu-wl{1,2,3,4}.png azu-blu.doodad |
||||
|
doodad edit-doodad --tag "color=blue" azu-blu.doodad |
||||
|
doodad install-script azulian.js azu-blu.doodad |
||||
|
|
||||
|
doodad convert -t "Red Azulian" red-front.png red-back.png \
|
||||
|
red-wr{1,2,3,4}.png red-wl{1,2,3,4}.png azu-red.doodad |
||||
|
doodad edit-doodad --tag "color=red" azu-red.doodad |
||||
|
doodad install-script azulian.js azu-red.doodad |
||||
|
|
||||
|
# Tag the category for these doodads |
||||
|
for i in *.doodad; do\
|
||||
|
doodad edit-doodad --tag "category=creatures" $${i};\
|
||||
|
done |
||||
|
|
||||
|
cp *.doodad ../../../assets/doodads/ |
@ -0,0 +1,43 @@ |
|||||
|
// Azulian (Red)
|
||||
|
// DEPRECATED: they both share azulian.js now.
|
||||
|
|
||||
|
function main() { |
||||
|
var playerSpeed = 4; |
||||
|
var gravity = 4; |
||||
|
var Vx = Vy = 0; |
||||
|
|
||||
|
var direction = "right"; |
||||
|
|
||||
|
Self.SetHitbox(0, 0, 32, 32) |
||||
|
Self.SetMobile(true); |
||||
|
Self.SetInventory(true); |
||||
|
Self.SetGravity(true); |
||||
|
Self.AddAnimation("walk-left", 100, ["red-wl1", "red-wl2", "red-wl3", "red-wl4"]); |
||||
|
Self.AddAnimation("walk-right", 100, ["red-wr1", "red-wr2", "red-wr3", "red-wr4"]); |
||||
|
|
||||
|
// 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++; |
||||
|
|
||||
|
// TODO: Vector() requires floats, pain in the butt for JS,
|
||||
|
// the JS API should be friendlier and custom...
|
||||
|
var Vx = parseFloat(playerSpeed * (direction === "left" ? -1 : 1)); |
||||
|
Self.SetVelocity(Vector(Vx, 0.0)); |
||||
|
|
||||
|
if (!Self.IsAnimating()) { |
||||
|
Self.PlayAnimation("walk-" + direction, null); |
||||
|
} |
||||
|
}, 100); |
||||
|
} |
@ -0,0 +1,83 @@ |
|||||
|
// Azulian (Red and Blue)
|
||||
|
var playerSpeed = 12, |
||||
|
animating = false, |
||||
|
direction = "right", |
||||
|
lastDirection = "right"; |
||||
|
|
||||
|
function setupAnimations(color) { |
||||
|
var left = color === 'blue' ? 'blu-wl' : 'red-wl', |
||||
|
right = color === 'blue' ? 'blu-wr' : 'red-wr', |
||||
|
leftFrames = [left + '1', left + '2', left + '3', left + '4'], |
||||
|
rightFrames = [right + '1', right + '2', right + '3', right + '4']; |
||||
|
|
||||
|
Self.AddAnimation("walk-left", 100, leftFrames); |
||||
|
Self.AddAnimation("walk-right", 100, rightFrames); |
||||
|
} |
||||
|
|
||||
|
function main() { |
||||
|
var color = Self.GetTag("color"); |
||||
|
playerSpeed = color === 'blue' ? 2 : 4; |
||||
|
|
||||
|
Self.SetMobile(true); |
||||
|
Self.SetGravity(true); |
||||
|
Self.SetInventory(true); |
||||
|
Self.SetHitbox(0, 0, 24, 32); |
||||
|
setupAnimations(color); |
||||
|
|
||||
|
if (Self.IsPlayer()) { |
||||
|
return playerControls(); |
||||
|
} |
||||
|
|
||||
|
// A.I. pattern: walks back and forth, turning around
|
||||
|
// when it meets resistance.
|
||||
|
|
||||
|
// 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 we changed directions, stop animating now so we can
|
||||
|
// turn around quickly without moonwalking.
|
||||
|
if (direction !== lastDirection) { |
||||
|
Self.StopAnimation(); |
||||
|
} |
||||
|
|
||||
|
if (!Self.IsAnimating()) { |
||||
|
Self.PlayAnimation("walk-" + direction, null); |
||||
|
} |
||||
|
|
||||
|
lastDirection = direction; |
||||
|
}, 100); |
||||
|
} |
||||
|
|
||||
|
function playerControls() { |
||||
|
// Note: player speed is controlled by the engine.
|
||||
|
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(); |
||||
|
animating = false; |
||||
|
} |
||||
|
}) |
||||
|
} |
After Width: | Height: | Size: 864 B |
After Width: | Height: | Size: 829 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 910 B |
After Width: | Height: | Size: 853 B |
After Width: | Height: | Size: 833 B |
After Width: | Height: | Size: 820 B |
After Width: | Height: | Size: 893 B |
After Width: | Height: | Size: 816 B |
After Width: | Height: | Size: 844 B |
After Width: | Height: | Size: 826 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 803 B |
After Width: | Height: | Size: 816 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 819 B |
After Width: | Height: | Size: 829 B |
After Width: | Height: | Size: 834 B |
After Width: | Height: | Size: 815 B |
After Width: | Height: | Size: 838 B |
@ -0,0 +1,14 @@ |
|||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
doodad convert -t "Bird (red)" left-1.png left-2.png right-1.png right-2.png \
|
||||
|
dive-left.png dive-right.png bird-red.doodad |
||||
|
doodad install-script bird.js bird-red.doodad |
||||
|
|
||||
|
# Tag the category for these doodads |
||||
|
for i in *.doodad; do\
|
||||
|
doodad edit-doodad --tag "category=creatures" $${i};\
|
||||
|
done |
||||
|
|
||||
|
cp *.doodad ../../../assets/doodads/ |
@ -0,0 +1,99 @@ |
|||||
|
// Bird
|
||||
|
|
||||
|
function main() { |
||||
|
var speed = 4; |
||||
|
var Vx = Vy = 0; |
||||
|
var altitude = Self.Position().Y; // original height in the level
|
||||
|
|
||||
|
var direction = "left", |
||||
|
lastDirection = "left"; |
||||
|
var states = { |
||||
|
flying: 0, |
||||
|
diving: 1, |
||||
|
}; |
||||
|
var state = states.flying; |
||||
|
|
||||
|
Self.SetMobile(true); |
||||
|
Self.SetGravity(false); |
||||
|
Self.SetHitbox(0, 0, 46, 32); |
||||
|
Self.AddAnimation("fly-left", 100, ["left-1", "left-2"]); |
||||
|
Self.AddAnimation("fly-right", 100, ["right-1", "right-2"]); |
||||
|
|
||||
|
// Player Character controls?
|
||||
|
if (Self.IsPlayer()) { |
||||
|
return player(); |
||||
|
} |
||||
|
|
||||
|
Events.OnCollide(function (e) { |
||||
|
if (e.Actor.IsMobile() && e.InHitbox) { |
||||
|
return false; |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
// Sample our X position every few frames and detect if we've hit a solid wall.
|
||||
|
var sampleTick = 0; |
||||
|
var sampleRate = 2; |
||||
|
var lastSampledX = 0; |
||||
|
var lastSampledY = 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++; |
||||
|
|
||||
|
// TODO: Vector() requires floats, pain in the butt for JS,
|
||||
|
// the JS API should be friendlier and custom...
|
||||
|
var Vx = parseFloat(speed * (direction === "left" ? -1 : 1)); |
||||
|
Self.SetVelocity(Vector(Vx, 0.0)); |
||||
|
|
||||
|
// If we changed directions, stop animating now so we can
|
||||
|
// turn around quickly without moonwalking.
|
||||
|
if (direction !== lastDirection) { |
||||
|
Self.StopAnimation(); |
||||
|
} |
||||
|
|
||||
|
if (!Self.IsAnimating()) { |
||||
|
Self.PlayAnimation("fly-" + direction, null); |
||||
|
} |
||||
|
|
||||
|
lastDirection = direction; |
||||
|
}, 100); |
||||
|
} |
||||
|
|
||||
|
// If under control of the player character.
|
||||
|
function player() { |
||||
|
Self.SetInventory(true); |
||||
|
Events.OnKeypress(function (ev) { |
||||
|
Vx = 0; |
||||
|
Vy = 0; |
||||
|
|
||||
|
if (ev.Up) { |
||||
|
Vy = -playerSpeed; |
||||
|
} else if (ev.Down) { |
||||
|
Vy = playerSpeed; |
||||
|
} |
||||
|
|
||||
|
if (ev.Right) { |
||||
|
if (!Self.IsAnimating()) { |
||||
|
Self.PlayAnimation("fly-right", null); |
||||
|
} |
||||
|
Vx = playerSpeed; |
||||
|
} else if (ev.Left) { |
||||
|
if (!Self.IsAnimating()) { |
||||
|
Self.PlayAnimation("fly-left", null); |
||||
|
} |
||||
|
Vx = -playerSpeed; |
||||
|
} else { |
||||
|
Self.StopAnimation(); |
||||
|
animating = false; |
||||
|
} |
||||
|
|
||||
|
Self.SetVelocity(Vector(Vx, Vy)); |
||||
|
}) |
||||
|
} |
After Width: | Height: | Size: 959 B |
After Width: | Height: | Size: 989 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1022 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,13 @@ |
|||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
doodad convert -t "Box" box-1.png box-2.png \
|
||||
|
box-3.png box-4.png box.doodad |
||||
|
doodad install-script box.js box.doodad |
||||
|
|
||||
|
for i in *.doodad; do \
|
||||
|
doodad edit-doodad --tag "category=objects" $${i}; \
|
||||
|
done |
||||
|
|
||||
|
cp *.doodad ../../../assets/doodads/ |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,64 @@ |
|||||
|
// Pushable Box.
|
||||
|
var speed = 4; |
||||
|
var size = 75; |
||||
|
|
||||
|
function main() { |
||||
|
Self.SetMobile(true); |
||||
|
Self.SetGravity(true); |
||||
|
Self.SetHitbox(0, 0, size, size); |
||||
|
|
||||
|
Events.OnCollide(function (e) { |
||||
|
// Ignore events from neighboring Boxes.
|
||||
|
if (e.Actor.Actor.Filename === "box.doodad") { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (e.Actor.IsMobile() && e.InHitbox) { |
||||
|
var overlap = e.Overlap; |
||||
|
|
||||
|
if (overlap.Y === 0 && !(overlap.X === 0 && overlap.W < 5) && !(overlap.X === size)) { |
||||
|
// Standing on top, ignore.
|
||||
|
return false; |
||||
|
} else if (overlap.Y === size) { |
||||
|
// From the bottom, boop it up.
|
||||
|
Self.SetVelocity(Vector(0, -speed * 2)) |
||||
|
} |
||||
|
|
||||
|
// If touching from the sides, slide away.
|
||||
|
if (overlap.X === 0) { |
||||
|
Self.SetVelocity(Vector(speed, 0)) |
||||
|
} else if (overlap.X === size) { |
||||
|
Self.SetVelocity(Vector(-speed, 0)) |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
}); |
||||
|
Events.OnLeave(function (e) { |
||||
|
Self.SetVelocity(Vector(0, 0)); |
||||
|
}); |
||||
|
|
||||
|
// When we receive power, we reset to our original position.
|
||||
|
var origPoint = Self.Position(); |
||||
|
Message.Subscribe("power", function (powered) { |
||||
|
Self.MoveTo(origPoint); |
||||
|
Self.SetVelocity(Vector(0, 0)); |
||||
|
}); |
||||
|
|
||||
|
// Start animation on a loop.
|
||||
|
animate(); |
||||
|
} |
||||
|
|
||||
|
function animate() { |
||||
|
Self.AddAnimation("animate", 100, [0, 1, 2, 3, 2, 1]); |
||||
|
|
||||
|
var running = false; |
||||
|
setInterval(function () { |
||||
|
if (!running) { |
||||
|
running = true; |
||||
|
Self.PlayAnimation("animate", function () { |
||||
|
running = false; |
||||
|
}) |
||||
|
} |
||||
|
}, 100); |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
doodad convert -t "Boy" 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 \
|
||||
|
boy.doodad |
||||
|
doodad install-script boy.js boy.doodad |
||||
|
|
||||
|
doodad edit-doodad --tag "category=creatures" boy.doodad |
||||
|
|
||||
|
cp *.doodad ../../../assets/doodads/ |
@ -0,0 +1,38 @@ |
|||||
|
function main() { |
||||
|
var playerSpeed = 12; |
||||
|
var gravity = 4; |
||||
|
var Vx = Vy = 0; |
||||
|
|
||||
|
var animating = false; |
||||
|
var animStart = animEnd = 0; |
||||
|
var animFrame = animStart; |
||||
|
|
||||
|
Self.SetMobile(true); |
||||
|
Self.SetInventory(true); |
||||
|
Self.SetGravity(true); |
||||
|
Self.SetHitbox(0, 0, 32, 52); |
||||
|
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"]); |
||||
|
|
||||
|
Events.OnKeypress(function (ev) { |
||||
|
Vx = 0; |
||||
|
Vy = 0; |
||||
|
|
||||
|
if (ev.Right) { |
||||
|
if (!Self.IsAnimating()) { |
||||
|
Self.PlayAnimation("walk-right", null); |
||||
|
} |
||||
|
Vx = playerSpeed; |
||||
|
} else if (ev.Left) { |
||||
|
if (!Self.IsAnimating()) { |
||||
|
Self.PlayAnimation("walk-left", null); |
||||
|
} |
||||
|
Vx = -playerSpeed; |
||||
|
} else { |
||||
|
Self.StopAnimation(); |
||||
|
animating = false; |
||||
|
} |
||||
|
|
||||
|
// Self.SetVelocity(Point(Vx, Vy));
|
||||
|
}) |
||||
|
} |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1,99 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
# Build all the doodads from their source files. |
||||
|
if [[ ! -d "./azulian" ]]; then |
||||
|
echo Run this script from the dev-assets/doodads/ working directory. |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
mkdir -p ../../assets/doodads |
||||
|
|
||||
|
boy() { |
||||
|
cd boy/ |
||||
|
make |
||||
|
cd .. |
||||
|
|
||||
|
cd thief/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
buttons() { |
||||
|
cd buttons/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
switches() { |
||||
|
cd switches/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
doors() { |
||||
|
cd doors/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
trapdoors() { |
||||
|
cd trapdoors/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
azulians() { |
||||
|
cd azulian/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
mobs() { |
||||
|
cd bird/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
objects() { |
||||
|
cd objects/ |
||||
|
make |
||||
|
cd .. |
||||
|
|
||||
|
cd box/ |
||||
|
make |
||||
|
cd .. |
||||
|
|
||||
|
cd crumbly-floor/ |
||||
|
make |
||||
|
cd .. |
||||
|
|
||||
|
cd regions/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
onoff() { |
||||
|
cd on-off/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
warpdoor() { |
||||
|
cd warp-door/ |
||||
|
make |
||||
|
cd .. |
||||
|
} |
||||
|
|
||||
|
boy |
||||
|
buttons |
||||
|
switches |
||||
|
doors |
||||
|
trapdoors |
||||
|
azulians |
||||
|
mobs |
||||
|
objects |
||||
|
onoff |
||||
|
warpdoor |
||||
|
doodad edit-doodad -quiet -lock -author "Noah" ../../assets/doodads/*.doodad |
||||
|
doodad edit-doodad ../../assets/doodads/azu-blu.doodad |
||||
|
doodad edit-doodad -hide ../../assets/doodads/boy.doodad |
@ -0,0 +1,19 @@ |
|||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
doodad convert -t "Sticky Button" sticky1.png sticky2.png button-sticky.doodad |
||||
|
doodad install-script sticky.js button-sticky.doodad |
||||
|
|
||||
|
doodad convert -t "Button" button1.png button2.png button.doodad |
||||
|
doodad install-script button.js button.doodad |
||||
|
|
||||
|
doodad convert -t "Button Type B" typeB1.png typeB2.png button-typeB.doodad |
||||
|
doodad install-script button.js button-typeB.doodad |
||||
|
|
||||
|
# Tag the category for these doodads |
||||
|
for i in *.doodad; do\
|
||||
|
doodad edit-doodad --tag "category=gizmos" $${i};\
|
||||
|
done |
||||
|
|
||||
|
cp *.doodad ../../../assets/doodads/ |
@ -0,0 +1,12 @@ |
|||||
|
# Button Doodads |
||||
|
|
||||
|
```bash |
||||
|
doodad convert -t "Sticky Button" sticky1.png sticky2.png sticky-button.doodad |
||||
|
doodad install-script sticky.js sticky-button.doodad |
||||
|
|
||||
|
doodad convert -t "Button" button1.png button2.png button.doodad |
||||
|
doodad install-script button.js button.doodad |
||||
|
|
||||
|
doodad convert -t "Button Type B" typeB1.png typeB2.png button-typeB.doodad |
||||
|
doodad install-script button.js button-typeB.doodad |
||||
|
``` |
@ -0,0 +1,48 @@ |
|||||
|
function main() { |
||||
|
var timer = 0; |
||||
|
var pressed = false; |
||||
|
|
||||
|
// Has a linked Sticky Button been pressed permanently down?
|
||||
|
var stickyDown = false; |
||||
|
Message.Subscribe("sticky:down", function(down) { |
||||
|
stickyDown = down; |
||||
|
Self.ShowLayer(stickyDown ? 1 : 0); |
||||
|
}); |
||||
|
|
||||
|
Events.OnCollide(function(e) { |
||||
|
if (!e.Settled) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// If a linked Sticky Button is pressed, button stays down too and
|
||||
|
// doesn't interact.
|
||||
|
if (stickyDown) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Verify they've touched the button.
|
||||
|
if (e.Overlap.Y + e.Overlap.H < 24) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!pressed && !stickyDown) { |
||||
|
Sound.Play("button-down.wav") |
||||
|
Message.Publish("power", true); |
||||
|
pressed = true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
if (timer > 0) { |
||||
|
clearTimeout(timer); |
||||
|
} |
||||
|
|
||||
|
Self.ShowLayer(1); |
||||
|
timer = setTimeout(function() { |
||||
|
Sound.Play("button-up.wav") |
||||
|
Self.ShowLayer(0); |
||||
|
Message.Publish("power", false); |
||||
|
timer = 0; |
||||
|
pressed = false; |
||||
|
}, 200); |
||||
|
}); |
||||
|
} |
After Width: | Height: | Size: 769 B |
After Width: | Height: | Size: 728 B |
@ -0,0 +1,35 @@ |
|||||
|
function main() { |
||||
|
var pressed = false; |
||||
|
|
||||
|
// When a sticky button receives power, it pops back up.
|
||||
|
Message.Subscribe("power", function (powered) { |
||||
|
if (powered && pressed) { |
||||
|
Self.ShowLayer(0); |
||||
|
pressed = false; |
||||
|
Sound.Play("button-up.wav") |
||||
|
Message.Publish("power", false); |
||||
|
Message.Publish("sticky:down", false); |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
Events.OnCollide(function (e) { |
||||
|
if (!e.Settled) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (pressed) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Verify they've touched the button.
|
||||
|
if (e.Overlap.Y + e.Overlap.H < 24) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Sound.Play("button-down.wav") |
||||
|
Self.ShowLayer(1); |
||||
|
pressed = true; |
||||
|
Message.Publish("power", true); |
||||
|
Message.Publish("sticky:down", true); |
||||
|
}); |
||||
|
} |
After Width: | Height: | Size: 767 B |
After Width: | Height: | Size: 726 B |
After Width: | Height: | Size: 736 B |
After Width: | Height: | Size: 695 B |
@ -0,0 +1,12 @@ |
|||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
doodad convert -t "Crumbly Floor" floor.png shake1.png shake2.png \
|
||||
|
fall1.png fall2.png fall3.png fall4.png fallen.png \
|
||||
|
crumbly-floor.doodad |
||||
|
doodad install-script crumbly-floor.js crumbly-floor.doodad |
||||
|
for i in *.doodad; do\
|
||||
|
doodad edit-doodad --tag "category=objects" $${i};\
|
||||
|
done |
||||
|
cp *.doodad ../../../assets/doodads/ |
@ -0,0 +1,62 @@ |
|||||
|
// Crumbly Floor.
|
||||
|
function main() { |
||||
|
Self.SetHitbox(0, 0, 98, 11); |
||||
|
|
||||
|
Self.AddAnimation("shake", 100, ["shake1", "shake2", "floor", "shake1", "shake2", "floor"]); |
||||
|
Self.AddAnimation("fall", 100, ["fall1", "fall2", "fall3", "fall4"]); |
||||
|
|
||||
|
// Recover time for the floor to respawn.
|
||||
|
var recover = 5000; |
||||
|
|
||||
|
// States of the floor.
|
||||
|
var stateSolid = 0; |
||||
|
var stateShaking = 1; |
||||
|
var stateFalling = 2; |
||||
|
var stateFallen = 3; |
||||
|
var state = stateSolid; |
||||
|
|
||||
|
// Started the animation?
|
||||
|
var startedAnimation = false; |
||||
|
|
||||
|
Events.OnCollide(function(e) { |
||||
|
|
||||
|
// If the floor is falling, the player passes right thru.
|
||||
|
if (state === stateFalling || state === stateFallen) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Floor is solid until it begins to fall.
|
||||
|
if (e.InHitbox && (state === stateSolid || state === stateShaking)) { |
||||
|
// Only activate when touched from the top.
|
||||
|
if (e.Overlap.Y > 0) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// If movement is not settled, be solid.
|
||||
|
if (!e.Settled) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// Begin the animation sequence if we're in the solid state.
|
||||
|
if (state === stateSolid) { |
||||
|
state = stateShaking; |
||||
|
Self.PlayAnimation("shake", function() { |
||||
|
state = stateFalling; |
||||
|
Self.PlayAnimation("fall", function() { |
||||
|
Sound.Play("crumbly-break.wav") |
||||
|
state = stateFallen; |
||||
|
Self.ShowLayerNamed("fallen"); |
||||
|
|
||||
|
// Recover after a while.
|
||||
|
setTimeout(function() { |
||||
|
Self.ShowLayer(0); |
||||
|
state = stateSolid; |
||||
|
}, recover); |
||||
|
}); |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
}); |
||||
|
} |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 1.0 KiB |
@ -0,0 +1,7 @@ |
|||||
|
SHELL = /bin/bash |
||||
|
|
||||
|
ALL: build |
||||
|
|
||||
|
.PHONY: build |
||||
|
build: |
||||
|
./build.sh |
@ -0,0 +1,15 @@ |
|||||
|
# Button Doodads |
||||
|
|
||||
|
```bash |
||||
|
doodad convert -t "Red Door" red1.png red2.png red-door.doodad |
||||
|
doodad convert -t "Blue Door" blue1.png blue2.png blue-door.doodad |
||||
|
doodad convert -t "Green Door" green1.png green2.png green-door.doodad |
||||
|
doodad convert -t "Yellow Door" yellow1.png yellow2.png yellow-door.doodad |
||||
|
|
||||
|
doodad convert -t "Red Key" red-key.png red-key.doodad |
||||
|
doodad convert -t "Blue Key" blue-key.png blue-key.doodad |
||||
|
doodad convert -t "Green Key" green-key.png green-key.doodad |
||||
|
doodad convert -t "Yellow Key" yellow-key.png yellow-key.doodad |
||||
|
|
||||
|
doodad convert -t "Electric Door" electric{1,2,3,4}.png electric-door.doodad |
||||
|
``` |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 732 B |
After Width: | Height: | Size: 892 B |
After Width: | Height: | Size: 884 B |
After Width: | Height: | Size: 906 B |
After Width: | Height: | Size: 787 B |
After Width: | Height: | Size: 743 B |
@ -0,0 +1,52 @@ |
|||||
|
# doodad convert -t "Red Door" red1.png red2.png door-red.doodad |
||||
|
# doodad edit-doodad -q --tag color=red door-red.doodad |
||||
|
# doodad install-script locked-door.js door-red.doodad |
||||
|
|
||||
|
doodad convert -t "Red Door" red-closed.png red-unlocked.png red-right.png red-left.png door-red.doodad |
||||
|
doodad edit-doodad -q --tag color=red door-red.doodad |
||||
|
doodad install-script colored-door.js door-red.doodad |
||||
|
|
||||
|
doodad convert -t "Blue Door" blue-closed.png blue-unlocked.png blue-right.png blue-left.png door-blue.doodad |
||||
|
doodad edit-doodad -q --tag color=blue door-blue.doodad |
||||
|
doodad install-script colored-door.js door-blue.doodad |
||||
|
|
||||
|
doodad convert -t "Green Door" green-closed.png green-unlocked.png green-right.png green-left.png door-green.doodad |
||||
|
doodad edit-doodad -q --tag color=green door-green.doodad |
||||
|
doodad install-script colored-door.js door-green.doodad |
||||
|
|
||||
|
doodad convert -t "Yellow Door" yellow-closed.png yellow-unlocked.png yellow-right.png yellow-left.png door-yellow.doodad |
||||
|
doodad edit-doodad -q --tag color=yellow door-yellow.doodad |
||||
|
doodad install-script colored-door.js door-yellow.doodad |
||||
|
|
||||
|
doodad convert -t "Small Key Door" small-closed.png small-unlocked.png small-right.png small-left.png small-key-door.doodad |
||||
|
doodad edit-doodad -q --tag color=small small-key-door.doodad |
||||
|
doodad install-script colored-door.js small-key-door.doodad |
||||
|
|
||||
|
doodad convert -t "Red Key" red-key.png key-red.doodad |
||||
|
doodad edit-doodad -q --tag color=red key-red.doodad |
||||
|
doodad install-script keys.js key-red.doodad |
||||
|
|
||||
|
doodad convert -t "Blue Key" blue-key.png key-blue.doodad |
||||
|
doodad edit-doodad -q --tag color=blue key-blue.doodad |
||||
|
doodad install-script keys.js key-blue.doodad |
||||
|
|
||||
|
doodad convert -t "Green Key" green-key.png key-green.doodad |
||||
|
doodad edit-doodad -q --tag color=green key-green.doodad |
||||
|
doodad install-script keys.js key-green.doodad |
||||
|
|
||||
|
doodad convert -t "Yellow Key" yellow-key.png key-yellow.doodad |
||||
|
doodad edit-doodad -q --tag color=yellow key-yellow.doodad |
||||
|
doodad install-script keys.js key-yellow.doodad |
||||
|
|
||||
|
doodad convert -t "Small Key" small-key.png small-key.doodad |
||||
|
doodad edit-doodad -q --tag color=small small-key.doodad |
||||
|
doodad install-script keys.js small-key.doodad |
||||
|
|
||||
|
doodad convert -t "Electric Door" electric{1,2,3,4}.png door-electric.doodad |
||||
|
doodad install-script electric-door.js door-electric.doodad |
||||
|
|
||||
|
# Tag the category for these doodads |
||||
|
for i in *.doodad; do doodad edit-doodad --tag "category=doors" $i; done |
||||
|
doodad edit-doodad --tag "category=doors,gizmos" door-electric.doodad |
||||
|
|
||||
|
cp *.doodad ../../../assets/doodads/ |
@ -0,0 +1,66 @@ |
|||||
|
function main() { |
||||
|
var color = Self.GetTag("color"); |
||||
|
var keyname = color === "small" ? "small-key.doodad" : "key-" + color + ".doodad"; |
||||
|
|
||||
|
// Layers in the doodad image.
|
||||
|
var layer = { |
||||
|
closed: 0, |
||||
|
unlocked: 1, |
||||
|
right: 2, |
||||
|
left: 3, |
||||
|
}; |
||||
|
|
||||
|
// Variables that change in event handler.
|
||||
|
var unlocked = false; // Key has been used to unlock the door (one time).
|
||||
|
var opened = false; // If door is currently showing its opened state.
|
||||
|
var enterSide = 0; // Side of player entering the door, -1 or 1, left or right.
|
||||
|
|
||||
|
Self.SetHitbox(34, 0, 13, 76); |
||||
|
|
||||
|
Events.OnCollide(function(e) { |
||||
|
// Record the side that this actor has touched us, in case the door
|
||||
|
// needs to open.
|
||||
|
if (enterSide === 0) { |
||||
|
enterSide = e.Overlap.X > 0 ? 1 : -1; |
||||
|
} |
||||
|
|
||||
|
if (opened) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (e.InHitbox) { |
||||
|
if (unlocked) { |
||||
|
Self.ShowLayer(enterSide < 0 ? layer.right : layer.left); |
||||
|
opened = true; |
||||
|
Sound.Play("door-open.wav") |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Do they have our key?
|
||||
|
var hasKey = e.Actor.HasItem(keyname) >= 0; |
||||
|
if (!hasKey) { |
||||
|
// Door is locked.
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (e.Settled) { |
||||
|
unlocked = true; |
||||
|
Self.ShowLayer(enterSide < 0 ? layer.right : layer.left); |
||||
|
Sound.Play("unlock.wav"); |
||||
|
|
||||
|
// If a Small Key door, consume a small key.
|
||||
|
if (color === "small") { |
||||
|
e.Actor.RemoveItem(keyname, 1) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
Events.OnLeave(function(e) { |
||||
|
Self.ShowLayer(unlocked ? layer.unlocked : layer.closed); |
||||
|
// Sound.Play("door-close.wav")
|
||||
|
|
||||
|
// Reset collision state.
|
||||
|
opened = false; |
||||
|
enterSide = 0; |
||||
|
}); |
||||
|
} |
@ -0,0 +1,66 @@ |
|||||
|
var animating = false; |
||||
|
var opened = false; |
||||
|
var powerState = false; |
||||
|
|
||||
|
// Function to handle the door opening or closing.
|
||||
|
function setPoweredState(powered) { |
||||
|
powerState = powered; |
||||
|
|
||||
|
console.log("setPoweredState: %+v", powered) |
||||
|
if (powered) { |
||||
|
if (animating || opened) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
animating = true; |
||||
|
Sound.Play("electric-door.wav") |
||||
|
Self.PlayAnimation("open", function() { |
||||
|
opened = true; |
||||
|
animating = false; |
||||
|
}); |
||||
|
} else { |
||||
|
animating = true; |
||||
|
Sound.Play("electric-door.wav") |
||||
|
Self.PlayAnimation("close", function() { |
||||
|
opened = false; |
||||
|
animating = false; |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function main() { |
||||
|
Self.AddAnimation("open", 100, [0, 1, 2, 3]); |
||||
|
Self.AddAnimation("close", 100, [3, 2, 1, 0]); |
||||
|
|
||||
|
|
||||
|
Self.SetHitbox(0, 0, 34, 76); |
||||
|
|
||||
|
// A linked Switch that activates the door will send the Toggle signal
|
||||
|
// immediately before the Power signal. The door can just invert its
|
||||
|
// state on this signal, and ignore the very next Power signal. Ordinary
|
||||
|
// power sources like Buttons will work as normal, as they emit only a power
|
||||
|
// signal.
|
||||
|
var ignoreNextPower = false; |
||||
|
Message.Subscribe("switch:toggle", function(powered) { |
||||
|
console.log("A switch powered %+v, setPoweredState(%+v) to opposite", powered, powerState); |
||||
|
ignoreNextPower = true; |
||||
|
setPoweredState(!powerState); |
||||
|
}) |
||||
|
|
||||
|
Message.Subscribe("power", function(powered) { |
||||
|
if (ignoreNextPower) { |
||||
|
ignoreNextPower = false; |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
setPoweredState(powered); |
||||
|
}); |
||||
|
|
||||
|
Events.OnCollide(function(e) { |
||||
|
if (e.InHitbox) { |
||||
|
if (!opened) { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 907 B |
After Width: | Height: | Size: 978 B |
After Width: | Height: | Size: 928 B |
After Width: | Height: | Size: 824 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 714 B |
After Width: | Height: | Size: 875 B |
After Width: | Height: | Size: 880 B |
After Width: | Height: | Size: 888 B |
After Width: | Height: | Size: 734 B |
After Width: | Height: | Size: 742 B |
@ -0,0 +1,14 @@ |
|||||
|
function main() { |
||||
|
var color = Self.GetTag("color"); |
||||
|
var quantity = color === "small" ? 1 : 0; |
||||
|
|
||||
|
Events.OnCollide(function (e) { |
||||
|
if (e.Settled) { |
||||
|
if (e.Actor.HasInventory()) { |
||||
|
Sound.Play("item-get.wav") |
||||
|
e.Actor.AddItem(Self.Filename, quantity); |
||||
|
Self.Destroy(); |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
} |
@ -0,0 +1,27 @@ |
|||||
|
// DEPRECATED: old locked door script. Superceded by colored-door.js.
|
||||
|
function main() { |
||||
|
Self.AddAnimation("open", 0, [1]); |
||||
|
var unlocked = false; |
||||
|
var color = Self.GetTag("color"); |
||||
|
|
||||
|
Self.SetHitbox(16, 0, 32, 64); |
||||
|
|
||||
|
Events.OnCollide(function(e) { |
||||
|
if (unlocked) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (e.InHitbox) { |
||||
|
var data = e.Actor.GetData("key:" + color); |
||||
|
if (data === "") { |
||||
|
// Door is locked.
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
if (e.Settled) { |
||||
|
unlocked = true; |
||||
|
Self.PlayAnimation("open", null); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
} |
After Width: | Height: | Size: 1010 B |
After Width: | Height: | Size: 699 B |