UNPKG

create-phaser-app

Version:

A boiler plate to start your phaser app with webpack4, babel7+ and Phaser 3

742 lines (706 loc) 22.8 kB
import machina from 'machina'; import sounds from '../../assets/sounds/processed'; import linearScale from '../../lib/linear-scale'; import AnimationSequencer from './animation-sequencer'; import animationList from './player-animation-list'; import playerJSON from './player.json'; import playerPNG from './player.png'; const shakeForceScale = linearScale([225, 900], [0, 0.03]); const shakeIntensityScale = linearScale([225, 900], [0, 0.03]); const shakeDurationScale = linearScale([225, 900], [0, 200]); class Directions extends machina.Fsm { constructor({ scene, entity, startDirection }) { const _aDelta = 35; const boosterOpts = { left: { x: 25, y: 10, angle: 90 - _aDelta }, right: { x: 0, y: 10, angle: 90 + _aDelta } }; const footBoosterOpts = { left: { x: 25, y: 40, angle: 0 }, right: { x: 0, y: 40, angle: 180 } }; const directionalFsm = { namespace: 'player-directions', initialState: startDirection || 'left', states: { left: { _onEnter: function() { this.handle('turn', { direction: 'left' }); this.emit('booster', boosterOpts.left); this.emit('footbooster', footBoosterOpts.left); } }, right: { _onEnter: function() { this.handle('turn', { direction: 'right' }); this.emit('booster', boosterOpts.right); this.emit('footbooster', footBoosterOpts.right); } }, left2right: { _onEnter: function() { this.handle('turn', { direction: 'left2right' }); } }, right2left: { _onEnter: function() { this.handle('turn', { direction: 'right2left' }); } } } }; super(directionalFsm); this.scene = scene; this.entity = entity; } } class Aims extends machina.Fsm { constructor({ scene, entity }) { const aimFsm = { namespace: 'player-aims', initialState: 'fwd', states: { up: { _onEnter: function() { this.handle('changeaim', { aim: 'up' }); } }, upfwd: { _onEnter: function() { this.handle('changeaim', { aim: 'upfwd' }); } }, fwd: { _onEnter: function() { this.handle('changeaim', { aim: 'fwd' }); } }, dwnfwd: { _onEnter: function() { this.handle('changeaim', { aim: 'dwnfwd' }); } }, dwn: { _onEnter: function() { this.handle('changeaim', { aim: 'dwn' }); } } } }; super(aimFsm); this.scene = scene; this.entity = entity; } } export default class Behaviors extends machina.Fsm { constructor({ scene, entity, startDirection }) { const directions = new Directions({ scene, entity, startDirection }); const aims = new Aims({ scene, entity }); const as = new AnimationSequencer({ scene, entity, animationList }); function getvulcanMuzzleSettings() { const direction = directions.state; const aim = aims.state; const settings = { left: { up: { x: 18, y: -20, angle: -90 }, upfwd: { x: -6, y: -1, angle: -150 }, fwd: { x: -15, y: 12, angle: 180 }, dwnfwd: { x: -6, y: 32, angle: 140 }, dwn: { x: 19, y: 40, angle: 90 } }, right: { up: { x: 18, y: -20, angle: -90 }, upfwd: { x: 40, y: 0, angle: -30 }, fwd: { x: 46, y: 12, angle: 0 }, dwnfwd: { x: 41, y: 33, angle: 40 }, dwn: { x: 12, y: 40, angle: 90 } } }; return settings[direction][aim]; } let _walkingSoundId = 0; let _shootingSoundId = 0; /*TODO: can I move these */ function startShootingSound() { stopShootingSound(); _shootingSoundId = sounds.play('Bullet'); sounds.loop(true, _shootingSoundId); sounds.rate(3, _shootingSoundId); sounds.volume(0.5, _shootingSoundId); } function stopShootingSound() { sounds.loop(false, _shootingSoundId); sounds.stop('Bullet'); } function startWalkingSound() { stopWalkingSound(); _walkingSoundId = sounds.play('Step'); sounds.loop(true, _walkingSoundId); sounds.rate(0.22, _walkingSoundId); sounds.volume(0.5, _walkingSoundId); } function stopWalkingSound() { sounds.loop(false, _walkingSoundId); sounds.stop('Step'); } const behaviorFsm = { namespace: 'player-behaviors', initialState: 'idling', states: { idling: { _child: directions, _onEnter: function() { entity.setVelocityX(0); stopWalkingSound(); stopShootingSound(); as.sequence(`${directions.state}-idle`); }, _onExit: function() {}, walk: function(data) { this.transition('walking'); }, crouch: function() { this.transition('crouchingDown'); }, jump: function(data) { this.transition('jumping'); }, shootMissiles: 'missilesLaunch', boost: function({ velocities }) { this.transition('sliding'); }, shoot: function(data) { //extend to tell WHICH thing is shooting this.transition('shooting'); } }, walking: { _child: directions, _onEnter: function() { as.sequence(`${directions.state}-walk`); startWalkingSound(); }, _onExit: function() { stopWalkingSound(); stopShootingSound(); }, idle: function(data) { stopWalkingSound(); stopShootingSound(); this.transition('idling'); }, walk: function(data) { const { velocities, direction } = data; let speed = velocities.walking; if (direction === 'left') { speed = -speed; } directions.transition(direction); entity.setVelocityX(speed); //console.log('walk called in walking', data); }, turn: function() { stopWalkingSound(); this.transition('turning'); }, crouch: function() { entity.setVelocityX(0); stopWalkingSound(); this.transition('crouchingDown'); }, jump: function(data) { stopWalkingSound(); this.transition('jumping'); }, unland: function() { stopWalkingSound(); this.transition('flying'); }, shootMissiles: 'missilesLaunch', boost: function({ velocities }) { stopWalkingSound(); this.transition('sliding'); }, shoot: function(data) { stopWalkingSound(); this.transition('walkshooting'); } }, turning: { _child: directions, _onEnter: function() { const { state } = directions; const turnDirection = state === 'right' ? 'left2right' : 'right2left'; directions.transition(turnDirection); const face = Math.round(Math.random()) ? 'front' : 'back'; const animation = `${directions.state}-walkturn-${face}`; stopWalkingSound(); as.sequence(animation).then(() => { const dir = turnDirection === 'left2right' ? 'right' : 'left'; directions.transition(dir); this.transition('walking'); }); }, walk: function(data) { const { velocities, direction } = data; let speed = velocities.turning; if (direction === 'left') { speed = -speed; } entity.setVelocityX(speed); }, shoot: function() {} }, crouchingDown: { _child: directions, _onEnter: function() { as.sequence(`${directions.state}-crouch-up2dwn`).then(() => { this.transition('crouching'); }); } }, crouchingUp: { _child: directions, _onEnter: function() { as.sequence(`${directions.state}-crouch-dwn2up`).then(() => { this.transition('idling'); }); } }, crouching: { _child: directions, _onEnter: function() { as.sequence(`${directions.state}-crouch`); }, idle: function() { this.transition('crouchingUp'); }, walk: function(data) { if (data.direction !== directions.state) { directions.transition(data.direction); this.transition('turning'); } }, uncrouch: function() { this.transition('crouchingUp'); }, jump: function(data) { this.transition('jumpPrepping'); } }, jumpPrepping: { _child: directions, _onEnter: function() { as.sequence(`${directions.state}-crouchjumpprep`) .then(() => as.sequence(`${directions.state}-crouchjump`)) .then(() => { this.transition('highJumping'); }); }, jump: function(data) { const { velocities, onFloor } = data; } }, highJumping: { _child: directions, _onEnter: function() { let _id = sounds.play('Boop'); sounds.volume(0.6, _id); as.sequence(`${directions.state}-aerial`).then(() => { let _id = sounds.play('SmallJump_1'); sounds.volume(0.3, _id); return this.transition('flying'); }); }, idle: function() { this.transition('idling'); }, jump: function(data) { const { velocities, onFloor } = data; if (onFloor) { entity.setVelocityY(-velocities.highjump); } } }, jumping: { _child: directions, _onEnter: function() { let _id = sounds.play('SmallJump'); sounds.volume(0.6, _id); as.sequence(`${directions.state}-aerial`).then(() => this.transition('flying') ); }, idle: function() { this.transition('idling'); }, jump: function(data) { const { velocities, onFloor } = data; if (onFloor) { entity.setVelocityY(-velocities.jump); } } }, //TODO: make this like a cannonball sort of thing launching: { _child: directions, _onEnter: function() { let { launchHalt, launchPowerX, launchPowerY } = entity.velocities; if (directions.state === 'left') { launchPowerX = -launchPowerX; launchHalt = -launchHalt; } //console.log('1'); entity.setVelocityX(launchHalt); this.emit('booster', { on: true }); as.sequence(`${directions.state}-crouchjumpprep`) .then(() => as.sequence(`${directions.state}-crouchjump`)) .then(() => { entity.setVelocityX(launchPowerX); if (entity.body.onFloor()) { this.emit('booster', { on: true }); entity.setVelocityY(-launchPowerY); this.transition('launched'); } else { this.transition('launched'); } }); } }, launched: { _child: directions, land: function() { this.transition('launchlanding'); } }, flying: { _child: directions, _onEnter: function() { as.sequence(`${directions.state}-aerial`); }, land: function(data) { let { velocities, shakes } = entity; let speed = velocities.landing; let _velX = entity.body.velocity.x; if (directions.state === 'left') { speed = -speed; speed = _velX > speed ? _velX : speed; } else { speed = _velX < speed ? _velX : speed; } if (data.fallForce) { let shakeForce = shakeForceScale(data.fallForce); let shakeIntensity = shakeIntensityScale(data.fallForce); let shakeDuration = shakeDurationScale(data.fallForce); //console.log(data.fallForce, shakeForce) entity.scene.cameras.main.shake( shakeDuration, shakeIntensity, shakeForce ); } entity.setVelocityX(speed); this.emit('booster', { on: false }); this.transition('landing'); }, veer: function(data) { const { velocities, direction } = data; let speed = velocities.flying; if (direction === 'left') { speed = -speed; } directions.transition(direction); entity.setVelocityX(speed); }, turn: function(data) { this.transition('flyTurning'); }, boost: function(data) { entity.setVelocityY(-data.velocities.aerialBoosting); this.emit('booster', { on: true }); }, unboost: function() { this.emit('booster', { on: false }); } }, flyTurning: { _child: directions, _onEnter: function() { const { state } = directions; const turnDirection = state === 'right' ? 'left2right' : 'right2left'; directions.transition(turnDirection); const animation = `${directions.state}-aerial`; as.sequence(animation).then(() => { const dir = turnDirection === 'left2right' ? 'right' : 'left'; directions.transition(dir); this.transition('flying'); }); } }, landing: { _child: directions, _onEnter: function() { let _id = sounds.play('Land'); sounds.volume(0.7, _id); as.sequence(`${directions.state}-crouch-up2dwn`) .then(() => as.sequence(`${directions.state}-crouch-dwn2up`)) .then(() => { this.transition('idling'); }); } }, launchlanding: { _child: directions, _onEnter: function() { let { velocities, shakes } = entity; let speed = velocities.launchlanding; let _velX = entity.body.velocity.x; let _velY = entity.body.velocity.y; let shakeThreshold = velocities.launchlanding; let doShake = false; if (directions.state === 'left') { speed = -speed; doShake = _velX < speed; speed = _velX > speed ? _velX : speed; } else { doShake = _velX > speed; speed = _velX < speed ? _velX : speed; } if (doShake) { entity.scene.cameras.main.shake(shakes.launchLand, 0.02, 0.02); } entity.setVelocityX(speed); this.emit('booster', { on: false }); let _id = sounds.play('Land'); sounds.volume(0.5, _id); as.sequence(`${directions.state}-crouch-up2dwn`) .then(() => as.sequence(`${directions.state}-crouch-dwn2up`)) .then(() => { this.transition('idling'); }); } }, missilesLaunch: { _onEnter: function() { entity.setVelocityX(0); as.sequence(`${directions.state}-firemissile`).then(() => this.transition('idling') ); } }, sliding: { _onEnter: function() { this.emit('footbooster', { on: true }); let direction = directions.state; let { sliding, slideBursting } = entity.velocities; if (direction === 'left') { sliding = -sliding; slideBursting = -slideBursting; } entity.setVelocityX(slideBursting); stopWalkingSound(); stopShootingSound(); sounds.volume(0.4, sounds.play('Scree')); as.sequence(`${directions.state}-slide-stand2slide`).then(() => { entity.setVelocityX(sliding); this.emit('footbooster', { on: false }); this.timer = setTimeout( function() { this.handle('unboost'); }.bind(this), entity.timings.slideDuration ); }); }, unboost: function() { entity.setVelocityX(0); this.transition('slidend'); }, jump: function() { this.transition('launching'); } }, slidend: { _onEnter: function() { as.sequence(`${directions.state}-slide-slide2stand`).then(() => { this.transition('idling'); }); } }, aiming: { _child: directions, turn: function() { this.transition('shootturning'); }, shoot: function() { const muzzleSettings = getvulcanMuzzleSettings(); this.emit('vulcanmuzzle', { on: true, ...muzzleSettings }); this.transition('shooting'); }, idle: 'idling', unshoot: function() { this.emit('vulcanmuzzle', { on: false }); } }, shootturning: { _child: directions, _onEnter: function() { this.emit('vulcanmuzzle', { on: false }); const { state } = directions; const turnDirection = state === 'right' ? 'left2right' : 'right2left'; directions.transition(turnDirection); const face = Math.round(Math.random()) ? 'front' : 'back'; const animation = `${directions.state}-walkturn-${face}`; as.sequence(animation).then(() => { const dir = turnDirection === 'left2right' ? 'right' : 'left'; directions.transition(dir); this.transition('shooting'); }); } }, shooting: { _child: aims, _onEnter: function() { this.emit('vulcanmuzzle', { on: true, ...getvulcanMuzzleSettings() }); as.sequence(`${directions.state}-firecannon-${aims.state}`).then( () => {} ); startShootingSound(); }, _onExit: function() { this.emit('vulcanmuzzle', { on: false }); }, aim: function({ aim, direction }) { aims.transition(aim); if (direction) { directions.transition(direction); } }, changeaim: function() { stopShootingSound(); this.transition('aiming'); }, idle: function() { this.emit('vulcanmuzzle', { on: false }); stopShootingSound(); this.transition('idling'); }, jump: function() { stopShootingSound(); this.transition('jumping'); }, unshoot: function() { this.emit('vulcanmuzzle', { on: false }); stopShootingSound(); this.transition('idling'); } }, walkaiming: { _child: directions, turn: function() { this.transition('walkshootturning'); }, shoot: function() { const muzzleSettings = getvulcanMuzzleSettings(); this.emit('vulcanmuzzle', { on: true, ...muzzleSettings }); this.transition('walkshooting'); }, idle: 'idling' }, walkshootturning: { _child: directions, _onEnter: function() { const { state } = directions; const turnDirection = state === 'right' ? 'left2right' : 'right2left'; directions.transition(turnDirection); const face = Math.round(Math.random()) ? 'front' : 'back'; const animation = `${directions.state}-walkturn-${face}`; as.sequence(animation).then(() => { const dir = turnDirection === 'left2right' ? 'right' : 'left'; directions.transition(dir); this.transition('walkshooting'); }); } }, walkshooting: { _child: aims, _onEnter: function() { this.emit('vulcanmuzzle', { on: true, ...getvulcanMuzzleSettings() }); startWalkingSound(); startShootingSound(); as.sequence(`${directions.state}-firecannonwalk-${aims.state}`); }, _onExit() { stopShootingSound(); stopWalkingSound(); this.emit('vulcanmuzzle', { on: false }); }, aim: function({ aim, direction, velocities }) { aims.transition(aim); if (direction) { directions.transition(direction); let speed = velocities.walking; if (direction === 'left') { speed = -speed; } directions.transition(direction); entity.setVelocityX(speed); } }, changeaim: function() { this.transition('walkaiming'); }, idle: 'idling', jump: 'jumping', unshoot: 'walking' } } }; super(behaviorFsm); this.scene = scene; this.entity = entity; } static preload(scene) { scene.load.atlas({ key: 'player-atlas', textureURL: playerPNG, atlasURL: playerJSON }); } }