diff --git a/.github/workflows/gcs-deploy.yml b/.github/workflows/gcs-deploy.yml new file mode 100644 index 00000000..13f549ef --- /dev/null +++ b/.github/workflows/gcs-deploy.yml @@ -0,0 +1,31 @@ +name: Deploy to GCS +on: + push: + branches: + - master + +jobs: + build_and_deploy: + runs-on: ubuntu-latest + + permissions: + contents: "read" + id-token: "write" + + steps: + - id: "checkout" + uses: "actions/checkout@v4" + + - id: "auth" + uses: "google-github-actions/auth@v3" + with: + credentials_json: "${{ secrets.GCS_DEPLOY }}" + + - id: "upload-folder" + uses: "google-github-actions/upload-cloud-storage@v3" + with: + path: "public" + destination: "super-mario.pomle.com" + parent: false + headers: | + cache-control: no-cache, max-age=0 diff --git a/public/audio/coin.ogg b/public/audio/coin.ogg deleted file mode 100644 index d21eba4c..00000000 Binary files a/public/audio/coin.ogg and /dev/null differ diff --git a/public/audio/fx/1up.ogg b/public/audio/fx/1up.ogg new file mode 100644 index 00000000..963f2773 Binary files /dev/null and b/public/audio/fx/1up.ogg differ diff --git a/public/audio/fx/bowser-die.ogg b/public/audio/fx/bowser-die.ogg new file mode 100644 index 00000000..8a8e98c3 Binary files /dev/null and b/public/audio/fx/bowser-die.ogg differ diff --git a/public/audio/fx/bowser-fire.ogg b/public/audio/fx/bowser-fire.ogg new file mode 100644 index 00000000..1785e8ca Binary files /dev/null and b/public/audio/fx/bowser-fire.ogg differ diff --git a/public/audio/fx/brick-bump.ogg b/public/audio/fx/brick-bump.ogg new file mode 100644 index 00000000..588a4ca2 Binary files /dev/null and b/public/audio/fx/brick-bump.ogg differ diff --git a/public/audio/fx/brick-destroy.ogg b/public/audio/fx/brick-destroy.ogg new file mode 100644 index 00000000..d3ce3c68 Binary files /dev/null and b/public/audio/fx/brick-destroy.ogg differ diff --git a/public/audio/fx/coin.ogg b/public/audio/fx/coin.ogg new file mode 100644 index 00000000..00070261 Binary files /dev/null and b/public/audio/fx/coin.ogg differ diff --git a/public/audio/fx/fireball.ogg b/public/audio/fx/fireball.ogg new file mode 100644 index 00000000..bc9dd358 Binary files /dev/null and b/public/audio/fx/fireball.ogg differ diff --git a/public/audio/fx/fireworks.ogg b/public/audio/fx/fireworks.ogg new file mode 100644 index 00000000..7a402c5f Binary files /dev/null and b/public/audio/fx/fireworks.ogg differ diff --git a/public/audio/fx/flagpole.ogg b/public/audio/fx/flagpole.ogg new file mode 100644 index 00000000..17a3228b Binary files /dev/null and b/public/audio/fx/flagpole.ogg differ diff --git a/public/audio/fx/jump-large.ogg b/public/audio/fx/jump-large.ogg new file mode 100644 index 00000000..86b5d254 Binary files /dev/null and b/public/audio/fx/jump-large.ogg differ diff --git a/public/audio/fx/jump.ogg b/public/audio/fx/jump.ogg new file mode 100644 index 00000000..d90f0576 Binary files /dev/null and b/public/audio/fx/jump.ogg differ diff --git a/public/audio/fx/kick.ogg b/public/audio/fx/kick.ogg new file mode 100644 index 00000000..bfc26f75 Binary files /dev/null and b/public/audio/fx/kick.ogg differ diff --git a/public/audio/fx/pause.ogg b/public/audio/fx/pause.ogg new file mode 100644 index 00000000..2c55474e Binary files /dev/null and b/public/audio/fx/pause.ogg differ diff --git a/public/audio/fx/pipe.ogg b/public/audio/fx/pipe.ogg new file mode 100644 index 00000000..e3396e78 Binary files /dev/null and b/public/audio/fx/pipe.ogg differ diff --git a/public/audio/fx/power-up-appears.ogg b/public/audio/fx/power-up-appears.ogg new file mode 100644 index 00000000..e21ce2ff Binary files /dev/null and b/public/audio/fx/power-up-appears.ogg differ diff --git a/public/audio/fx/power-up-consume.ogg b/public/audio/fx/power-up-consume.ogg new file mode 100644 index 00000000..eccd525c Binary files /dev/null and b/public/audio/fx/power-up-consume.ogg differ diff --git a/public/audio/fx/stomp.ogg b/public/audio/fx/stomp.ogg new file mode 100644 index 00000000..9ac79d3e Binary files /dev/null and b/public/audio/fx/stomp.ogg differ diff --git a/public/audio/fx/thwomp.ogg b/public/audio/fx/thwomp.ogg new file mode 100644 index 00000000..b4831ad0 Binary files /dev/null and b/public/audio/fx/thwomp.ogg differ diff --git a/public/audio/fx/vine.ogg b/public/audio/fx/vine.ogg new file mode 100644 index 00000000..620b657c Binary files /dev/null and b/public/audio/fx/vine.ogg differ diff --git a/public/audio/jump.ogg b/public/audio/jump.ogg deleted file mode 100644 index 94cd13a6..00000000 Binary files a/public/audio/jump.ogg and /dev/null differ diff --git a/public/audio/music/castle-clear.ogg b/public/audio/music/castle-clear.ogg new file mode 100644 index 00000000..c7989e34 Binary files /dev/null and b/public/audio/music/castle-clear.ogg differ diff --git a/public/audio/music/castle.ogg b/public/audio/music/castle.ogg new file mode 100644 index 00000000..cbc242b3 Binary files /dev/null and b/public/audio/music/castle.ogg differ diff --git a/public/audio/music/die.ogg b/public/audio/music/die.ogg new file mode 100644 index 00000000..aaff5779 Binary files /dev/null and b/public/audio/music/die.ogg differ diff --git a/public/audio/music/game-over.ogg b/public/audio/music/game-over.ogg new file mode 100644 index 00000000..ff480808 Binary files /dev/null and b/public/audio/music/game-over.ogg differ diff --git a/public/audio/music/hurry.ogg b/public/audio/music/hurry.ogg index 6fa58686..ecb9e712 100644 Binary files a/public/audio/music/hurry.ogg and b/public/audio/music/hurry.ogg differ diff --git a/public/audio/music/level-clear.ogg b/public/audio/music/level-clear.ogg new file mode 100644 index 00000000..e5844930 Binary files /dev/null and b/public/audio/music/level-clear.ogg differ diff --git a/public/audio/music/overworld.ogg b/public/audio/music/overworld.ogg index e0c557b9..e7932d04 100644 Binary files a/public/audio/music/overworld.ogg and b/public/audio/music/overworld.ogg differ diff --git a/public/audio/music/princess.ogg b/public/audio/music/princess.ogg new file mode 100644 index 00000000..2792b60f Binary files /dev/null and b/public/audio/music/princess.ogg differ diff --git a/public/audio/music/starman.ogg b/public/audio/music/starman.ogg new file mode 100644 index 00000000..4223d4d1 Binary files /dev/null and b/public/audio/music/starman.ogg differ diff --git a/public/audio/music/underwater.ogg b/public/audio/music/underwater.ogg new file mode 100644 index 00000000..2133a59d Binary files /dev/null and b/public/audio/music/underwater.ogg differ diff --git a/public/audio/music/underworld.ogg b/public/audio/music/underworld.ogg index 25d423a3..3610e51a 100644 Binary files a/public/audio/music/underworld.ogg and b/public/audio/music/underworld.ogg differ diff --git a/public/audio/music/uw-entrance.ogg b/public/audio/music/uw-entrance.ogg new file mode 100644 index 00000000..ad4bbafb Binary files /dev/null and b/public/audio/music/uw-entrance.ogg differ diff --git a/public/audio/stomp.ogg b/public/audio/stomp.ogg deleted file mode 100644 index a2e0e425..00000000 Binary files a/public/audio/stomp.ogg and /dev/null differ diff --git a/public/audio/thwomp.ogg b/public/audio/thwomp.ogg deleted file mode 100644 index 51e5973e..00000000 Binary files a/public/audio/thwomp.ogg and /dev/null differ diff --git a/public/css/main.css b/public/css/main.css new file mode 100644 index 00000000..878d588e --- /dev/null +++ b/public/css/main.css @@ -0,0 +1,22 @@ +body { + background: #000; + margin: 0; +} + +#screen { + display: block; + image-rendering: pixelated; + margin: auto; + width: 100vw; + max-height: 100vh; +} + +.aspect-4-3 { + height: 75vw; + max-width: 133.3vh; +} + +.aspect-16-9 { + height: 56.25vw; + max-width: 177.7vh; +} \ No newline at end of file diff --git a/public/img/characters.gif b/public/img/characters.gif deleted file mode 100644 index 02fdba0d..00000000 Binary files a/public/img/characters.gif and /dev/null differ diff --git a/public/img/font.png b/public/img/font.png index 4fb4c064..790290eb 100644 Binary files a/public/img/font.png and b/public/img/font.png differ diff --git a/public/img/points.png b/public/img/points.png new file mode 100644 index 00000000..d73612ef Binary files /dev/null and b/public/img/points.png differ diff --git a/public/img/sprites.png b/public/img/sprites.png new file mode 100644 index 00000000..7eed6ea3 Binary files /dev/null and b/public/img/sprites.png differ diff --git a/public/img/tiles.png b/public/img/tiles.png index 31d7a8f9..cb9c4c11 100644 Binary files a/public/img/tiles.png and b/public/img/tiles.png differ diff --git a/public/index.html b/public/index.html index d5b402b5..6050b5f3 100644 --- a/public/index.html +++ b/public/index.html @@ -2,22 +2,10 @@ Super Mario - + - + diff --git a/public/js/BoundingBox.js b/public/js/BoundingBox.js index 9534d5ed..ebde30e8 100644 --- a/public/js/BoundingBox.js +++ b/public/js/BoundingBox.js @@ -1,3 +1,5 @@ +import { Vec2 } from "./math.js"; + export default class BoundingBox { constructor(pos, size, offset) { this.pos = pos; @@ -12,6 +14,31 @@ export default class BoundingBox { && this.right > box.left; } + getCenter() { + return new Vec2(this.meridian, this.equator); + } + + setCenter(vec2) { + this.meridian = vec2.x; + this.equator = vec2.y; + } + + get meridian() { + return this.pos.x + this.offset.x + this.size.x / 2; + } + + set meridian(c) { + this.pos.x = c - (this.size.x / 2 + this.offset.x); + } + + get equator() { + return this.pos.y + this.offset.y + this.size.y / 2; + } + + set equator(c) { + this.pos.y = c - (this.size.y / 2 + this.offset.y); + } + get bottom() { return this.pos.y + this.size.y + this.offset.y; } diff --git a/public/js/Camera.js b/public/js/Camera.js index 1dfe0be3..d1238811 100644 --- a/public/js/Camera.js +++ b/public/js/Camera.js @@ -4,5 +4,8 @@ export default class Camera { constructor() { this.pos = new Vec2(0, 0); this.size = new Vec2(256, 224); + + this.min = new Vec2(0, 0); + this.max = new Vec2(Infinity, Infinity); } } diff --git a/public/js/Entity.js b/public/js/Entity.js index e07b6dd2..42491410 100644 --- a/public/js/Entity.js +++ b/public/js/Entity.js @@ -1,8 +1,30 @@ import {Vec2} from './math.js'; -import Trait from './Trait.js'; import AudioBoard from './AudioBoard.js'; import BoundingBox from './BoundingBox.js'; import EventBuffer from './EventBuffer.js'; +import Trait from './Trait.js'; + +export const Align = { + center(target, subject) { + subject.bounds.setCenter(target.bounds.getCenter()); + }, + + bottom(target, subject) { + subject.bounds.bottom = target.bounds.bottom; + }, + + top(target, subject) { + subject.bounds.top = target.bounds.top; + }, + + left(target, subject) { + subject.bounds.left = target.bounds.left; + }, + + right(target, subject) { + subject.bounds.right = target.bounds.right; + }, +}; export const Sides = { TOP: Symbol('top'), @@ -13,12 +35,11 @@ export const Sides = { export default class Entity { constructor() { + this.id = null; this.audio = new AudioBoard(); this.events = new EventBuffer(); this.sounds = new Set(); - this.events = new EventBuffer(); - this.pos = new Vec2(0, 0); this.vel = new Vec2(0, 0); this.size = new Vec2(0, 0); @@ -45,10 +66,6 @@ export default class Entity { }); } - draw() { - - } - finalize() { this.events.emit(Trait.EVENT_TASK, this); diff --git a/public/js/Level.js b/public/js/Level.js index 64fe0d4f..53506f86 100644 --- a/public/js/Level.js +++ b/public/js/Level.js @@ -1,26 +1,41 @@ import Camera from './Camera.js'; -import Compositor from './Compositor.js'; -import EventEmitter from './EventEmitter.js'; import MusicController from './MusicController.js'; import EntityCollider from './EntityCollider.js'; import Scene from './Scene.js'; import TileCollider from './TileCollider.js'; +import { clamp } from './math.js'; import { findPlayers } from './player.js'; function focusPlayer(level) { for (const player of findPlayers(level.entities)) { - level.camera.pos.x = Math.max(0, player.pos.x - 100); + level.camera.pos.x = clamp( + player.pos.x - 100, + level.camera.min.x, + level.camera.max.x - level.camera.size.x); + } +} + +class EntityCollection extends Set { + get(id) { + for (const entity of this) { + if (entity.id === id) { + return entity; + } + } } } export default class Level extends Scene { static EVENT_TRIGGER = Symbol('trigger'); + static EVENT_COMPLETE = Symbol('complete'); constructor() { super(); this.name = ""; + this.checkpoints = []; + this.gravity = 1500; this.totalTime = 0; @@ -28,7 +43,7 @@ export default class Level extends Scene { this.music = new MusicController(); - this.entities = new Set(); + this.entities = new EntityCollection(); this.entityCollider = new EntityCollider(this.entities); this.tileCollider = new TileCollider(); diff --git a/public/js/TileCollider.js b/public/js/TileCollider.js index 7a923167..8c0cfa00 100644 --- a/public/js/TileCollider.js +++ b/public/js/TileCollider.js @@ -69,7 +69,7 @@ export default class TileCollider { level, }; - const handler = handlers[match.tile.type]; + const handler = handlers[match.tile.behavior]; if (handler) { handler[index](tileCollisionContext); } diff --git a/public/js/entities.js b/public/js/entities.js index 833fd22b..5e5403f6 100644 --- a/public/js/entities.js +++ b/public/js/entities.js @@ -1,23 +1,77 @@ import {loadMario} from './entities/Mario.js'; -import {loadGoomba} from './entities/Goomba.js'; -import {loadKoopa} from './entities/Koopa.js'; +import {loadGoombaBrown, loadGoombaBlue} from './entities/Goomba.js'; +import {loadKoopaGreen, loadKoopaBlue} from './entities/Koopa.js'; +import {loadCheepSlow, loadCheepFast, loadCheepSlowWavy, loadCheepFastWavy} from './entities/CheepCheep.js'; +import {loadPiranhaPlant} from './entities/PiranhaPlant.js'; import {loadBullet} from './entities/Bullet.js'; import {loadCannon} from './entities/Cannon.js'; +import {loadBrickShrapnel} from './entities/BrickShrapnel.js'; +import {loadPipePortal} from './entities/PipePortal.js'; +import {loadFlagPole} from './entities/FlagPole.js'; -export function loadEntities(audioContext) { +function createPool(size) { + const pool = []; + + return function createPooledFactory(factory) { + for (let i = 0; i < size; i++) { + pool.push(factory()); + } + + let count = 0; + return function pooledFactory() { + const entity = pool[count++ % pool.length]; + entity.lifetime = 0; + return entity; + } + } +} + +export async function loadEntities(audioContext) { const entityFactories = {}; + function setup(loader) { + return loader(audioContext); + } + function addAs(name) { - return factory => entityFactories[name] = factory; + return function addFactory(factory) { + entityFactories[name] = factory; + } } - return Promise.all([ - loadMario(audioContext).then(addAs('mario')), - loadGoomba(audioContext).then(addAs('goomba')), - loadKoopa(audioContext).then(addAs('koopa')), - loadBullet(audioContext).then(addAs('bullet')), - loadCannon(audioContext).then(addAs('cannon')), + await Promise.all([ + setup(loadMario) + .then(addAs('mario')), + setup(loadPiranhaPlant) + .then(addAs('piranha-plant')), + setup(loadGoombaBrown) + .then(addAs('goomba-brown')), + setup(loadGoombaBlue) + .then(addAs('goomba-blue')), + setup(loadKoopaGreen) + .then(addAs('koopa-green')), + setup(loadKoopaBlue) + .then(addAs('koopa-blue')), + setup(loadCheepSlow) + .then(addAs('cheep-slow')), + setup(loadCheepFast) + .then(addAs('cheep-fast')), + setup(loadCheepSlowWavy) + .then(addAs('cheep-slow-wavy')), + setup(loadCheepFastWavy) + .then(addAs('cheep-fast-wavy')), + setup(loadBullet) + .then(addAs('bullet')), + setup(loadCannon) + .then(addAs('cannon')), + setup(loadPipePortal) + .then(addAs('pipe-portal')), + setup(loadFlagPole) + .then(addAs('flag-pole')), + setup(loadBrickShrapnel) + .then(createPool(8)) + .then(addAs('brickShrapnel')), + ]); - ]) - .then(() => entityFactories); + return entityFactories; } diff --git a/public/js/entities/BrickShrapnel.js b/public/js/entities/BrickShrapnel.js new file mode 100644 index 00000000..aac69b9e --- /dev/null +++ b/public/js/entities/BrickShrapnel.js @@ -0,0 +1,35 @@ +import Entity from '../Entity.js'; +import LifeLimit from '../traits/LifeLimit.js'; +import Gravity from '../traits/Gravity.js'; +import Velocity from '../traits/Velocity.js'; +import {loadAudioBoard} from '../loaders/audio.js'; +import {loadSpriteSheet} from '../loaders/sprite.js'; + +export function loadBrickShrapnel(audioContext) { + return Promise.all([ + loadSpriteSheet('brick-shrapnel'), + loadAudioBoard('brick-shrapnel', audioContext), + ]) + .then(([sprite, audio]) => { + return createFactory(sprite, audio); + }); +} + +function createFactory(sprite, audio) { + const spinBrick = sprite.animations.get('spinning-brick'); + + function draw(context) { + sprite.draw(spinBrick(this.lifetime), context, 0, 0); + } + + return function createBrickShrapnel() { + const entity = new Entity(); + entity.audio = audio; + entity.size.set(8, 8); + entity.addTrait(new LifeLimit()); + entity.addTrait(new Gravity()); + entity.addTrait(new Velocity()); + entity.draw = draw; + return entity; + }; +} diff --git a/public/js/entities/Bullet.js b/public/js/entities/Bullet.js index d41fea37..2be8691c 100644 --- a/public/js/entities/Bullet.js +++ b/public/js/entities/Bullet.js @@ -1,8 +1,8 @@ -import Entity, {Sides} from '../Entity.js'; +import Entity from '../Entity.js'; import Trait from '../Trait.js'; import Killable from '../traits/Killable.js'; -import Stomper from '../traits/Stomper.js'; import Gravity from '../traits/Gravity.js'; +import Stomper from '../traits/Stomper.js'; import Velocity from '../traits/Velocity.js'; import {loadSpriteSheet} from '../loaders/sprite.js'; @@ -44,7 +44,7 @@ class Behavior extends Trait { function createBulletFactory(sprite) { function drawBullet(context) { - sprite.draw('bullet', context, 0, 0, this.vel.x < 0); + sprite.draw('bullet', context, 0, 0, this.vel.x > 0); } return function createBullet() { diff --git a/public/js/entities/CheepCheep.js b/public/js/entities/CheepCheep.js new file mode 100644 index 00000000..5b22d1c0 --- /dev/null +++ b/public/js/entities/CheepCheep.js @@ -0,0 +1,155 @@ +import Entity from '../Entity.js'; +import Trait from '../Trait.js'; +import Killable from '../traits/Killable.js'; +import {loadSpriteSheet} from '../loaders/sprite.js'; + +export function loadCheepSlow() { + return loadSpriteSheet('cheep-gray') + .then(createCheepSlowFactory); +} + +export function loadCheepSlowWavy() { + return loadSpriteSheet('cheep-gray') + .then(createCheepSlowWavyFactory); +} + +export function loadCheepFast() { + return loadSpriteSheet('cheep-red') + .then(createCheepFastFactory); +} + +export function loadCheepFastWavy() { + return loadSpriteSheet('cheep-red') + .then(createCheepFastWavyFactory); +} + +class Behavior extends Trait { + + collides(us, them) { + if(them.traits.has(Killable)) { + them.traits.get(Killable).kill(); + } + } + + update(entity, gameContext, level) { + const {deltaTime} = gameContext; + entity.pos.x += entity.vel.x * deltaTime; + } + +} + +class Wavy extends Trait { + constructor() { + super(); + this.amplitude = 16; + this.direction = 1; + this.offset = 0; + this.speed = 0.5; + } + + update(entity, gameContext, level) { + const {deltaTime} = gameContext; + const movementY = (entity.vel.x * deltaTime * this.direction) * this.speed; + entity.pos.y += movementY; + + this.offset += movementY; + if (Math.abs(this.offset) > this.amplitude) { + this.direction = -this.direction; + } + } +} + +function createCheepSlowFactory(sprite) { + const swimAnim = sprite.animations.get('swim'); + + function routeAnim(entity) { + return swimAnim(entity.lifetime); + } + + function drawCheepSlow(context) { + sprite.draw(routeAnim(this), context, 0, 0, true); + } + + return function createCheepSlow() { + const entity = new Entity(); + entity.size.set(16, 16); + entity.vel.x = -16; + entity.addTrait(new Behavior()); + entity.draw = drawCheepSlow; + + return entity; + }; +} + +function createCheepSlowWavyFactory(sprite) { + const swimAnim = sprite.animations.get('swim'); + + function routeAnim(entity) { + return swimAnim(entity.lifetime); + } + + function drawCheepSlowWavy(context) { + sprite.draw(routeAnim(this), context, 0, 0, true); + } + + return function createCheepSlowWavy() { + const entity = new Entity(); + entity.size.set(16, 16); + entity.vel.x = -16; + + entity.addTrait(new Behavior()); + entity.addTrait(new Wavy()); + + entity.draw = drawCheepSlowWavy; + + return entity; + }; +} + +function createCheepFastFactory(sprite) { + const swimAnim = sprite.animations.get('swim'); + + function routeAnim(entity) { + return swimAnim(entity.lifetime); + } + + function drawCheepFast(context) { + sprite.draw(routeAnim(this), context, 0, 0, true); + } + + return function createCheepFast() { + const entity = new Entity(); + entity.size.set(16, 16); + entity.vel.x = -32; + entity.addTrait(new Behavior()); + entity.draw = drawCheepFast; + + return entity; + }; +} + +function createCheepFastWavyFactory(sprite) { + const swimAnim = sprite.animations.get('swim'); + + function routeAnim(entity) { + return swimAnim(entity.lifetime); + } + + function drawCheepFastWavy(context) { + sprite.draw(routeAnim(this), context, 0, 0, true); + } + + return function createCheepFastWavy() { + const entity = new Entity(); + entity.size.set(16, 16); + entity.vel.x = -32; + + entity.addTrait(new Behavior()); + entity.addTrait(new Wavy()); + entity.traits.get(Wavy).speed = 0.25; + + entity.draw = drawCheepFastWavy; + + return entity; + }; +} diff --git a/public/js/entities/FlagPole.js b/public/js/entities/FlagPole.js new file mode 100644 index 00000000..94488a01 --- /dev/null +++ b/public/js/entities/FlagPole.js @@ -0,0 +1,24 @@ +import Entity from '../Entity.js'; +import Pole from '../traits/Pole.js'; +import {loadAudioBoard} from '../loaders/audio.js'; + +export function loadFlagPole(audioContext) { + return Promise.all([ + loadAudioBoard('flag-pole', audioContext), + ]) + .then(([audio]) => { + return createFactory(audio); + }); +} + +function createFactory(audio) { + return function createFlagPole() { + const entity = new Entity(); + const pole = new Pole(); + entity.audio = audio; + entity.size.set(8, 144); + entity.offset.set(4, 0); + entity.addTrait(pole); + return entity; + }; +} diff --git a/public/js/entities/Goomba.js b/public/js/entities/Goomba.js index 2ce1df84..1c06be40 100644 --- a/public/js/entities/Goomba.js +++ b/public/js/entities/Goomba.js @@ -1,16 +1,22 @@ -import Entity, {Sides} from '../Entity.js'; +import Entity from '../Entity.js'; import Trait from '../Trait.js'; import Killable from '../traits/Killable.js'; import PendulumMove from '../traits/PendulumMove.js'; import Physics from '../traits/Physics.js'; import Solid from '../traits/Solid.js'; +import Stomper from '../traits/Stomper.js'; import {loadSpriteSheet} from '../loaders/sprite.js'; -export function loadGoomba() { - return loadSpriteSheet('goomba') - .then(createGoombaFactory); +export function loadGoombaBrown() { + return loadSpriteSheet('goomba-brown') + .then(createGoombaFactory); } +export function loadGoombaBlue() { + return loadSpriteSheet('goomba-blue') + .then(createGoombaFactory); + } + class Behavior extends Trait { collides(us, them) { @@ -18,7 +24,7 @@ class Behavior extends Trait { return; } - if (them.stomper) { + if (them.traits.has(Stomper)) { if (them.vel.y > us.vel.y) { us.traits.get(Killable).kill(); us.traits.get(PendulumMove).speed = 0; diff --git a/public/js/entities/Koopa.js b/public/js/entities/Koopa.js index 979f7a90..2162b858 100644 --- a/public/js/entities/Koopa.js +++ b/public/js/entities/Koopa.js @@ -1,17 +1,23 @@ -import Entity, {Sides} from '../Entity.js'; +import Entity from '../Entity.js'; import Trait from '../Trait.js'; import Killable from '../traits/Killable.js'; -import Stomper from '../traits/Stomper.js'; import PendulumMove from '../traits/PendulumMove.js'; import Physics from '../traits/Physics.js'; import Solid from '../traits/Solid.js'; +import Stomper from '../traits/Stomper.js'; import {loadSpriteSheet} from '../loaders/sprite.js'; -export function loadKoopa() { - return loadSpriteSheet('koopa') +export function loadKoopaGreen() { + return loadSpriteSheet('koopa-green') .then(createKoopaFactory); } +export function loadKoopaBlue() { + return loadSpriteSheet('koopa-blue') + .then(createKoopaFactory); + } + + const STATE_WALKING = Symbol('walking'); const STATE_HIDING = Symbol('hiding'); const STATE_PANIC = Symbol('panic'); diff --git a/public/js/entities/Mario.js b/public/js/entities/Mario.js index d0f1a780..60e328df 100644 --- a/public/js/entities/Mario.js +++ b/public/js/entities/Mario.js @@ -3,6 +3,8 @@ import Go from '../traits/Go.js'; import Jump from '../traits/Jump.js'; import Killable from '../traits/Killable.js'; import Physics from '../traits/Physics.js'; +import PipeTraveller from '../traits/PipeTraveller.js'; +import PoleTraveller from '../traits/PoleTraveller.js'; import Solid from '../traits/Solid.js'; import Stomper from '../traits/Stomper.js'; import {loadAudioBoard} from '../loaders/audio.js'; @@ -23,8 +25,30 @@ export function loadMario(audioContext) { function createMarioFactory(sprite, audio) { const runAnim = sprite.animations.get('run'); + const climbAnim = sprite.animations.get('climb'); + + function getHeading(mario) { + const poleTraveller = mario.traits.get(PoleTraveller); + if (poleTraveller.distance) { + return false; + } + return mario.traits.get(Go).heading < 0; + } function routeFrame(mario) { + const pipeTraveller = mario.traits.get(PipeTraveller); + if (pipeTraveller.movement.x != 0) { + return runAnim(pipeTraveller.distance.x * 2); + } + if (pipeTraveller.movement.y != 0) { + return 'idle'; + } + + const poleTraveller = mario.traits.get(PoleTraveller); + if (poleTraveller.distance) { + return climbAnim(poleTraveller.distance); + } + if (mario.traits.get(Jump).falling) { return 'jump'; } @@ -35,7 +59,7 @@ function createMarioFactory(sprite, audio) { return 'break'; } - return runAnim(go.distance); + return runAnim(mario.traits.get(Go).distance); } return 'idle'; @@ -46,8 +70,7 @@ function createMarioFactory(sprite, audio) { } function drawMario(context) { - const go = this.traits.get(Go); - sprite.draw(routeFrame(this), context, 0, 0, go.heading < 0); + sprite.draw(routeFrame(this), context, 0, 0, getHeading(this)); } return function createMario() { @@ -61,8 +84,11 @@ function createMarioFactory(sprite, audio) { mario.addTrait(new Jump()); mario.addTrait(new Killable()); mario.addTrait(new Stomper()); + mario.addTrait(new PipeTraveller()); + mario.addTrait(new PoleTraveller()); - mario.traits.get(Killable).removeAfter = 0; + mario.traits.get(Killable).removeAfter = Infinity; + mario.traits.get(Jump).velocity = 175; mario.turbo = setTurboState; mario.draw = drawMario; diff --git a/public/js/entities/PipePortal.js b/public/js/entities/PipePortal.js new file mode 100644 index 00000000..37bf7d4c --- /dev/null +++ b/public/js/entities/PipePortal.js @@ -0,0 +1,27 @@ +import { Direction } from '../math.js'; +import Entity from '../Entity.js'; +import Pipe from '../traits/Pipe.js'; +import {loadAudioBoard} from '../loaders/audio.js'; + +export function loadPipePortal(audioContext) { + return Promise.all([ + loadAudioBoard('pipe-portal', audioContext), + ]) + .then(([audio]) => { + return createFactory(audio); + }); +} + +function createFactory(audio) { + + return function createPipePortal(props) { + const pipe = new Pipe(); + pipe.direction.copy(Direction[props.dir]); + const entity = new Entity(); + entity.props = props; + entity.audio = audio; + entity.size.set(24, 30); + entity.addTrait(pipe); + return entity; + }; +} diff --git a/public/js/entities/PiranhaPlant.js b/public/js/entities/PiranhaPlant.js new file mode 100644 index 00000000..b5cb5000 --- /dev/null +++ b/public/js/entities/PiranhaPlant.js @@ -0,0 +1,102 @@ +import Entity from '../Entity.js'; +import Trait from '../Trait.js'; +import {loadSpriteSheet} from '../loaders/sprite.js'; +import {findPlayers} from '../player.js'; + +export function loadPiranhaPlant() { + return loadSpriteSheet('piranha-plant') + .then(createPiranhaPlantFactory); +} + +class Behavior extends Trait { + constructor() { + super(); + + this.graceDistance = 32; + + this.idleTime = 4; + this.idleCounter = 0; + this.attackTime = 2; + this.attackCounter = null; + this.holdTime = 2; + this.holdCounter = null; + this.retreatTime = 2; + this.retreatCounter = null; + + this.velocity = 30; + this.deltaMove = 0; + } + + update(entity, gameContext, level) { + const {deltaTime} = gameContext; + + if (this.idleCounter !== null) { + for (const player of findPlayers(level.entities)) { + const distance = player.bounds.getCenter().distance(entity.bounds.getCenter()); + if (distance < this.graceDistance) { + this.idleCounter = 0; + return; + } + } + + this.idleCounter += deltaTime; + if (this.idleCounter >= this.idleTime) { + this.attackCounter = 0; + this.idleCounter = null; + } + } + else if (this.attackCounter !== null) { + this.attackCounter += deltaTime; + const movement = this.velocity * deltaTime; + this.deltaMove += movement; + entity.pos.y -= movement; + if (this.deltaMove >= entity.size.y) { + entity.pos.y += entity.size.y - this.deltaMove; + this.attackCounter = null; + this.holdCounter = 0; + } + } + else if (this.holdCounter !== null) { + this.holdCounter += deltaTime; + if (this.holdCounter >= this.holdTime) { + this.retreatCounter = 0; + this.holdCounter = null; + } + } + else if (this.retreatCounter !== null) { + this.retreatCounter += deltaTime; + const movement = this.velocity * deltaTime; + this.deltaMove -= movement; + entity.pos.y += movement; + if (this.deltaMove <= 0) { + entity.pos.y -= this.deltaMove; + this.retreatCounter = null; + this.idleCounter = 0; + } + } + } +} + + +function createPiranhaPlantFactory(sprite) { + const chewAnim = sprite.animations.get('chew'); + + function routeAnim(entity) { + return chewAnim(entity.lifetime); + } + + function drawPiranhaPlant(context) { + sprite.draw(routeAnim(this), context, 0, 0); + } + + return function createPiranhaPlant() { + const entity = new Entity(); + entity.size.set(16, 24); + + entity.addTrait(new Behavior()); + + entity.draw = drawPiranhaPlant; + + return entity; + }; +} diff --git a/public/js/input.js b/public/js/input.js index 05385683..34d8ab11 100644 --- a/public/js/input.js +++ b/public/js/input.js @@ -1,7 +1,17 @@ import Keyboard from './KeyboardState.js'; import InputRouter from './InputRouter.js'; -import Go from './traits/Go.js'; import Jump from './traits/Jump.js'; +import PipeTraveller from './traits/PipeTraveller.js'; +import Go from './traits/Go.js'; + +const KEYMAP = { + UP: 'KeyW', + DOWN: 'KeyS', + LEFT: 'KeyA', + RIGHT: 'KeyD', + A: "KeyP", + B: "KeyO", +}; export function setupKeyboard(window) { const input = new Keyboard(); @@ -9,7 +19,7 @@ export function setupKeyboard(window) { input.listenTo(window); - input.addMapping('KeyP', keyState => { + input.addMapping(KEYMAP.A, keyState => { if (keyState) { router.route(entity => entity.traits.get(Jump).start()); } else { @@ -17,16 +27,34 @@ export function setupKeyboard(window) { } }); - input.addMapping('KeyO', keyState => { + input.addMapping(KEYMAP.B, keyState => { router.route(entity => entity.turbo(keyState)); }); - input.addMapping('KeyD', keyState => { - router.route(entity => entity.traits.get(Go).dir += keyState ? 1 : -1); + input.addMapping(KEYMAP.UP, keyState => { + router.route(entity => { + entity.traits.get(PipeTraveller).direction.y += keyState ? -1 : 1; + }); + }); + + input.addMapping(KEYMAP.DOWN, keyState => { + router.route(entity => { + entity.traits.get(PipeTraveller).direction.y += keyState ? 1 : -1; + }); + }); + + input.addMapping(KEYMAP.RIGHT, keyState => { + router.route(entity => { + entity.traits.get(Go).dir += keyState ? 1 : -1; + entity.traits.get(PipeTraveller).direction.x += keyState ? 1 : -1; + }); }); - input.addMapping('KeyA', keyState => { - router.route(entity => entity.traits.get(Go).dir += keyState ? -1 : 1); + input.addMapping(KEYMAP.LEFT, keyState => { + router.route(entity => { + entity.traits.get(Go).dir += keyState ? -1 : 1; + entity.traits.get(PipeTraveller).direction.x += keyState ? -1 : 1; + }); }); return router; diff --git a/public/js/layers/background.js b/public/js/layers/background.js index 3808ddb0..9ac310dd 100644 --- a/public/js/layers/background.js +++ b/public/js/layers/background.js @@ -16,10 +16,10 @@ export function createBackgroundLayer(level, tiles, sprites) { const col = tiles.grid[x]; if (col) { col.forEach((tile, y) => { - if (sprites.animations.has(tile.name)) { - sprites.drawAnim(tile.name, context, x - startIndex, y, level.totalTime); + if (sprites.animations.has(tile.style)) { + sprites.drawAnim(tile.style, context, x - startIndex, y, level.totalTime); } else { - sprites.drawTile(tile.name, context, x - startIndex, y); + sprites.drawTile(tile.style, context, x - startIndex, y); } }); } diff --git a/public/js/layers/collision.js b/public/js/layers/collision.js index 02a6e987..3757f0de 100644 --- a/public/js/layers/collision.js +++ b/public/js/layers/collision.js @@ -4,10 +4,10 @@ function createEntityLayer(entities) { entities.forEach(entity => { context.beginPath(); context.rect( - entity.bounds.left - camera.pos.x, - entity.bounds.top - camera.pos.y, - entity.size.x, - entity.size.y); + Math.floor(entity.bounds.left - camera.pos.x) + .5, + Math.floor(entity.bounds.top - camera.pos.y) + .5, + entity.size.x - 1, + entity.size.y -1); context.stroke(); }); }; @@ -29,9 +29,10 @@ function createTileCandidateLayer(tileResolver) { resolvedTiles.forEach(({x, y}) => { context.beginPath(); context.rect( - x * tileSize - camera.pos.x, - y * tileSize - camera.pos.y, - tileSize, tileSize); + Math.floor(x * tileSize - camera.pos.x) + .5, + Math.floor(y * tileSize - camera.pos.y) + .5, + tileSize - 1, + tileSize - 1); context.stroke(); }); diff --git a/public/js/layers/dashboard.js b/public/js/layers/dashboard.js index d49ec70d..f717d50e 100644 --- a/public/js/layers/dashboard.js +++ b/public/js/layers/dashboard.js @@ -2,38 +2,23 @@ import Player from "../traits/Player.js"; import LevelTimer from "../traits/LevelTimer.js"; import {findPlayers} from "../player.js"; -function getPlayerTrait(entities) { - for (const entity of findPlayers(entities)) { - return entity.traits.get(Player); - } -} - -function getTimerTrait(entities) { - for (const entity of entities) { - if (entity.traits.has(LevelTimer)) { - return entity.traits.get(LevelTimer); - } - } -} - -export function createDashboardLayer(font, level) { - const LINE1 = font.size; - const LINE2 = font.size * 2; - - const timerTrait = getTimerTrait(level.entities); +export function createDashboardLayer(font, entity) { + const LINE1 = font.size * 2; + const LINE2 = font.size * 3; return function drawDashboard(context) { - const playerTrait = getPlayerTrait(level.entities); + const playerTrait = entity.traits.get(Player); + const timerTrait = entity.traits.get(LevelTimer); - font.print(playerTrait.name, context, 16, LINE1); - font.print(playerTrait.score.toString().padStart(6, '0'), context, 16, LINE2); + font.print(playerTrait.name, context, 24, LINE1); + font.print(playerTrait.score.toString().padStart(6, '0'), context, 24, LINE2); - font.print('@x' + playerTrait.coins.toString().padStart(2, '0'), context, 96, LINE2); + font.print('×' + playerTrait.coins.toString().padStart(2, '0'), context, 96, LINE2); - font.print('WORLD', context, 152, LINE1); - font.print(level.name, context, 160, LINE2); + font.print('WORLD', context, 144, LINE1); + font.print(playerTrait.world, context, 152, LINE2); - font.print('TIME', context, 208, LINE1); - font.print(timerTrait.currentTime.toFixed().toString().padStart(3, '0'), context, 216, LINE2); + font.print('TIME', context, 200, LINE1); + font.print(timerTrait.currentTime.toFixed().toString().padStart(3, '0'), context, 208, LINE2); }; } diff --git a/public/js/layers/player-progress.js b/public/js/layers/player-progress.js index 25d67b3a..45a326bc 100644 --- a/public/js/layers/player-progress.js +++ b/public/js/layers/player-progress.js @@ -1,5 +1,5 @@ -import Player from "../traits/Player.js"; import {findPlayers} from "../player.js"; +import Player from "../traits/Player.js"; function getPlayer(entities) { for (const entity of findPlayers(entities)) { @@ -20,12 +20,12 @@ export function createPlayerProgressLayer(font, level) { const player = entity.traits.get(Player); font.print('WORLD ' + level.name, context, size * 12, size * 12); - font.print('x ' + player.lives.toString().padStart(3, ' '), + font.print('×' + player.lives.toString().padStart(3, ' '), context, size * 16, size * 16); spriteBufferContext.clearRect(0, 0, spriteBuffer.width, spriteBuffer.height); entity.draw(spriteBufferContext); - context.drawImage(spriteBuffer, size * 12, size * 15); + context.drawImage(spriteBuffer, size * 13, size * 15); }; } diff --git a/public/js/layers/sprites.js b/public/js/layers/sprites.js index 88360fd1..6608b56d 100644 --- a/public/js/layers/sprites.js +++ b/public/js/layers/sprites.js @@ -6,6 +6,10 @@ export function createSpriteLayer(entities, width = 64, height = 64) { return function drawSpriteLayer(context, camera) { entities.forEach(entity => { + if (!entity.draw) { + return; + } + spriteBufferContext.clearRect(0, 0, width, height); entity.draw(spriteBufferContext); diff --git a/public/js/layers/text.js b/public/js/layers/text.js index 64c17d5f..80f904c4 100644 --- a/public/js/layers/text.js +++ b/public/js/layers/text.js @@ -1,11 +1,11 @@ export function createTextLayer(font, text) { const size = font.size; - return function drawText(context) { const textW = text.length; const screenW = Math.floor(context.canvas.width / size); + const screenH = Math.floor(context.canvas.height / size); const x = screenW / 2 - textW / 2; - const y = 12; + const y = screenH / 2; font.print(text, context, x * size, y * size); }; } diff --git a/public/js/loaders/font.js b/public/js/loaders/font.js index b1266850..28070c5e 100644 --- a/public/js/loaders/font.js +++ b/public/js/loaders/font.js @@ -1,7 +1,7 @@ import {loadImage} from '../loaders.js'; import SpriteSheet from '../SpriteSheet.js'; -const CHARS = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'; +const CHARS = ' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ©!-×.'; class Font { constructor(sprites, size) { @@ -10,7 +10,7 @@ class Font { } print(text, context, x, y) { - [...text].forEach((char, pos) => { + [...text.toUpperCase()].forEach((char, pos) => { this.sprites.draw(char, context, x + pos * this.size, y); }); } diff --git a/public/js/loaders/level.js b/public/js/loaders/level.js index 1c25eb0f..f2e3b477 100644 --- a/public/js/loaders/level.js +++ b/public/js/loaders/level.js @@ -1,5 +1,6 @@ -import {Matrix} from '../math.js'; +import {Matrix, Vec2} from '../math.js'; import Entity from '../Entity.js'; +import Trait from '../Trait.js'; import LevelTimer from '../traits/LevelTimer.js'; import Trigger from '../traits/Trigger.js'; import Level from '../Level.js'; @@ -9,16 +10,33 @@ import {loadMusicSheet} from './music.js'; import {loadSpriteSheet} from './sprite.js'; import {loadJSON} from '../loaders.js'; -function createTimer() { - const timer = new Entity(); - timer.addTrait(new LevelTimer()); - return timer; -} +function createSpawner() { + class Spawner extends Trait { + constructor() { + super(); + this.entities = []; + this.offsetX = 64; + } + + addEntity(entity) { + this.entities.push(entity); + this.entities.sort((a, b) => a.pos.x < b.pos.x ? -1 : 1); + } + + update(entity, gameContext, level) { + const cameraMaxX = level.camera.pos.x + level.camera.size.x + this.offsetX; + while (this.entities[0]) { + if (cameraMaxX > this.entities[0].pos.x) { + level.entities.add(this.entities.shift()); + } else { + break; + } + } + + } + } -function createTrigger() { - const entity = new Entity(); - entity.addTrait(new Trigger()); - return entity; + return new Spawner(); } function loadPattern(name) { @@ -26,9 +44,6 @@ function loadPattern(name) { } function setupBehavior(level) { - const timer = createTimer(); - level.entities.add(timer); - level.events.listen(LevelTimer.EVENT_TIMER_OK, () => { level.music.playTheme(); }); @@ -37,25 +52,62 @@ function setupBehavior(level) { }); } -function setupBackgrounds(levelSpec, level, backgroundSprites, patterns) { +function setupBackgrounds(levelSpec, level, patterns) { levelSpec.layers.forEach(layer => { const grid = createGrid(layer.tiles, patterns); - const backgroundLayer = createBackgroundLayer(level, grid, backgroundSprites); - level.comp.layers.push(backgroundLayer); level.tileCollider.addGrid(grid); }); } +function setupCamera(level) { + let maxX = 0; + let maxTileSize = 0; + for (const resolver of level.tileCollider.resolvers) { + if (resolver.tileSize > maxTileSize) { + maxTileSize = resolver.tileSize; + } + resolver.matrix.forEach((tile, x, y) => { + if (x > maxX) { + maxX = x; + } + }); + } + level.camera.max.x = (maxX + 1) * maxTileSize; +} + +function setupCheckpoints(levelSpec, level) { + if (!levelSpec.checkpoints) { + level.checkpoints.push(new Vec2(0, 0)); + return; + } + + levelSpec.checkpoints.forEach(([x, y]) => { + level.checkpoints.push(new Vec2(x, y)); + }); +} + function setupEntities(levelSpec, level, entityFactory) { - levelSpec.entities.forEach(({name, pos: [x, y]}) => { + const spawner = createSpawner(); + levelSpec.entities.forEach(({id, name, pos: [x, y], props}) => { const createEntity = entityFactory[name]; - const entity = createEntity(); + if (!createEntity) { + throw new Error(`No entity ${name}`); + } + + const entity = createEntity(props); entity.pos.set(x, y); - level.entities.add(entity); + + if (id) { + entity.id = id; + level.entities.add(entity); + } else { + spawner.addEntity(entity); + } }); - const spriteLayer = createSpriteLayer(level.entities); - level.comp.layers.push(spriteLayer); + const entityProxy = new Entity(); + entityProxy.addTrait(spawner); + level.entities.add(entityProxy); } function setupTriggers(levelSpec, level) { @@ -65,9 +117,11 @@ function setupTriggers(levelSpec, level) { for (const triggerSpec of levelSpec.triggers) { const trigger = new Trigger(); + trigger.conditions.push((entity, touches, gc, level) => { level.events.emit(Level.EVENT_TRIGGER, triggerSpec, entity, touches); }); + const entity = new Entity(); entity.addTrait(trigger); entity.size.set(64, 64); @@ -90,10 +144,21 @@ export function createLevelLoader(entityFactory) { level.name = name; level.music.setPlayer(musicPlayer); - setupBackgrounds(levelSpec, level, backgroundSprites, patterns); + setupBackgrounds(levelSpec, level, patterns); setupEntities(levelSpec, level, entityFactory); setupTriggers(levelSpec, level); + setupCheckpoints(levelSpec, level); + setupBehavior(level); + setupCamera(level); + + for (const resolver of level.tileCollider.resolvers) { + const backgroundLayer = createBackgroundLayer(level, resolver.matrix, backgroundSprites); + level.comp.layers.push(backgroundLayer); + } + + const spriteLayer = createSpriteLayer(level.entities); + level.comp.layers.splice(level.comp.layers.length - 1, 0, spriteLayer); return level; }); diff --git a/public/js/main.js b/public/js/main.js index efa9bfd8..9a0cfb77 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -1,18 +1,20 @@ import Level from './Level.js'; import Timer from './Timer.js'; +import Pipe from './traits/Pipe.js'; import {createLevelLoader} from './loaders/level.js'; import {loadFont} from './loaders/font.js'; import {loadEntities} from './entities.js'; -import {makePlayer, createPlayerEnv, findPlayers} from './player.js'; +import {makePlayer, bootstrapPlayer, resetPlayer, findPlayers} from './player.js'; import {setupKeyboard} from './input.js'; import {createColorLayer} from './layers/color.js'; import {createTextLayer} from './layers/text.js'; import {createCollisionLayer} from './layers/collision.js'; import {createDashboardLayer} from './layers/dashboard.js'; +import { createPlayerProgressLayer } from './layers/player-progress.js'; import SceneRunner from './SceneRunner.js'; import Scene from './Scene.js'; -import { createPlayerProgressLayer } from './layers/player-progress.js'; import TimedScene from './TimedScene.js'; +import { connectEntity } from './traits/Pipe.js'; async function main(canvas) { const videoContext = canvas.getContext('2d'); @@ -29,49 +31,80 @@ async function main(canvas) { const sceneRunner = new SceneRunner(); const mario = entityFactory.mario(); - makePlayer(mario, 'MARIO'); + makePlayer(mario, "MARIO"); + + window.mario = mario; const inputRouter = setupKeyboard(window); inputRouter.addReceiver(mario); - async function runLevel(name) { - const loadScreen = new Scene(); - loadScreen.comp.layers.push(createColorLayer('#000')); - loadScreen.comp.layers.push(createTextLayer(font, `Loading ${name}...`)); - sceneRunner.addScene(loadScreen); + function createLoadingScreen(name) { + const scene = new Scene(); + scene.comp.layers.push(createColorLayer('#000')); + scene.comp.layers.push(createTextLayer(font, `Loading ${name}...`)); + return scene; + } + + async function setupLevel(name) { + const loadingScreen = createLoadingScreen(name); + sceneRunner.addScene(loadingScreen); sceneRunner.runNext(); const level = await loadLevel(name); + bootstrapPlayer(mario, level); level.events.listen(Level.EVENT_TRIGGER, (spec, trigger, touches) => { if (spec.type === "goto") { for (const _ of findPlayers(touches)) { - runLevel(spec.name); + startWorld(spec.name); return; } } }); - const playerProgressLayer = createPlayerProgressLayer(font, level); - const dashboardLayer = createDashboardLayer(font, level); + level.events.listen(Pipe.EVENT_PIPE_COMPLETE, async pipe => { + if (pipe.props.goesTo) { + const nextLevel = await setupLevel(pipe.props.goesTo.name); + sceneRunner.addScene(nextLevel); + sceneRunner.runNext(); + if (pipe.props.backTo) { + console.log(pipe.props); + nextLevel.events.listen(Level.EVENT_COMPLETE, async () => { + const level = await setupLevel(name); + const exitPipe = level.entities.get(pipe.props.backTo); + connectEntity(exitPipe, mario); + sceneRunner.addScene(level); + sceneRunner.runNext(); + }); + } + } else { + level.events.emit(Level.EVENT_COMPLETE); + } + }); - mario.pos.set(0, 0); - level.entities.add(mario); + level.comp.layers.push(createCollisionLayer(level)); - const playerEnv = createPlayerEnv(mario); - level.entities.add(playerEnv); + const dashboardLayer = createDashboardLayer(font, mario); + level.comp.layers.push(dashboardLayer); + + return level; + } + + async function startWorld(name) { + const level = await setupLevel(name); + resetPlayer(mario, name); + + const playerProgressLayer = createPlayerProgressLayer(font, level); + const dashboardLayer = createDashboardLayer(font, mario); const waitScreen = new TimedScene(); - waitScreen.countDown = 2; + waitScreen.countDown = 4; waitScreen.comp.layers.push(createColorLayer('#000')); waitScreen.comp.layers.push(dashboardLayer); waitScreen.comp.layers.push(playerProgressLayer); - sceneRunner.addScene(waitScreen); - level.comp.layers.push(createCollisionLayer(level)); - level.comp.layers.push(dashboardLayer); + sceneRunner.addScene(waitScreen); sceneRunner.addScene(level); - sceneRunner.runNext(); } @@ -80,17 +113,19 @@ async function main(canvas) { videoContext, entityFactory, deltaTime: null, + tick: 0, }; const timer = new Timer(1/60); timer.update = function update(deltaTime) { + gameContext.tick++; gameContext.deltaTime = deltaTime; sceneRunner.update(gameContext); } timer.start(); - runLevel('debug-progression'); + startWorld('1-1'); } const canvas = document.getElementById('screen'); diff --git a/public/js/math.js b/public/js/math.js index 9e0b9506..93c301fa 100644 --- a/public/js/math.js +++ b/public/js/math.js @@ -45,8 +45,34 @@ export class Vec2 { this.y = vec2.y; } + equals(vec2) { + return this.x === vec2.x && this.y === vec2.y; + } + + distance(v) { + const dx = this.x - v.x, dy = this.y - v.y; + return Math.sqrt(dx * dx + dy * dy); + } + set(x, y) { this.x = x; this.y = y; } } + +export function clamp(value, min, max) { + if (value > max) { + return max; + } + if (value < min) { + return min; + } + return value +} + +export const Direction = { + UP: new Vec2(0, -1), + DOWN: new Vec2(0, 1), + RIGHT: new Vec2(1, 0), + LEFT: new Vec2(-1, 0), +}; diff --git a/public/js/player.js b/public/js/player.js index 511a7f4b..33c69666 100644 --- a/public/js/player.js +++ b/public/js/player.js @@ -1,20 +1,24 @@ -import Entity from './Entity.js'; import Player from './traits/Player.js'; -import PlayerController from './traits/PlayerController.js'; - -export function createPlayerEnv(playerEntity) { - const playerEnv = new Entity(); - const playerControl = new PlayerController(); - playerControl.checkpoint.set(64, 64); - playerControl.setPlayer(playerEntity); - playerEnv.addTrait(playerControl); - return playerEnv; -} +import LevelTimer from './traits/LevelTimer.js'; export function makePlayer(entity, name) { const player = new Player(); - player.name = name; + player.name = "MARIO"; entity.addTrait(player); + + const timer = new LevelTimer(); + entity.addTrait(timer); +} + +export function resetPlayer(entity, worldName) { + entity.traits.get(LevelTimer).reset(); + entity.traits.get(Player).world = worldName; +} + +export function bootstrapPlayer(entity, level) { + entity.traits.get(LevelTimer).hurryEmitted = null; + entity.pos.copy(level.checkpoints[0]); + level.entities.add(entity); } export function* findPlayers(entities) { diff --git a/public/js/tiles/brick.js b/public/js/tiles/brick.js index 64fff1a8..fcc59104 100644 --- a/public/js/tiles/brick.js +++ b/public/js/tiles/brick.js @@ -1,8 +1,40 @@ -import {Sides} from '../Entity.js'; +import { Vec2 } from '../math.js'; +import { Sides } from '../Entity.js'; import Player from "../traits/Player.js"; -function handleX({entity, match}) { +function centerEntity(entity, pos) { + entity.pos.x = pos.x - entity.size.x / 2; + entity.pos.y = pos.y - entity.size.y / 2; +} + +function getMatchCenter(match) { + return new Vec2( + match.x1 + ((match.x2 - match.x1) / 2), + match.y1 + ((match.y2 - match.y1) / 2), + ); +} + +function addShrapnel(level, gameContext, match) { + const center = getMatchCenter(match); + const bricks = []; + for (let i = 0; i < 4; i++) { + const brick = gameContext.entityFactory.brickShrapnel(); + centerEntity(brick, center); + level.entities.add(brick); + bricks.push(brick); + } + + const spreadH = 60; + const spreadV = 400; + bricks[0].sounds.add('break'); + bricks[0].vel.set(-spreadH, -spreadV * 1.2); + bricks[1].vel.set(-spreadH, -spreadV); + bricks[2].vel.set(spreadH, -spreadV * 1.2); + bricks[3].vel.set(spreadH, -spreadV); +} + +function handleX({entity, match}) { if (entity.vel.x > 0) { if (entity.bounds.right > match.x1) { entity.obstruct(Sides.RIGHT, match); @@ -23,11 +55,7 @@ function handleY({entity, match, resolver, gameContext, level}) { if (entity.traits.has(Player)) { const grid = resolver.matrix; grid.delete(match.indexX, match.indexY); - - const goomba = gameContext.entityFactory.goomba(); - goomba.vel.set(50, -400); - goomba.pos.set(entity.pos.x, match.y1); - level.entities.add(goomba); + addShrapnel(level, gameContext, match); } if (entity.bounds.top < match.y2) { diff --git a/public/js/tiles/coin.js b/public/js/tiles/coin.js index 2a1335aa..196c5e12 100644 --- a/public/js/tiles/coin.js +++ b/public/js/tiles/coin.js @@ -1,6 +1,9 @@ +import Player from "../traits/Player.js"; + function handle({entity, match, resolver}) { - if (entity.player) { - entity.player.addCoins(1); + const player = entity.traits.get(Player); + if (player) { + player.addCoins(1); const grid = resolver.matrix; grid.delete(match.indexX, match.indexY); } diff --git a/public/js/traits/Killable.js b/public/js/traits/Killable.js index 41268e69..f0b60725 100644 --- a/public/js/traits/Killable.js +++ b/public/js/traits/Killable.js @@ -1,4 +1,3 @@ -import {Sides} from '../Entity.js'; import Trait from '../Trait.js'; export default class Killable extends Trait { diff --git a/public/js/traits/LevelTimer.js b/public/js/traits/LevelTimer.js index 98c10eef..34d46ba9 100644 --- a/public/js/traits/LevelTimer.js +++ b/public/js/traits/LevelTimer.js @@ -1,19 +1,30 @@ import Trait from '../Trait.js'; +const MARK = Symbol('level timer earmark'); + export default class LevelTimer extends Trait { static EVENT_TIMER_HURRY = Symbol('timer hurry'); static EVENT_TIMER_OK = Symbol('timer ok'); constructor() { super(); - this.totalTime = 300; + this.totalTime = 400; this.currentTime = this.totalTime; this.hurryTime = 100; this.hurryEmitted = null; } + reset() { + this.currentTime = this.totalTime; + } + update(entity, {deltaTime}, level) { - this.currentTime -= deltaTime * 2; + this.currentTime -= deltaTime * 2.5; + + if (!level[MARK]) { + this.hurryEmitted = null; + } + if (this.hurryEmitted !== true && this.currentTime < this.hurryTime) { level.events.emit(LevelTimer.EVENT_TIMER_HURRY); this.hurryEmitted = true; @@ -22,5 +33,7 @@ export default class LevelTimer extends Trait { level.events.emit(LevelTimer.EVENT_TIMER_OK); this.hurryEmitted = false; } + + level[MARK] = true; } } diff --git a/public/js/traits/LifeLimit.js b/public/js/traits/LifeLimit.js new file mode 100644 index 00000000..703b9e36 --- /dev/null +++ b/public/js/traits/LifeLimit.js @@ -0,0 +1,16 @@ +import Trait from '../Trait.js'; + +export default class LifeLimit extends Trait { + constructor() { + super(); + this.time = 2; + } + + update(entity, _, level) { + if (entity.lifetime > this.time) { + this.queue(() => { + level.entities.delete(entity); + }); + } + } +} diff --git a/public/js/traits/Pipe.js b/public/js/traits/Pipe.js new file mode 100644 index 00000000..5a1e1501 --- /dev/null +++ b/public/js/traits/Pipe.js @@ -0,0 +1,103 @@ +import { Vec2, Direction } from '../math.js'; +import { Sides, Align } from '../Entity.js'; +import Trait from '../Trait.js'; +import PipeTraveller from './PipeTraveller.js'; + +function createTravellerState() { + return { + time: 0, + start: new Vec2(), + end: new Vec2(), + }; +} + +export function connectEntity(pipeEntity, travellerEntity) { + const pipeTrait = pipeEntity.traits.get(Pipe); + Align.center(pipeEntity, travellerEntity); + if (pipeTrait.direction.equals(Direction.UP)) { + Align.bottom(pipeEntity, travellerEntity); + } + else if (pipeTrait.direction.equals(Direction.DOWN)) { + Align.top(pipeEntity, travellerEntity); + } + else if (pipeTrait.direction.equals(Direction.LEFT)) { + Align.right(pipeEntity, travellerEntity); + } + else if (pipeTrait.direction.equals(Direction.RIGHT)) { + Align.left(pipeEntity, travellerEntity); + } + pipeTrait.addTraveller(pipeEntity, travellerEntity); +} + +export default class Pipe extends Trait { + static EVENT_PIPE_COMPLETE = Symbol('pipe complete'); + + constructor() { + super(); + this.duration = 1; + this.direction = new Vec2(0, 0); + this.travellers = new Map(); + } + + addTraveller(pipe, traveller) { + + const pipeTraveller = traveller.traits.get(PipeTraveller); + pipeTraveller.distance.set(0, 0); + + const state = createTravellerState(); + state.start.copy(traveller.pos); + state.end.copy(traveller.pos); + state.end.x += this.direction.x * pipe.size.x; + state.end.y += this.direction.y * pipe.size.y; + this.travellers.set(traveller, state); + } + + collides(pipe, traveller) { + if (!traveller.traits.has(PipeTraveller)) { + return; + } + + if (this.travellers.has(traveller)) { + return; + } + + if (traveller.traits.get(PipeTraveller).direction.equals(this.direction)) { + const tBounds = traveller.bounds; + const pBounds = pipe.bounds; + if (this.direction.x && + (tBounds.top < pBounds.top || tBounds.bottom > pBounds.bottom)) { + return; + } + if (this.direction.y && + (tBounds.left < pBounds.left || tBounds.right > pBounds.right)) { + return; + } + pipe.sounds.add('pipe'); + this.addTraveller(pipe, traveller); + } + } + + update(pipe, gameContext, level) { + const {deltaTime} = gameContext; + for (const [traveller, state] of this.travellers.entries()) { + state.time += deltaTime; + const progress = state.time / this.duration; + traveller.pos.x = state.start.x + (state.end.x - state.start.x) * progress; + traveller.pos.y = state.start.y + (state.end.y - state.start.y) * progress; + traveller.vel.set(0, 0); + + const pipeTraveller = traveller.traits.get(PipeTraveller); + pipeTraveller.movement.copy(this.direction); + pipeTraveller.distance.x = traveller.pos.x - state.start.x; + pipeTraveller.distance.y = traveller.pos.y - state.start.y; + + if (state.time > this.duration) { + this.travellers.delete(traveller); + pipeTraveller.movement.set(0, 0); + pipeTraveller.distance.set(0, 0); + + level.events.emit(Pipe.EVENT_PIPE_COMPLETE, pipe, traveller); + } + } + } +} diff --git a/public/js/traits/PipeTraveller.js b/public/js/traits/PipeTraveller.js new file mode 100644 index 00000000..8144c815 --- /dev/null +++ b/public/js/traits/PipeTraveller.js @@ -0,0 +1,11 @@ +import { Vec2 } from '../math.js'; +import Trait from '../Trait.js'; + +export default class PipeTraveller extends Trait { + constructor() { + super(); + this.direction = new Vec2(0, 0); + this.movement = new Vec2(0, 0); + this.distance = new Vec2(0, 0); + } +} diff --git a/public/js/traits/Player.js b/public/js/traits/Player.js index 3055b4a2..ead8222e 100644 --- a/public/js/traits/Player.js +++ b/public/js/traits/Player.js @@ -7,6 +7,7 @@ export default class Player extends Trait { constructor() { super(); this.name = "UNNAMED"; + this.world = "UNKNOWN"; this.coins = 0; this.lives = 3; this.score = 0; diff --git a/public/js/traits/PlayerController.js b/public/js/traits/PlayerController.js deleted file mode 100644 index 6ec88832..00000000 --- a/public/js/traits/PlayerController.js +++ /dev/null @@ -1,22 +0,0 @@ -import Trait from '../Trait.js'; -import {Vec2} from '../math.js'; - -export default class PlayerController extends Trait { - constructor() { - super(); - this.checkpoint = new Vec2(0, 0); - this.player = null; - } - - setPlayer(entity) { - this.player = entity; - } - - update(entity, {deltaTime}, level) { - if (!level.entities.has(this.player)) { - this.player.killable.revive(); - this.player.pos.set(this.checkpoint.x, this.checkpoint.y); - level.entities.add(this.player); - } - } -} diff --git a/public/js/traits/Pole.js b/public/js/traits/Pole.js new file mode 100644 index 00000000..fdf228eb --- /dev/null +++ b/public/js/traits/Pole.js @@ -0,0 +1,69 @@ +import { Vec2, Direction } from '../math.js'; +import { Sides, Align } from '../Entity.js'; +import Trait from '../Trait.js'; +import PoleTraveller from './PoleTraveller.js'; + +function createTravellerState() { + return { + current: new Vec2(), + goal: new Vec2(), + done: false, + }; +} + +export default class Pole extends Trait { + constructor() { + super(); + this.velocity = 100; + this.travellers = new Map(); + } + + addTraveller(pole, traveller) { + pole.sounds.add('ride'); + + const poleTraveller = traveller.traits.get(PoleTraveller); + poleTraveller.distance = 0; + + const state = createTravellerState(); + state.current.x = pole.bounds.meridian; + state.current.y = traveller.bounds.bottom; + state.goal.x = state.current.x; + state.goal.y = pole.bounds.bottom; + this.travellers.set(traveller, state); + } + + collides(pole, traveller) { + if (!traveller.traits.has(PoleTraveller)) { + return; + } + + if (this.travellers.has(traveller)) { + return; + } + + this.addTraveller(pole, traveller); + } + + update(pole, gameContext, level) { + const {deltaTime} = gameContext; + const distance = this.velocity * deltaTime; + for (const [traveller, state] of this.travellers.entries()) { + if (!state.done) { + state.current.y += distance; + traveller.bounds.right = state.current.x; + traveller.bounds.bottom = state.current.y; + + const poleTraveller = traveller.traits.get(PoleTraveller); + poleTraveller.distance += distance; + + if (traveller.bounds.bottom > state.goal.y) { + state.done = true; + traveller.bounds.bottom = state.goal.y; + poleTraveller.distance = 0; + } + } else if (!pole.bounds.overlaps(traveller.bounds)) { + this.travellers.delete(traveller); + } + } + } +} diff --git a/public/js/traits/PoleTraveller.js b/public/js/traits/PoleTraveller.js new file mode 100644 index 00000000..0ea40c9d --- /dev/null +++ b/public/js/traits/PoleTraveller.js @@ -0,0 +1,9 @@ +import { Vec2 } from '../math.js'; +import Trait from '../Trait.js'; + +export default class PoleTraveller extends Trait { + constructor() { + super(); + this.distance = 0; + } +} diff --git a/public/js/traits/Stomper.js b/public/js/traits/Stomper.js index 8e2475fc..89b13207 100644 --- a/public/js/traits/Stomper.js +++ b/public/js/traits/Stomper.js @@ -1,5 +1,5 @@ -import {Sides} from '../Entity.js'; import Trait from '../Trait.js'; +import Killable from './Killable.js'; export default class Stomper extends Trait { static EVENT_STOMP = Symbol('stomp'); @@ -15,7 +15,7 @@ export default class Stomper extends Trait { } collides(us, them) { - if (!them.killable || them.killable.dead) { + if (!them.traits.has(Killable) || them.traits.get(Killable).dead) { return; } diff --git a/public/js/traits/Velocity.js b/public/js/traits/Velocity.js index 3b744a2b..7f519b5d 100644 --- a/public/js/traits/Velocity.js +++ b/public/js/traits/Velocity.js @@ -1,10 +1,6 @@ import Trait from '../Trait.js'; export default class Velocity extends Trait { - constructor() { - super(); - } - update(entity, {deltaTime}, level) { entity.pos.x += entity.vel.x * deltaTime; entity.pos.y += entity.vel.y * deltaTime; diff --git a/public/levels/1-1.json b/public/levels/1-1.json index b9f2130b..ba9c3159 100644 --- a/public/levels/1-1.json +++ b/public/levels/1-1.json @@ -2,267 +2,292 @@ "spriteSheet": "overworld", "musicSheet": "overworld", "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], "layers": [ { "tiles": [ { - "name": "sky", + "style": "sky", "ranges": [ - [ - 0, 212, - 0, 13 - ] + [0, 212, 0, 15] ] }, { - "name": "ground", - "type": "ground", + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 69, 13, 2], + [71, 15, 13, 2], + [89, 64, 13, 2], + [155, 57, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "cloud-single", "ranges": [ - [ - 0, 212, - 13, 2 - ] + [8, 3], + [19, 2], + [56, 3], + [67, 2], + [104, 3], + [115, 2], + [152, 3], + [163, 2], + [200, 3] ] }, { - "name": "sky", + "pattern": "cloud-double", "ranges": [ - [ - 75, 2, - 13, 2 - ], - [ - 92, 2, - 13, 2 - ], - [ - 157, 2, - 13, 2 - ] + [36, 2], + [84, 2], + [132, 2], + [180, 2] ] }, { - "name": "ground", - "type": "ground", + "pattern": "cloud-triple", "ranges": [ - [ - 5, 3, - 9, 1 - ], - [ - 29, 5 - ], - [ - 5, 7, - 9 - ], - [ - 12, 6, - 11, 1 - ], - [ - 2, 1, - 11, 1 - ], - [ - 10, 2, - 10, 1 - ], - [ - 10, 2, - 10 - ], - [ - 9, 1, - 0, 7 - ] + [27, 3], + [75, 3], + [123, 3], + [171, 3] ] - } - ] - }, - { - "tiles": [ + }, { - "name": "bricks", - "type": "brick", + "pattern": "bush-single", "ranges": [ - [ - 27, 5, - 9 - ], - [ - 83, 3, - 9 - ], - [ - 86, 6, - 5 - ], - [ - 96, 3, - 5 - ], - [ - 99, 9 - ], - [ - 105, 2, - 9 - ], - [ - 123, 5 - ], - [ - 126, 3, - 5 - ], - [ - 132, 4, - 5 - ], - [ - 133, 2, - 9 - ], - [ - 171, 4, - 9 - ] + [23, 12], + [71, 12], + [119, 12], + [167, 12] ] }, { - "name": "chance", - "type": "ground", + "pattern": "bush-double", "ranges": [ - [2, 2], - + [41, 12], + [89, 12], + [137, 12] + ] + }, + { + "pattern": "bush-triple", + "ranges": [ + [11, 12], + [59, 12], + [107, 12] + ] + }, + { + "style": "bush-3", + "ranges": [ + [159, 12], + [207, 12] + ] + }, + { + "pattern": "hill-small", + "ranges": [ + [16, 11], + [64, 11], + [112, 11], + [160, 11], + [208, 11] + ] + }, + { + "pattern": "hill-large", + "ranges": [ + [0, 10], + [48, 10], + [96, 10], + [144, 10], + [192, 10] + ] + }, + { + "style": "metal", + "behavior": "ground", + "ranges": [ + [64, 8] + ] + }, + { + "style": "bricks-top", + "behavior": "brick", + "ranges": [ + [20, 5, 9], + [77, 3, 9], + [80, 8, 5], + [91, 4, 5], + [94, 9], + [100, 2, 9], + [118, 9], + [121, 3, 5], + [128, 4, 5], + [129, 2, 9], + [168, 4, 9] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [16, 9], + [22, 5], + [21, 9], [23, 9], - [28, 9], - [30, 9], - [29, 5], - [84, 9], - [99, 5], - - [114, 5], - [111, 9], - [114, 9], - [117, 9], - - [133, 2, 5], - - [173, 9] - + [78, 9], + [94, 5], + [106, 9], + [109, 5], + [109, 9], + [112, 9], + [129, 2, 5], + [170, 9] ] }, { - "name": "chocolate", - "type": "ground", + "pattern": "chocolate-stairs-4h", "ranges": [ - [141, 1, 9], - [140, 2, 10], - [139, 3, 11], - [138, 4, 12], - - [144, 1, 9], - [144, 2, 10], - [144, 3, 11], - [144, 4, 12], - - [155, 2, 9], - [154, 3, 10], - [153, 4, 11], - [152, 5, 12], - - [159, 1, 9], - [159, 2, 10], - [159, 3, 11], - [159, 4, 12], - - [191, 2, 5], - [190, 3, 6], - [189, 4, 7], - [188, 5, 8], - [187, 6, 9], - [186, 7, 10], - [185, 8, 11], - [184, 9, 12] + [134, 9], + [148, 9] ] }, { - "pattern": "pipe-2h", + "pattern": "chocolate-stairs-4h-reverse", "ranges": [ - [35, 11], - [167, 11], - [182, 11] + [140, 9], + [155, 9] ] }, { - "pattern": "pipe-3h", + "pattern": "chocolate-stairs-final", "ranges": [ - [45, 10] + [181, 5] ] }, { - "pattern": "pipe-4h", + "pattern": "chocolate-stack-4h", "ranges": [ - [53, 9], - [64, 9] + [152, 1, 9] ] }, { - "pattern": "cloud-single", + "pattern": "flag-pole-green", "ranges": [ - [2, 2], - [25, 2], - [35, 3], - [44, 2], - [64, 3], - [74, 2], - [80, 3], - [90, 2], - [108, 3], - [118, 2], - [128, 3], - [138, 2] + [198, 2] ] - } - ] - }, - { - "tiles": [ + }, + { + "pattern": "castle-small", + "ranges": [ + [202, 8] + ] + }, + { + "pattern": "pipe-2h", + "ranges": [ + [28, 11], + [163, 11], + [179, 11] + ] + }, + { + "pattern": "pipe-3h", + "ranges": [ + [38, 10] + ] + }, { - "pattern": "cannon-2h", + "pattern": "pipe-4h", "ranges": [ - [ - 6, 7 - ] + [46, 9], + [57, 9] ] } + ] } ], "entities": [ { - "name": "koopa", - "pos": [260, 0] + "name": "goomba-brown", + "pos": [352, 192] }, { - "name": "goomba", - "pos": [220, 0] + "name": "goomba-brown", + "pos": [640, 192] }, { - "name": "cannon", - "pos": [96, 112] - } - ], - - "triggers": [ + "name": "goomba-brown", + "pos": [816, 192] + }, { - "type": "goto", - "name": "1-2", - "pos": [64, 64] + "name": "goomba-brown", + "pos": [840, 192] + }, + { + "name": "goomba-brown", + "pos": [1280, 64] + }, + { + "name": "goomba-brown", + "pos": [1312, 64] + }, + { + "name": "goomba-brown", + "pos": [1552, 192] + }, + { + "name": "goomba-brown", + "pos": [1576, 192] + }, + { + "name": "koopa-green", + "pos": [1712, 185] + }, + { + "name": "goomba-brown", + "pos": [1824, 192] + }, + { + "name": "goomba-brown", + "pos": [1848, 192] + }, + { + "name": "goomba-brown", + "pos": [1984, 192] + }, + { + "name": "goomba-brown", + "pos": [2008, 192] + }, + { + "name": "goomba-brown", + "pos": [2048, 192] + }, + { + "name": "goomba-brown", + "pos": [2072, 192] + }, + { + "name": "goomba-brown", + "pos": [2784, 192] + }, + { + "name": "goomba-brown", + "pos": [2808, 192] } - ] + ], + "triggers": [] } diff --git a/public/levels/1-2.json b/public/levels/1-2.json index 3a834882..97f1fc39 100644 --- a/public/levels/1-2.json +++ b/public/levels/1-2.json @@ -1,35 +1,239 @@ { "spriteSheet": "underworld", "musicSheet": "underworld", - "patternSheet": "overworld-pattern", + "patternSheet": "underworld-pattern", + "checkpoints": [ + [40, 48] + ], "layers": [ { "tiles": [ { - "name": "sky", + "style": "sky", "ranges": [ - [ - 0, 212, - 0, 13 - ] + [0, 192, 0, 15] ] }, { - "name": "ground", - "type": "ground", + "style": "ground", + "behavior": "ground", "ranges": [ - [ - 0, 212, - 13, 2 - ] + [0, 80, 13, 2], + [83, 37, 13, 2], + [122, 2, 13, 2], + [126, 12, 13, 2], + [145, 8, 13, 2], + [160, 32, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "style": "bricks", + "behavior": "ground", + "ranges": [ + [0, 1 ,2, 11], + [6, 132 ,2], + [39, 1, 7, 3], + [41, 1, 7, 3], + [44, 1, 7, 3], + [46, 1, 8, 2], + [40, 9], + [42, 2, 7], + [45, 9], + [52, 2, 5, 5], + [54, 2, 3, 2], + [54, 2, 9, 3], + [58, 6, 3, 2], + [62, 2, 5, 5], + [58, 4, 9], + [66, 4, 3, 2], + [67, 1, 5, 5], + [68, 2, 9], + [72, 2, 5, 5], + [76, 4, 3, 2], + [76, 4, 9], + [84, 6, 7, 2], + [122, 2, 11, 2], + [145, 6, 8], + [161, 7, 2], + [160, 17, 10, 3], + [170, 7, 2, 8], + [177, 10, 2], + [190, 2, 2, 11] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [10, 5, 9] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [41, 4, 5], + [40, 8], + [45, 8], + [58, 4, 8], + [68, 8], + [84, 6, 5] + ] + }, + { + "style": "metal", + "behavior": "ground", + "ranges": [ + [29, 8], + [46, 7], + [69, 8], + [73, 8], + [89, 2], + [150, 8] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [17, 12] + ] + }, + { + "pattern": "chocolate-stack-2h", + "ranges": [ + [19, 11], + [33, 11] + ] + }, + { + "pattern": "chocolate-stack-3h", + "ranges": [ + [21, 10], + [27, 10], + [31, 10] + ] + }, + { + "pattern": "chocolate-stack-4h", + "ranges": [ + [23, 9], + [25, 9], + [137, 9] + ] + }, + { + "pattern": "pipe-3h", + "ranges": [ + [103, 10], + [178, 10], + [182, 10], + [186, 10] + ] + }, + { + "pattern": "pipe-4h", + "ranges": [ + [109, 9] + ] + }, + { + "pattern": "pipe-2h", + "ranges": [ + [115, 11] + ] + }, + { + "pattern": "chocolate-stairs-4h", + "ranges": [ + [133, 9] + ] + }, + { + "pattern": "exit-pipe-8h", + "ranges": [ + [166, 2] ] } ] } ], - "entities": [], + "entities": [ + { + "name": "goomba-blue", + "pos": [256, 192] + }, + { + "name": "goomba-blue", + "pos": [272, 192] + }, + { + "name": "goomba-blue", + "pos": [464, 192] + }, + { + "name": "koopa-blue", + "pos": [704, 185] + }, + { + "name": "koopa-blue", + "pos": [728, 185] + }, + { + "name": "koopa-blue", + "pos": [944, 185] + }, + { + "name": "goomba-blue", + "pos": [992, 192] + }, + { + "name": "goomba-blue", + "pos": [1024, 192] + }, + { + "name": "goomba-blue", + "pos": [1168, 64] + }, + { + "name": "goomba-blue", + "pos": [1216, 128] + }, + { + "name": "goomba-blue", + "pos": [1240, 128] + }, + { + "name": "goomba-blue", + "pos": [1548, 192] + }, + { + "name": "goomba-blue", + "pos": [1608, 192] + }, + { + "name": "goomba-blue", + "pos": [1632, 192] + }, + { + "name": "goomba-blue", + "pos": [1808, 192] + }, + { + "name": "goomba-blue", + "pos": [2160, 144] + }, + { + "name": "goomba-blue", + "pos": [2184, 128] + } + ], "triggers": [ { diff --git a/public/levels/1-3.json b/public/levels/1-3.json new file mode 100644 index 00000000..8e3699fb --- /dev/null +++ b/public/levels/1-3.json @@ -0,0 +1,208 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 166, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 13, 2], + [129, 37, 13, 2] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [59, 10] + ] + } + ] + }, + { + "tiles": [ + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [27, 3, 4], + [33, 11], + [50, 2, 6], + [60, 4, 4], + [85, 2, 5], + [93, 2, 4], + [97, 2, 4], + [113, 3, 12], + [120, 2, 5] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "cloud-double", + "ranges": [ + [3, 3], + [19, 2], + [51, 3], + [99, 3], + [114, 2], + [147, 3], + [162, 2] + ] + }, + { + "pattern": "cloud-single", + "ranges": [ + [9, 7], + [35, 7], + [38, 6], + [46, 11], + [57, 7], + [76, 11], + [83, 7], + [86, 6], + [94, 11], + [124, 11], + [131, 7], + [134, 6], + [142, 11], + [153, 7] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [138, 2, 9, 4], + [140, 2, 7, 6], + [142, 2, 5, 8] + ] + }, + { + "pattern": "castle-small", + "ranges": [ + [0, 8] + ] + }, + { + "pattern": "castle-large", + "ranges": [ + [155, 2] + ] + }, + { + "pattern": "castle-wall-6h", + "ranges": [ + [164, 2, 7] + ] + }, + { + "pattern": "flag-pole-green", + "ranges": [ + [152, 2] + ] + }, + { + "style": "dirt", + "ranges": [ + [19, 2, 13, 2], + [25, 6, 10, 5], + [27, 3, 6, 3], + [33, 1, 13, 2], + [36, 3, 9, 6], + [41, 5, 5, 10], + [51, 2, 14], + [60, 3, 14], + [61, 2, 6, 7], + [66, 3, 14], + [71, 1, 10, 5], + [77, 4, 7, 8], + [99, 2, 12, 3], + [105, 6, 8, 7], + [114, 1, 14], + [117, 2, 10, 5], + [123, 2, 10, 5] + ] + }, + { + "pattern": "grass-top-3w", + "ranges": [ + [32, 12], + [70, 9], + [113, 13] + ] + }, + { + "pattern": "grass-top-4w", + "ranges": [ + [18, 12], + [50, 13], + [60, 5], + [98, 11], + [116, 9], + [122, 9] + ] + }, + { + "pattern": "grass-top-5w", + "ranges": [ + [26, 5], + [35, 8], + [59, 13], + [65, 13] + ] + }, + { + "pattern": "grass-top-6w", + "ranges": [ + [76, 6] + ] + }, + { + "pattern": "grass-top-7w", + "ranges": [ + [40, 4] + ] + }, + { + "pattern": "grass-top-8w", + "ranges": [ + [24, 9], + [104, 7] + ] + } + ] + } + ], + + "entities": [ + { + "name": "goomba-brown", + "pos": [704, 48] + }, + { + "name": "goomba-brown", + "pos": [736, 48] + }, + { + "name": "goomba-brown", + "pos": [1280, 64] + } + ], + "triggers": [] +} diff --git a/public/levels/1-4.json b/public/levels/1-4.json new file mode 100644 index 00000000..63504370 --- /dev/null +++ b/public/levels/1-4.json @@ -0,0 +1,127 @@ +{ + "spriteSheet": "castle", + "musicSheet": "castle", + "patternSheet": "castle-pattern", + "checkpoints": [ + [40, 96] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 161, 0, 15] + ] + } + ] + }, + { + "tiles": [ + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 25, 2, 3], + [0, 13, 10, 5], + [15, 12, 10, 5], + [30, 3, 10, 5], + [25, 13, 2], + [24, 5], + [36, 37, 9, 6], + [38, 35, 2, 4], + [73, 32, 10, 5], + [73, 88, 2], + [81, 3], + [89, 3], + [98, 7, 3, 2], + [105, 24, 13, 2], + [117, 4, 10, 3], + [124, 5, 3, 2], + [124, 5, 10, 3], + [142, 3, 9, 6], + [143, 2, 3, 2], + [145, 16, 13, 2] + ] + }, + { + "pattern": "entrance-stairs", + "ranges": [ + [0, 6] + ] + }, + { + "style": "waves", + "ranges": [ + [13, 2, 12], + [27, 3, 13], + [33, 3, 13], + [129, 13, 13] + ] + }, + { + "style": "tile-red", + "ranges": [ + [13, 2, 13, 2], + [27, 3, 14], + [33, 3, 14], + [129, 13, 14] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [31, 6] + ] + }, + { + "style": "metal", + "behavior": "ground", + "ranges": [ + [107, 9], + [108, 5], + [110, 9], + [111, 5], + [113, 9], + [114, 5] + ] + }, + { + "style": "metal-alt", + "behavior": "ground", + "ranges": [ + [24, 6], + [31, 10], + [38, 6], + [50, 6], + [61, 6], + [68, 6], + [77, 9], + [81, 4], + [85, 9], + [89, 4], + [93, 9] + ] + }, + { + "pattern": "bridge", + "behavior": "ground", + "ranges": [ + [129, 9] + ] + }, + { + "pattern": "toad", + "ranges": [ + [154, 11] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/2-1.json b/public/levels/2-1.json new file mode 100644 index 00000000..30fbfe99 --- /dev/null +++ b/public/levels/2-1.json @@ -0,0 +1,339 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 214, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 92, 13, 2], + [96, 10, 13, 2], + [109, 30, 13, 2], + [142, 10, 13, 2], + [154, 60, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "style": "bricks-top", + "behavior": "ground", + "ranges": [ + [15, 3, 9], + [28, 4, 5], + [68, 9], + [69, 4, 5], + [81, 5, 5], + [92, 4, 5], + [125, 4, 5], + [161, 9], + [164, 5, 5], + [172, 5], + [185, 2, 9] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [53, 5, 5], + [53, 5, 9], + [79, 4, 9], + [85, 3, 9], + [170, 9] + ] + }, + { + "style": "metal", + "behavior": "ground", + "ranges": [ + [17, 9], + [28, 5], + [28, 9], + [69, 5], + [125, 5], + [186, 5] + ] + }, + { + "pattern": "castle-large", + "ranges": [ + [-2, 2] + ] + }, + { + "pattern": "cloud-single", + "ranges": [ + [18, 3], + [27, 2], + [45, 2], + [66, 3], + [75, 2], + [93, 2], + [114, 3], + [123, 2], + [141, 2], + [162, 3], + [171, 2], + [189, 2], + [210, 3] + ] + }, + { + "pattern": "cloud-double", + "ranges": [ + [30, 3], + [48, 3], + [78, 3], + [96, 3], + [126, 3], + [144, 3], + [174, 3], + [192, 3] + ] + }, + + { + "pattern": "tree-small", + "ranges": [ + [11, 11], + [40, 11], + [59, 11], + [71, 11], + [72, 11], + [88, 11], + [119, 11], + [120, 11], + [136, 11], + [155, 11], + [167, 11], + [168, 11], + [184, 11], + [203, 11] + ] + }, + { + "pattern": "tree-large", + "ranges": [ + [13, 10], + [43, 10], + [61, 10], + [69, 10], + [91, 10], + [109, 10], + [117, 10], + [157, 10], + [165, 10], + [187, 10], + [213, 10] + ] + }, + { + "style": "tree-large-top", + "ranges": [ + [21, 10] + ] + }, + { + "style": "fence", + "ranges": [ + [14, 4, 12], + [38, 2, 12], + [41, 12], + [62, 4, 12], + [86, 2, 12], + [89, 12], + [110, 4, 12], + [134, 2, 12], + [137, 12], + [158, 4, 12], + [182, 2, 12], + [185, 12], + [209, 12] + ] + }, + { + "pattern": "chocolate-stairs-4h", + "ranges": [ + [20, 9] + ] + }, + { + "pattern": "chocolate-stack-2h", + "ranges": [ + [35, 11] + ] + }, { + "pattern": "chocolate-stack-3h", + "ranges": [ + [154, 10] + ] + }, + { + "pattern": "chocolate-stack-4h", + "ranges": [ + [34, 9] + ] + }, + { + "pattern": "chocolate-stack-5h", + "ranges": [ + [24, 8], + [190, 2, 3], + [190, 2, 8] + ] + }, + { + "pattern": "pipe-2h", + "ranges": [ + [115, 11] + ] + }, { + "pattern": "pipe-3h", + "ranges": [ + [126, 10], + [176, 10] + ] + }, + { + "pattern": "pipe-4h", + "ranges": [ + [46, 9], + [74, 9], + [103, 9], + [122, 9] + ] + }, + { + "pattern": "pipe-5h", + "ranges": [ + [130, 8] + ] + }, + { + "pattern": "flag-pole-green", + "ranges": [ + [200, 2] + ] + }, + { + "pattern": "castle-small", + "ranges": [ + [204, 8] + ] + } + ] + } + ], + + "entities": [ + { + "name": "goomba-brown", + "pos": [384, 112] + }, + { + "name": "koopa-green", + "pos": [496, 185] + }, + { + "name": "koopa-green", + "pos": [528, 185] + }, + { + "name": "goomba-brown", + "pos": [672, 192] + }, + { + "name": "goomba-brown", + "pos": [696, 192] + }, + { + "name": "koopa-green", + "pos": [880, 121] + }, + { + "name": "goomba-brown", + "pos": [944, 192] + }, + { + "name": "goomba-brown", + "pos": [968, 192] + }, + { + "name": "koopa-green", + "pos": [1056, 185] + }, + { + "name": "goomba-brown", + "pos": [1088, 192] + }, + { + "name": "goomba-brown", + "pos": [1088, 192] + }, + { + "name": "goomba-brown", + "pos": [1112, 192] + }, + { + "name": "goomba-brown", + "pos": [1136, 192] + }, + { + "name": "goomba-brown", + "pos": [1392, 192] + }, + { + "name": "goomba-brown", + "pos": [1416, 192] + }, + { + "name": "goomba-brown", + "pos": [1440, 192] + }, + { + "name": "goomba-brown", + "pos": [1640, 128] + }, + { + "name": "goomba-brown", + "pos": [1832, 160] + }, + { + "name": "goomba-brown", + "pos": [1920, 192] + }, + { + "name": "koopa-green", + "pos": [2192, 185] + }, + { + "name": "goomba-brown", + "pos": [2592, 192] + }, + { + "name": "koopa-green", + "pos": [2616, 185] + }, + { + "name": "koopa-green", + "pos": [2960, 185] + } + ], + "triggers": [] +} diff --git a/public/levels/2-2.json b/public/levels/2-2.json new file mode 100644 index 00000000..5706b7da --- /dev/null +++ b/public/levels/2-2.json @@ -0,0 +1,197 @@ +{ + "spriteSheet": "underwater", + "musicSheet": "underwater", + "patternSheet": "underwater-pattern", + "checkpoints": [ + [40, 16] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 192, 0, 3] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "water", + "ranges": [ + [0, 190, 2] + ] + } + + ] + }, + { + "tiles": [ + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 66, 13, 2], + [18, 3, 9], + [42, 2, 9], + [64, 1, 10, 3], + [65, 1, 8, 5], + [71, 60, 13, 2], + [71, 1, 8, 5], + [72, 1, 10, 3], + [78, 2, 10, 3], + [78, 2, 2, 3], + [82, 3, 5], + [102, 2, 9], + [115, 2, 8], + [129, 1, 9, 4], + [130, 1, 11, 2], + [131, 1, 2, 3], + [132, 8, 4], + [140, 17, 13, 2], + [140, 1, 11, 2], + [141, 1, 9, 4], + [156, 1, 5, 8], + [157, 2, 5], + [162, 2, 5], + [164, 1, 5, 8], + [164, 28, 13, 2], + [172, 5, 5], + [172, 5, 9], + [180, 4, 5], + [180, 4, 9], + [185, 12], + [186, 1, 11, 2], + [187, 1, 10, 3], + [188, 4, 2, 4], + [188, 4, 9, 4], + [190, 2, 6, 3] + + ] + }, + { + "style": "coral", + "behavior": "ground", + "ranges": [ + [11, 1, 10, 3], + [33, 1, 8, 5], + [42, 1, 7, 2], + [50, 1, 9, 4], + [83, 1, 3, 2], + [89, 1, 10, 3], + [102, 1, 5, 4], + [120, 1, 9, 4], + [147, 1, 11, 2], + [149, 1, 10, 3], + [173, 1, 3, 2] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [14, 2, 12], + [27, 3, 5], + [36, 3, 12], + [67, 3, 10], + [101, 3, 11], + [113, 3, 6], + [134, 3, 12], + [133, 11], + [137, 11], + [159, 3, 9], + [159, 3, 12] + ] + }, + { + "pattern": "pipe-cap-hor", + "ranges": [ + [189, 1, 7] + ] + } + ] + }, + { + "tiles": [] + } + ], + + "entities": [ + { + "name": "cheep-slow", + "pos": [1184, 112] + }, + { + "name": "cheep-slow", + "pos": [1376, 160] + }, + { + "name": "cheep-slow", + "pos": [1664, 160] + }, + { + "name": "cheep-fast", + "pos": [1184, 144] + }, + { + "name": "cheep-fast", + "pos": [1616, 64] + }, + { + "name": "cheep-slow-wavy", + "pos": [1248, 112] + }, + { + "name": "cheep-slow-wavy", + "pos": [1552, 96] + }, + { + "name": "cheep-slow-wavy", + "pos": [1872, 80] + }, + { + "name": "cheep-fast-wavy", + "pos": [2048, 160] + }, + { + "name": "cheep-slow-wavy", + "pos": [2098, 176] + }, + { + "name": "cheep-slow", + "pos": [2192, 128] + }, + { + "name": "cheep-slow-wavy", + "pos": [2320, 144] + }, + { + "name": "cheep-fast", + "pos": [2400, 80] + }, + { + "name": "cheep-slow", + "pos": [2624, 48] + }, + { + "name": "cheep-fast", + "pos": [2672, 160] + }, + { + "name": "cheep-slow-wavy", + "pos": [2800, 128] + }, + { + "name": "cheep-fast", + "pos": [2928, 64] + }, + { + "name": "cheep-fast-wavy", + "pos": [2976, 128] + } + ], + "triggers": [] +} diff --git a/public/levels/2-3.json b/public/levels/2-3.json new file mode 100644 index 00000000..844216f4 --- /dev/null +++ b/public/levels/2-3.json @@ -0,0 +1,216 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 237, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 7, 13, 2], + [207, 30, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "cloud-double", + "ranges": [ + [3, 3], + [18, 2], + [51, 3], + [66, 2], + [99, 3], + [114, 2], + [147, 3], + [162, 2], + [195, 3], + [210, 2] + ] + }, + { + "pattern": "cloud-single", + "ranges": [ + [9, 7], + [28, 11], + [35, 7], + [38, 6], + [46, 11], + [57, 7], + [76, 11], + [83, 7], + [86, 6], + [94, 11], + [105, 7], + [124, 11], + [131, 7], + [134, 6], + [142, 11], + [153, 7], + [172, 11], + [179, 7], + [182, 6], + [190, 11], + [201, 7], + [220, 11], + [227, 7] + ] + }, + { + "pattern": "chocolate-stairs-3h", + "ranges": [ + [10, 10] + ] + }, + { + "pattern": "chocolate-stairs-3h-reverse", + "ranges": [ + [194, 10] + ] + }, + { + "pattern": "chocolate-stack-3h", + "ranges": [ + [13, 2, 10], + [146, 1, 12], + [155, 1, 12], + [193, 1, 10] + ] + }, + { + "pattern": "chocolate-stack-5h", + "ranges": [ + [31, 1, 10], + [47, 1, 10], + [63, 1, 10], + [68, 1, 10], + [79, 1, 10], + [84, 1, 10], + [95, 1, 10], + [127, 1, 10], + [143, 1, 10], + [159, 1, 10], + [168, 1, 10], + [183, 1, 10] + ] + }, + { + "pattern": "chocolate-stack-6h", + "ranges": [ + [99, 1, 9], + [105, 1, 9] + ] + }, + { + "pattern": "bridge-green", + "ranges": [ + [15, 16, 9], + [32, 15, 9], + [48, 15, 9], + [69, 10, 9], + [85, 10, 9], + [100, 5, 8], + [122, 3, 9], + [128, 15, 9], + [147, 8, 11], + [160, 8, 9], + [171, 2, 9], + [175, 2, 9], + [179, 2, 9], + [184, 9, 9] + + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [36, 4, 5], + [55, 5], + [56, 6], + [57, 5], + [58, 6], + [59, 5], + [72, 5], + [73, 2, 4], + [75, 5], + [97, 3, 5], + [108, 3, 5], + [133, 6, 5], + [149, 4, 8], + [173, 6, 6] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [102, 5] + ] + }, + { + "style": "dirt", + "ranges": [ + [9, 6, 13, 2], + [113, 6, 13, 2], + [193, 11, 13, 2] + ] + }, + { + "pattern": "grass-top-8w", + "ranges": [ + [8, 13], + [112, 13] + ] + }, + { + "pattern": "grass-top-13w", + "ranges": [ + [192, 13] + ] + }, + { + "pattern": "castle-small", + "ranges": [ + [0, 8] + ] + }, + { + "pattern": "chocolate-stairs-final", + "ranges": [ + [208, 5] + ] + }, + { + "pattern": "castle-large", + "ranges": [ + [228, 2] + ] + }, + { + "pattern": "flag-pole-green", + "ranges": [ + [225, 2] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/2-4.json b/public/levels/2-4.json new file mode 100644 index 00000000..ac61ec7f --- /dev/null +++ b/public/levels/2-4.json @@ -0,0 +1,141 @@ +{ + "spriteSheet": "castle", + "musicSheet": "castle", + "patternSheet": "castle-pattern", + "checkpoints": [ + [40, 96] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 160, 0, 15] + ] + } + ] + }, + { + "tiles": [ + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 2, 3], + [0, 16, 10, 5], + [18, 2, 9], + [22, 3, 7], + [27, 2, 9], + [32, 2, 10, 5], + [34, 49, 2, 4], + [34, 46, 13, 2], + [37, 36, 9], + [80, 4, 10, 5], + [92, 7, 10, 5], + [93, 6, 2, 3], + [99, 10, 13, 2], + [108, 1, 10, 3], + [111, 2, 10, 5], + [115, 5, 10, 5], + [115, 13, 2, 3], + [120, 8, 13, 2], + [122, 2, 10, 3], + [126, 2, 10, 3], + [128, 32, 2], + [141, 3, 9, 6], + [142, 2, 3, 3], + [144, 16, 13, 2] + ] + }, + { + "style": "bricks", + "behavior": "ground", + "ranges": [ + [128, 6, 5] + ] + }, + { + "style": "metal-alt", + "behavior": "ground", + "ranges": [ + [23, 7], + [43, 13], + [49, 9], + [55, 5], + [55, 13], + [61, 9], + [67, 13], + [73, 9], + [82, 6], + [92, 10], + [103, 11] + ] + }, + { + "pattern": "entrance-stairs", + "ranges": [ + [0, 6] + ] + }, + { + "style": "waves", + "ranges": [ + [16, 16, 13], + [109, 2, 13], + [113, 2, 13], + [128, 13, 13] + ] + }, + { + "style": "tile-red", + "ranges": [ + [16, 16, 14], + [109, 2, 14], + [113, 2, 14], + [128, 13, 14] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [23, 3] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [102, 3, 8, 1], + [102, 3, 12, 1] + ] + }, + { + "style": "beam-track", + "ranges": [ + [86, 1, 2, 13], + [89, 1, 2, 13] + ] + }, + { + "pattern": "bridge", + "behavior": "ground", + "ranges": [ + [128, 9] + ] + }, + { + "pattern": "toad", + "ranges": [ + [153, 11] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/3-1.json b/public/levels/3-1.json new file mode 100644 index 00000000..9bc1ee41 --- /dev/null +++ b/public/levels/3-1.json @@ -0,0 +1,270 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "tile-black", + "ranges": [ + [0, 214, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 45, 13, 2], + [48, 29, 13, 2], + [85, 1, 13, 2], + [88, 40, 13, 2], + [132, 10, 13, 2], + [144, 33, 13, 2], + [180, 34, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "castle-large", + "ranges": [ + [-2, 2] + ] + }, + { + "style": "tree-white-small", + "ranges": [ + [136, 11] + ] + }, + { + "pattern": "tree-white-small", + "ranges": [ + [11, 11], + [23, 11], + [24, 11], + [40, 11], + [59, 11], + [71, 11], + [72, 11], + [107, 11], + [119, 11], + [120, 11], + [155, 11], + [167, 11], + [168, 11], + [203, 11] + ] + }, + { + "pattern": "tree-white-large", + "ranges": [ + [13, 10], + [21, 10], + [43, 10], + [61, 10], + [69, 10], + [91, 10], + [109, 10], + [117, 10], + [157, 10], + [165, 10], + [213, 10] + ] + }, + { + "style": "fence", + "ranges": [ + [14, 4, 12], + [41, 12], + [62, 4, 12], + [110, 4, 12], + [134, 2, 12], + [158, 4, 12], + [182, 12], + [209, 12] + ] + }, + { + "pattern": "cloud-single", + "ranges": [ + [18, 3], + [27, 2], + [45, 2], + [66, 3], + [75, 2], + [93, 2], + [114, 3], + [123, 2], + [141, 2], + [162, 3], + [171, 2], + [189, 2], + [210, 3] + ] + }, + { + "pattern": "cloud-double", + "ranges": [ + [30, 3], + [48, 3], + [78, 3], + [96, 3], + [126, 3], + [144, 3], + [174, 3], + [192, 3] + ] + }, + { + "style": "bricks-top", + "behavior": "ground", + "ranges":[ + [26, 3, 9], + [61, 9], + [90, 3, 5], + [111, 10, 5], + [111, 11, 9], + [129, 3, 5], + [129, 3, 8], + [150, 3, 5], + [150, 3, 9], + [155, 3, 5], + [155, 3, 9], + [166, 5, 9] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [16, 9], + [19, 8], + [22, 8], + [113, 5], + [117, 5], + [151, 5], + [151, 9], + [156, 5], + [156, 9] + ] + }, + { + "style": "metal", + "ranges":[ + [90, 5], + [131, 5], + [167, 9] + ] + }, + { + "pattern": "pipe-chrome-2h", + "ranges":[ + [67, 11] + ] + }, + { + "pattern": "pipe-chrome-3h", + "ranges":[ + [32, 10], + [57, 10] + ] + }, + { + "pattern": "pipe-chrome-4h", + "ranges":[ + [38, 9], + [103, 9] + ] + }, + { + "pattern": "chocolate-stairs-2h", + "ranges": [ + [140, 7] + ] + }, + { + "pattern": "chocolate-stairs-4h", + "ranges": [ + [73, 9], + [136, 9] + ] + }, + { + "style": "waves", + "ranges": [ + [77, 8, 12], + [86, 2, 12] + ] + }, + { + "style": "tile-light-blue", + "ranges": [ + [77, 8, 13, 2], + [86, 2, 13, 2] + ] + }, + { + "pattern": "bridge-white", + "ranges": [ + [77, 8, 8] + ] + }, + { + "pattern": "chocolate-stack-2h", + "ranges": [ + [89, 11] + ] + }, + { + "pattern": "chocolate-stack-3h", + "ranges": [ + [174, 10] + ] + }, + { + "pattern": "chocolate-stack-4h", + "ranges": [ + [85, 9], + [88, 9], + [140, 2, 9] + ] + }, + { + "pattern": "chocolate-stack-6h", + "ranges": [ + [175, 7] + ] + }, + { + "pattern": "chocolate-stairs-final", + "ranges": [ + [183, 5] + ] + }, + { + "pattern": "flag-pole-dark-grey", + "ranges": [ + [200, 2] + ] + }, + { + "pattern": "castle-small", + "ranges": [ + [204, 8] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/5-3.json b/public/levels/5-3.json new file mode 100644 index 00000000..970287c7 --- /dev/null +++ b/public/levels/5-3.json @@ -0,0 +1,192 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 166, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 13, 2], + [129, 37, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [27, 3, 4, 1], + [33, 11], + [50, 2, 6, 1], + [60, 4, 4, 1], + [85, 2, 5, 1], + [93, 2, 4, 1], + [97, 2, 4, 1], + [113, 3, 12, 1], + [120, 2, 5, 1] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [59, 10] + ] + }, + { + "pattern": "cloud-double", + "ranges": [ + [3, 3], + [19, 2], + [51, 3], + [99, 3], + [114, 2], + [147, 3], + [162, 2] + ] + }, + { + "pattern": "cloud-single", + "ranges": [ + [9, 7], + [35, 7], + [38, 6], + [46, 11], + [57, 7], + [76, 11], + [83, 7], + [86, 6], + [94, 11], + [124, 11], + [131, 7], + [134, 6], + [142, 11], + [153, 7] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [138, 2, 9, 4], + [140, 2, 7, 6], + [142, 2, 5, 8] + ] + }, + { + "pattern": "castle-small", + "ranges": [ + [0, 8] + ] + }, + { + "pattern": "castle-large", + "ranges": [ + [155, 2] + ] + }, + { + "pattern": "castle-wall-6h", + "ranges": [ + [164, 2, 7, 1] + ] + }, + { + "pattern": "flag-pole-green", + "ranges": [ + [152, 2] + ] + }, + { + "style": "dirt", + "ranges": [ + [19, 2, 13, 2], + [25, 6, 10, 5], + [27, 3, 6, 3], + [33, 1, 13, 2], + [36, 3, 9, 6], + [41, 5, 5, 10], + [51, 2, 14], + [60, 3, 14], + [61, 2, 6, 7], + [66, 3, 14], + [71, 1, 10, 5], + [77, 4, 7, 8], + [99, 2, 12, 3], + [105, 6, 8, 7], + [114, 1, 14], + [117, 2, 10, 5], + [123, 2, 10, 5] + ] + }, + { + "pattern": "grass-top-3w", + "ranges": [ + [32, 12], + [70, 9], + [113, 13] + ] + }, + { + "pattern": "grass-top-4w", + "ranges": [ + [18, 12], + [50, 13], + [60, 5], + [98, 11], + [116, 9], + [122, 9] + ] + }, + { + "pattern": "grass-top-5w", + "ranges": [ + [26, 5], + [35, 8], + [59, 13], + [65, 13] + ] + }, + { + "pattern": "grass-top-6w", + "ranges": [ + [76, 6] + ] + }, + { + "pattern": "grass-top-7w", + "ranges": [ + [40, 4] + ] + }, + { + "pattern": "grass-top-8w", + "ranges": [ + [24, 9], + [104, 7] + ] + } + + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/7-2.json b/public/levels/7-2.json new file mode 100644 index 00000000..591ebc96 --- /dev/null +++ b/public/levels/7-2.json @@ -0,0 +1,121 @@ +{ + "spriteSheet": "underwater", + "musicSheet": "underwater", + "patternSheet": "underwater-pattern", + "checkpoints": [ + [40, 16] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 192, 0, 3] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "water", + "ranges": [ + [0, 190, 2] + ] + } + + ] + }, + { + "tiles": [ + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 66, 13, 2], + [18, 3, 9], + [42, 2, 9], + [64, 1, 10, 3], + [65, 1, 8, 5], + [71, 60, 13, 2], + [71, 1, 8, 5], + [72, 1, 10, 3], + [78, 2, 10, 3], + [78, 2, 2, 3], + [82, 3, 5], + [102, 2, 9], + [115, 2, 8], + [129, 1, 9, 4], + [130, 1, 11, 2], + [131, 1, 2, 3], + [132, 8, 4], + [140, 17, 13, 2], + [140, 1, 11, 2], + [141, 1, 9, 4], + [156, 1, 5, 8], + [157, 2, 5], + [162, 2, 5], + [164, 1, 5, 8], + [164, 28, 13, 2], + [172, 5, 5], + [172, 5, 9], + [180, 4, 5], + [180, 4, 9], + [185, 12], + [186, 1, 11, 2], + [187, 1, 10, 3], + [188, 4, 2, 4], + [188, 4, 9, 4], + [190, 2, 6, 3] + + ] + }, + { + "style": "coral", + "behavior": "ground", + "ranges": [ + [11, 1, 10, 3], + [33, 1, 8, 5], + [42, 1, 7, 2], + [50, 1, 9, 4], + [83, 1, 3, 2], + [89, 1, 10, 3], + [102, 1, 5, 4], + [120, 1, 9, 4], + [147, 1, 11, 2], + [149, 1, 10, 3], + [173, 1, 3, 2] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [14, 2, 12], + [27, 3, 5], + [36, 3, 12], + [67, 3, 10], + [101, 3, 11], + [113, 3, 4], + [134, 3, 12], + [133, 11], + [137, 11], + [159, 3, 9], + [159, 3, 12] + ] + }, + { + "pattern": "pipe-cap-hor", + "ranges": [ + [189, 1, 7] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/7-3.json b/public/levels/7-3.json new file mode 100644 index 00000000..844216f4 --- /dev/null +++ b/public/levels/7-3.json @@ -0,0 +1,216 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 237, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 7, 13, 2], + [207, 30, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "cloud-double", + "ranges": [ + [3, 3], + [18, 2], + [51, 3], + [66, 2], + [99, 3], + [114, 2], + [147, 3], + [162, 2], + [195, 3], + [210, 2] + ] + }, + { + "pattern": "cloud-single", + "ranges": [ + [9, 7], + [28, 11], + [35, 7], + [38, 6], + [46, 11], + [57, 7], + [76, 11], + [83, 7], + [86, 6], + [94, 11], + [105, 7], + [124, 11], + [131, 7], + [134, 6], + [142, 11], + [153, 7], + [172, 11], + [179, 7], + [182, 6], + [190, 11], + [201, 7], + [220, 11], + [227, 7] + ] + }, + { + "pattern": "chocolate-stairs-3h", + "ranges": [ + [10, 10] + ] + }, + { + "pattern": "chocolate-stairs-3h-reverse", + "ranges": [ + [194, 10] + ] + }, + { + "pattern": "chocolate-stack-3h", + "ranges": [ + [13, 2, 10], + [146, 1, 12], + [155, 1, 12], + [193, 1, 10] + ] + }, + { + "pattern": "chocolate-stack-5h", + "ranges": [ + [31, 1, 10], + [47, 1, 10], + [63, 1, 10], + [68, 1, 10], + [79, 1, 10], + [84, 1, 10], + [95, 1, 10], + [127, 1, 10], + [143, 1, 10], + [159, 1, 10], + [168, 1, 10], + [183, 1, 10] + ] + }, + { + "pattern": "chocolate-stack-6h", + "ranges": [ + [99, 1, 9], + [105, 1, 9] + ] + }, + { + "pattern": "bridge-green", + "ranges": [ + [15, 16, 9], + [32, 15, 9], + [48, 15, 9], + [69, 10, 9], + [85, 10, 9], + [100, 5, 8], + [122, 3, 9], + [128, 15, 9], + [147, 8, 11], + [160, 8, 9], + [171, 2, 9], + [175, 2, 9], + [179, 2, 9], + [184, 9, 9] + + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [36, 4, 5], + [55, 5], + [56, 6], + [57, 5], + [58, 6], + [59, 5], + [72, 5], + [73, 2, 4], + [75, 5], + [97, 3, 5], + [108, 3, 5], + [133, 6, 5], + [149, 4, 8], + [173, 6, 6] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [102, 5] + ] + }, + { + "style": "dirt", + "ranges": [ + [9, 6, 13, 2], + [113, 6, 13, 2], + [193, 11, 13, 2] + ] + }, + { + "pattern": "grass-top-8w", + "ranges": [ + [8, 13], + [112, 13] + ] + }, + { + "pattern": "grass-top-13w", + "ranges": [ + [192, 13] + ] + }, + { + "pattern": "castle-small", + "ranges": [ + [0, 8] + ] + }, + { + "pattern": "chocolate-stairs-final", + "ranges": [ + [208, 5] + ] + }, + { + "pattern": "castle-large", + "ranges": [ + [228, 2] + ] + }, + { + "pattern": "flag-pole-green", + "ranges": [ + [225, 2] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/coin-clouds-1.json b/public/levels/coin-clouds-1.json new file mode 100644 index 00000000..c3c087d9 --- /dev/null +++ b/public/levels/coin-clouds-1.json @@ -0,0 +1,48 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "coin-clouds", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [80, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 79, 0, 15] + ] + } + + ] + }, + { + "tiles": [ + { + "style": "cloud-tile", + "behavior": "ground", + "ranges": [ + [0, 4, 13], + [5, 57, 13] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [15, 16, 6], + [32, 3, 4], + [36, 16, 5], + [53, 3, 4], + [69, 3, 12] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/coin-room-1.json b/public/levels/coin-room-1.json new file mode 100644 index 00000000..ddbd5927 --- /dev/null +++ b/public/levels/coin-room-1.json @@ -0,0 +1,68 @@ +{ + "spriteSheet": "underworld", + "musicSheet": "underworld", + "patternSheet": "underworld-pattern", + "checkpoints": [ + [24, 48] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 16, 0, 13] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "style": "bricks", + "behavior": "ground", + "ranges": [ + [0, 1, 2, 11], + [4, 7, 2], + [4, 7, 10, 3] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [5, 5, 5], + [4, 7, 7], + [4, 7, 9] + ] + }, + { + "pattern": "exit-pipe-12h", + "ranges": [ + [13, 2] + ] + } + ] + } + ], + + "entities": [ + { + "name": "pipe-portal", + "pos": [206, 184], + "props": { + "dir": "RIGHT" + } + } + ], + + "triggers": [] +} diff --git a/public/levels/coin-room-2.json b/public/levels/coin-room-2.json new file mode 100644 index 00000000..821a1332 --- /dev/null +++ b/public/levels/coin-room-2.json @@ -0,0 +1,66 @@ +{ + "spriteSheet": "underworld", + "musicSheet": "underworld", + "patternSheet": "underworld-pattern", + "checkpoints": [ + [24, 48] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 16, 0, 13] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "style": "bricks", + "behavior": "ground", + "ranges": [ + [0, 1, 2, 11], + [3, 10, 2, 4], + [13, 2, 2, 9], + [3, 9, 9] + ] + }, + { + "style": "metal", + "behavior": "ground", + "ranges": [ + [12, 9] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [4, 8, 8], + [3, 9, 12] + ] + }, + { + "pattern": "exit-pipe-12h", + "ranges": [ + [13, 2] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/coin-room-3.json b/public/levels/coin-room-3.json new file mode 100644 index 00000000..b3314cc4 --- /dev/null +++ b/public/levels/coin-room-3.json @@ -0,0 +1,82 @@ +{ + "spriteSheet": "underworld", + "musicSheet": "underworld", + "patternSheet": "underworld-pattern", + "checkpoints": [ + [24, 48] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 16, 0, 13] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "style": "bricks", + "behavior": "ground", + "ranges": [ + [0, 1, 2, 11], + [3, 2, 5, 2], + [7, 2, 5, 2], + [11, 2, 5, 2], + [3, 1, 7, 2], + [12, 1, 7, 2], + [10, 5], + [9, 7], + [6, 7], + [5, 8], + [4, 9], + [10, 8], + [11, 9], + [10, 8] + ] + }, + { + "style" : "metal", + "behavior": "ground", + "ranges":[ + [5, 5] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [7, 2, 3], + [6, 4, 4], + [6, 6], + [9, 6], + [5, 7], + [10, 7], + [4, 8], + [11, 8] + ] + }, + { + "pattern": "exit-pipe-12h", + "ranges": [ + [13, 2] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/coin-room-4.json b/public/levels/coin-room-4.json new file mode 100644 index 00000000..d3d8658e --- /dev/null +++ b/public/levels/coin-room-4.json @@ -0,0 +1,67 @@ +{ + "spriteSheet": "underworld", + "musicSheet": "underworld", + "patternSheet": "underworld-pattern", + "checkpoints": [ + [24, 48] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 16, 0, 13] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "style": "bricks", + "behavior": "ground", + "ranges": [ + [0, 1, 2, 11], + [3, 12, 2], + [3, 8, 9], + [3, 1, 10, 2], + [10, 1, 10, 2] + ] + }, + { + "style": "metal", + "behavior": "ground", + "ranges": [ + [13, 9] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [3, 8, 8], + [3, 10, 12] + ] + }, + { + "pattern": "exit-pipe-12h", + "ranges": [ + [13, 2] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/coin-room-5.json b/public/levels/coin-room-5.json new file mode 100644 index 00000000..cf753d21 --- /dev/null +++ b/public/levels/coin-room-5.json @@ -0,0 +1,68 @@ +{ + "spriteSheet": "underworld", + "musicSheet": "underworld", + "patternSheet": "underworld-pattern", + "checkpoints": [ + [24, 48] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 16, 0, 13] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "style": "bricks", + "behavior": "ground", + "ranges": [ + [0, 1, 2, 11], + [4, 7, 2], + [10, 1, 3, 5], + [4, 6, 7], + [4, 6], + [11, 2, 6] + ] + }, + { + "style": "metal", + "behavior": "ground", + "ranges": [ + [14, 7] + ] + }, + { + "style": "coin", + "behavior": "coin", + "ranges": [ + [5, 5, 5], + [5, 5, 6] + ] + }, + { + "pattern": "exit-pipe-12h", + "ranges": [ + [13, 2] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/debug-coin.json b/public/levels/debug-coin.json index 729a8c48..dac85bf0 100644 --- a/public/levels/debug-coin.json +++ b/public/levels/debug-coin.json @@ -2,12 +2,15 @@ "spriteSheet": "overworld", "musicSheet": "silent", "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], "layers": [ { "tiles": [ { - "name": "sky", + "style": "sky", "ranges": [ [ 0, 212, @@ -16,8 +19,8 @@ ] }, { - "name": "ground", - "type": "ground", + "style": "ground", + "behavior": "ground", "ranges": [ [ 0, 212, @@ -30,8 +33,8 @@ { "tiles": [ { - "name": "coin", - "type": "coin", + "style": "coin", + "behavior": "coin", "ranges": [ [6, 100, 8, 5] ] diff --git a/public/levels/debug-flag.json b/public/levels/debug-flag.json new file mode 100644 index 00000000..9641af33 --- /dev/null +++ b/public/levels/debug-flag.json @@ -0,0 +1,54 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [160, 32] + ], + + "layers": [ + { + "tiles": [ + { + "name": "sky", + "ranges": [ + [0, 212, 0, 15] + ] + }, + { + "name": "ground", + "type": "ground", + "ranges": [ + [0, 69, 13, 2], + [71, 15, 13, 2], + [89, 64, 13, 2], + [155, 57, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "chocolate-stairs-final", + "ranges": [ + [2, 5] + ] + }, + { + "pattern": "flag-pole-green", + "ranges": [ + [12, 2] + ] + } + ] + } + ], + + "entities": [ + { + "name": "flag-pole", + "pos": [192, 48] + } + ] +} diff --git a/public/levels/debug-level.json b/public/levels/debug-level.json new file mode 100644 index 00000000..3d76fc30 --- /dev/null +++ b/public/levels/debug-level.json @@ -0,0 +1,295 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [ + 0, 212, + 0, 13 + ] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [ + 0, 212, + 13, 2 + ] + ] + }, + { + "style": "sky", + "ranges": [ + [ + 75, 2, + 13, 2 + ], + [ + 92, 2, + 13, 2 + ], + [ + 157, 2, + 13, 2 + ] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [ + 5, 3, + 9, 1 + ], + [ + 29, 5 + ], + [ + 5, 7, + 9 + ], + [ + 12, 6, + 11, 1 + ], + [ + 2, 1, + 11, 1 + ], + [ + 10, 2, + 10, 1 + ], + [ + 10, 2, + 10 + ], + [ + 9, 1, + 0, 7 + ] + ] + } + ] + }, + { + "tiles": [ + { + "style": "bricks", + "behavior": "brick", + "ranges": [ + [ + 27, 5, + 9 + ], + [ + 83, 3, + 9 + ], + [ + 86, 6, + 5 + ], + [ + 96, 3, + 5 + ], + [ + 99, 9 + ], + [ + 105, 2, + 9 + ], + [ + 123, 5 + ], + [ + 126, 3, + 5 + ], + [ + 132, 4, + 5 + ], + [ + 133, 2, + 9 + ], + [ + 171, 4, + 9 + ] + ] + }, + { + "style": "chance", + "behavior": "ground", + "ranges": [ + [2, 2], + + [23, 9], + [28, 9], + [30, 9], + [29, 5], + [84, 9], + [99, 5], + + [114, 5], + [111, 9], + [114, 9], + [117, 9], + + [133, 2, 5], + + [173, 9] + + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [141, 1, 9], + [140, 2, 10], + [139, 3, 11], + [138, 4, 12], + + [144, 1, 9], + [144, 2, 10], + [144, 3, 11], + [144, 4, 12], + + [155, 2, 9], + [154, 3, 10], + [153, 4, 11], + [152, 5, 12], + + [159, 1, 9], + [159, 2, 10], + [159, 3, 11], + [159, 4, 12], + + [191, 2, 5], + [190, 3, 6], + [189, 4, 7], + [188, 5, 8], + [187, 6, 9], + [186, 7, 10], + [185, 8, 11], + [184, 9, 12] + ] + }, + { + "pattern": "pipe-2h", + "ranges": [ + [35, 11], + [167, 11], + [182, 11] + ] + }, + { + "pattern": "pipe-3h", + "ranges": [ + [45, 10] + ] + }, + { + "pattern": "pipe-4h", + "ranges": [ + [53, 9], + [64, 9] + ] + }, + { + "pattern": "cloud-single", + "ranges": [ + [2, 2], + [25, 2], + [35, 3], + [44, 2], + [64, 3], + [74, 2], + [80, 3], + [90, 2], + [108, 3], + [118, 2], + [128, 3], + [138, 2] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "cannon-2h", + "ranges": [ + [ + 6, 7 + ] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "bush-single", + "ranges": [ + [ + 8, 12 + ] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "bush-double", + "ranges": [ + [ + 20, 12 + ] + ] + } + ] + } + ], + + "entities": [ + { + "name": "koopa-green", + "pos": [260, 0] + }, + { + "name": "goomba-brown", + "pos": [220, 0] + }, + { + "name": "cannon", + "pos": [96, 112] + } + ], + + "triggers": [ + { + "type": "goto", + "name": "1-2", + "pos": [64, 64] + } + ] +} diff --git a/public/levels/debug-pipe.json b/public/levels/debug-pipe.json new file mode 100644 index 00000000..08248a71 --- /dev/null +++ b/public/levels/debug-pipe.json @@ -0,0 +1,66 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 212, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 69, 13, 2], + [71, 15, 13, 2], + [89, 64, 13, 2], + [155, 57, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "pipe-2h", + "ranges": [ + [2, 11], + [6, 11], + [12, 11] + ] + } + ] + } + ], + + "entities": [ + { + "name": "piranha-plant", + "pos": [104, 176] + }, + { + "name": "pipe-portal", + "pos": [100, 174], + "props": { + "dir": "DOWN", + "goesTo": { + "name": "coin-room-1" + }, + "backTo": "outlet1" + } + }, + { + "id": "outlet1", + "name": "pipe-portal", + "pos": [196, 176], + "props": { + "dir": "UP" + } + } + ] +} diff --git a/public/levels/debug-progression.json b/public/levels/debug-progression.json index 77ba65f2..2a83950b 100644 --- a/public/levels/debug-progression.json +++ b/public/levels/debug-progression.json @@ -2,12 +2,15 @@ "spriteSheet": "overworld", "musicSheet": "silent", "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], "layers": [ { "tiles": [ { - "name": "sky", + "style": "sky", "ranges": [ [ 0, 212, @@ -16,8 +19,8 @@ ] }, { - "name": "ground", - "type": "ground", + "style": "ground", + "behavior": "ground", "ranges": [ [ 0, 212, diff --git a/public/levels/uw-entrance.json b/public/levels/uw-entrance.json new file mode 100644 index 00000000..1c24db3e --- /dev/null +++ b/public/levels/uw-entrance.json @@ -0,0 +1,59 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "uw-entrance", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [40, 192] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 16, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 16, 13, 2] + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "cloud-single", + "ranges": [ + [9, 7] + ] + }, + { + "pattern": "cloud-double", + "ranges": [ + [3, 3] + ] + }, + { + "pattern": "castle-small", + "ranges": [ + [0, 8] + ] + }, + { + "pattern": "pipe-uw-entrance", + "ranges": [ + [10, 9] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/levels/uw-exit.json b/public/levels/uw-exit.json new file mode 100644 index 00000000..1b281de2 --- /dev/null +++ b/public/levels/uw-exit.json @@ -0,0 +1,90 @@ +{ + "spriteSheet": "overworld", + "musicSheet": "overworld", + "patternSheet": "overworld-pattern", + "checkpoints": [ + [56, 160] + ], + + "layers": [ + { + "tiles": [ + { + "style": "sky", + "ranges": [ + [0, 36, 0, 15] + ] + }, + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 36, 13, 2] + + ] + } + ] + }, + { + "tiles": [ + { + "pattern": "cloud-single", + "ranges": [ + [24, 3] + ] + }, + { + "pattern": "cloud-double", + "ranges": [ + [4, 2] + ] + }, + { + "pattern": "pipe-2h", + "ranges": [ + [3, 11] + ] + }, + { + "pattern": "chocolate-stairs-final", + "ranges": [ + [5, 5] + ] + }, + { + "pattern": "hill-large", + "ranges": [ + [16, 10] + ] + }, + { + "pattern": "hill-small", + "ranges": [ + [32, 11] + ] + }, + { + "pattern": "flag-pole-green", + "ranges": [ + [22, 2] + ] + }, + { + "pattern": "castle-small", + "ranges": [ + [26, 8] + ] + }, + { + "style": "bush-3", + "ranges": [ + [31, 12] + ] + } + ] + } + ], + + "entities": [], + "triggers": [] +} diff --git a/public/music/castle.json b/public/music/castle.json new file mode 100644 index 00000000..59aa1a45 --- /dev/null +++ b/public/music/castle.json @@ -0,0 +1,8 @@ +{ + "main": { + "url": "/audio/music/castle.ogg" + }, + "hurry": { + "url": "/audio/music/hurry.ogg" + } +} diff --git a/public/music/coin-clouds.json b/public/music/coin-clouds.json new file mode 100644 index 00000000..6f61e03a --- /dev/null +++ b/public/music/coin-clouds.json @@ -0,0 +1,5 @@ +{ + "main": { + "url": "/audio/music/starman.ogg" + } +} diff --git a/public/music/underwater.json b/public/music/underwater.json new file mode 100644 index 00000000..d96957ec --- /dev/null +++ b/public/music/underwater.json @@ -0,0 +1,8 @@ +{ + "main": { + "url": "/audio/music/underwater.ogg" + }, + "hurry": { + "url": "/audio/music/hurry.ogg" + } +} diff --git a/public/music/uw-entrance.json b/public/music/uw-entrance.json new file mode 100644 index 00000000..3fd46848 --- /dev/null +++ b/public/music/uw-entrance.json @@ -0,0 +1,5 @@ +{ + "main": { + "url": "/audio/music/uw-entrance.ogg" + } +} diff --git a/public/sounds/brick-shrapnel.json b/public/sounds/brick-shrapnel.json new file mode 100644 index 00000000..95aaf8f4 --- /dev/null +++ b/public/sounds/brick-shrapnel.json @@ -0,0 +1,7 @@ +{ + "fx": { + "break": { + "url": "/audio/fx/brick-destroy.ogg" + } + } +} diff --git a/public/sounds/cannon.json b/public/sounds/cannon.json index 058f433d..75c5437a 100644 --- a/public/sounds/cannon.json +++ b/public/sounds/cannon.json @@ -1,7 +1,7 @@ { "fx": { "shoot": { - "url": "/audio/thwomp.ogg" + "url": "/audio/fx/thwomp.ogg" } } } diff --git a/public/sounds/flag-pole.json b/public/sounds/flag-pole.json new file mode 100644 index 00000000..7f027163 --- /dev/null +++ b/public/sounds/flag-pole.json @@ -0,0 +1,7 @@ +{ + "fx": { + "ride": { + "url": "/audio/fx/flagpole.ogg" + } + } +} diff --git a/public/sounds/mario.json b/public/sounds/mario.json index 249ae90c..b2070da0 100644 --- a/public/sounds/mario.json +++ b/public/sounds/mario.json @@ -1,13 +1,13 @@ { "fx": { "coin": { - "url": "/audio/coin.ogg" + "url": "/audio/fx/coin.ogg" }, "jump": { - "url": "/audio/jump.ogg" + "url": "/audio/fx/jump.ogg" }, "stomp": { - "url": "/audio/stomp.ogg" + "url": "/audio/fx/stomp.ogg" } } } diff --git a/public/sounds/pipe-portal.json b/public/sounds/pipe-portal.json new file mode 100644 index 00000000..9c083fcc --- /dev/null +++ b/public/sounds/pipe-portal.json @@ -0,0 +1,7 @@ +{ + "fx": { + "pipe": { + "url": "/audio/fx/pipe.ogg" + } + } +} diff --git a/public/sprites/brick-shrapnel.json b/public/sprites/brick-shrapnel.json new file mode 100644 index 00000000..8db63680 --- /dev/null +++ b/public/sprites/brick-shrapnel.json @@ -0,0 +1,35 @@ +{ + "imageURL": "/img/sprites.png", + + "frames": [ + { + "name": "brick-1", + "rect": [192, 168, 8, 8] + }, + { + "name": "brick-2", + "rect": [200, 168, 8, 8] + }, + { + "name": "brick-3", + "rect": [192, 176, 8, 8] + }, + { + "name": "brick-4", + "rect": [200, 176, 8, 8] + } + ], + + "animations": [ + { + "name": "spinning-brick", + "frameLen": 0.15, + "frames": [ + "brick-1", + "brick-2", + "brick-3", + "brick-4" + ] + } + ] +} diff --git a/public/sprites/bullet.json b/public/sprites/bullet.json index fde315ae..5a51ac92 100644 --- a/public/sprites/bullet.json +++ b/public/sprites/bullet.json @@ -1,10 +1,10 @@ { - "imageURL": "/img/characters.gif", + "imageURL": "/img/sprites.png", "frames": [ { "name": "bullet", - "rect": [267, 334, 16, 14] + "rect": [128, 0, 16, 16] } ] } diff --git a/public/sprites/castle.json b/public/sprites/castle.json new file mode 100644 index 00000000..390ecda0 --- /dev/null +++ b/public/sprites/castle.json @@ -0,0 +1,121 @@ +{ + "imageURL": "/img/tiles.png", + "tileW": 16, + "tileH": 16, + + "tiles": [ + { + "name": "ground", + "index": [14, 1] + }, + { + "name": "sky", + "index": [13, 7] + }, + { + "name": "bricks", + "index": [1, 1] + }, + { + "name": "tile-red", + "index": [8, 7] + }, + { + "name": "waves", + "index": [2, 7] + }, + { + "name": "metal", + "index": [2, 1] + }, + { + "name": "metal-alt", + "index": [7, 1] + }, + { + "name": "chance-1", + "index": [4, 1] + }, + { + "name": "chance-2", + "index": [5, 1] + }, + { + "name": "chance-3", + "index": [6, 1] + }, + { + "name": "coin-1", + "index": [15, 9] + }, + { + "name": "coin-2", + "index": [15, 10] + }, + { + "name": "coin-3", + "index": [15, 11] + }, + { + "name": "pipe-insert-vert-left", + "index": [0, 3] + }, + { + "name": "pipe-insert-vert-right", + "index": [1, 3] + }, + { + "name": "pipe-vert-left", + "index": [0, 4] + }, + { + "name": "pipe-vert-right", + "index": [1, 4] + }, + { + "name": "beam-track", + "index": [11, 13] + }, + { + "name": "bridge", + "index": [13, 4] + }, + { + "name": "bridge-chain", + "index": [13, 3] + }, + { + "name": "toad-1", + "index": [15, 12] + }, + { + "name": "toad-2", + "index": [15, 13] + } + ], + + "animations": [ + { + "name": "chance", + "frameLen": 0.16, + "frames": [ + "chance-1", + "chance-1", + "chance-2", + "chance-3", + "chance-2" + ] + }, + { + "name": "coin", + "frameLen": 0.16, + "frames": [ + "coin-1", + "coin-1", + "coin-2", + "coin-3", + "coin-2" + ] + } + ] +} diff --git a/public/sprites/cheep-gray.json b/public/sprites/cheep-gray.json new file mode 100644 index 00000000..f0c3e10c --- /dev/null +++ b/public/sprites/cheep-gray.json @@ -0,0 +1,25 @@ +{ + "imageURL": "/img/sprites.png", + + "frames": [ + { + "name": "swim-1", + "rect": [48, 32, 16, 16] + }, + { + "name": "swim-2", + "rect": [64, 32, 16, 16] + } + ], + + "animations": [ + { + "name": "swim", + "frameLen": 0.13, + "frames": [ + "swim-1", + "swim-2" + ] + } + ] +} diff --git a/public/sprites/cheep-red.json b/public/sprites/cheep-red.json new file mode 100644 index 00000000..65087860 --- /dev/null +++ b/public/sprites/cheep-red.json @@ -0,0 +1,25 @@ +{ + "imageURL": "/img/sprites.png", + + "frames": [ + { + "name": "swim-1", + "rect": [48, 0, 16, 16] + }, + { + "name": "swim-2", + "rect": [64, 0, 16, 16] + } + ], + + "animations": [ + { + "name": "swim", + "frameLen": 0.13, + "frames": [ + "swim-1", + "swim-2" + ] + } + ] +} diff --git a/public/sprites/goomba.json b/public/sprites/goomba-blue.json similarity index 70% rename from public/sprites/goomba.json rename to public/sprites/goomba-blue.json index 5795a71e..3186486e 100644 --- a/public/sprites/goomba.json +++ b/public/sprites/goomba-blue.json @@ -1,18 +1,18 @@ { - "imageURL": "/img/characters.gif", + "imageURL": "/img/sprites.png", "frames": [ { "name": "walk-1", - "rect": [296, 187, 16, 16] + "rect": [80, 16, 16, 16] }, { "name": "walk-2", - "rect": [315, 187, 16, 16] + "rect": [96, 16, 16, 16] }, { "name": "flat", - "rect": [277, 187, 16, 16] + "rect": [112, 16, 16, 16] } ], diff --git a/public/sprites/goomba-brown.json b/public/sprites/goomba-brown.json new file mode 100644 index 00000000..00a5633a --- /dev/null +++ b/public/sprites/goomba-brown.json @@ -0,0 +1,29 @@ +{ + "imageURL": "/img/sprites.png", + + "frames": [ + { + "name": "walk-1", + "rect": [80, 0, 16, 16] + }, + { + "name": "walk-2", + "rect": [96, 0, 16, 16] + }, + { + "name": "flat", + "rect": [112, 0, 16, 16] + } + ], + + "animations": [ + { + "name": "walk", + "frameLen": 0.15, + "frames": [ + "walk-1", + "walk-2" + ] + } + ] +} diff --git a/public/sprites/koopa.json b/public/sprites/koopa-blue.json similarity index 75% rename from public/sprites/koopa.json rename to public/sprites/koopa-blue.json index 6ee79e4a..9c3432ce 100644 --- a/public/sprites/koopa.json +++ b/public/sprites/koopa-blue.json @@ -1,22 +1,22 @@ { - "imageURL": "/img/characters.gif", + "imageURL": "/img/sprites.png", "frames": [ { "name": "walk-1", - "rect": [296, 206, 16, 24] + "rect": [224, 48, 16, 24] }, { "name": "walk-2", - "rect": [315, 206, 16, 24] + "rect": [240, 48, 16, 24] }, { "name": "hiding", - "rect": [144, 206, 16, 24] + "rect": [240, 168, 16, 24] }, { "name": "hiding-with-legs", - "rect": [163, 206, 16, 24] + "rect": [240, 192, 16, 24] } ], diff --git a/public/sprites/koopa-green.json b/public/sprites/koopa-green.json new file mode 100644 index 00000000..5e579c0d --- /dev/null +++ b/public/sprites/koopa-green.json @@ -0,0 +1,41 @@ +{ + "imageURL": "/img/sprites.png", + + "frames": [ + { + "name": "walk-1", + "rect": [224, 0, 16, 24] + }, + { + "name": "walk-2", + "rect": [240, 0, 16, 24] + }, + { + "name": "hiding", + "rect": [208, 168, 16, 24] + }, + { + "name": "hiding-with-legs", + "rect": [208, 192, 16, 24] + } + ], + + "animations": [ + { + "name": "walk", + "frameLen": 0.15, + "frames": [ + "walk-1", + "walk-2" + ] + }, + { + "name": "wake", + "frameLen": 0.15, + "frames": [ + "hiding-with-legs", + "hiding" + ] + } + ] +} diff --git a/public/sprites/mario.json b/public/sprites/mario.json index 4f530528..ffef6394 100644 --- a/public/sprites/mario.json +++ b/public/sprites/mario.json @@ -1,30 +1,90 @@ { - "imageURL": "/img/characters.gif", + "imageURL": "/img/sprites.png", "frames": [ { "name": "idle", - "rect": [276, 44, 16, 16] + "rect": [0, 88, 16, 16] }, { "name": "run-1", - "rect": [290, 44, 16, 16] + "rect": [16, 88, 16, 16] }, { "name": "run-2", - "rect": [304, 43, 16, 16] + "rect": [32, 88, 16, 16] }, { "name": "run-3", - "rect": [321, 44, 16, 16] + "rect": [48, 88, 16, 16] }, { "name": "break", - "rect": [337, 44, 16, 16] + "rect": [64, 88, 16, 16] }, { "name": "jump", - "rect": [355, 44, 16, 16] + "rect": [80, 88, 16, 16] + }, + { + "name": "die", + "rect": [96, 88, 16, 16] + }, + { + "name": "climb-1", + "rect": [0, 104, 16, 16] + }, + { + "name": "climb-2", + "rect": [16, 104, 16, 16] + }, + { + "name": "swim-1", + "rect": [32, 104, 16, 16] + }, + { + "name": "swim-2", + "rect": [48, 104, 16, 16] + }, + { + "name": "swim-3", + "rect": [64, 104, 16, 16] + }, + { + "name": "swim-4", + "rect": [80, 104, 16, 16] + }, + { + "name": "swim-5", + "rect": [96, 104, 16, 16] + }, + { + "name": "idle-large", + "rect": [112, 88, 16, 32] + }, + { + "name": "run-1-large", + "rect": [128, 88, 16, 32] + }, + { + "name": "run-2-large", + "rect": [144, 88, 16, 32] + }, + { + "name": "run-3-large", + "rect": [160, 88, 16, 32] + }, + { + "name": "break-large", + "rect": [176, 88, 16, 32] + }, + { + "name": "jump-large", + "rect": [192, 88, 16, 32] + }, + { + "name": "crouch-large", + "rect": [0, 120, 16, 32] } ], @@ -37,6 +97,40 @@ "run-2", "run-3" ] + }, + { + "name": "climb", + "frameLen": 4, + "frames": [ + "climb-1", + "climb-2" + ] + }, + { + "name": "swim-idle", + "frameLen": 4, + "frames": [ + "swim-1", + "swim-2" + ] + }, + { + "name": "swim", + "frameLen": 6, + "frames": [ + "swim-3", + "swim-4", + "swim-5" + ] + }, + { + "name": "run-large", + "frameLen": 6, + "frames": [ + "run-1-large", + "run-2-large", + "run-3-large" + ] } ] } diff --git a/public/sprites/overworld.json b/public/sprites/overworld.json index 65770e83..0d6075ce 100644 --- a/public/sprites/overworld.json +++ b/public/sprites/overworld.json @@ -10,105 +10,294 @@ }, { "name": "sky", - "index": [3, 23] + "index": [14, 7] }, { "name": "chocolate", - "index": [0, 1] + "index": [3, 0] }, { "name": "bricks", "index": [1, 0] }, { - "name": "chance", - "index": [24, 0] + "name": "bricks-top", + "index": [14, 0] + }, + { + "name": "metal", + "index": [2, 0] }, - { "name": "chance-1", - "index": [24, 0] + "index": [4, 0] }, { "name": "chance-2", - "index": [25, 0] + "index": [5, 0] }, { "name": "chance-3", - "index": [26, 0] + "index": [6, 0] }, - { "name": "coin-1", - "index": [24, 1] + "index": [15, 0] }, { "name": "coin-2", - "index": [25, 1] + "index": [15, 1] }, { "name": "coin-3", - "index": [26, 1] + "index": [15, 2] }, - { "name": "pipe-insert-vert-left", - "index": [0, 8] + "index": [0, 5] }, { "name": "pipe-insert-vert-right", - "index": [1, 8] + "index": [1, 5] }, { "name": "pipe-vert-left", - "index": [0, 9] + "index": [0, 6] }, { "name": "pipe-vert-right", - "index": [1, 9] + "index": [1, 6] + }, + { + "name": "pipe-chrome-insert-vert-left", + "index": [2, 3] + }, + { + "name": "pipe-chrome-insert-vert-right", + "index": [3, 3] + }, + { + "name": "pipe-chrome-vert-left", + "index": [2, 4] + }, + { + "name": "pipe-chrome-vert-right", + "index": [3, 4] + }, + { + "name": "pipe-insert-hor-top", + "index": [6, 3] + }, + { + "name": "pipe-insert-hor-bottom", + "index": [6, 4] + }, + { + "name": "pipe-hor-top", + "index": [7, 3] + }, + { + "name": "pipe-hor-bottom", + "index": [7, 4] + }, + { + "name": "pipe-conn-hor-top", + "index": [8, 3] + }, + { + "name": "pipe-conn-hor-bottom", + "index": [8, 4] + }, + { + "name": "cloud-tile", + "index": [14, 8] }, { "name": "cloud-1-1", - "index": [0, 20] + "index": [11, 10] }, { "name": "cloud-1-2", - "index": [1, 20] + "index": [12, 10] }, { "name": "cloud-1-3", - "index": [2, 20] + "index": [13, 10] }, { "name": "cloud-2-1", - "index": [0, 21] + "index": [11, 11] }, { "name": "cloud-2-2", - "index": [1, 21] + "index": [12, 11] }, { "name": "cloud-2-3", - "index": [2, 21] + "index": [13, 11] }, { "name": "cannon-1", - "index": [9, 0] + "index": [14, 3] }, { "name": "cannon-2", - "index": [8, 1] + "index": [14, 4] }, { "name": "cannon-3", - "index": [9, 1] + "index": [14, 5] + }, + { + "name": "bush-1", + "index": [11, 12] + }, + { + "name": "bush-2", + "index": [12, 12] + }, + { + "name": "bush-3", + "index": [13, 12] + }, + { + "name": "grass-left", + "index": [9, 2] + }, + { + "name": "grass", + "index": [10, 2] + }, + { + "name": "grass-right", + "index": [11, 2] + }, + { + "name": "dirt", + "index": [13, 0] + }, + { + "name": "tile-black", + "index": [13, 7] + }, + { + "name": "tile-light-blue", + "index": [10, 7] + }, + { + "name": "castle-top-closed", + "index": [8, 0] + }, + { + "name": "castle-top-open", + "index": [9, 0] + }, + { + "name": "castle-window-right", + "index": [10, 0] + }, + { + "name": "castle-arch", + "index": [11, 0] + }, + { + "name": "castle-window-left", + "index": [12, 0] + }, + { + "name": "pole-green", + "index": [12, 13] + }, + { + "name": "pole-white", + "index": [11, 13] + }, + { + "name": "pole-finial-dark-grey", + "index": [7, 8] + }, + { + "name": "pole-finial-green", + "index": [8, 8] + }, + { + "name": "hill-left", + "index": [4, 7] + }, + { + "name": "hill-right", + "index": [6, 7] + }, + { + "name": "hill-top", + "index": [7, 7] + }, + { + "name": "hill-stains-right", + "index": [5, 7] + }, + { + "name": "hill-stains-left", + "index": [3, 7] + }, + { + "name": "tile-green", + "index": [12, 7] + }, + { + "name": "tree-large-top", + "index": [10, 5] + }, + { + "name": "tree-large-bottom", + "index": [10, 6] + }, + { + "name": "tree-small", + "index": [12, 5] + }, + { + "name": "tree-white-large-top", + "index": [11, 5] + }, + { + "name": "tree-white-large-bottom", + "index": [11, 6] + }, + { + "name": "tree-white-small", + "index": [13, 5] + }, + { + "name": "tree-trunk", + "index": [12, 6] + }, + { + "name": "fence", + "index": [14, 6] + }, + { + "name": "bridge", + "index": [13, 6] + }, + { + "name": "bridge-rail-green", + "index": [14, 11] + }, + { + "name": "bridge-rail-white", + "index": [14, 10] + }, + { + "name": "waves", + "index": [0, 7] } ], "animations": [ { "name": "chance", - "frameLen": 0.12, + "frameLen": 0.16, "frames": [ "chance-1", "chance-1", @@ -119,7 +308,7 @@ }, { "name": "coin", - "frameLen": 0.12, + "frameLen": 0.16, "frames": [ "coin-1", "coin-1", diff --git a/public/sprites/patterns/castle-pattern.json b/public/sprites/patterns/castle-pattern.json new file mode 100644 index 00000000..dc2f135e --- /dev/null +++ b/public/sprites/patterns/castle-pattern.json @@ -0,0 +1,149 @@ +{ + "entrance-stairs": { + "tiles": [ + { + "style": "ground", + "behavior": "ground", + "ranges": [ + [0, 3, 1, 1], + [0, 4, 2, 1], + [0, 5, 3, 1] + ] + } + ] + }, + + "pipe-section-vert": { + "tiles": [ + { + "style": "pipe-vert-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "pipe-vert-right", + "behavior": "ground", + "ranges": [ + [1, 0] + ] + } + ] + }, + + "pipe-cap-vert": { + "tiles": [ + { + "style": "pipe-insert-vert-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "pipe-insert-vert-right", + "behavior": "ground", + "ranges": [ + [1, 0] + ] + } + ] + }, + + "pipe-2h": { + "tiles": [ + { + "pattern": "pipe-cap-vert", + "ranges": [ + [0, 0] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [ + 0, 1, + 1, 1 + ] + ] + } + ] + }, + + "pipe-3h": { + "tiles": [ + { + "pattern": "pipe-cap-vert", + "ranges": [ + [0, 0] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [ + 0, 1, + 1, 2 + ] + ] + } + ] + }, + + "pipe-4h": { + "tiles": [ + { + "pattern": "pipe-cap-vert", + "ranges": [ + [0, 0] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [ + 0, 1, + 1, 3 + ] + ] + } + ] + }, + + "bridge": { + "tiles": [ + { + "style": "bridge", + "behavior": "ground", + "ranges": [ + [0, 13, 1] + ] + }, + { + "style": "bridge-chain", + "ranges": [ + [12, 0] + ] + } + ] + }, + + "toad": { + "tiles": [ + { + "style": "toad-1", + "ranges": [ + [0, 0] + ] + }, + { + "style": "toad-2", + "ranges": [ + [0, 1] + ] + } + ] + } + +} diff --git a/public/sprites/patterns/overworld-pattern.json b/public/sprites/patterns/overworld-pattern.json index cc669748..4439da13 100644 --- a/public/sprites/patterns/overworld-pattern.json +++ b/public/sprites/patterns/overworld-pattern.json @@ -2,28 +2,222 @@ "cloud-single": { "tiles": [ { - "name": "cloud-1-1", - "ranges": [[0, 0]] + "style": "cloud-1-1", + "ranges": [ + [0, 0] + ] + }, + { + "style": "cloud-1-2", + "ranges": [ + [1, 0] + ] + }, + { + "style": "cloud-1-3", + "ranges": [ + [2, 0] + ] + }, + { + "style": "cloud-2-1", + "ranges": [ + [0, 1] + ] + }, + { + "style": "cloud-2-2", + "ranges": [ + [1, 1] + ] + }, + { + "style": "cloud-2-3", + "ranges": [ + [2, 1] + ] + } + ] + }, + + "cloud-double": { + "tiles": [ + { + "style": "cloud-1-1", + "ranges": [ + [0, 0] + ] + }, + { + "style": "cloud-1-2", + "ranges": [ + [1, 2, 0] + ] + }, + { + "style": "cloud-1-3", + "ranges": [ + [3, 0] + ] + }, + + { + "style": "cloud-2-1", + "ranges": [ + [0, 1] + ] + }, + { + "style": "cloud-2-2", + "ranges": [ + [1, 2, 1] + ] + }, + { + "style": "cloud-2-3", + "ranges": [ + [3, 1] + ] + } + ] + }, + + "cloud-triple": { + "tiles": [ + { + "style": "cloud-1-1", + "ranges": [ + [0, 0] + ] + }, + { + "style": "cloud-1-2", + "ranges": [ + [1, 3, 0] + ] + }, + { + "style": "cloud-1-3", + "ranges": [ + [4, 0] + ] + }, + + { + "style": "cloud-2-1", + "ranges": [ + [0, 1] + ] + }, + { + "style": "cloud-2-2", + "ranges": [ + [1, 3, 1] + ] + }, + { + "style": "cloud-2-3", + "ranges": [ + [4, 1] + ] + } + ] + }, + + "pipe-chrome-section-vert": { + "tiles": [ + { + "style": "pipe-chrome-vert-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] }, { - "name": "cloud-1-2", - "ranges": [[1, 0]] + "style": "pipe-chrome-vert-right", + "behavior": "ground", + "ranges": [ + [1, 0] + ] + } + ] + }, + + "pipe-chrome-cap-vert": { + "tiles": [ + { + "style": "pipe-chrome-insert-vert-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] }, { - "name": "cloud-1-3", - "ranges": [[2, 0]] + "style": "pipe-chrome-insert-vert-right", + "behavior": "ground", + "ranges": [ + [1, 0] + ] + } + ] + }, + + "pipe-chrome-2h": { + "tiles": [ + { + "pattern": "pipe-chrome-cap-vert", + "ranges": [ + [0, 0] + ] }, { - "name": "cloud-2-1", - "ranges": [[0, 1]] + "pattern": "pipe-chrome-section-vert", + "ranges": [ + [ + 0, 1, + 1, 1 + ] + ] + } + ] + }, + + "pipe-chrome-3h": { + "tiles": [ + { + "pattern": "pipe-chrome-cap-vert", + "ranges": [ + [0, 0] + ] }, { - "name": "cloud-2-2", - "ranges": [[1, 1]] + "pattern": "pipe-chrome-section-vert", + "ranges": [ + [ + 0, 1, + 1, 2 + ] + ] + } + ] + }, + + "pipe-chrome-4h": { + "tiles": [ + { + "pattern": "pipe-chrome-cap-vert", + "ranges": [ + [0, 0] + ] }, { - "name": "cloud-2-3", - "ranges": [[2, 1]] + "pattern": "pipe-chrome-section-vert", + "ranges": [ + [ + 0, 1, + 1, 3 + ] + ] } ] }, @@ -31,15 +225,15 @@ "pipe-section-vert": { "tiles": [ { - "name": "pipe-vert-left", - "type": "ground", + "style": "pipe-vert-left", + "behavior": "ground", "ranges": [ [0, 0] ] }, { - "name": "pipe-vert-right", - "type": "ground", + "style": "pipe-vert-right", + "behavior": "ground", "ranges": [ [1, 0] ] @@ -50,15 +244,15 @@ "pipe-cap-vert": { "tiles": [ { - "name": "pipe-insert-vert-left", - "type": "ground", + "style": "pipe-insert-vert-left", + "behavior": "ground", "ranges": [ [0, 0] ] }, { - "name": "pipe-insert-vert-right", - "type": "ground", + "style": "pipe-insert-vert-right", + "behavior": "ground", "ranges": [ [1, 0] ] @@ -126,22 +320,913 @@ ] }, + "pipe-5h": { + "tiles": [ + { + "pattern": "pipe-cap-vert", + "ranges": [ + [0, 0] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [ + 0, 1, + 1, 4 + ] + ] + } + ] + }, + + "pipe-uw-entrance": { + "tiles": [ + { + "pattern": "pipe-4h", + "ranges": [ + [2, 0] + ] + }, + { + "style": "pipe-insert-hor-top", + "ranges": [ + [0, 2] + ] + }, + { + "style": "pipe-insert-hor-bottom", + "ranges": [ + [0, 3] + ] + }, + { + "style": "pipe-hor-top", + "ranges": [ + [1, 2] + ] + }, + { + "style": "pipe-hor-bottom", + "ranges": [ + [1, 3] + ] + }, + { + "style": "pipe-conn-hor-top", + "ranges": [ + [2, 2] + ] + }, + { + "style": "pipe-conn-hor-bottom", + "ranges": [ + [2, 3] + ] + } + ] + }, + "cannon-2h": { "tiles": [ { - "name": "cannon-1", - "type": "ground", + "style": "cannon-1", + "behavior": "ground", "ranges": [ [0, 0] ] }, { - "name": "cannon-3", - "type": "ground", + "style": "cannon-2", + "behavior": "ground", "ranges": [ [0, 1] ] } ] - } + }, + + "bush-single": { + "tiles": [ + { + "style": "bush-1", + "ranges": [ + [0, 0] + ] + }, + { + "style": "bush-2", + "ranges": [ + [1, 0] + ] + }, + { + "style": "bush-3", + "ranges": [ + [2, 0] + ] + } + + ] + }, + + "bush-double": { + "tiles": [ + { + "style": "bush-1", + "ranges": [ + [0, 0] + ] + }, + { + "style": "bush-2", + "ranges": [ + [1, 0], + [2, 0] + ] + }, + { + "style": "bush-3", + "ranges": [ + [3, 0] + ] + } + ] + }, + + "bush-triple": { + "tiles": [ + { + "style": "bush-1", + "ranges": [ + [0, 0] + ] + }, + { + "style": "bush-2", + "ranges": [ + [1, 0], + [2, 0], + [3, 0] + ] + }, + { + "style": "bush-3", + "ranges": [ + [4, 0] + ] + } + ] + }, + + "hill-small": { + "tiles": [ + { + "style": "hill-top", + "ranges": [ + [1, 0] + ] + }, + { + "style": "hill-left", + "ranges": [ + [0, 1] + ] + }, + { + "style": "hill-stains-right", + "ranges": [ + [1, 1] + ] + }, + { + "style": "hill-right", + "ranges": [ + [2, 1] + ] + } + ] + }, + + "hill-large": { + "tiles": [ + { + "pattern": "hill-small", + "ranges": [ + [1, 0] + ] + }, + { + "style": "hill-left", + "ranges": [ + [0, 2] + ] + }, + { + "style": "hill-stains-right", + "ranges": [ + [1, 2] + ] + }, + { + "style": "tile-green", + "ranges": [ + [2, 2] + ] + }, + { + "style": "hill-stains-left", + "ranges": [ + [3, 2] + ] + }, + { + "style": "hill-right", + "ranges": [ + [4, 2] + ] + } + ] + }, + + "grass-top-3w": { + "tiles": [ + { + "style": "grass-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "grass", + "behavior": "ground", + "ranges": [ + [1, 0] + ] + }, + { + "style": "grass-right", + "behavior": "ground", + "ranges": [ + [2, 0] + ] + } + ] + }, + + "grass-top-4w": { + "tiles": [ + { + "style": "grass-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "grass", + "behavior": "ground", + "ranges": [ + [1, 2, 0, 1] + ] + }, + { + "style": "grass-right", + "behavior": "ground", + "ranges": [ + [3, 0] + ] + } + ] + }, + + "grass-top-5w": { + "tiles": [ + { + "style": "grass-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "grass", + "behavior": "ground", + "ranges": [ + [1, 3, 0, 1] + ] + }, + { + "style": "grass-right", + "behavior": "ground", + "ranges": [ + [4, 0] + ] + } + ] + }, + + "grass-top-6w": { + "tiles": [ + { + "style": "grass-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "grass", + "behavior": "ground", + "ranges": [ + [1, 4, 0, 1] + ] + }, + { + "style": "grass-right", + "behavior": "ground", + "ranges": [ + [5, 0] + ] + } + ] + }, + + "grass-top-7w": { + "tiles": [ + { + "style": "grass-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "grass", + "behavior": "ground", + "ranges": [ + [1, 5, 0, 1] + ] + }, + { + "style": "grass-right", + "behavior": "ground", + "ranges": [ + [6, 0] + ] + } + ] + }, + + "grass-top-8w": { + "tiles": [ + { + "style": "grass-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "grass", + "behavior": "ground", + "ranges": [ + [1, 6, 0, 1] + ] + }, + { + "style": "grass-right", + "behavior": "ground", + "ranges": [ + [7, 0] + ] + } + ] + }, + + "grass-top-13w": { + "tiles": [ + { + "style": "grass-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "grass", + "behavior": "ground", + "ranges": [ + [1, 11, 0, 1] + ] + }, + { + "style": "grass-right", + "behavior": "ground", + "ranges": [ + [12, 0] + ] + } + ] + }, + + "castle-wall-3h": { + "tiles": [ + { + "style": "castle-top-open", + "ranges": [ + [0, 0] + ] + }, + { + "style": "bricks", + "ranges": [ + [0, 1, 1, 2] + ] + } + ] + }, + + "castle-wall-6h": { + "tiles": [ + { + "style": "castle-top-open", + "ranges": [ + [0, 0] + ] + }, + { + "style": "bricks", + "ranges": [ + [0, 1, 1, 5] + ] + } + ] + }, + + "castle-opening": { + "tiles": [ + { + "style": "castle-arch", + "ranges": [ + [0, 0] + ] + }, + { + "style": "tile-black", + "ranges": [ + [0, 1] + ] + } + ] + }, + + "castle-small": { + "tiles": [ + { + "pattern": "castle-wall-3h", + "ranges": [ + [0, 2], + [4, 2] + ] + }, + { + "style": "castle-top-open", + "ranges": [ + [1, 3, 0, 1] + ] + }, + { + "style": "castle-window-left", + "ranges": [ + [1, 1] + ] + }, + { + "style": "castle-window-right", + "ranges": [ + [3, 1] + ] + }, + { + "style": "bricks", + "ranges": [ + [2, 1], + [1, 3, 3, 2] + + ] + }, + { + "style": "castle-top-closed", + "ranges": [ + [1, 3, 2, 1] + ] + }, + { + "pattern": "castle-opening", + "ranges": [ + [2, 3] + ] + } + ] + }, + + "castle-large": { + "tiles": [ + { + "pattern": "castle-small", + "ranges": [ + [2, 0] + ] + }, + { + "pattern": "castle-wall-6h", + "ranges": [ + [0, 2, 5, 1], + [7, 2, 5, 1] + ] + }, + { + "style": "castle-top-closed", + "ranges": [ + [2, 5, 5, 1] + ] + }, + { + "style": "bricks", + "ranges": [ + [2, 5, 6, 5] + ] + }, + { + "pattern": "castle-opening", + "ranges": [ + [3, 6], + [5, 6], + [2, 9], + [4, 9], + [6, 9] + ] + } + ] + }, + + "flag-pole-green": { + "tiles": [ + { + "style": "pole-finial-green", + "ranges": [ + [0, 0] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 10] + ] + }, + { + "style": "pole-green", + "ranges": [ + [0, 1, 1, 9] + ] + } + + ] + }, + + "flag-pole-dark-grey": { + "tiles": [ + { + "style": "pole-finial-dark-grey", + "ranges": [ + [0, 0] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 10] + ] + }, + { + "style": "pole-white", + "ranges": [ + [0, 1, 1, 9] + ] + } + + ] + }, + + "chocolate-stack-2h": { + "tiles": [ + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 1, 0, 2] + ] + } + ] + }, + + "chocolate-stack-3h": { + "tiles": [ + { + "pattern": "chocolate-stack-2h", + "ranges": [ + [0, 0] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 2] + ] + } + ] + }, + + "chocolate-stack-4h": { + "tiles": [ + { + "pattern": "chocolate-stack-2h", + "ranges": [ + [0, 0], + [0, 2] + ] + } + ] + }, + + "chocolate-stack-5h": { + "tiles": [ + { + "pattern": "chocolate-stack-4h", + "ranges": [ + [0, 0] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 4] + ] + } + ] + }, + + "chocolate-stack-6h": { + "tiles": [ + { + "pattern": "chocolate-stack-3h", + "ranges": [ + [0, 0], + [0, 3] + ] + } + ] + }, + + "chocolate-stairs-2h": { + "tiles": [ + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [1, 1, 0, 2], + [0, 1] + ] + } + ] + }, + + "chocolate-stairs-2h-reverse": { + "tiles": [ + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 0], + [0, 2, 1, 1] + ] + } + ] + }, + + "chocolate-stairs-3h": { + "tiles": [ + { + "pattern": "chocolate-stairs-2h", + "ranges": [ + [0, 1] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [2, 1, 0, 3] + ] + } + ] + }, + + "chocolate-stairs-3h-reverse": { + "tiles": [ + { + "pattern": "chocolate-stairs-2h-reverse", + "ranges": [ + [0, 0] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 3, 2, 1] + ] + } + ] + }, + + "chocolate-stairs-4h": { + "tiles": [ + { + "pattern": "chocolate-stairs-3h", + "ranges": [ + [0, 1] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [3, 1, 0, 4] + ] + } + ] + }, + + "chocolate-stairs-4h-reverse": { + "tiles": [ + { + "pattern": "chocolate-stairs-3h-reverse", + "ranges": [ + [0, 0] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 4, 3, 1] + ] + } + ] + }, + + "chocolate-stairs-final": { + "tiles": [ + { + "pattern": "chocolate-stairs-4h", + "ranges": [ + [0, 4], + [4, 0] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [4, 4, 4, 4], + [8, 1, 0, 8] + ] + } + + ] + }, + + "tree-small": { + "tiles": [ + { + "style": "tree-small", + "ranges": [ + [0, 0] + ] + }, + { + "style": "tree-trunk", + "ranges": [ + [0, 1] + ] + } + ] + }, + + "tree-large": { + "tiles": [ + { + "style": "tree-large-top", + "ranges": [ + [0, 0] + ] + }, + { + "style": "tree-large-bottom", + "ranges": [ + [0, 1] + ] + }, + { + "style": "tree-trunk", + "ranges": [ + [0, 2] + ] + } + ] + }, + + "tree-white-small": { + "tiles": [ + { + "style": "tree-white-small", + "ranges": [ + [0, 0] + ] + }, + { + "style": "tree-trunk", + "ranges": [ + [0, 1] + ] + } + ] + }, + + "tree-white-large": { + "tiles": [ + { + "style": "tree-white-large-top", + "ranges": [ + [0, 0] + ] + }, + { + "style": "tree-white-large-bottom", + "ranges": [ + [0, 1] + ] + }, + { + "style": "tree-trunk", + "ranges": [ + [0, 2] + ] + } + ] + }, + + "bridge-green": { + "tiles": [ + { + "style": "bridge", + "behavior": "ground", + "ranges": [ + [0, 1] + ] + }, + { + "style": "bridge-rail-green", + "ranges": [ + [0, 0] + ] + } + ] + }, + + "bridge-white": { + "tiles": [ + { + "style": "bridge", + "behavior": "ground", + "ranges": [ + [0, 1] + ] + }, + { + "style": "bridge-rail-white", + "ranges": [ + [0, 0] + ] + } + ] + } + } diff --git a/public/sprites/patterns/underwater-pattern.json b/public/sprites/patterns/underwater-pattern.json new file mode 100644 index 00000000..6f77fbcb --- /dev/null +++ b/public/sprites/patterns/underwater-pattern.json @@ -0,0 +1,37 @@ +{ + "water": { + "tiles": [ + { + "style": "waves", + "ranges": [ + [0, 0] + ] + }, + { + "style": "water", + "ranges": [ + [0, 1, 1, 12] + ] + } + ] + }, + "pipe-cap-hor": { + "tiles": [ + { + "style": "pipe-insert-hor-top", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "pipe-insert-hor-bottom", + "behavior": "ground", + "ranges": [ + [0, 1] + ] + } + ] + } + +} diff --git a/public/sprites/patterns/underworld-pattern.json b/public/sprites/patterns/underworld-pattern.json new file mode 100644 index 00000000..e26ed4d6 --- /dev/null +++ b/public/sprites/patterns/underworld-pattern.json @@ -0,0 +1,299 @@ +{ + "pipe-section-vert": { + "tiles": [ + { + "style": "pipe-vert-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "pipe-vert-right", + "behavior": "ground", + "ranges": [ + [1, 0] + ] + } + ] + }, + + "pipe-cap-vert": { + "tiles": [ + { + "style": "pipe-insert-vert-left", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "pipe-insert-vert-right", + "behavior": "ground", + "ranges": [ + [1, 0] + ] + } + ] + }, + + "pipe-section-hor": { + "tiles": [ + { + "style": "pipe-hor-top", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "pipe-hor-bottom", + "behavior": "ground", + "ranges": [ + [0, 1] + ] + } + ] + }, + + "pipe-cap-hor": { + "tiles": [ + { + "style": "pipe-insert-hor-top", + "behavior": "ground", + "ranges": [ + [0, 0] + ] + }, + { + "style": "pipe-insert-hor-bottom", + "behavior": "ground", + "ranges": [ + [0, 1] + ] + } + ] + }, + + "pipe-conn-hor": { + "tiles": [ + { + "style": "pipe-conn-hor-top", + "ranges": [ + [0, 0] + ] + }, + { + "style": "pipe-conn-hor-bottom", + "ranges": [ + [0, 1] + ] + } + ] + }, + + "exit-pipe-12h" : { + "tiles": [ + { + "pattern": "pipe-cap-hor", + "ranges": [ + [0, 9] + ] + }, + { + "pattern": "pipe-section-hor", + "ranges": [ + [1, 9] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [2, 1, 0, 11] + ] + }, + { + "pattern": "pipe-conn-hor", + "ranges": [ + [2, 9] + ] + } + ] + }, + + "exit-pipe-8h" : { + "tiles": [ + { + "pattern": "pipe-cap-hor", + "ranges": [ + [0, 6] + ] + }, + { + "pattern": "pipe-section-hor", + "ranges": [ + [1, 6] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [2, 1, 0, 8] + ] + }, + { + "pattern": "pipe-conn-hor", + "ranges": [ + [2, 6] + ] + } + ] + }, + + + "pipe-2h": { + "tiles": [ + { + "pattern": "pipe-cap-vert", + "ranges": [ + [0, 0] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [ + 0, 1, + 1, 1 + ] + ] + } + ] + }, + + "pipe-3h": { + "tiles": [ + { + "pattern": "pipe-cap-vert", + "ranges": [ + [0, 0] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [ + 0, 1, + 1, 2 + ] + ] + } + ] + }, + + "pipe-4h": { + "tiles": [ + { + "pattern": "pipe-cap-vert", + "ranges": [ + [0, 0] + ] + }, + { + "pattern": "pipe-section-vert", + "ranges": [ + [ + 0, 1, + 1, 3 + ] + ] + } + ] + }, + + "chocolate-stack-2h": { + "tiles": [ + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 1, 0, 2] + ] + } + ] + }, + + "chocolate-stack-3h": { + "tiles": [ + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [0, 1, 0, 3] + ] + } + ] + }, + + "chocolate-stack-4h": { + "tiles": [ + { + "pattern": "chocolate-stack-2h", + "ranges": [ + [0, 0], + [0, 2] + ] + } + ] + }, + + "chocolate-stairs-2h": { + "tiles": [ + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [1, 1, 0, 2], + [0, 1] + ] + } + ] + }, + + "chocolate-stairs-3h": { + "tiles": [ + { + "pattern": "chocolate-stairs-2h", + "ranges": [ + [0, 1] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [2, 1, 0, 3] + ] + } + ] + }, + + "chocolate-stairs-4h": { + "tiles": [ + { + "pattern": "chocolate-stairs-3h", + "ranges": [ + [0, 1] + ] + }, + { + "style": "chocolate", + "behavior": "ground", + "ranges": [ + [3, 1, 0, 4] + ] + } + ] + } + +} diff --git a/public/sprites/piranha-plant.json b/public/sprites/piranha-plant.json new file mode 100644 index 00000000..9814bd17 --- /dev/null +++ b/public/sprites/piranha-plant.json @@ -0,0 +1,25 @@ +{ + "imageURL": "/img/sprites.png", + + "frames": [ + { + "name": "close", + "rect": [240, 72, 16, 24] + }, + { + "name": "open", + "rect": [240, 96, 16, 24] + } + ], + + "animations": [ + { + "name": "chew", + "frameLen": 0.15, + "frames": [ + "close", + "open" + ] + } + ] +} diff --git a/public/sprites/underwater.json b/public/sprites/underwater.json new file mode 100644 index 00000000..1f749b47 --- /dev/null +++ b/public/sprites/underwater.json @@ -0,0 +1,62 @@ +{ + "imageURL": "/img/tiles.png", + "tileW": 16, + "tileH": 16, + + "tiles": [ + { + "name": "ground", + "index": [12, 2] + }, + { + "name": "sky", + "index": [10, 7] + }, + { + "name": "water", + "index": [9, 7] + }, + { + "name": "waves", + "index": [1, 7] + }, + { + "name": "coral", + "index": [13, 2] + }, + { + "name": "coin-1", + "index": [15, 6] + }, + { + "name": "coin-2", + "index": [15, 7] + }, + { + "name": "coin-3", + "index": [15, 8] + }, + { + "name": "pipe-insert-hor-top", + "index": [9, 5] + }, + { + "name": "pipe-insert-hor-bottom", + "index": [9, 6] + } + ], + + "animations": [ + { + "name": "coin", + "frameLen": 0.16, + "frames": [ + "coin-1", + "coin-1", + "coin-2", + "coin-3", + "coin-2" + ] + } + ] +} diff --git a/public/sprites/underworld.json b/public/sprites/underworld.json index 26fac104..ae77d3c4 100644 --- a/public/sprites/underworld.json +++ b/public/sprites/underworld.json @@ -10,7 +10,109 @@ }, { "name": "sky", - "index": [13, 3] + "index": [13, 7] + }, + { + "name": "bricks", + "index": [1, 2] + }, + { + "name": "chocolate", + "index": [3, 2] + }, + { + "name": "metal", + "index": [2, 2] + }, + { + "name": "chance-1", + "index": [4, 2] + }, + { + "name": "chance-2", + "index": [5, 2] + }, + { + "name": "chance-3", + "index": [6, 2] + }, + { + "name": "coin-1", + "index": [15, 3] + }, + { + "name": "coin-2", + "index": [15, 4] + }, + { + "name": "coin-3", + "index": [15, 5] + }, + { + "name": "pipe-insert-vert-left", + "index": [2, 5] + }, + { + "name": "pipe-insert-vert-right", + "index": [3, 5] + }, + { + "name": "pipe-vert-left", + "index": [2, 6] + }, + { + "name": "pipe-vert-right", + "index": [3, 6] + }, + { + "name": "pipe-insert-hor-top", + "index": [6, 5] + }, + { + "name": "pipe-insert-hor-bottom", + "index": [6, 6] + }, + { + "name": "pipe-hor-top", + "index": [7, 5] + }, + { + "name": "pipe-hor-bottom", + "index": [7, 6] + }, + { + "name": "pipe-conn-hor-top", + "index": [8, 5] + }, + { + "name": "pipe-conn-hor-bottom", + "index": [8, 6] + } + + ], + + "animations": [ + { + "name": "chance", + "frameLen": 0.16, + "frames": [ + "chance-1", + "chance-1", + "chance-2", + "chance-3", + "chance-2" + ] + }, + { + "name": "coin", + "frameLen": 0.16, + "frames": [ + "coin-1", + "coin-1", + "coin-2", + "coin-3", + "coin-2" + ] } ] }