diff --git a/src/classes/Ship.ts b/src/classes/Ship.ts index 367f518..12dfa9f 100644 --- a/src/classes/Ship.ts +++ b/src/classes/Ship.ts @@ -1,16 +1,19 @@ import Phaser from 'phaser' import Bullets from './Bullets' +import Thruster from './Thruster' export default class Ship extends Phaser.Physics.Arcade.Sprite { readonly acceleration = 5 readonly dragForce = 0.6 + readonly maxSpeed = 300 readonly colliderRadiusRatio = 0.43 readonly wrapMargin = 10 readonly fireRate = 5 //shoots/s - bullets?: Bullets + bullets: Bullets + thruster: Thruster constructor(scene: Phaser.Scene) { super( @@ -32,6 +35,8 @@ export default class Ship extends Phaser.Physics.Arcade.Sprite { this.body.setCircle(this.width * this.colliderRadiusRatio) this.bullets = new Bullets(scene, this.fireRate) + this.thruster = new Thruster(scene, this) + this.setMaxVelocity(this.maxSpeed) } preUpdate(time: number, delta: number) { @@ -59,5 +64,6 @@ export default class Ship extends Phaser.Physics.Arcade.Sprite { this.body.velocity.add(vec) this.scene.physics.world.wrap(this, this.wrapMargin) + this.thruster.update(time, delta) } } diff --git a/src/classes/Thruster.ts b/src/classes/Thruster.ts new file mode 100644 index 0000000..4be2651 --- /dev/null +++ b/src/classes/Thruster.ts @@ -0,0 +1,59 @@ +import Phaser from 'phaser' +import Utils from './Utils' + +export default class Thruster { + readonly angleSpan = 40 + readonly frequency = 100 + readonly speed = 100 + readonly framesIndex = 30 + + emitter: Phaser.GameObjects.Particles.ParticleEmitter + parent: Phaser.Physics.Arcade.Sprite + + constructor(scene: Phaser.Scene, parent: Phaser.Physics.Arcade.Sprite) { + this.emitter = scene.add.particles('particles') + .createEmitter({ + frame: [25, 26, 27, 28, 29, 30, 31, 32, 34, 35], + speed: this.speed, + frequency: this.frequency, + scale: { start: 0.2, end: 0 }, + blendMode: 'ADD', + follow: parent + }) + + this.parent = parent + } + + update(time: number, delta: number) { + const thrustDirection = Phaser.Math.RadToDeg( + this.parent.body.velocity.clone().negate().angle() + ) + + this.emitter.angle.start = thrustDirection - this.angleSpan / 2 + this.emitter.angle.end = thrustDirection + this.angleSpan / 2 + + const thrustPower = this.getThrustPower() + + this.emitter.setFrequency(thrustPower.frequency) + this.emitter.setAlpha(thrustPower.opacity) + } + + getThrustPower() { + const velocityRange = [0, 320] as const + const frequencyRange = [300, 0] as const + const opacityRange = [0, 1] as const + + return { + frequency: Utils.clampMap( + this.parent.body.velocity.length(), + ...velocityRange, + ...frequencyRange + ), + opacity: Utils.clampMap( + this.parent.body.velocity.length(), + ...velocityRange, + ...opacityRange + ) + } + } +} diff --git a/src/classes/Utils.ts b/src/classes/Utils.ts new file mode 100644 index 0000000..333434c --- /dev/null +++ b/src/classes/Utils.ts @@ -0,0 +1,49 @@ +export default { + map(value: number, + sourceMin: number, + sourceMax: number, + targetMin: number, + targetMax: number) { + + const sourceRange = sourceMax - sourceMin + const targetRange = targetMax - targetMin + return (value - sourceMin) / sourceRange * targetRange + targetMin + }, + + clamp(value: number, + min: number, + max: number) { + let leftLimit = Math.min + let rightLimit = Math.max + + if (max < min) { + leftLimit = Math.max + rightLimit = Math.max + } + + return leftLimit( + rightLimit(min, value), + max) + }, + + clampMap(value: number, + sourceMin: number, + sourceMax: number, + targetMin: number, + targetMax: number) { + + const v = this.map(value, + sourceMin, + sourceMax, + targetMin, + targetMax + ) + + const min = Math.min(targetMin, targetMax) + const max = Math.max(targetMin, targetMax) + + return this.clamp( + v, min, max + ) + } +} diff --git a/src/scenes/DefaultScene.ts b/src/scenes/DefaultScene.ts index 052800e..2f1c337 100644 --- a/src/scenes/DefaultScene.ts +++ b/src/scenes/DefaultScene.ts @@ -19,22 +19,7 @@ export default class DefaultScene extends Phaser.Scene { create() { this.add.image(400, 300, 'sky') - const particles = this.add.particles('particles', 21) - - const emitter = particles.createEmitter({ - speed: 300, - scale: { start: 1, end: 0 }, - blendMode: 'ADD', - }) - - const logo = this.physics.add.image(400, 100, 'logo') - - logo.setVelocity(100, 200) - logo.setBounce(1, 1) - logo.setCollideWorldBounds(true) - - emitter.startFollow(logo) - + this.player = new Ship(this) } }