added entitys, enemys, bats and custom attack hitboxes for players
added map loading and one-way collision (needs to move to tiled attribute tho) Signed-off-by: Pascal Syma <pascal@syma.dev>
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2020. Pascal Syma <pascal@syma.dev>
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
import Player from "../entities/Player";
|
||||
import Bat from "../entities/Enemys/Bat";
|
||||
|
||||
export default class Game extends Phaser.Scene {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
key: "Game",
|
||||
pixelArt: true,
|
||||
physics: {
|
||||
default: 'arcade',
|
||||
arcade: {
|
||||
gravity: {y: 300},
|
||||
// debug: true
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static setTileCollision(mapLayer, idxOrArray, dirs) {
|
||||
|
||||
let mFunc; // tile index matching function
|
||||
if (idxOrArray.length) {
|
||||
// if idxOrArray is an array, use a function with a loop
|
||||
mFunc = function (inp) {
|
||||
for (let i = 0; i < idxOrArray.length; i++) {
|
||||
if (idxOrArray[i] === inp - 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
// if idxOrArray is a single number, use a simple function
|
||||
mFunc = function (inp) {
|
||||
return inp - 1 === idxOrArray;
|
||||
};
|
||||
}
|
||||
|
||||
// get the 2-dimensional tiles array for this layer
|
||||
// const d = mapLayer.map.layers[mapLayer.index].data;
|
||||
const d = mapLayer.layer.data;
|
||||
|
||||
for (let i = 0; i < d.length; i++) {
|
||||
for (let j = 0; j < d[i].length; j++) {
|
||||
const t = d[i][j];
|
||||
if (mFunc(t.index)) {
|
||||
|
||||
t.collideUp = dirs.top;
|
||||
t.collideDown = dirs.bottom;
|
||||
t.collideLeft = dirs.left;
|
||||
t.collideRight = dirs.right;
|
||||
|
||||
t.faceTop = dirs.top;
|
||||
t.faceBottom = dirs.bottom;
|
||||
t.faceLeft = dirs.left;
|
||||
t.faceRight = dirs.right;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create() {
|
||||
|
||||
this.anims.create({
|
||||
key: 'idle',
|
||||
frames: this.anims.generateFrameNumbers('char', {start: 126, end: 131}),
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'run',
|
||||
frames: this.anims.generateFrameNumbers('char', {start: 154, end: 161}),
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'jump_start',
|
||||
frames: this.anims.generateFrameNumbers('char', {start: 140, end: 143}),
|
||||
frameRate: 10
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'jump',
|
||||
frames: this.anims.generateFrameNumbers('char', {start: 144, end: 145}),
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'attack_a',
|
||||
frames: this.anims.generateFrameNumbers('char', {start: 0, end: 13}),
|
||||
frameRate: 15
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'attack_b',
|
||||
frames: this.anims.generateFrameNumbers('char', {start: 14, end: 26}),
|
||||
frameRate: 15
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'attack_c',
|
||||
frames: this.anims.generateFrameNumbers('char', {start: 28, end: 41}),
|
||||
frameRate: 15
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'die',
|
||||
frames: this.anims.generateFrameNumbers('char', {start: 42, end: 51}),
|
||||
frameRate: 10
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'batIdle',
|
||||
frames: this.anims.generateFrameNumbers('batFly', {start: 0, end: 5}),
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
this.anims.create({
|
||||
key: 'batDie',
|
||||
frames: this.anims.generateFrameNumbers('batDie', {start: 0, end: 4}),
|
||||
frameRate: 15
|
||||
});
|
||||
|
||||
|
||||
const map = this.make.tilemap({key: "map"});
|
||||
const tileset = map.addTilesetImage("tileset", "tiles", 16, 16, 1, 2);
|
||||
|
||||
this.backLayer = map.createStaticLayer("Back", tileset, 0, 0);
|
||||
this.backLayer2 = map.createStaticLayer("Back2", tileset, 0, 0);
|
||||
|
||||
this.worldLayer = map.createDynamicLayer("Main", tileset, 0, 0);
|
||||
|
||||
|
||||
const spawnPoint = map.findObject("Objects", obj => obj.name === "player");
|
||||
|
||||
this.enemys = this.add.group();
|
||||
this.player = new Player(this, spawnPoint, 'char');
|
||||
|
||||
const batSpawns = map.objects[0].objects.filter(obj => obj.name === "bat");
|
||||
|
||||
|
||||
batSpawns.forEach(s => {
|
||||
let bat = new Bat(this, s);
|
||||
bat.fly(s.type === "" ? 90 : parseInt(s.type));
|
||||
this.enemys.add(bat)
|
||||
});
|
||||
|
||||
|
||||
this.worldLayer.setCollisionByProperty({collides: true});
|
||||
Game.setTileCollision(this.worldLayer, [29, 30, 31, 39], {
|
||||
top: true,
|
||||
bottom: false,
|
||||
right: false,
|
||||
left: false
|
||||
})
|
||||
|
||||
this.physics.world.bounds.width = this.backLayer.width;
|
||||
this.physics.world.bounds.height = this.backLayer.height;
|
||||
|
||||
this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
|
||||
|
||||
|
||||
this.cameras.main.setBackgroundColor('#ccccff');
|
||||
|
||||
|
||||
this.cameras.main.startFollow(this.player);
|
||||
|
||||
this.physics.add.collider(this.player, this.worldLayer);
|
||||
this.physics.add.overlap(this.player.attackHitbox, this.enemys, (h, b) => {
|
||||
if (h.getData('active') && h.overlap !== undefined) {
|
||||
h.overlap(b);
|
||||
}
|
||||
})
|
||||
|
||||
this.keyW = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W);
|
||||
this.keyS = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S);
|
||||
this.keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A);
|
||||
this.keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D);
|
||||
this.keySpace = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
|
||||
this.keyUp = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.UP);
|
||||
this.keyLeft = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT);
|
||||
this.keyRight = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT);
|
||||
this.keyDown = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DOWN);
|
||||
this.keyDie = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.C);
|
||||
}
|
||||
|
||||
update(time, delta) {
|
||||
this.enemys.getChildren().forEach(c => {
|
||||
c.update()
|
||||
});
|
||||
this.player.update(time, delta);
|
||||
|
||||
}
|
||||
|
||||
dieActive() {
|
||||
return this.keyDie.isDown;
|
||||
}
|
||||
|
||||
rightActive() {
|
||||
return this.keyRight.isDown || this.keyD.isDown/* || (this.game.input.activePointer.isDown &&
|
||||
this.game.input.activePointer.x > 2*this.game.config.width/3)*/;
|
||||
}
|
||||
|
||||
leftActive() {
|
||||
return this.keyLeft.isDown || this.keyA.isDown/* || (this.game.input.activePointer.isDown &&
|
||||
this.game.input.activePointer.x < this.game.config.width/3)*/;
|
||||
}
|
||||
|
||||
downActive() {
|
||||
return this.keyDown.isDown || this.keyS.isDown/* || (this.game.input.activePointer.isDown &&
|
||||
this.game.input.activePointer.y > 2*this.game.config.height/3)*/;
|
||||
}
|
||||
|
||||
upActive() {
|
||||
return this.keyUp.isDown || this.keyW.isDown/* || (this.game.input.activePointer.isDown &&
|
||||
this.game.input.activePointer.y < this.game.config.height/3)*/;
|
||||
}
|
||||
}
|
||||
+42
-18
@@ -3,29 +3,53 @@
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
import logoImg from "../assets/logo.png";
|
||||
import Player from "../entities/Player";
|
||||
|
||||
export default class Menu extends Phaser.Scene {
|
||||
|
||||
constructor() {
|
||||
super("Menu");
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.load.image("logo", logoImg);
|
||||
}
|
||||
|
||||
create() {
|
||||
const logo = this.add.image(this.cameras.main.centerX, this.cameras.main.centerY * 1.5, "logo").setOrigin(0.5, 0.5);
|
||||
|
||||
this.tweens.add({
|
||||
targets: logo,
|
||||
y: this.cameras.main.centerY,
|
||||
duration: 2000,
|
||||
ease: "Power2",
|
||||
yoyo: true,
|
||||
loop: -1
|
||||
super({
|
||||
key: "Menu",
|
||||
pixelArt: true,
|
||||
physics: {
|
||||
default: 'arcade',
|
||||
arcade: {
|
||||
gravity: {y: 0},
|
||||
// debug: true
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
create() {
|
||||
const w = this.cameras.main.centerX;
|
||||
const h = this.cameras.main.centerY;
|
||||
[{x: w / 2, y: h / 2, key: 'A'},
|
||||
{x: w / 2 + w, y: h / 2, key: 'B'},
|
||||
{x: w / 2, y: h / 2 + h, key: 'C'},
|
||||
{x: w / 2 + w, y: h / 2 + h, key: 'D'}]
|
||||
.forEach((e) => this.addOption(e));
|
||||
|
||||
}
|
||||
|
||||
addOption(options) {
|
||||
this.anims.create({
|
||||
key: 'idle' + options.key,
|
||||
frames: this.anims.generateFrameNumbers('char' + options.key, {start: 126, end: 131}),
|
||||
frameRate: 10,
|
||||
repeat: -1
|
||||
});
|
||||
|
||||
new Player(this, options, 'char' + options.key).play('idle' + options.key, true)
|
||||
.setInteractive()
|
||||
.on('pointerdown', () => {
|
||||
|
||||
this.textures.addSpriteSheet('char', this.textures.get('char' + options.key).getSourceImage(), {
|
||||
frameWidth: 79,
|
||||
frameHeight: 63
|
||||
});
|
||||
|
||||
this.scene.start('Game');
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2020. Pascal Syma <pascal@syma.dev>
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
import logoImg from "../../public/favicon.png";
|
||||
import map from "../assets/map.json";
|
||||
import charA from "../assets/char_a/spritesheet.png";
|
||||
import charB from "../assets/char_b/spritesheet.png";
|
||||
import charC from "../assets/char_c/spritesheet.png";
|
||||
import charD from "../assets/char_d/spritesheet.png";
|
||||
import tiles from "../assets/tileset.png";
|
||||
import batFly from "../assets/BatFly.png";
|
||||
import batDie from "../assets/BatDie.png";
|
||||
|
||||
export default class Preload extends Phaser.Scene {
|
||||
|
||||
constructor() {
|
||||
super('Loading');
|
||||
}
|
||||
|
||||
preload() {
|
||||
this.loadingScreen();
|
||||
this.load.image("logo", logoImg);
|
||||
this.load.spritesheet('charA', charA, {frameWidth: 79, frameHeight: 63/*, margin: 1, spacing: 2*/});
|
||||
this.load.spritesheet('charB', charB, {frameWidth: 79, frameHeight: 63/*, margin: 1, spacing: 2*/});
|
||||
this.load.spritesheet('charC', charC, {frameWidth: 79, frameHeight: 63/*, margin: 1, spacing: 2*/});
|
||||
this.load.spritesheet('charD', charD, {frameWidth: 79, frameHeight: 63/*, margin: 1, spacing: 2*/});
|
||||
this.load.spritesheet('tiles', tiles, {frameWidth: 16, frameHeight: 16, margin: 1, spacing: 2});
|
||||
this.load.spritesheet('batFly', batFly, {frameWidth: 48, frameHeight: 32/*, margin: 1, spacing: 2*/});
|
||||
this.load.spritesheet('batDie', batDie, {frameWidth: 48, frameHeight: 32/*, margin: 1, spacing: 2*/});
|
||||
this.load.tilemapTiledJSON("map", map);
|
||||
}
|
||||
|
||||
create() {
|
||||
this.add.image(this.cameras.main.centerX, this.cameras.main.centerY, 'logo').setOrigin(0.5, 0.5).setDisplaySize(this.cameras.main.centerX, this.cameras.main.centerX);
|
||||
setTimeout(() => {
|
||||
this.scene.start('Menu');
|
||||
}, 2 * 1000)
|
||||
}
|
||||
|
||||
loadingScreen() {
|
||||
const progressBar = this.add.graphics();
|
||||
const progressBox = this.add.graphics();
|
||||
const width = this.cameras.main.width;
|
||||
const height = this.cameras.main.height;
|
||||
|
||||
progressBox.fillStyle(0x222222, 0.8);
|
||||
progressBox.fillRect(width / 4, height / 2 - 25, width / 2, 50);
|
||||
|
||||
const loadingText = this.make.text({
|
||||
x: width / 2,
|
||||
y: height / 2 - 25 - 20,
|
||||
text: 'Loading...',
|
||||
style: {
|
||||
font: '20px monospace',
|
||||
fill: '#ffffff'
|
||||
}
|
||||
});
|
||||
loadingText.setOrigin(0.5, 1);
|
||||
|
||||
const percentText = this.make.text({
|
||||
x: width / 2,
|
||||
y: height / 2,
|
||||
text: '0%',
|
||||
style: {
|
||||
font: '18px monospace',
|
||||
fill: '#ffffff'
|
||||
}
|
||||
});
|
||||
percentText.setOrigin(0.5, 0.5);
|
||||
|
||||
this.load.on('progress', (value) => {
|
||||
percentText.setText(parseInt(value * 100) + '%');
|
||||
progressBar.clear();
|
||||
progressBar.fillStyle(0xffffff, 1);
|
||||
progressBar.fillRect(width / 4 + 10, height / 2 - 25 + 10, (width / 2 - 20) * value, 50 - 20);
|
||||
});
|
||||
|
||||
this.load.on('complete', () => {
|
||||
progressBar.destroy();
|
||||
progressBox.destroy();
|
||||
loadingText.destroy();
|
||||
percentText.destroy();
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user