diff --git a/Jenkinsfile b/Jenkinsfile index c59d1b3..da70eab 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -31,6 +31,23 @@ pipeline { steps { echo 'Deploying....' dir("dist") { + withCredentials([sshUserPrivateKey(credentialsId: 'id_rsa', keyFileVariable: 'identity', passphraseVariable: '', usernameVariable: 'userName')]) + { + script { + def remote = [:] + remote.name = "1blu" + remote.host = "webhosting72.1blu.de" + remote.allowAnyHosts = true + remote.user = userName + remote.identityFile = identity + + sshCommand remote: remote, command: "mkdir www/mi2.mama.productions/releases/${BUILD_NUMBER}" + sshPut remote: remote, from: "${WORKSPACE}\\dist\\", into: "www/mi2.mama.productions/releases/${BUILD_NUMBER}" + sshCommand remote: remote, command: "rm www/mi2.mama.productions/public" + sshCommand remote: remote, command: "ln -s releases/${BUILD_NUMBER}/dist www/mi2.mama.productions/public" + } + } + bat 'git init' bat 'git add .' bat 'git config --global user.email "jenkins@bosym.de"' diff --git a/index.html b/index.html index 9081e0f..c576d03 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ @@ -13,8 +13,7 @@ body { height: 100%; margin: 0; - background-color: gray; - /*TODO: Change to black later on: background-color: black;*/ + background-color: black; overflow: hidden; } diff --git a/src/TextElement.js b/src/TextElement.js index 1081732..5e08a2c 100644 --- a/src/TextElement.js +++ b/src/TextElement.js @@ -22,7 +22,11 @@ export default class TextElement { if (item.name === "action") { this.text.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.text.width, this.text.height), Phaser.Geom.Rectangle.Contains) + .on('pointerover', () => { + this.scene.sound.play('menu_hover', {volume: 0.3}); + }) .on('pointerdown', () => { + this.scene.sound.play('menu_click', {volume: 0.5}); let action = item.properties.filter(obj => obj.name === "action"); if (action.length <= 0) return; @@ -33,6 +37,7 @@ export default class TextElement { case "pause_resume": this.endMyself(); scene.scene.resume('Game'); + this.scene.scene.get('Game').music.play(); break; case "pause_exit": this.endMyself(); diff --git a/src/assets/audio/background_loop.wav b/src/assets/audio/background_loop.wav new file mode 100644 index 0000000..b943eec Binary files /dev/null and b/src/assets/audio/background_loop.wav differ diff --git a/src/assets/audio/background_start.wav b/src/assets/audio/background_start.wav new file mode 100644 index 0000000..cae4c64 Binary files /dev/null and b/src/assets/audio/background_start.wav differ diff --git a/src/assets/audio/menu_click.wav b/src/assets/audio/menu_click.wav new file mode 100644 index 0000000..9c4e7a4 Binary files /dev/null and b/src/assets/audio/menu_click.wav differ diff --git a/src/assets/audio/menu_hover.wav b/src/assets/audio/menu_hover.wav new file mode 100644 index 0000000..053b7f0 Binary files /dev/null and b/src/assets/audio/menu_hover.wav differ diff --git a/src/assets/char_a/spritesheet.png b/src/assets/char_a/spritesheet.png index 7729fe3..bf13184 100644 Binary files a/src/assets/char_a/spritesheet.png and b/src/assets/char_a/spritesheet.png differ diff --git a/src/assets/char_b/spritesheet.png b/src/assets/char_b/spritesheet.png index ae74464..a729809 100644 Binary files a/src/assets/char_b/spritesheet.png and b/src/assets/char_b/spritesheet.png differ diff --git a/src/assets/char_c/spritesheet.png b/src/assets/char_c/spritesheet.png index e0ae492..af501ef 100644 Binary files a/src/assets/char_c/spritesheet.png and b/src/assets/char_c/spritesheet.png differ diff --git a/src/assets/char_d/spritesheet.png b/src/assets/char_d/spritesheet.png index 3de1d46..3994930 100644 Binary files a/src/assets/char_d/spritesheet.png and b/src/assets/char_d/spritesheet.png differ diff --git a/src/assets/chest.png b/src/assets/chest.png new file mode 100644 index 0000000..300cfca Binary files /dev/null and b/src/assets/chest.png differ diff --git a/src/assets/heart.png b/src/assets/heart.png new file mode 100644 index 0000000..ba7db0a Binary files /dev/null and b/src/assets/heart.png differ diff --git a/src/assets/items/heal.png b/src/assets/items/heal.png new file mode 100644 index 0000000..e65e106 Binary files /dev/null and b/src/assets/items/heal.png differ diff --git a/src/assets/items/slow.png b/src/assets/items/slow.png new file mode 100644 index 0000000..0392831 Binary files /dev/null and b/src/assets/items/slow.png differ diff --git a/src/assets/items/speed.png b/src/assets/items/speed.png new file mode 100644 index 0000000..0f56794 Binary files /dev/null and b/src/assets/items/speed.png differ diff --git a/src/assets/items/storm.png b/src/assets/items/storm.png new file mode 100644 index 0000000..6e813ea Binary files /dev/null and b/src/assets/items/storm.png differ diff --git a/src/entities/Attacks/Hitbox.js b/src/entities/Attacks/Hitbox.js index d6b3629..b29ef21 100644 --- a/src/entities/Attacks/Hitbox.js +++ b/src/entities/Attacks/Hitbox.js @@ -28,7 +28,6 @@ export default class Hitbox extends Entity { } overlap(obj) { - this.setData('active', false); obj.hit(this.getData('dmg')); } } \ No newline at end of file diff --git a/src/entities/Chest.js b/src/entities/Chest.js new file mode 100644 index 0000000..f073829 --- /dev/null +++ b/src/entities/Chest.js @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020. Antonio Martinez Casadesus and Pascal Syma. + * All rights reserved. + */ + +import Interactable from "./Interactable"; +import Item from "./Item"; + +export default class Chest extends Interactable { + + constructor(scene, item) { + super(scene, item.x, item.y, 'chest'); + + this.setFrame(4); + this.body.setAllowGravity(false); + this.setOrigin(0.5, 1); + + this.setData('opened', false); + } + + + canInteract() { + return !this.getData('opened'); + } + + interact() { + super.interact(); + this.setData('opened', true); + + this.play('chest_open'); + + const options = [/*"slow", "speed", "storm", */"heal"]; + + let item = new Item(this.scene, { + x: this.x, + y: this.y - this.height + }, options[Math.floor(Math.random() * options.length)]) + + this.scene.interactables.add(item); + } +} \ No newline at end of file diff --git a/src/entities/Enemys/Zombie.js b/src/entities/Enemys/Zombie.js index fef0465..822d623 100644 --- a/src/entities/Enemys/Zombie.js +++ b/src/entities/Enemys/Zombie.js @@ -17,6 +17,9 @@ export default class Zombie extends Enemy { this.dieAnimation = 'zombie_die'; this.hitAnimation = 'zombie_hit'; + + this.setData('hp', 2); + this.setData('dmg', 1); } diff --git a/src/entities/Entity.js b/src/entities/Entity.js index f8a0d9f..54f189b 100644 --- a/src/entities/Entity.js +++ b/src/entities/Entity.js @@ -17,7 +17,7 @@ export default class Entity extends Phaser.GameObjects.Sprite { } hit(dmg) { - if (dmg <= 0) + if (dmg === 0) return; if (this.hitCooldown) @@ -25,8 +25,8 @@ export default class Entity extends Phaser.GameObjects.Sprite { this.hitCooldown = true; - this.setData('hp', this.getData('hp') - dmg); - console.log(this, this.getData('hp')); + const newHp = this.getData('hp') - dmg; + this.setData('hp', newHp < 0 ? 0 : newHp); // play hit animation const shouldDie = this.getData('hp') <= 0; @@ -38,6 +38,7 @@ export default class Entity extends Phaser.GameObjects.Sprite { } if (this.hitAnimation !== null) { + // TODO: bug, not working, no clue why not this.anims.stop(); this.play(this.hitAnimation) .once('animationcomplete', () => { diff --git a/src/entities/Interactable.js b/src/entities/Interactable.js new file mode 100644 index 0000000..bbe0ef9 --- /dev/null +++ b/src/entities/Interactable.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020. Antonio Martinez Casadesus and Pascal Syma. + * All rights reserved. + */ + +import Entity from "./Entity"; + +export default class Interactable extends Entity { + + canInteract() { + return true; + } + + interact() { + } +} \ No newline at end of file diff --git a/src/entities/Item.js b/src/entities/Item.js index 4c58087..557e63e 100644 --- a/src/entities/Item.js +++ b/src/entities/Item.js @@ -1,30 +1,43 @@ /* - * Copyright (c) 2020. Pascal Syma + * Copyright (c) 2020. Antonio Martinez Casadesus and Pascal Syma. * All rights reserved. */ -import Entity from "./Entity"; +import Interactable from "./Interactable"; -export default class Item extends Entity { +export default class Item extends Interactable { - constructor(scene, obj) { - super(scene, obj.x, obj.y, obj.properties.filter(obj => obj.name === "texture")[0].value); + constructor(scene, obj, texture) { + super(scene, obj.x, obj.y, texture); this.body.setAllowGravity(false); + this.setData('texture', texture); + this.setDisplaySize(16, 16); this.setData('collectable', true); + + this.play('item_' + texture); } - canPickup() { + canInteract() { return this.getData('collectable'); } - pickup() { + interact() { this.setData('collectable', false); } + use(user) { + switch (this.getData('texture')) { + case "heal": + user.hit(-2) + break; + } + this.die(); + } + drop() { this.setData('collectable', true); diff --git a/src/entities/Player.js b/src/entities/Player.js index de5cced..fddf2e5 100644 --- a/src/entities/Player.js +++ b/src/entities/Player.js @@ -6,6 +6,8 @@ import Entity from "./Entity"; import AttackA from "./Attacks/AttackA"; import AttackB from "./Attacks/AttackB"; +import Item from "./Item"; +import Chest from "./Chest"; export default class Player extends Entity { @@ -34,17 +36,34 @@ export default class Player extends Entity { this.hitAnimation = 'hit'; } - pickup(item) { - if (this.items.length >= 1) { - this.items.shift().setPosition(this.x, this.y).drop(); + interact(item) { + + if (item instanceof Item) { + if (this.items.length >= 1) { + this.items.shift().setPosition(this.x, this.y).drop(); + } + + + item.interact(); + + this.items[0] = item; + } else if (item instanceof Chest) { + item.interact(); } + } - console.log(item); - item.pickup(); - - this.items[0] = item; + hit(dmg) { + super.hit(dmg); + if (this.getData('hp') > this.scene.hearts.length) + this.setData('hp', this.scene.hearts.length); + for (let i = this.getData('hp'); i < this.scene.hearts.length; i++) { + this.scene.hearts[i].alpha = 0; + } + for (let i = 0; i < this.getData('hp'); i++) { + this.scene.hearts[i].alpha = 1; + } } update(...args) { @@ -103,7 +122,7 @@ export default class Player extends Entity { this.items.forEach(i => i.setPosition(this.body.x, this.body.y - 16)); if (this.scene.keyAction1.isDown && this.items.length >= 1) { - this.items.shift().die(); + this.items.shift().use(this); } } @@ -114,6 +133,7 @@ export default class Player extends Entity { .once('animationcomplete', () => { this.setFrame(51); this.scene.scene.pause(); + this.scene.music.pause(); this.scene.scene.launch('GUI', {key: 'Dead'}).bringToTop('GUI'); }) } diff --git a/src/scenes/GUI.js b/src/scenes/GUI.js index 89fbb8d..b795d11 100644 --- a/src/scenes/GUI.js +++ b/src/scenes/GUI.js @@ -49,8 +49,13 @@ export default class GUI extends Phaser.Scene { new Player(this, s, 'char' + charKey).play('idle' + charKey, true) .setInteractive() + .on('pointerover', () => { + this.sound.play('menu_hover', {volume: 0.3}); + }) .on('pointerdown', () => { + this.sound.play('menu_click', {volume: 0.5}); + if (this.textures.exists('char')) this.textures.removeKey('char'); diff --git a/src/scenes/Game.js b/src/scenes/Game.js index f25b6d3..778760c 100644 --- a/src/scenes/Game.js +++ b/src/scenes/Game.js @@ -5,13 +5,13 @@ import Player from "../entities/Player"; import Bat from "../entities/Enemys/Bat"; -import Item from "../entities/Item"; import Storage from "../Storage"; import Win from "../entities/Win"; import TextElement from "../TextElement"; import DamageEntity from "../entities/Enemys/DamageEntity"; import Zombie from "../entities/Enemys/Zombie"; import Skeleton from "../entities/Enemys/Skeleton"; +import Chest from "../entities/Chest"; export default class Game extends Phaser.Scene { @@ -24,7 +24,7 @@ export default class Game extends Phaser.Scene { default: 'arcade', arcade: { gravity: {y: 300}, - debug: true + // debug: true } } }); @@ -196,6 +196,40 @@ export default class Game extends Phaser.Scene { frameRate: 15 }); + this.anims.create({ + key: 'chest_open', + frames: this.anims.generateFrameNumbers('chest', {start: 0, end: 3}), + frameRate: 10 + }); + + this.anims.create({ + key: 'item_heal', + frames: this.anims.generateFrameNumbers('heal', {start: 0, end: 7}), + frameRate: 10, + repeat: -1 + }); + + this.anims.create({ + key: 'item_slow', + frames: this.anims.generateFrameNumbers('slow', {start: 0, end: 10}), + frameRate: 10, + repeat: -1 + }); + + this.anims.create({ + key: 'item_speed', + frames: this.anims.generateFrameNumbers('speed', {start: 0, end: 7}), + frameRate: 10, + repeat: -1 + }); + + this.anims.create({ + key: 'item_storm', + frames: this.anims.generateFrameNumbers('storm', {start: 0, end: 11}), + frameRate: 10, + repeat: -1 + }); + const mapKey = "map"; const mapTilesetKey = "tiles"; @@ -216,7 +250,8 @@ export default class Game extends Phaser.Scene { const spawnPoint = map.findObject("Player/Enemys", obj => obj.name === "player"); this.enemys = this.add.group(); - this.items = this.add.group(); + this.environment = this.add.group(); + this.interactables = this.add.group(); map.objects[0].objects.filter(obj => obj.name === "bat").forEach(s => { let bat = new Bat(this, s); @@ -232,12 +267,12 @@ export default class Game extends Phaser.Scene { }); map.objects[0].objects.filter(obj => obj.type === "dmg").forEach(s => { - this.enemys.add(new DamageEntity(this, s)) + this.environment.add(new DamageEntity(this, s)) }); - map.objects[0].objects.filter(obj => obj.name === "item").forEach(s => { - let item = new Item(this, s); - this.items.add(item) + map.objects[0].objects.filter(obj => obj.name === "chest").forEach(s => { + let chest = new Chest(this, s); + this.interactables.add(chest) }); this.wins = this.add.group(); @@ -283,8 +318,19 @@ export default class Game extends Phaser.Scene { this.player.hit(e.getData('dmg')); }) - this.physics.add.overlap(this.player, this.wins, (p, w) => { - console.log("win!"); + this.physics.add.overlap(this.player, this.enemys, (p, e) => { + if (e.getData('active')) + this.player.hit(e.getData('dmg')); + }) + + this.physics.add.overlap(this.player, this.environment, (p, e) => { + if (e.getData('active')) + this.player.hit(e.getData('dmg')); + }) + + this.physics.add.overlap(this.enemys, this.environment, (p, e) => { + if (e.getData('active')) + p.hit(e.getData('dmg')); }) let controls = Storage.get().controls; @@ -299,9 +345,9 @@ export default class Game extends Phaser.Scene { this.keyAction2 = this.input.keyboard.addKey(controls.use_right.bind); this.keyEsc = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.ESC); - this.physics.add.overlap(this.player, this.items, (p, i) => { - if (this.keyPickup.isDown && i.canPickup()) { - p.pickup(i); + this.physics.add.overlap(this.player, this.interactables, (p, i) => { + if (this.keyPickup.isDown && i.canInteract()) { + p.interact(i); this.keyPickup.reset(); } }) @@ -311,12 +357,26 @@ export default class Game extends Phaser.Scene { console.log(s); new TextElement(this, s); }); + + this.hearts = []; + for (let i = 0; i < this.player.getData('hp'); i++) { + this.hearts.push(this.add.image(i * 16, 0, 'heart') + .setScrollFactor(0, 0) + .setOrigin(0, 0)); + } + + this.music = this.sound.add('background_start', {volume: 0.5}) + .once('complete', () => { + this.music = this.sound.add('background_loop', {loop: true, volume: 0.5}); + this.music.play(); + }) + this.music.play(); } update(time, delta) { if (this.keyEsc.isDown) { this.scene.pause(); - + this.music.pause(); this.input.keyboard.keys.forEach(k => k.reset()); this.scene.launch('GUI', {key: 'Pause'}).bringToTop('GUI'); return; diff --git a/src/scenes/Preload.js b/src/scenes/Preload.js index 0969a11..83dff9e 100644 --- a/src/scenes/Preload.js +++ b/src/scenes/Preload.js @@ -21,6 +21,17 @@ import batDie from "../assets/BatDie.png"; import item_01 from "../assets/items/itemshard_01.png"; import item_02 from "../assets/items/itemshard_02.png"; import item_03 from "../assets/items/itemshard_03.png"; +import heal from "../assets/items/heal.png"; +import slow from "../assets/items/slow.png"; +import speed from "../assets/items/speed.png"; +import storm from "../assets/items/storm.png"; +import heart from "../assets/heart.png"; +import chest from "../assets/chest.png"; + +import menu_click from "../assets/audio/menu_click.wav"; +import menu_hover from "../assets/audio/menu_hover.wav"; +import background_start from "../assets/audio/background_start.wav"; +import background_loop from "../assets/audio/background_loop.wav"; export default class Preload extends Phaser.Scene { @@ -34,6 +45,7 @@ export default class Preload extends Phaser.Scene { this.load.image("item_01", item_01); this.load.image("item_02", item_02); this.load.image("item_03", item_03); + this.load.image("heart", heart); 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}); @@ -44,11 +56,21 @@ export default class Preload extends Phaser.Scene { this.load.spritesheet('buttontiles', buttontiles, {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.spritesheet('chest', chest, {frameWidth: 32, frameHeight: 32, margin: 1, spacing: 2}); + this.load.spritesheet('heal', heal, {frameWidth: 16, frameHeight: 16, margin: 1, spacing: 2}); + this.load.spritesheet('storm', storm, {frameWidth: 16, frameHeight: 16, margin: 1, spacing: 2}); + this.load.spritesheet('speed', speed, {frameWidth: 16, frameHeight: 16, margin: 1, spacing: 2}); + this.load.spritesheet('slow', slow, {frameWidth: 16, frameHeight: 16, margin: 1, spacing: 2}); this.load.tilemapTiledJSON("map", map); this.load.tilemapTiledJSON("menu", menu); this.load.atlas({key: 'skeleton', textureURL: skeletonSprite, atlasURL: skeletonAtlas}); + this.load.audio('menu_click', menu_click); + this.load.audio('menu_hover', menu_hover); + this.load.audio('background_start', background_start); + this.load.audio('background_loop', background_loop); + } create() { @@ -113,4 +135,4 @@ export default class Preload extends Phaser.Scene { }); } -} \ No newline at end of file +}