@import url("https://fonts.googleapis.com/css2?family=VT323&display=swap");
* {
font-family: "VT323", monospace;
}
body {
background-color: #000000;
}
View Compiled
'use strict';
console.clear();
class Settings {
static MAP = [
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 2, 2, 2, 2, 2, 2, 0, 1],
[1, 0, 2, 0, 0, 0, 0, 2, 2, 1],
[1, 0, 2, 0, 2, 2, 0, 2, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
[1, 0, 0, 1, 1, 0, 1, 1, 1, 1],
[1, 1, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 3, 3, 0, 0, 0, 1],
[3, 3, 3, 3, 4, 4, 3, 3, 3, 3],
];
static TRAPS_MAP = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
static BLOCK_SIZE = 32;
static CHARACTER_X = this.BLOCK_SIZE * 8;
static CHARACTER_Y = this.BLOCK_SIZE * 1;
static FINISH_X = this.BLOCK_SIZE * 8;
static FINISH_Y = this.BLOCK_SIZE * 13;
static FONT_SETTINGS = {
fontFamily: 'VT323',
fontSize: 24,
stroke: '#000000',
strokeThickness: 4,
};
static IS_DEBUG = false;
}
class PreloadScene extends Phaser.Scene {
constructor() {
super('Preload');
}
preload() {
const path = 'https://assets.codepen.io/430361';
this.load.image('character', `${path}/bit-maze-character.png`);
this.load.image('block', `${path}/bit-maze-block.png`);
this.load.image('grass', `${path}/bit-maze-grass.png`);
this.load.image('land', `${path}/bit-maze-land.png`);
this.load.image('cloud', `${path}/bit-maze-cloud.png`);
this.load.image('background', `${path}/bit-maze-background.png`);
this.load.image('tilemap', `${path}/bit-maze-tilemap.png`);
this.load.spritesheet('character-run', `${path}/bit-maze-character-run.png`, {
frameWidth: 24,
frameHeight: 24,
});
this.load.spritesheet('character-jump', `${path}/bit-maze-character-jump.png`, {
frameWidth: 24,
frameHeight: 24,
});
this.load.spritesheet('character-idle', `${path}/bit-maze-character-idle.png`, {
frameWidth: 24,
frameHeight: 24,
});
this.load.spritesheet('character-trap', `${path}/bit-maze-character-trap.png`, {
frameWidth: 24,
frameHeight: 24,
});
this.load.spritesheet('buttons', `${path}/bit-maze-buttons.png`, {
frameWidth: 48,
frameHeight: 48,
});
this.load.spritesheet('trap', `${path}/bit-maze-trap.png`, {
frameWidth: Settings.BLOCK_SIZE,
frameHeight: Settings.BLOCK_SIZE,
});
this.load.spritesheet('finish', `${path}/bit-maze-finish.png`, {
frameWidth: Settings.BLOCK_SIZE,
frameHeight: Settings.BLOCK_SIZE,
});
this.load.on("complete", (evt) => {
this.cameras.main.fadeOut(128);
this.cameras.main.once("camerafadeoutcomplete", () => {
this.scene.start('Main');
}, this);
});
}
}
class MainScene extends Phaser.Scene {
mapLayer = null;
finish = null;
traps = null;
leftKey = false;
rightKey = false;
jumpKey = false;
constructor() {
super('Main');
}
createMap() {
let width = this.game.config.width;
let height = this.game.config.height;
this.add.image(width / 2, height / 2, 'background').setScrollFactor(0);
const map = this.make.tilemap({
data: Settings.MAP,
tileWidth: Settings.BLOCK_SIZE,
tileHeight: Settings.BLOCK_SIZE,
});
const tileset = map.addTilesetImage('tilemap');
this.mapLayer = map.createLayer(0, tileset, 0, 0);
this.mapLayer.setCollision([1, 2, 3, 4]);
}
placeCharacter() {
const x = Settings.CHARACTER_X;
const y = Settings.CHARACTER_Y;
this.physics.add.sprite(x, y, 'character')
.setName('character')
.setOrigin(0)
.refreshBody()
.setBounce(0.3)
.setDepth(1);
let character = this.children.getByName('character');
character.setCollideWorldBounds(true);
const b = Settings.BLOCK_SIZE;
const width = Settings.MAP[0].length * b;
const height = Settings.MAP.length * b;
this.setCharacterCamera(width, height);
}
setGameOver(otherText) {
this.physics.world.pause();
let width = this.game.config.width;
this.add.text(
width / 2, 168, otherText, Settings.FONT_SETTINGS)
.setOrigin(0.5)
.setScrollFactor(0)
.setDepth(2);
this.add.text(
width / 2, 192, 'PRESS ANYWHERE TO RETRY', Settings.FONT_SETTINGS)
.setOrigin(0.5)
.setScrollFactor(0)
.setDepth(2);
this.tweens.add({
targets: [
this.children.getByName('btn-left'),
this.children.getByName('btn-right'),
this.children.getByName('btn-up'),
],
alpha: 0,
tease: 'Sine.easeOut',
duration: 256,
});
this.input.once('pointerdown', () => {
this.scene.restart();
});
this.input.keyboard.once('keydown', () => {
this.scene.restart();
});
}
setCharacterCamera(width, height) {
let boundary = new Phaser.Geom.Rectangle(0, 0, width, height);
let character = this.children.getByName('character');
character.body.setBoundsRectangle(boundary);
this.cameras.main.setBounds(0, 0, width, height);
this.cameras.main.startFollow(character, true, 1, 1);
}
setCharacterAnimation() {
this.anims.create({
key: 'character-run',
frames: this.anims.generateFrameNumbers('character-run', {
start: 0,
end: 7,
}),
frameRate: 10,
repeat: -1,
});
this.anims.create({
key: 'character-jump',
frames: this.anims.generateFrameNumbers('character-jump', {
start: 0,
end: 1,
}),
frameRate: 17.5,
});
this.anims.create({
key: 'character-idle',
frames: this.anims.generateFrameNumbers('character-idle', {
start: 0,
end: 2,
}),
frameRate: 7,
repeat: -1,
yoyo: true,
});
this.anims.create({
key: 'character-trap',
frames: this.anims.generateFrameNumbers('character-trap', {
start: 0,
end: 7,
}),
frameRate: 10,
});
}
createLeftController() {
this.add.image(32, 208, 'buttons')
.setName('btn-left')
.setFrame(0)
.setScrollFactor(0)
.setInteractive()
.on('pointerdown', () => {
this.leftKey = true;
this.hideInstructions();
}).on('pointerup', () => {
this.leftKey = false;
});
this.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.LEFT
).on('down', () => {
this.leftKey = true;
this.hideInstructions();
}).on('up', () => {
this.leftKey = false;
});
}
createRightController() {
this.add.image(288, 208, 'buttons')
.setName('btn-right')
.setFrame(1)
.setScrollFactor(0)
.setInteractive()
.on('pointerdown', () => {
this.rightKey = true;
this.hideInstructions();
}).on('pointerup', () => {
this.rightKey = false;
});
this.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.RIGHT
).on('down', () => {
this.rightKey = true;
this.hideInstructions();
}).on('up', () => {
this.rightKey = false;
});
}
createJumpController() {
this.add.image(288, 154, 'buttons')
.setName('btn-up')
.setFrame(2)
.setScrollFactor(0)
.setInteractive()
.on('pointerdown', () => {
this.jumpKey = true;
this.hideInstructions();
}).on('pointerup', () => {
this.jumpKey = false;
});
this.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.UP
).on('down', () => {
this.jumpKey = true;
this.hideInstructions();
}).on('up', () => {
this.jumpKey = false;
});
this.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.SPACE
).on('down', () => {
this.jumpKey = true;
this.hideInstructions();
}).on('up', () => {
this.jumpKey = false;
});
}
createController() {
this.input.addPointer(2);
this.createLeftController();
this.createRightController();
this.createJumpController();
}
hideInstructions() {
const txtInstructions = this.children.getByName('txt-instructions');
if (txtInstructions === null || this.tweens.getTweensOf(txtInstructions).length > 0) {
return;
}
this.tweens.add({
targets: txtInstructions,
alpha: 0,
tease: 'Sine.easeOut',
duration: 512,
onComplete: (evt) => {
evt.targets[0].destroy();
},
});
}
placeFinish() {
const x = Settings.FINISH_X;
const y = Settings.FINISH_Y;
this.finish = this.physics.add.staticSprite(x, y, 'finish')
.setName('finish')
.setOrigin(0)
.refreshBody()
.setDepth(1);
this.finish.anims.play('finish');
}
placeTraps() {
const map = Settings.TRAPS_MAP;
const b = Settings.BLOCK_SIZE;
this.traps = this.physics.add.staticGroup();
for (let y = 0; y < map.length; y++) {
for (let x = 0; x < map[y].length; x++) {
if (map[y][x] === 0) {
continue;
}
this.traps.create(x * b, y * b, 'trap')
.setOrigin(0)
.refreshBody();
}
}
}
setCollision() {
let character = this.children.getByName('character');
this.physics.add.collider(character, this.mapLayer);
this.physics.add.collider(character, this.traps, (obj1, obj2) => {
character.anims.play('character-trap');
obj2.anims.play('trap');
this.setGameOver('YOU GOT CAUGHT BY A TRAP!');
});
this.physics.add.collider(character, this.finish, () => {
this.setGameOver('YOU COMPLETED THE GAME!');
});
}
setObjectAnimation() {
this.anims.create({
key: 'trap',
frames: this.anims.generateFrameNumbers('trap', {
start: 1,
end: 4,
}),
frameRate: 10,
repeat: -1,
});
this.anims.create({
key: 'finish',
frames: this.anims.generateFrameNumbers('finish', {
start: 0,
end: 2,
}),
frameRate: 7.5,
repeat: -1,
yoyo: true,
});
}
create() {
this.placeCharacter();
this.createMap();
this.createController();
this.setCharacterAnimation();
this.setObjectAnimation();
this.placeFinish();
this.placeTraps();
this.setCollision();
let width = this.game.config.width;
this.add.text(
width / 2, 192, 'PRESS ARROW KEYS TO MOVE', Settings.FONT_SETTINGS)
.setName('txt-instructions')
.setOrigin(0.5)
.setScrollFactor(0)
.setDepth(2);
}
animateCharacter() {
let character = this.children.getByName('character');
if (this.leftKey === true) {
character.setVelocityX(-60);
character.setFlipX(false);
character.anims.play('character-run', true);
}
else if (this.rightKey === true) {
character.setVelocityX(60);
character.setFlipX(true);
character.anims.play('character-run', true);
}
else {
character.setVelocityX(0);
}
if (character.body.blocked.down && character.body.velocity.x === 0) {
character.anims.play('character-idle', true);
}
if (character.body.blocked.down && this.jumpKey === true) {
character.setVelocityY(760);
}
if (
!character.body.blocked.down
&&
(
character.anims.currentAnim === null
||
character.anims.currentAnim.key !== 'character-jump'
)
) {
character.anims.play('character-jump');
}
}
update() {
if (this.physics.world.isPaused === true) {
return;
}
this.animateCharacter();
}
}
new Phaser.Game({
type: Phaser.AUTO,
parent: 'bit-maze',
pixelArt: true,
parent: {
activePointers: 3,
},
physics: {
default: 'arcade',
arcade: {
gravity: {
y: 400,
},
debug: false,
},
},
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
width: 320,
height: 240,
min: {
width: 40,
height: 30,
},
max: {
width: 1280,
height: 960,
},
},
scene: [
PreloadScene,
MainScene,
],
});
View Compiled
This Pen doesn't use any external CSS resources.