Cleanup: Use Phaser.Bullet & Phaser.Weapon
[ld40.git] / ld40.js
1 var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update });
2 var player;
3 var walls;
4 var determinations; // I know it's grammatically incorrect. :P
5 var monsters;
6 var nexttime_monsterspawn;
7 var nexttime_determination;
8
9 const WAIT_KEY = 200;
10 const WAIT_SHOOT = 200;
11 const WAIT_INVINCIBILITY = 800;
12 const WAIT_SOULMODE = 10000;
13 const WAIT_MONSTERSHOOT = 500;
14 const WAIT_MONSTERSPAWN = 20000;
15 const WAIT_DETERMINATION = 4000;
16 const WALL_THICKNESS = 16;
17 const WALL_BORDER = 8;
18 const WALL_BORDERBOTTOM = 48;
19 const HB_THICKNESS = 20;
20 const MAX_HEALTH = 20;
21 const MONSTER_HEALTH = 20;
22 const MODE_DETERMINATION = 0;
23 const MODE_JUSTICE = 1;
24 const SPEED_PLAYER = 150;
25 const SPEED_PROJECTILE = 500;
26
27 window.addEventListener("keydown", function(e) {
28 // Prevent default browser action for arrows and spacebar
29 if([32, 37, 38, 39, 40].indexOf(e.keyCode) > -1) {
30 e.preventDefault();
31 }
32 }, false);
33
34
35 class Player extends Phaser.Text {
36 constructor(x, y) {
37 super(game, x, y, "♥️", { align: 'center', fill: 'red', font: 'Ubuntu Mono', fontSize: 32, fontWeight: 'bold' });
38 this.anchor.setTo(0.5, 0.5);
39 this.maxHealth = MAX_HEALTH;
40 this.health = this.maxHealth;
41 this.love = 1;
42 this.lastmovetime = 0;
43 this.lasttime_shoot = 0;
44 this.lasttime_mode = 0;
45 this.lasttime_damage = 0;
46 this.speed = 150;
47 this.switchmode(MODE_DETERMINATION);
48 this.weapon = new JusticeBlaster(game, this);
49 this.healthBar = new HealthBar(60, game.world.height - (WALL_BORDERBOTTOM / 2));
50 }
51
52 enablePhysics() {
53 game.physics.arcade.enable(this);
54 this.body.bounce.y = 0.2;
55 this.body.bounce.x = 0.2;
56 this.body.collideWorldBounds = true;
57 }
58
59 overlap_determination(determination) {
60 determination.kill();
61 this.heal(2);
62 this.speed += 50;
63 this.switchmode(MODE_JUSTICE);
64 }
65
66 damage(amount) {
67 if ((game.time.now - this.lasttime_damage) > WAIT_INVINCIBILITY)
68 {
69 super.damage(amount);
70 this.lasttime_damage = game.time.now;
71 }
72 }
73
74 loveUp() {
75 this.love++
76 this.maxHealth += this.love;
77 this.heal(this.love);
78 }
79
80 control() {
81 if (this.alive)
82 {
83 if (cursors.left.isDown)
84 {
85 player.body.velocity.x = -player.speed;
86 player.lastmovetime = game.time.now;
87 }
88 else if (cursors.right.isDown)
89 {
90 player.body.velocity.x = player.speed;
91 player.lastmovetime = game.time.now;
92 }
93 if (cursors.up.isDown)
94 {
95 player.body.velocity.y = -player.speed;
96 player.lastmovetime = game.time.now;
97 }
98 else if (cursors.down.isDown)
99 {
100 player.body.velocity.y = player.speed;
101 player.lastmovetime = game.time.now;
102 }
103 if ((this.mode == MODE_JUSTICE) && game.input.keyboard.isDown(Phaser.Keyboard.SPACEBAR) && ((game.time.now - this.lasttime_shoot) > WAIT_SHOOT))
104 {
105 this.shoot();
106 }
107 }
108 }
109
110 switchmode(soulmode) {
111 switch(soulmode)
112 {
113 case MODE_DETERMINATION:
114 this.addColor('red', 0);
115 break;
116 case MODE_JUSTICE:
117 this.addColor('yellow', 0);
118 this.lasttime_mode = game.time.now;
119 break;
120 }
121 this.mode = soulmode;
122 }
123
124 shoot() {
125 this.weapon.fire(this, 0, this.y);
126 this.weapon.fire(this, this.x, 0);
127 this.weapon.fire(this, this.x, game.world.height);
128 this.weapon.fire(this, game.world.width, this.y);
129 this.lasttime_shoot = game.time.now;
130 }
131
132 update() {
133 super.update();
134 this.control();
135 this.healthBar.update(this.love, this.maxHealth, this.health);
136 game.physics.arcade.overlap(monsters, this.weapon.bullets, function(m,b) { b.overlap_monster(m); });
137 if ((game.time.now - this.lasttime_mode) > WAIT_SOULMODE) { this.switchmode(MODE_DETERMINATION); }
138 }
139 }
140
141 class Monster extends Phaser.Sprite {
142 constructor(x, y) {
143 super(game, x, y, 'monster');
144 this.anchor.setTo(0.5, 0.5);
145 this.health = MONSTER_HEALTH;
146 this.nexttime_shoot = game.time.now;
147 this.weapon = new Phaser.Weapon(game, this);
148 this.weapon.x = x;
149 this.weapon.y = y;
150 this.weapon.createBullets(20, 'projectile');
151 }
152
153 enablePhysics() {
154 game.physics.arcade.enable(this);
155 }
156
157 kill() {
158 super.kill();
159 player.loveUp();
160 }
161
162 overlap_player(player) {
163 player.damage(10);
164 player.switchmode(MODE_DETERMINATION);
165 }
166
167 update() {
168 super.update();
169 if (this.alive && player.alive && (game.time.now > this.nexttime_shoot))
170 {
171 this.weapon.fireAtSprite(player);
172 this.nexttime_shoot = game.time.now + (WAIT_MONSTERSHOOT / 2) + (Math.random() * WAIT_MONSTERSHOOT);
173 }
174 game.physics.arcade.overlap(player, this.weapon.bullets, function(p,b) { p.damage(p.love); });
175 }
176 }
177
178 class Determination extends Phaser.Sprite {
179 constructor(x, y) {
180 super(game, x, y, 'determination');
181 this.anchor.setTo(0.5, 0.5);
182 }
183
184 enablePhysics() {
185 game.physics.arcade.enable(this);
186 }
187 }
188
189 class Justice extends Phaser.Bullet {
190 constructor(game, x, y, key, frame) {
191 super(game, x, y, 'projectile');
192 this.anchor.setTo(0.5, 0.5);
193 }
194
195 overlap_monster(entity) {
196 entity.damage(player.love);
197 this.kill();
198 }
199 }
200
201 class JusticeBlaster extends Phaser.Weapon {
202 constructor(game, parent) {
203 super(game, parent);
204 this.bulletClass = Justice;
205 this.bulletSpeed = SPEED_PROJECTILE;
206 this.multiFire = true;
207 this.createBullets(100, null);
208 }
209 }
210
211 class HealthBar {
212 constructor(x, y) {
213 this.mhealth = game.add.tileSprite(x + 10, y, 0, HB_THICKNESS, 'wall');
214 this.ahealth = game.add.tileSprite(x + 10, y, 0, HB_THICKNESS, 'wall');
215 this.mhealth.anchor.setTo(0, 0.5);
216 this.ahealth.anchor.setTo(0, 0.5);
217 this.mhealth.tint = '0xff0000';
218 this.ahealth.tint = '0xffff00';
219 this.text_love = new Phaser.Text(game, x - 50, y + 2, null, { align: 'center', fill: 'white', font: 'Ubuntu Mono', fontSize: 16, fontWeight: 'bold' });
220 this.text_love.anchor.setTo(0, 0.5);
221 game.add.existing(this.text_love);
222 }
223
224 update(love, mhealth, ahealth) {
225 this.mhealth.width = mhealth;
226 this.ahealth.width = ahealth;
227 this.text_love.text = "LV " + love;
228 }
229 }
230
231 function preload () {
232
233 game.load.image('wall', 'wall.png');
234 game.load.image('player', 'player.png');
235 game.load.image('monster', 'monster.png');
236 game.load.image('determination', 'determination.png');
237 game.load.image('projectile', 'projectile.png');
238
239 }
240
241 function create () {
242
243 game.world.setBounds(0, 0, 800, 600);
244 game.stage.backgroundColor = '#000000';
245 game.physics.startSystem(Phaser.Physics.ARCADE);
246
247 walls = game.add.group();
248 walls.classType = Phaser.TileSprite;
249 walls.enableBody = true;
250
251 walls.add(game.add.tileSprite(WALL_BORDER, WALL_BORDER, game.world.width - (WALL_BORDER * 2), WALL_THICKNESS, 'wall'));
252 walls.add(game.add.tileSprite(WALL_BORDER, game.world.height - WALL_THICKNESS - WALL_BORDERBOTTOM, game.world.width - (WALL_BORDER * 2), WALL_THICKNESS, 'wall'));
253 walls.add(game.add.tileSprite(WALL_BORDER, WALL_BORDER, WALL_THICKNESS, game.world.height - WALL_BORDER - WALL_BORDERBOTTOM, 'wall'));
254 walls.add(game.add.tileSprite(game.world.width - WALL_THICKNESS - WALL_BORDER, WALL_BORDER, WALL_THICKNESS, game.world.height - WALL_BORDER - WALL_BORDERBOTTOM, 'wall'));
255 walls.children.forEach(function(wall) { wall.body.immovable = true; });
256
257 determinations = game.add.group();
258 nexttime_determination = Math.random() * WAIT_DETERMINATION;
259
260 monsters = game.add.group();
261 monsters.add(new Monster(400, 500));
262 monsters.children.forEach(function(monster) { monster.enablePhysics(); });
263 nexttime_monsterspawn = WAIT_MONSTERSPAWN;
264
265 player = new Player(game.world.width / 2, game.world.height / 2);
266 player.enablePhysics();
267 game.add.existing(player);
268 game.camera.follow(player);
269 cursors = game.input.keyboard.createCursorKeys();
270
271 keyboard_handler = keyPress_default;
272
273 }
274
275 function update () {
276
277 game.physics.arcade.collide(player, walls);
278 game.physics.arcade.overlap(player, determinations, function(p,d) { p.overlap_determination(d); });
279 game.physics.arcade.overlap(player, monsters, function(p,m) { m.overlap_player(p); });
280
281 if (game.time.now > nexttime_determination)
282 {
283 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));
284 determination.enablePhysics();
285 determinations.add(determination);
286 nexttime_determination = game.time.now + (WAIT_DETERMINATION / 2) + (Math.random() * WAIT_DETERMINATION);
287 }
288
289 if (game.time.now > nexttime_monsterspawn)
290 {
291 var monster = new Monster(Math.random() * game.world.width, Math.random() * game.world.height);
292 monster.enablePhysics();
293 monsters.add(monster);
294 nexttime_monsterspawn = game.time.now + (WAIT_MONSTERSPAWN / player.love) + (Math.random() * WAIT_MONSTERSPAWN);
295 }
296
297 if ((game.time.now - player.lastmovetime) > WAIT_KEY) player.body.velocity.x = player.body.velocity.y = 0;
298 if (keyboard_handler) keyboard_handler();
299
300 }
301
302 function keyPress_default() {
303
304 // Maybe needed later.
305
306 }