var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: function() { this.state.add('GamePlay', GamePlay, true); } }); var cursors; var player; var walls; var determinations; // I know it's grammatically incorrect. :P var monsters; var nexttime_monsterspawn; var nexttime_determination; const WAIT_KEY = 200; const WAIT_SHOOT = 200; const WAIT_INVINCIBILITY = 800; const WAIT_SOULMODE = 10000; const WAIT_MONSTERSHOOT = 500; const WAIT_MONSTERSPAWN = 20000; const WAIT_DETERMINATION = 4000; const WAIT_DEATH = 4000; const WALL_THICKNESS = 16; const WALL_BORDER = 8; const WALL_BORDERBOTTOM = 48; const HB_THICKNESS = 20; const MAX_HEALTH = 20; const MONSTER_HEALTH = 20; const MODE_DETERMINATION = 0; const MODE_JUSTICE = 1; const SPEED_PLAYER = 150; const SPEED_PPROJECTILE = 500; const SPEED_MPROJECTILE = 200; window.addEventListener("keydown", function(e) { // Prevent default browser action for arrows and spacebar if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) { e.preventDefault(); } }, false); function sign(n) { if (n >= 0) { return 1 } else { return -1 }; } class Player extends Phaser.Text { constructor(x, y) { super(game, x, y, "♥️", { align: 'center', fill: 'red', font: 'Ubuntu Mono', fontSize: 32, fontWeight: 'bold' }); this.anchor.setTo(0.5, 0.5); this.maxHealth = MAX_HEALTH; this.health = this.maxHealth; this.love = 1; this.lastmovetime = 0; this.lasttime_shoot = 0; this.lasttime_mode = 0; this.lasttime_damage = 0; this.lasttime_death = 0; this.speed = SPEED_PLAYER; this.switchmode(MODE_DETERMINATION); this.weapon = new JusticeBlaster(game, this); this.weapon.bulletSpeed = SPEED_PPROJECTILE; this.healthBar = new HealthBar(60, game.world.height - (WALL_BORDERBOTTOM / 2)); this.soulbreakEmitter = this.game.add.emitter(0, 0, 8); this.soulbreakEmitter.gravity = 1000; this.soulbreakEmitter.setXSpeed(-300, 300); this.soulbreakEmitter.makeParticles('soulbreak'); } enablePhysics() { game.physics.arcade.enable(this); this.body.bounce.y = 0.2; this.body.bounce.x = 0.2; this.body.collideWorldBounds = true; } overlap_determination(determination) { determination.kill(); this.heal(2); this.speed += 50; this.switchmode(MODE_JUSTICE); } damage(amount) { if ((game.time.now - this.lasttime_damage) > WAIT_INVINCIBILITY) { super.damage(amount); this.lasttime_damage = game.time.now; } } kill() { this.health = 0; this.healthBar.update(this.love, this.maxHealth, this.health); super.kill(); this.soulbreakEmitter.x = this.x; this.soulbreakEmitter.y = this.y; this.soulbreakEmitter.explode(2000, 8); this.lasttime_death = this.game.time.now; } loveUp() { this.love++ this.maxHealth += this.love; this.heal(this.love); } control() { if (this.alive) { if (cursors.left.isDown) { player.body.velocity.x = -player.speed; player.lastmovetime = game.time.now; } else if (cursors.right.isDown) { player.body.velocity.x = player.speed; player.lastmovetime = game.time.now; } if (cursors.up.isDown) { player.body.velocity.y = -player.speed; player.lastmovetime = game.time.now; } else if (cursors.down.isDown) { player.body.velocity.y = player.speed; player.lastmovetime = game.time.now; } if ((this.mode == MODE_JUSTICE) && game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR) && ((game.time.now - this.lasttime_shoot) > WAIT_SHOOT)) { this.shoot(); } } } switchmode(soulmode) { switch(soulmode) { case MODE_DETERMINATION: this.addColor('red', 0); break; case MODE_JUSTICE: this.addColor('yellow', 0); this.lasttime_mode = game.time.now; break; } this.mode = soulmode; } shoot() { this.weapon.fire(this, 0, this.y); this.weapon.fire(this, this.x, 0); this.weapon.fire(this, this.x, game.world.height); this.weapon.fire(this, game.world.width, this.y); this.lasttime_shoot = game.time.now; } update() { super.update(); this.control(); this.healthBar.update(this.love, this.maxHealth, this.health); game.physics.arcade.overlap(monsters, this.weapon.bullets, function(m,b) { b.overlap_monster(m); }); if ((game.time.now - this.lasttime_mode) > WAIT_SOULMODE) { this.switchmode(MODE_DETERMINATION); } } } class Monster extends Phaser.Sprite { constructor(x, y) { super(game, x, y, 'monster'); this.anchor.setTo(0.5, 0.5); this.health = MONSTER_HEALTH; this.nexttime_shoot = game.time.now; this.weapon = new JusticeBlaster(game, this); this.weapon.bulletSpeed = SPEED_MPROJECTILE; this.weapon.trackSprite(this); this.shaketween = game.add.tween(this).to({ x: this.x + (sign(Math.random() - 0.5)) * 5 }, 10, Phaser.Easing.Sinusoidal.InOut, false, 0, 8, true); } enablePhysics() { game.physics.arcade.enable(this); } damage(amount) { super.damage(amount); if (this.alive) { this.shaketween.start(); } } kill() { super.kill(); player.loveUp(); } overlap_player(player) { player.damage(10); player.switchmode(MODE_DETERMINATION); } update() { super.update(); if (this.alive && player.alive && (game.time.now > this.nexttime_shoot)) { this.weapon.fireAtSprite(player); this.nexttime_shoot = game.time.now + (WAIT_MONSTERSHOOT / 2) + (Math.random() * WAIT_MONSTERSHOOT); } game.physics.arcade.overlap(player, this.weapon.bullets, function(p,b) { b.overlap_player(p); }); } } class Determination extends Phaser.Sprite { constructor(x, y) { super(game, x, y, 'determination'); this.anchor.setTo(0.5, 0.5); } enablePhysics() { game.physics.arcade.enable(this); } } class Justice extends Phaser.Bullet { constructor(game, x, y, key, frame) { super(game, x, y, 'projectile'); this.anchor.setTo(0.5, 0.5); } overlap_monster(entity) { entity.damage(player.love); this.kill(); } overlap_player(player) { player.damage(player.love); this.kill(); } } class JusticeBlaster extends Phaser.Weapon { constructor(game, parent) { super(game, parent); this.bulletClass = Justice; this.multiFire = true; this.createBullets(100, null); } } class HealthBar { constructor(x, y) { this.mhealth = game.add.tileSprite(x + 10, y, 0, HB_THICKNESS, 'wall'); this.ahealth = game.add.tileSprite(x + 10, y, 0, HB_THICKNESS, 'wall'); this.mhealth.anchor.setTo(0, 0.5); this.ahealth.anchor.setTo(0, 0.5); this.mhealth.tint = '0xff0000'; this.ahealth.tint = '0xffff00'; this.text_love = new Phaser.Text(game, x - 50, y + 2, null, { align: 'center', fill: 'white', font: 'Ubuntu Mono', fontSize: 16, fontWeight: 'bold' }); this.text_love.anchor.setTo(0, 0.5); game.add.existing(this.text_love); } update(love, mhealth, ahealth) { this.mhealth.width = mhealth; this.ahealth.width = ahealth; this.text_love.text = "LV " + love; } } class GamePlay extends Phaser.State { constructor() { super(); game.state.add('GameOver', GameOver, false); } preload() { game.load.image('wall', 'wall.png'); game.load.image('player', 'player.png'); game.load.image('monster', 'monster.png'); game.load.image('determination', 'determination.png'); game.load.image('projectile', 'projectile.png'); game.load.image('soulbreak', 'soulbreak.png'); } create() { game.world.setBounds(0, 0, 800, 600); game.stage.backgroundColor = '#000000'; game.physics.startSystem(Phaser.Physics.ARCADE); walls = game.add.group(); walls.classType = Phaser.TileSprite; walls.enableBody = true; walls.add(game.add.tileSprite(WALL_BORDER, WALL_BORDER, game.world.width - (WALL_BORDER * 2), WALL_THICKNESS, 'wall')); walls.add(game.add.tileSprite(WALL_BORDER, game.world.height - WALL_THICKNESS - WALL_BORDERBOTTOM, game.world.width - (WALL_BORDER * 2), WALL_THICKNESS, 'wall')); walls.add(game.add.tileSprite(WALL_BORDER, WALL_BORDER, WALL_THICKNESS, game.world.height - WALL_BORDER - WALL_BORDERBOTTOM, 'wall')); walls.add(game.add.tileSprite(game.world.width - WALL_THICKNESS - WALL_BORDER, WALL_BORDER, WALL_THICKNESS, game.world.height - WALL_BORDER - WALL_BORDERBOTTOM, 'wall')); walls.children.forEach(function(wall) { wall.body.immovable = true; }); determinations = game.add.group(); nexttime_determination = Math.random() * WAIT_DETERMINATION; monsters = game.add.group(); nexttime_monsterspawn = WAIT_MONSTERSPAWN / 4; player = new Player(game.world.width / 2, game.world.height / 2); player.enablePhysics(); game.add.existing(player); game.camera.follow(player); cursors = game.input.keyboard.createCursorKeys(); } update() { game.physics.arcade.collide(player, walls); game.physics.arcade.overlap(player, determinations, function(p,d) { p.overlap_determination(d); }); game.physics.arcade.overlap(player, monsters, function(p,m) { m.overlap_player(p); }); if (game.time.now > nexttime_determination) { var determination = new Determination((Math.random() * (game.world.width - ((WALL_THICKNESS + WALL_BORDER) * 4))) + ((WALL_THICKNESS + WALL_BORDER) * 2), (Math.random() * (game.world.height - ((WALL_THICKNESS + WALL_BORDER) * 4) - WALL_BORDERBOTTOM)) + ((WALL_THICKNESS + WALL_BORDER) * 2)); determination.enablePhysics(); determinations.add(determination); nexttime_determination = game.time.now + (WAIT_DETERMINATION / 2) + (Math.random() * WAIT_DETERMINATION); } if (game.time.now > nexttime_monsterspawn) { var monster = new Monster(Math.random() * game.world.width, Math.random() * game.world.height); monster.enablePhysics(); monsters.add(monster); var waittime = WAIT_MONSTERSPAWN - ((Math.random() * 2000) * player.love); nexttime_monsterspawn = game.time.now + waittime; console.log('Next monster in ' + waittime); } if ((game.time.now - player.lastmovetime) > WAIT_KEY) player.body.velocity.x = player.body.velocity.y = 0; if ((!player.alive) && (game.time.now > (player.lasttime_death + WAIT_DEATH))) { game.state.start('GameOver'); } } } class GameOver extends Phaser.State { create() { this.game.add.text(this.game.world.width / 2, 0, "GAME\nOVER", { align: 'center', fill: 'white', font: 'Ubuntu Mono', fontSize: 160, fontWeight: 'bold' }).anchor.setTo(0.5, 0); this.game.add.text(this.game.world.width / 2, this.game.world.height * 0.75, "Stay determined...", { align: 'center', fill: 'white', font: 'Ubuntu Mono', fontSize: 24, fontWeight: 'bold' }).anchor.setTo(0.5, 0); } update() { if (this.game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR)) { this.game.state.start('GamePlay'); } } }