class Boing extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.ball; this.shadow; } create () { const bg = this.add.image(0, 0, 'boing', 'boing-window').setOrigin(0); this.cameras.main.setViewport(this.parent.x, this.parent.y, Boing.WIDTH, Boing.HEIGHT); this.physics.world.setBounds(10, 24, 330, 222); this.ball = this.physics.add.sprite(100, 32, 'boing', 'boing1').play('boing'); this.shadow = this.add.image(this.ball.x + 62, this.ball.y - 2, 'boing', 'shadow'); this.ball.setVelocity(Phaser.Math.Between(40,80), 110); this.ball.setBounce(1, 1); this.ball.setCollideWorldBounds(true); this.events.on('postupdate', this.postUpdate, this); } postUpdate () { this.shadow.setPosition(this.ball.x + 44, this.ball.y - 2); } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Boing.WIDTH = 344; Boing.HEIGHT = 266;
class Juggler extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; } create () { const bg = this.add.image(0, 0, 'jugglerWindow').setOrigin(0); this.cameras.main.setViewport(this.parent.x, this.parent.y, Juggler.WIDTH, Juggler.HEIGHT); this.add.sprite(100, 22, 'juggler').setOrigin(0).play('juggler'); } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Juggler.WIDTH = 328; Juggler.HEIGHT = 226;
class Invaders extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.left; this.right; this.ship; this.invaders; this.mothership; this.bullet; this.topLeft; this.bottomRight; this.bulletTimer; this.mothershipTimer; this.isGameOver = false; this.invadersBounds = { x: 12, y: 62, right: 152 }; } create (config) { this.left = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT); this.right = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT); this.physics.world.setBounds(4, 22, 400, 300); this.cameras.main.setViewport(this.parent.x, this.parent.y, Invaders.WIDTH, Invaders.HEIGHT); this.cameras.main.setBackgroundColor('#000'); this.createInvaders(); this.bullet = this.physics.add.image(200, 290, 'invaders.bullet2'); this.mothership = this.physics.add.image(500, 40, 'invaders.mothership'); this.ship = this.physics.add.image(200, 312, 'invaders.ship'); var bg = this.add.image(0, 0, 'invadersWindow').setOrigin(0); this.ship.setCollideWorldBounds(true); this.physics.add.overlap(this.bullet, this.invaders, this.bulletHit, null, this); this.physics.add.overlap(this.bullet, this.mothership, this.bulletHitMothership, null, this); this.launchBullet(); this.mothershipTimer = this.time.addEvent({ delay: 10000, callback: this.launchMothership, callbackScope: this, repeat: -1 }); this.invaders.setVelocityX(50); } launchMothership () { this.mothership.setVelocityX(-100); } bulletHit (bullet, invader) { this.launchBullet(); invader.body.enable = false; this.invaders.killAndHide(invader); this.refreshOutliers(); } bulletHitMothership (bullet, mothership) { this.launchBullet(); this.mothership.body.reset(500, 40); } refreshOutliers () { const list = this.invaders.getChildren(); let first = this.invaders.getFirst(true); let last = this.invaders.getLast(true); for (let i = 0; i < list.length; i++) { const vader = list[i]; if (vader.active) { if (vader.x < first.x) { first = vader; } else if (vader.x > last.x) { last = vader; } } } if (this.topLeft === null && this.bottomRight === null) { this.gameOver(); } this.topLeft = first; this.bottomRight = last; } launchBullet () { this.bullet.body.reset(this.ship.x, this.ship.y); this.bullet.body.velocity.y = -400; } createInvaders () { this.invaders = this.physics.add.group(); let x = this.invadersBounds.x; let y = this.invadersBounds.y; for (let i = 0; i < 10; i++) { this.invaders.create(x, y, 'invaders.invader1').setTint(0xff0000).play('invader1'); x += 26; } x = this.invadersBounds.x; y += 28 for (let i = 0; i < 16; i++) { this.invaders.create(x, y, 'invaders.invader2').setTint(0x00ff00).play('invader2'); x += 33; if (i === 7) { x = this.invadersBounds.x; y += 28; } } x = this.invadersBounds.x; y += 28 for (let i = 0; i < 14; i++) { this.invaders.create(x, y, 'invaders.invader3').setTint(0x00ffff).play('invader3'); x += 38; if (i === 6) { x = this.invadersBounds.x; y += 28; } } // We can use these markers to work out where the whole Group is and how wide it is this.topLeft = this.invaders.getFirst(true); this.bottomRight = this.invaders.getLast(true); } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } gameOver () { this.invaders.setVelocityX(0); this.ship.setVisible(false); this.bullet.setVisible(false); this.isGameOver = true; } update () { if (this.isGameOver || (this.bottomRight === null && this.topLeft === null)) { return; } if (this.left.isDown) { this.ship.body.velocity.x = -400; } else if (this.right.isDown) { this.ship.body.velocity.x = 400; } else { this.ship.body.velocity.x = 0; } // Bullet bounds if (this.bullet.y < -32) { this.launchBullet(); } // Invaders bounds let moveDown = false; if (this.bottomRight.body.velocity.x > 0 && this.bottomRight.x >= 390) { this.invaders.setVelocityX(-50); moveDown = true; } else if (this.topLeft.body.velocity.x < 0 && this.topLeft.x <= 12) { this.invaders.setVelocityX(50); moveDown = true; } if (moveDown) { const list = this.invaders.getChildren(); let lowest = 0; for (let i = 0; i < list.length; i++) { const vader = list[i]; vader.body.y += 4; if (vader.active && vader.body.y > lowest) { lowest = vader.body.y; } } if (lowest > 240) { this.gameOver(); } } } } Invaders.WIDTH = 408; Invaders.HEIGHT = 326;
class Stars extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.blitter; this.width = 320; this.height = 220; this.depth = 1700; this.distance = 200; this.speed = 6; this.max = 300; this.xx = []; this.yy = []; this.zz = []; } create () { this.cameras.main.setViewport(this.parent.x, this.parent.y, Stars.WIDTH, Stars.HEIGHT); this.cameras.main.setBackgroundColor(0x000000); this.blitter = this.add.blitter(0, 0, 'star'); for (let i = 0; i < this.max; i++) { this.xx[i] = Math.floor(Math.random() * this.width) - (this.width / 2); this.yy[i] = Math.floor(Math.random() * this.height) - (this.height / 2); this.zz[i] = Math.floor(Math.random() * this.depth) - 100; const perspective = this.distance / (this.distance - this.zz[i]); const x = (this.width / 2) + this.xx[i] * perspective; const y = (this.height / 2) + this.yy[i] * perspective; const a = (x < 0 || x > 320 || y < 20 || y > 260) ? 0 : 1; this.blitter.create(x, y); } const bg = this.add.image(0, 0, 'starsWindow').setOrigin(0); } update (time, delta) { const list = this.blitter.children.list; for (let i = 0; i < this.max; i++) { const perspective = this.distance / (this.distance - this.zz[i]); const x = (this.width / 2) + this.xx[i] * perspective; const y = (this.height / 2) + this.yy[i] * perspective; this.zz[i] += this.speed; if (this.zz[i] > this.distance) { this.zz[i] -= (this.distance * 2); } list[i].x = x; list[i].y = y; list[i].a = (x < 0 || x > 320 || y < 20 || y > 260) ? 0 : 1; } } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Stars.WIDTH = 328; Stars.HEIGHT = 266;
const config = { type: Phaser.WEBGL, width: window.innerWidth, height: window.innerHeight, backgroundColor: '#0055aa', parent: 'phaser-example', scene: Controller, physics: { default: 'arcade', arcade: { debug: false, gravity: { y: 0 } } } }; const game = new Phaser.Game(config); window.addEventListener('resize', function (event) { // game.resize(window.innerWidth, window.innerHeight); }, false);
class Clock extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.graphics; this.clockSize = 120; } create () { const bg = this.add.image(0, 0, 'clockWindow').setOrigin(0); this.cameras.main.setViewport(this.parent.x, this.parent.y, Clock.WIDTH, Clock.HEIGHT); this.cameras.main.setBackgroundColor(0x0055aa); this.graphics = this.add.graphics(); } update () { const graphics = this.graphics; const timer = this.timerEvent; const clockSize = this.clockSize; const x = Clock.WIDTH / 2; const y = 8 + Clock.HEIGHT / 2; graphics.clear(); // Progress is between 0 and 1, where 0 = the hand pointing up and then rotating clockwise a full 360 // The frame graphics.fillStyle(0xffffff, 1); graphics.lineStyle(3, 0x000000, 1); graphics.fillCircle(x, y, clockSize); graphics.strokeCircle(x, y, clockSize); let date = new Date; let seconds = date.getSeconds() / 60; let mins = date.getMinutes() / 60; let hours = date.getHours() / 24; // The hours hand let size = clockSize * 0.9; let angle = (360 * hours) - 90; let dest = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle), size); graphics.fillStyle(0x000000, 1); graphics.beginPath(); graphics.moveTo(x, y); let p1 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle - 5), size * 0.7); graphics.lineTo(p1.x, p1.y); graphics.lineTo(dest.x, dest.y); graphics.moveTo(x, y); let p2 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle + 5), size * 0.7); graphics.lineTo(p2.x, p2.y); graphics.lineTo(dest.x, dest.y); graphics.fillPath(); graphics.closePath(); // The minutes hand size = clockSize * 0.9; angle = (360 * mins) - 90; dest = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle), size); graphics.fillStyle(0x000000, 1); graphics.beginPath(); graphics.moveTo(x, y); p1 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle - 5), size * 0.7); graphics.lineTo(p1.x, p1.y); graphics.lineTo(dest.x, dest.y); graphics.moveTo(x, y); p2 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle + 5), size * 0.7); graphics.lineTo(p2.x, p2.y); graphics.lineTo(dest.x, dest.y); graphics.fillPath(); graphics.closePath(); // The seconds hand size = clockSize * 0.9; angle = (360 * seconds) - 90; dest = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle), size); graphics.fillStyle(0xff0000, 1); graphics.beginPath(); graphics.moveTo(x, y); p1 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle - 5), size * 0.3); graphics.lineTo(p1.x, p1.y); graphics.lineTo(dest.x, dest.y); graphics.moveTo(x, y); p2 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle + 5), size * 0.3); graphics.lineTo(p2.x, p2.y); graphics.lineTo(dest.x, dest.y); graphics.fillPath(); graphics.closePath(); } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Clock.WIDTH = 275; Clock.HEIGHT = 276;
class Controller extends Phaser.Scene { constructor () { super(); this.count = 0; this.workbench; this.workbenchTitle; this.workbenchIcons; } preload () { this.load.setBaseURL('https://cdn.phaserfiles.com/v355'); this.load.image('disk', 'assets/phaser3/disk.png'); this.load.image('workbenchTitle', 'assets/phaser3/workbench-title.png'); this.load.image('workbenchIcons', 'assets/phaser3/workbench-icons.png'); this.load.image('demosWindow', 'assets/phaser3/demos-window.png'); this.load.image('eyesIcon', 'assets/phaser3/eyes-icon.png'); this.load.image('starsIcon', 'assets/phaser3/stars-icon.png'); this.load.image('jugglerIcon', 'assets/phaser3/juggler-icon.png'); this.load.image('twistIcon', 'assets/phaser3/twist-icon.png'); this.load.image('invadersIcon', 'assets/phaser3/invaders-icon.png'); this.load.image('clockIcon', 'assets/phaser3/clock-icon.png'); this.load.image('boingIcon', 'assets/phaser3/boing-icon.png'); this.load.image('starsWindow', 'assets/phaser3/stars-window.png'); this.load.image('sineWindow', 'assets/phaser3/sinewave-window.png'); this.load.image('eyesWindow', 'assets/phaser3/eyes-window.png'); this.load.image('jugglerWindow', 'assets/phaser3/juggler-window.png'); this.load.image('invadersWindow', 'assets/phaser3/invaders-window.png'); this.load.image('clockWindow', 'assets/phaser3/clock-window.png'); this.load.atlas('boing', 'assets/phaser3/boing.png', 'assets/phaser3/boing.json'); this.load.spritesheet('juggler', 'assets/phaser3/juggler.png', { frameWidth: 128, frameHeight: 184 }); this.load.image('star', 'assets/phaser3/star2.png'); this.load.image('eye', 'assets/phaser3/eye.png'); this.load.image('invaders.boom', 'assets/games/multi/boom.png'); this.load.spritesheet('invaders.bullet', 'assets/games/multi/bullet.png', { frameWidth: 12, frameHeight: 14 }); this.load.image('invaders.bullet2', 'assets/games/multi/bullet2.png'); this.load.image('invaders.explode', 'assets/games/multi/explode.png'); this.load.spritesheet('invaders.invader1', 'assets/games/multi/invader1.png', { frameWidth: 16, frameHeight: 16 }); this.load.spritesheet('invaders.invader2', 'assets/games/multi/invader2.png', { frameWidth: 22, frameHeight: 16 }); this.load.spritesheet('invaders.invader3', 'assets/games/multi/invader3.png', { frameWidth: 24, frameHeight: 16 }); this.load.image('invaders.mothership', 'assets/games/multi/mothership.png'); this.load.image('invaders.ship', 'assets/games/multi/ship.png'); } create () { // Create animations this.anims.create({ key: 'juggler', frames: this.anims.generateFrameNumbers('juggler'), frameRate: 28, repeat: -1 }); this.anims.create({ key: 'boing', frames: this.anims.generateFrameNames('boing', { prefix: 'boing', start: 1, end: 14 }), frameRate: 28, repeat: -1 }); this.anims.create({ key: 'bullet', frames: this.anims.generateFrameNumbers('invaders.bullet'), frameRate: 8, repeat: -1 }); this.anims.create({ key: 'invader1', frames: this.anims.generateFrameNumbers('invaders.invader1'), frameRate: 2, repeat: -1 }); this.anims.create({ key: 'invader2', frames: this.anims.generateFrameNumbers('invaders.invader2'), frameRate: 2, repeat: -1 }); this.anims.create({ key: 'invader3', frames: this.anims.generateFrameNumbers('invaders.invader3'), frameRate: 2, repeat: -1 }); this.workbench = this.add.graphics({ x: 16, y: 21 }); this.workbench.fillStyle(0xffffff); this.workbench.fillRect(0, 0, this.sys.game.config.width - 105, 20); this.workbenchTitle = this.add.image(16, 21, 'workbenchTitle').setOrigin(0); this.workbenchIcons = this.add.image(this.sys.game.config.width - 87, 21, 'workbenchIcons').setOrigin(0); const disk = this.add.image(16, 64, 'disk').setOrigin(0).setInteractive(); const demosWindow = this.add.image(0, 0, 'demosWindow').setOrigin(0); const eyesIcon = this.add.image(32, 34, 'eyesIcon', 0).setOrigin(0).setInteractive(); const jugglerIcon = this.add.image(48, 110, 'jugglerIcon', 0).setOrigin(0).setInteractive(); const starsIcon = this.add.image(230, 40, 'starsIcon', 0).setOrigin(0).setInteractive(); const invadersIcon = this.add.image(120, 34, 'invadersIcon', 0).setOrigin(0).setInteractive(); const clockIcon = this.add.image(240, 120, 'clockIcon', 0).setOrigin(0).setInteractive(); const boingIcon = this.add.image(146, 128, 'boingIcon', 0).setOrigin(0).setInteractive(); const demosContainer = this.add.container(32, 70, [ demosWindow, eyesIcon, jugglerIcon, starsIcon, invadersIcon, clockIcon, boingIcon ]); demosContainer.setVisible(false); demosContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, demosWindow.width, demosWindow.height), Phaser.Geom.Rectangle.Contains); this.input.setDraggable(demosContainer); demosContainer.on('drag', function (pointer, dragX, dragY) { this.x = dragX; this.y = dragY; }); disk.once('pointerup', function () { demosContainer.setVisible(true); }); eyesIcon.on('pointerup', function () { this.createWindow(Eyes); }, this); jugglerIcon.on('pointerup', function () { this.createWindow(Juggler); }, this); starsIcon.on('pointerup', function () { this.createWindow(Stars); }, this); invadersIcon.on('pointerup', function () { this.createWindow(Invaders); }, this); clockIcon.on('pointerup', function () { this.createWindow(Clock); }, this); boingIcon.on('pointerup', function () { this.createWindow(Boing); }, this); this.events.on('resize', this.resize, this); } createWindow (func) { const x = Phaser.Math.Between(400, 600); const y = Phaser.Math.Between(64, 128); const handle = 'window' + this.count++; const win = this.add.zone(x, y, func.WIDTH, func.HEIGHT).setInteractive().setOrigin(0); const demo = new func(handle, win); this.input.setDraggable(win); win.on('drag', function (pointer, dragX, dragY) { this.x = dragX; this.y = dragY; demo.refresh() }); this.scene.add(handle, demo, true); } resize (width, height) { if (width === undefined) { width = this.game.config.width; } if (height === undefined) { height = this.game.config.height; } this.cameras.resize(width, height); this.workbench.clear(); this.workbench.fillStyle(0xffffff); this.workbench.fillRect(0, 0, width - 105, 20); this.workbenchIcons.x = (width - 87); } }
class Eyes extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.left; this.right; this.leftTarget; this.rightTarget; this.leftBase; this.rightBase; this.mid = new Phaser.Math.Vector2(); } create () { const bg = this.add.image(0, 0, 'eyesWindow').setOrigin(0); this.cameras.main.setViewport(this.parent.x, this.parent.y, Eyes.WIDTH, Eyes.HEIGHT); this.left = this.add.image(46, 92, 'eye'); this.right = this.add.image(140, 92, 'eye'); this.leftTarget = new Phaser.Geom.Line(this.left.x, this.left.y, 0, 0); this.rightTarget = new Phaser.Geom.Line(this.right.x, this.right.y, 0, 0); this.leftBase = new Phaser.Geom.Ellipse(this.left.x, this.left.y, 24, 40); this.rightBase = new Phaser.Geom.Ellipse(this.right.x, this.right.y, 24, 40); } update () { this.leftTarget.x2 = this.input.activePointer.x - this.parent.x; this.leftTarget.y2 = this.input.activePointer.y - this.parent.y; // Within the left eye? if (this.leftBase.contains(this.leftTarget.x2, this.leftTarget.y2)) { this.mid.x = this.leftTarget.x2; this.mid.y = this.leftTarget.y2; } else { Phaser.Geom.Ellipse.CircumferencePoint(this.leftBase, Phaser.Geom.Line.Angle(this.leftTarget), this.mid); } this.left.x = this.mid.x; this.left.y = this.mid.y; this.rightTarget.x2 = this.input.activePointer.x - this.parent.x; this.rightTarget.y2 = this.input.activePointer.y - this.parent.y; // Within the right eye? if (this.rightBase.contains(this.rightTarget.x2, this.rightTarget.y2)) { this.mid.x = this.rightTarget.x2; this.mid.y = this.rightTarget.y2; } else { Phaser.Geom.Ellipse.CircumferencePoint(this.rightBase, Phaser.Geom.Line.Angle(this.rightTarget), this.mid); } this.right.x = this.mid.x; this.right.y = this.mid.y; } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Eyes.WIDTH = 183; Eyes.HEIGHT = 162;
Scan to open on your mobile device
class Boing extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.ball; this.shadow; } create () { const bg = this.add.image(0, 0, 'boing', 'boing-window').setOrigin(0); this.cameras.main.setViewport(this.parent.x, this.parent.y, Boing.WIDTH, Boing.HEIGHT); this.physics.world.setBounds(10, 24, 330, 222); this.ball = this.physics.add.sprite(100, 32, 'boing', 'boing1').play('boing'); this.shadow = this.add.image(this.ball.x + 62, this.ball.y - 2, 'boing', 'shadow'); this.ball.setVelocity(Phaser.Math.Between(40,80), 110); this.ball.setBounce(1, 1); this.ball.setCollideWorldBounds(true); this.events.on('postupdate', this.postUpdate, this); } postUpdate () { this.shadow.setPosition(this.ball.x + 44, this.ball.y - 2); } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Boing.WIDTH = 344; Boing.HEIGHT = 266;
class Juggler extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; } create () { const bg = this.add.image(0, 0, 'jugglerWindow').setOrigin(0); this.cameras.main.setViewport(this.parent.x, this.parent.y, Juggler.WIDTH, Juggler.HEIGHT); this.add.sprite(100, 22, 'juggler').setOrigin(0).play('juggler'); } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Juggler.WIDTH = 328; Juggler.HEIGHT = 226;
class Invaders extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.left; this.right; this.ship; this.invaders; this.mothership; this.bullet; this.topLeft; this.bottomRight; this.bulletTimer; this.mothershipTimer; this.isGameOver = false; this.invadersBounds = { x: 12, y: 62, right: 152 }; } create (config) { this.left = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.LEFT); this.right = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.RIGHT); this.physics.world.setBounds(4, 22, 400, 300); this.cameras.main.setViewport(this.parent.x, this.parent.y, Invaders.WIDTH, Invaders.HEIGHT); this.cameras.main.setBackgroundColor('#000'); this.createInvaders(); this.bullet = this.physics.add.image(200, 290, 'invaders.bullet2'); this.mothership = this.physics.add.image(500, 40, 'invaders.mothership'); this.ship = this.physics.add.image(200, 312, 'invaders.ship'); var bg = this.add.image(0, 0, 'invadersWindow').setOrigin(0); this.ship.setCollideWorldBounds(true); this.physics.add.overlap(this.bullet, this.invaders, this.bulletHit, null, this); this.physics.add.overlap(this.bullet, this.mothership, this.bulletHitMothership, null, this); this.launchBullet(); this.mothershipTimer = this.time.addEvent({ delay: 10000, callback: this.launchMothership, callbackScope: this, repeat: -1 }); this.invaders.setVelocityX(50); } launchMothership () { this.mothership.setVelocityX(-100); } bulletHit (bullet, invader) { this.launchBullet(); invader.body.enable = false; this.invaders.killAndHide(invader); this.refreshOutliers(); } bulletHitMothership (bullet, mothership) { this.launchBullet(); this.mothership.body.reset(500, 40); } refreshOutliers () { const list = this.invaders.getChildren(); let first = this.invaders.getFirst(true); let last = this.invaders.getLast(true); for (let i = 0; i < list.length; i++) { const vader = list[i]; if (vader.active) { if (vader.x < first.x) { first = vader; } else if (vader.x > last.x) { last = vader; } } } if (this.topLeft === null && this.bottomRight === null) { this.gameOver(); } this.topLeft = first; this.bottomRight = last; } launchBullet () { this.bullet.body.reset(this.ship.x, this.ship.y); this.bullet.body.velocity.y = -400; } createInvaders () { this.invaders = this.physics.add.group(); let x = this.invadersBounds.x; let y = this.invadersBounds.y; for (let i = 0; i < 10; i++) { this.invaders.create(x, y, 'invaders.invader1').setTint(0xff0000).play('invader1'); x += 26; } x = this.invadersBounds.x; y += 28 for (let i = 0; i < 16; i++) { this.invaders.create(x, y, 'invaders.invader2').setTint(0x00ff00).play('invader2'); x += 33; if (i === 7) { x = this.invadersBounds.x; y += 28; } } x = this.invadersBounds.x; y += 28 for (let i = 0; i < 14; i++) { this.invaders.create(x, y, 'invaders.invader3').setTint(0x00ffff).play('invader3'); x += 38; if (i === 6) { x = this.invadersBounds.x; y += 28; } } // We can use these markers to work out where the whole Group is and how wide it is this.topLeft = this.invaders.getFirst(true); this.bottomRight = this.invaders.getLast(true); } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } gameOver () { this.invaders.setVelocityX(0); this.ship.setVisible(false); this.bullet.setVisible(false); this.isGameOver = true; } update () { if (this.isGameOver || (this.bottomRight === null && this.topLeft === null)) { return; } if (this.left.isDown) { this.ship.body.velocity.x = -400; } else if (this.right.isDown) { this.ship.body.velocity.x = 400; } else { this.ship.body.velocity.x = 0; } // Bullet bounds if (this.bullet.y < -32) { this.launchBullet(); } // Invaders bounds let moveDown = false; if (this.bottomRight.body.velocity.x > 0 && this.bottomRight.x >= 390) { this.invaders.setVelocityX(-50); moveDown = true; } else if (this.topLeft.body.velocity.x < 0 && this.topLeft.x <= 12) { this.invaders.setVelocityX(50); moveDown = true; } if (moveDown) { const list = this.invaders.getChildren(); let lowest = 0; for (let i = 0; i < list.length; i++) { const vader = list[i]; vader.body.y += 4; if (vader.active && vader.body.y > lowest) { lowest = vader.body.y; } } if (lowest > 240) { this.gameOver(); } } } } Invaders.WIDTH = 408; Invaders.HEIGHT = 326;
class Stars extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.blitter; this.width = 320; this.height = 220; this.depth = 1700; this.distance = 200; this.speed = 6; this.max = 300; this.xx = []; this.yy = []; this.zz = []; } create () { this.cameras.main.setViewport(this.parent.x, this.parent.y, Stars.WIDTH, Stars.HEIGHT); this.cameras.main.setBackgroundColor(0x000000); this.blitter = this.add.blitter(0, 0, 'star'); for (let i = 0; i < this.max; i++) { this.xx[i] = Math.floor(Math.random() * this.width) - (this.width / 2); this.yy[i] = Math.floor(Math.random() * this.height) - (this.height / 2); this.zz[i] = Math.floor(Math.random() * this.depth) - 100; const perspective = this.distance / (this.distance - this.zz[i]); const x = (this.width / 2) + this.xx[i] * perspective; const y = (this.height / 2) + this.yy[i] * perspective; const a = (x < 0 || x > 320 || y < 20 || y > 260) ? 0 : 1; this.blitter.create(x, y); } const bg = this.add.image(0, 0, 'starsWindow').setOrigin(0); } update (time, delta) { const list = this.blitter.children.list; for (let i = 0; i < this.max; i++) { const perspective = this.distance / (this.distance - this.zz[i]); const x = (this.width / 2) + this.xx[i] * perspective; const y = (this.height / 2) + this.yy[i] * perspective; this.zz[i] += this.speed; if (this.zz[i] > this.distance) { this.zz[i] -= (this.distance * 2); } list[i].x = x; list[i].y = y; list[i].a = (x < 0 || x > 320 || y < 20 || y > 260) ? 0 : 1; } } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Stars.WIDTH = 328; Stars.HEIGHT = 266;
const config = { type: Phaser.WEBGL, width: window.innerWidth, height: window.innerHeight, backgroundColor: '#0055aa', parent: 'phaser-example', scene: Controller, physics: { default: 'arcade', arcade: { debug: false, gravity: { y: 0 } } } }; const game = new Phaser.Game(config); window.addEventListener('resize', function (event) { // game.resize(window.innerWidth, window.innerHeight); }, false);
class Clock extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.graphics; this.clockSize = 120; } create () { const bg = this.add.image(0, 0, 'clockWindow').setOrigin(0); this.cameras.main.setViewport(this.parent.x, this.parent.y, Clock.WIDTH, Clock.HEIGHT); this.cameras.main.setBackgroundColor(0x0055aa); this.graphics = this.add.graphics(); } update () { const graphics = this.graphics; const timer = this.timerEvent; const clockSize = this.clockSize; const x = Clock.WIDTH / 2; const y = 8 + Clock.HEIGHT / 2; graphics.clear(); // Progress is between 0 and 1, where 0 = the hand pointing up and then rotating clockwise a full 360 // The frame graphics.fillStyle(0xffffff, 1); graphics.lineStyle(3, 0x000000, 1); graphics.fillCircle(x, y, clockSize); graphics.strokeCircle(x, y, clockSize); let date = new Date; let seconds = date.getSeconds() / 60; let mins = date.getMinutes() / 60; let hours = date.getHours() / 24; // The hours hand let size = clockSize * 0.9; let angle = (360 * hours) - 90; let dest = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle), size); graphics.fillStyle(0x000000, 1); graphics.beginPath(); graphics.moveTo(x, y); let p1 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle - 5), size * 0.7); graphics.lineTo(p1.x, p1.y); graphics.lineTo(dest.x, dest.y); graphics.moveTo(x, y); let p2 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle + 5), size * 0.7); graphics.lineTo(p2.x, p2.y); graphics.lineTo(dest.x, dest.y); graphics.fillPath(); graphics.closePath(); // The minutes hand size = clockSize * 0.9; angle = (360 * mins) - 90; dest = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle), size); graphics.fillStyle(0x000000, 1); graphics.beginPath(); graphics.moveTo(x, y); p1 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle - 5), size * 0.7); graphics.lineTo(p1.x, p1.y); graphics.lineTo(dest.x, dest.y); graphics.moveTo(x, y); p2 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle + 5), size * 0.7); graphics.lineTo(p2.x, p2.y); graphics.lineTo(dest.x, dest.y); graphics.fillPath(); graphics.closePath(); // The seconds hand size = clockSize * 0.9; angle = (360 * seconds) - 90; dest = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle), size); graphics.fillStyle(0xff0000, 1); graphics.beginPath(); graphics.moveTo(x, y); p1 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle - 5), size * 0.3); graphics.lineTo(p1.x, p1.y); graphics.lineTo(dest.x, dest.y); graphics.moveTo(x, y); p2 = Phaser.Math.RotateAroundDistance({ x: x, y: y }, x, y, Phaser.Math.DegToRad(angle + 5), size * 0.3); graphics.lineTo(p2.x, p2.y); graphics.lineTo(dest.x, dest.y); graphics.fillPath(); graphics.closePath(); } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Clock.WIDTH = 275; Clock.HEIGHT = 276;
class Controller extends Phaser.Scene { constructor () { super(); this.count = 0; this.workbench; this.workbenchTitle; this.workbenchIcons; } preload () { this.load.setBaseURL('https://cdn.phaserfiles.com/v355'); this.load.image('disk', 'assets/phaser3/disk.png'); this.load.image('workbenchTitle', 'assets/phaser3/workbench-title.png'); this.load.image('workbenchIcons', 'assets/phaser3/workbench-icons.png'); this.load.image('demosWindow', 'assets/phaser3/demos-window.png'); this.load.image('eyesIcon', 'assets/phaser3/eyes-icon.png'); this.load.image('starsIcon', 'assets/phaser3/stars-icon.png'); this.load.image('jugglerIcon', 'assets/phaser3/juggler-icon.png'); this.load.image('twistIcon', 'assets/phaser3/twist-icon.png'); this.load.image('invadersIcon', 'assets/phaser3/invaders-icon.png'); this.load.image('clockIcon', 'assets/phaser3/clock-icon.png'); this.load.image('boingIcon', 'assets/phaser3/boing-icon.png'); this.load.image('starsWindow', 'assets/phaser3/stars-window.png'); this.load.image('sineWindow', 'assets/phaser3/sinewave-window.png'); this.load.image('eyesWindow', 'assets/phaser3/eyes-window.png'); this.load.image('jugglerWindow', 'assets/phaser3/juggler-window.png'); this.load.image('invadersWindow', 'assets/phaser3/invaders-window.png'); this.load.image('clockWindow', 'assets/phaser3/clock-window.png'); this.load.atlas('boing', 'assets/phaser3/boing.png', 'assets/phaser3/boing.json'); this.load.spritesheet('juggler', 'assets/phaser3/juggler.png', { frameWidth: 128, frameHeight: 184 }); this.load.image('star', 'assets/phaser3/star2.png'); this.load.image('eye', 'assets/phaser3/eye.png'); this.load.image('invaders.boom', 'assets/games/multi/boom.png'); this.load.spritesheet('invaders.bullet', 'assets/games/multi/bullet.png', { frameWidth: 12, frameHeight: 14 }); this.load.image('invaders.bullet2', 'assets/games/multi/bullet2.png'); this.load.image('invaders.explode', 'assets/games/multi/explode.png'); this.load.spritesheet('invaders.invader1', 'assets/games/multi/invader1.png', { frameWidth: 16, frameHeight: 16 }); this.load.spritesheet('invaders.invader2', 'assets/games/multi/invader2.png', { frameWidth: 22, frameHeight: 16 }); this.load.spritesheet('invaders.invader3', 'assets/games/multi/invader3.png', { frameWidth: 24, frameHeight: 16 }); this.load.image('invaders.mothership', 'assets/games/multi/mothership.png'); this.load.image('invaders.ship', 'assets/games/multi/ship.png'); } create () { // Create animations this.anims.create({ key: 'juggler', frames: this.anims.generateFrameNumbers('juggler'), frameRate: 28, repeat: -1 }); this.anims.create({ key: 'boing', frames: this.anims.generateFrameNames('boing', { prefix: 'boing', start: 1, end: 14 }), frameRate: 28, repeat: -1 }); this.anims.create({ key: 'bullet', frames: this.anims.generateFrameNumbers('invaders.bullet'), frameRate: 8, repeat: -1 }); this.anims.create({ key: 'invader1', frames: this.anims.generateFrameNumbers('invaders.invader1'), frameRate: 2, repeat: -1 }); this.anims.create({ key: 'invader2', frames: this.anims.generateFrameNumbers('invaders.invader2'), frameRate: 2, repeat: -1 }); this.anims.create({ key: 'invader3', frames: this.anims.generateFrameNumbers('invaders.invader3'), frameRate: 2, repeat: -1 }); this.workbench = this.add.graphics({ x: 16, y: 21 }); this.workbench.fillStyle(0xffffff); this.workbench.fillRect(0, 0, this.sys.game.config.width - 105, 20); this.workbenchTitle = this.add.image(16, 21, 'workbenchTitle').setOrigin(0); this.workbenchIcons = this.add.image(this.sys.game.config.width - 87, 21, 'workbenchIcons').setOrigin(0); const disk = this.add.image(16, 64, 'disk').setOrigin(0).setInteractive(); const demosWindow = this.add.image(0, 0, 'demosWindow').setOrigin(0); const eyesIcon = this.add.image(32, 34, 'eyesIcon', 0).setOrigin(0).setInteractive(); const jugglerIcon = this.add.image(48, 110, 'jugglerIcon', 0).setOrigin(0).setInteractive(); const starsIcon = this.add.image(230, 40, 'starsIcon', 0).setOrigin(0).setInteractive(); const invadersIcon = this.add.image(120, 34, 'invadersIcon', 0).setOrigin(0).setInteractive(); const clockIcon = this.add.image(240, 120, 'clockIcon', 0).setOrigin(0).setInteractive(); const boingIcon = this.add.image(146, 128, 'boingIcon', 0).setOrigin(0).setInteractive(); const demosContainer = this.add.container(32, 70, [ demosWindow, eyesIcon, jugglerIcon, starsIcon, invadersIcon, clockIcon, boingIcon ]); demosContainer.setVisible(false); demosContainer.setInteractive(new Phaser.Geom.Rectangle(0, 0, demosWindow.width, demosWindow.height), Phaser.Geom.Rectangle.Contains); this.input.setDraggable(demosContainer); demosContainer.on('drag', function (pointer, dragX, dragY) { this.x = dragX; this.y = dragY; }); disk.once('pointerup', function () { demosContainer.setVisible(true); }); eyesIcon.on('pointerup', function () { this.createWindow(Eyes); }, this); jugglerIcon.on('pointerup', function () { this.createWindow(Juggler); }, this); starsIcon.on('pointerup', function () { this.createWindow(Stars); }, this); invadersIcon.on('pointerup', function () { this.createWindow(Invaders); }, this); clockIcon.on('pointerup', function () { this.createWindow(Clock); }, this); boingIcon.on('pointerup', function () { this.createWindow(Boing); }, this); this.events.on('resize', this.resize, this); } createWindow (func) { const x = Phaser.Math.Between(400, 600); const y = Phaser.Math.Between(64, 128); const handle = 'window' + this.count++; const win = this.add.zone(x, y, func.WIDTH, func.HEIGHT).setInteractive().setOrigin(0); const demo = new func(handle, win); this.input.setDraggable(win); win.on('drag', function (pointer, dragX, dragY) { this.x = dragX; this.y = dragY; demo.refresh() }); this.scene.add(handle, demo, true); } resize (width, height) { if (width === undefined) { width = this.game.config.width; } if (height === undefined) { height = this.game.config.height; } this.cameras.resize(width, height); this.workbench.clear(); this.workbench.fillStyle(0xffffff); this.workbench.fillRect(0, 0, width - 105, 20); this.workbenchIcons.x = (width - 87); } }
class Eyes extends Phaser.Scene { constructor (handle, parent) { super(handle); this.parent = parent; this.left; this.right; this.leftTarget; this.rightTarget; this.leftBase; this.rightBase; this.mid = new Phaser.Math.Vector2(); } create () { const bg = this.add.image(0, 0, 'eyesWindow').setOrigin(0); this.cameras.main.setViewport(this.parent.x, this.parent.y, Eyes.WIDTH, Eyes.HEIGHT); this.left = this.add.image(46, 92, 'eye'); this.right = this.add.image(140, 92, 'eye'); this.leftTarget = new Phaser.Geom.Line(this.left.x, this.left.y, 0, 0); this.rightTarget = new Phaser.Geom.Line(this.right.x, this.right.y, 0, 0); this.leftBase = new Phaser.Geom.Ellipse(this.left.x, this.left.y, 24, 40); this.rightBase = new Phaser.Geom.Ellipse(this.right.x, this.right.y, 24, 40); } update () { this.leftTarget.x2 = this.input.activePointer.x - this.parent.x; this.leftTarget.y2 = this.input.activePointer.y - this.parent.y; // Within the left eye? if (this.leftBase.contains(this.leftTarget.x2, this.leftTarget.y2)) { this.mid.x = this.leftTarget.x2; this.mid.y = this.leftTarget.y2; } else { Phaser.Geom.Ellipse.CircumferencePoint(this.leftBase, Phaser.Geom.Line.Angle(this.leftTarget), this.mid); } this.left.x = this.mid.x; this.left.y = this.mid.y; this.rightTarget.x2 = this.input.activePointer.x - this.parent.x; this.rightTarget.y2 = this.input.activePointer.y - this.parent.y; // Within the right eye? if (this.rightBase.contains(this.rightTarget.x2, this.rightTarget.y2)) { this.mid.x = this.rightTarget.x2; this.mid.y = this.rightTarget.y2; } else { Phaser.Geom.Ellipse.CircumferencePoint(this.rightBase, Phaser.Geom.Line.Angle(this.rightTarget), this.mid); } this.right.x = this.mid.x; this.right.y = this.mid.y; } refresh () { this.cameras.main.setPosition(this.parent.x, this.parent.y); this.scene.bringToTop(); } } Eyes.WIDTH = 183; Eyes.HEIGHT = 162;