Last active
August 6, 2018 20:14
-
-
Save rmartone/01e63fd36aa825bb08f85872b5493a56 to your computer and use it in GitHub Desktop.
Excerpt from "Building Multiplayer Board Games with Phaser"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { guid } from '../shared/stringutils'; | |
import { READONLY_ERR_MSG } from './constants'; | |
/** | |
* Components add specific behaviors to their GameObjects through composition. | |
* Components typically span diverse domains from AI and rendering to physics. | |
* This provides a means for them to coexist within a single entity with | |
* minimal coupling. | |
* | |
* @see GameObject | |
* @link http://gameprogrammingpatterns.com/component.html | |
*/ | |
export class Component { | |
/** | |
* @param json Component settings as JSON | |
*/ | |
constructor(json) { | |
this._container = null; | |
this._name = json.name || guid(); | |
} | |
/** | |
* @returns {Container} typically its GameObject | |
*/ | |
get container() { | |
return this._container; | |
} | |
/** | |
* throw Error on attempt to set read-only prop | |
* @throws Error | |
*/ | |
set container(value) { | |
throw Error(READONLY_ERR_MSG); | |
} | |
/** | |
* @returns {string} name for component | |
*/ | |
get name() { | |
return this._name; | |
} | |
/** | |
* throw Error on attempt to set read-only prop | |
* @throws Error | |
*/ | |
set name(value) { | |
throw Error(READONLY_ERR_MSG); | |
} | |
/** | |
* Registers a component with its container | |
* @param container typically a GameObject or another component | |
* @returns {this} | |
*/ | |
register(container) { | |
this._container = container; | |
this.onAdd(); | |
return this; | |
} | |
/** | |
* Unregister the component from its Container | |
* @returns {this} | |
*/ | |
unregister() { | |
this.onRemove(); | |
// avoid circular reference | |
this._container = null; | |
return this; | |
} | |
/** | |
* Called when component is added to a Container. Override to add | |
* component specific initialization like event registration. | |
*/ | |
onAdd() {} | |
/** | |
* Called when the component is removed from a Container. Override to | |
* perform component specific cleanup like removing event listeners. | |
*/ | |
onRemove() {} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Category, logError, logInfo } from '../shared/log'; | |
import { Client } from './client'; | |
/** | |
* Adds a batch of assets to the loader's queue | |
* @param assets is a JSON object with one or more keyed assets | |
* in the form {type: string, url?: string ...} | |
*/ | |
export function loadAssets(assets) { | |
for (let key in assets) { | |
queueAsset(key, assets[key]); | |
} | |
} | |
/** | |
* adds an Asset to the loader's queue | |
* @param key cache key | |
* @param asset JSON | |
*/ | |
function queueAsset(key, asset) { | |
const loader = Client.phaser.load; | |
loader.crossOrigin = 'anonymous'; | |
// register loader listeners, if not present | |
if (!loader.onFileComplete.has(fileComplete)) { | |
loader.onFileComplete.add(fileComplete); | |
} | |
if (!loader.onFileError.has(fileError)) { | |
loader.onFileError.add(fileError); | |
} | |
switch (asset.type) { | |
case assetType.audio: | |
loader.audio(key, resolveAll(asset.urls), true); | |
break; | |
case assetType.audioSprite: | |
loader.audiosprite(key, resolveAll(asset.urls), undefined, { spritemap: asset.spritemap }, true); | |
break; | |
case assetType.image: | |
loader.image(key, asset.url); | |
break; | |
case assetType.textureAtlas: | |
loader.atlasJSONHash(key, asset.url, resolve(asset.atlas)); | |
break; | |
case assetType.textureAtlas: | |
loader.json(key, asset.url); | |
break; | |
default: | |
throw Error(`undefined asset type ${asset.type} for ${key}`); | |
} | |
} | |
/** | |
* Fully qualifies an array of URLs | |
* @param urls array of potentially relative urls | |
* @return urls new array of urls that are fully qualified | |
*/ | |
function resolveAll(urls) { | |
// careful not to mutate arg | |
const result = urls.slice(); | |
for (let i = 0; i < result.length; ++i) { | |
result[i] = resolve(result[i]); | |
} | |
return result; | |
} | |
/** | |
* Qualifies an asset's URL if it's relative | |
* @param url | |
* @returns fully qualified url to an asset | |
*/ | |
function resolve(url) { | |
// if relative url prepend root | |
if (url !== '/' && !/^https?:\/\//.test(url)) { | |
// combine s3 bucket name w/ asset's relative url | |
return `${Client.bucket}${url}`; | |
} | |
return url; | |
} | |
/** | |
* Event is dispatched when a file completes loading successfully | |
* @param progress percent complete | |
* @param key asset's cache key | |
*/ | |
function fileComplete(progress, key) { | |
logInfo(Category.Loader, `loaded asset for key: "${key}"`); | |
} | |
/** | |
* Event dispatched when a file errors as a result of the load request | |
* @param key asset's cache key | |
*/ | |
function fileError(key) { | |
logError(Category.Loader, `file error loading asset for key: "${key}"`); | |
} | |
const assetType = { | |
audio: 'Audio', | |
audioSprite: 'AudioSprite', | |
image: 'Image', | |
textureAtlas: 'TextureAtlas', | |
json: 'JSON', | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { classNameForInstance, classNameFromType } from '../shared/classutils'; | |
import { Category, logInfo } from '../shared/log'; | |
import { READONLY_ERR_MSG } from './constants'; | |
import { Client } from './client'; | |
import { GameObject } from './gameobject'; | |
import { loadAssets } from './loader'; | |
/** | |
* Screen class extends Phaser.State and provides screen | |
* wrangling by factoring common tasks. | |
*/ | |
export class Screen extends Phaser.State { | |
constructor() { | |
super(); | |
// declare props upfront | |
this._gameObject = null; | |
// subclass name is used to lookup a screen's assets | |
this._name = classNameForInstance(this); | |
} | |
/** | |
* a screen's root GameObject | |
* @returns {GameObject} | |
*/ | |
get gameObject() { | |
return this._gameObject; | |
} | |
/** | |
* throw Error on attempt to set read-only prop | |
* @throws Error | |
*/ | |
set gameObject(value) { | |
throw Error(READONLY_ERR_MSG); | |
} | |
/** | |
* ensures the state is registered using its class name | |
* e.g. MyState.register(); | |
*/ | |
static register() { | |
Client.phaser.state.add(classNameFromType(this), this); | |
} | |
/** | |
* starts the state for this class i.e. preload, create sequence | |
*/ | |
static start() { | |
// starts the state using name of subclass registered above | |
Client.phaser.state.start(classNameFromType(this)); | |
} | |
/** | |
* called once preload has completed | |
* typically where you'd setup a screen | |
*/ | |
create() { | |
// get the screen's children from its JSON | |
const json = Client.screen[this._name]; | |
// create the root gameObject | |
this._gameObject = new GameObject(json); | |
// attach the gameObject | |
Client.phaser.world.add(this._gameObject); | |
logInfo(Category.System, `cache size ${GameObject.cacheSize}`); | |
return this; | |
} | |
/** | |
* Loads assets required by the preloader | |
*/ | |
preload() { | |
// preload assets keyed to this state | |
loadAssets(Client.assets[this._name]); | |
} | |
/** | |
* called when the Screen is shutdown (i.e. you switched to another screen). | |
*/ | |
shutdown() { | |
if (this._gameObject) { | |
this._gameObject.destroy(); | |
// explicitly clear since Phaser keeps States around | |
this._gameObject = null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment