reldens
Version:
Reldens - MMORPG Platform
604 lines (560 loc) • 22.7 kB
JavaScript
/**
*
* Reldens - ScenePreloader
*
*/
const { Scene, Geom } = require('phaser');
const { MinimapUi } = require('./minimap-ui');
const { InstructionsUi } = require('./instructions-ui');
const { SettingsUi } = require('./settings-ui');
const { Joystick } = require('./joystick');
const { GameConst } = require('../constants');
const { ActionsConst } = require('../../actions/constants');
const { Logger, sc } = require('@reldens/utils');
class ScenePreloader extends Scene
{
constructor(props)
{
super({key: props.name});
this.relatedSceneKey = props.name.replace(GameConst.SCENE_PRELOADER, '');
this.progressBar = null;
this.progressCompleteRect = null;
this.progressRect = null;
this.userInterfaces = {};
this.preloadMapKey = props.map;
this.preloadImages = props.images;
this.uiScene = props.uiScene;
this.elementsUi = {};
this.gameManager = props.gameManager;
this.eventsManager = props.gameManager.events;
this.preloadAssets = props.preloadAssets || {};
this.directionalAnimations = {};
this.objectsAnimations = {};
if(!this.gameManager.createdAnimations){
this.gameManager.createdAnimations = {};
}
let currentScene = this.gameManager.activeRoomEvents.getActiveScene();
currentScene.objectsAnimationsData = props.objectsAnimationsData;
this.playerSpriteSize = {
frameWidth: this.gameManager.config.get('client/players/size/width', 52),
frameHeight: this.gameManager.config.get('client/players/size/height', 71)
};
this.useJoystick = this.gameManager.config.getWithoutLogs('client/ui/controls/useJoystick', false);
this.joystick = new Joystick({scenePreloader: this});
}
preload()
{
// @NOTE: this event run ONLY ONE TIME for each scene.
let eventUiScene = this.uiScene ? this : this.gameManager.gameEngine.uiScene;
this.eventsManager.emitSync('reldens.beforePreload', this, eventUiScene);
this.preloadUiScene();
this.preloadMapJson();
// @TODO - BETA - CHECK - Test a multiple tiles images case.
this.preloadMapImages();
this.preloadValidAssets();
this.preloadPlayerDefaultSprite();
this.preloadArrowPointer();
// @TODO - BETA - Move everything related to player stats into the users pack or create a new pack.
this.load.image(
GameConst.ICON_STATS,
this.gameManager.config.get('client/general/assets/statsIconPath', '/assets/icons/book.png')
);
this.load.on('fileprogress', this.onFileProgress, this);
this.load.on('progress', this.onLoadProgress, this);
this.load.on('complete', this.onLoadComplete, this);
this.configuredFrameRate = this.gameManager.config.get('client/general/animations/frameRate', 10);
this.showLoadingProgressBar();
}
preloadMapJson()
{
if(!this.preloadMapKey){
return;
}
// @TODO - BETA - Refactor to pass the map_filename from the server as a parameter.
this.load.tilemapTiledJSON(this.preloadMapKey, '/assets/maps/'+this.preloadMapKey+'.json');
}
preloadArrowPointer()
{
if(!this.gameManager.config.get('client/ui/pointer/show')){
return;
}
let pointerData = {
frameWidth: this.gameManager.config.getWithoutLogs('client/general/assets/arrowDownFrameWidth', 32),
frameHeight: this.gameManager.config.getWithoutLogs('client/general/assets/arrowDownFrameHeight', 32)
};
this.load.spritesheet(
GameConst.ARROW_DOWN,
this.gameManager.config.get('client/general/assets/arrowDownPath', '/assets/sprites/arrow-down.png'),
pointerData
);
}
preloadUiScene()
{
if(!this.uiScene){
return;
}
// @NOTE: the events here run only once over all the game progress.
this.eventsManager.emitSync('reldens.beforePreloadUiScene', this);
if(this.gameManager.config.get('client/ui/playerBox/enabled')){
this.load.html('playerBox', '/assets/html/ui-player-box.html');
}
if(this.gameManager.config.get('client/ui/controls/enabled')){
this.load.html('controls', '/assets/html/ui-controls.html');
}
if(this.useJoystick){
this.load.html('joystick', '/assets/html/ui-joystick.html');
}
if(this.gameManager.config.get('client/ui/sceneLabel/enabled')){
this.load.html('sceneLabel', '/assets/html/ui-scene-label.html');
}
if(this.gameManager.config.get('client/ui/instructions/enabled')){
this.load.html('instructions', '/assets/html/ui-instructions.html');
}
if(this.gameManager.config.get('client/ui/minimap/enabled')){
this.load.html('minimap', '/assets/html/ui-minimap.html');
}
if(this.gameManager.config.get('client/ui/settings/enabled')){
this.load.html('settings', '/assets/html/ui-settings.html');
this.load.html('settings-content', '/assets/html/ui-settings-content.html');
}
if(this.gameManager.config.getWithoutLogs('client/ui/preloadTarget/enabled', true)){
this.load.html('uiTarget', '/assets/html/ui-target.html');
}
if(this.gameManager.config.getWithoutLogs('client/ui/preloadOptionsTemplates/enabled', true)){
this.load.html('uiOptionButton', '/assets/html/ui-option-button.html');
this.load.html('uiOptionIcon', '/assets/html/ui-option-icon.html');
this.load.html('uiOptionsContainer', '/assets/html/ui-options-container.html');
}
if(this.gameManager.config.getWithoutLogs('client/ui/preloadLoading/enabled', true)){
this.load.html('uiLoading', '/assets/html/ui-loading.html');
}
this.eventsManager.emitSync('reldens.preloadUiScene', this);
}
preloadMapImages()
{
if(!this.preloadImages){
return;
}
for(let imageFile of this.preloadImages){
this.load.image(imageFile, `/assets/maps/${imageFile}`);
//Logger.debug('Preload map image: "'+imageFile+'".');
}
}
preloadValidAssets()
{
if(!sc.isObject(this.preloadAssets)){
Logger.info('None assets available for preload.');
return;
}
// @TODO - BETA - Remove the hardcoded file extensions.
let preloadAssetsKeys = Object.keys(this.preloadAssets);
for(let i of preloadAssetsKeys){
let asset = this.preloadAssets[i];
if('spritesheet' !== asset.asset_type){
continue;
}
let assetParams = sc.toJson(asset.extra_params);
if(!assetParams){
Logger.error('Missing spritesheet params.', asset);
continue;
}
this.load.spritesheet(asset.asset_key, `/assets/custom/sprites/${asset.asset_file}`, assetParams);
}
}
create()
{
// @NOTE: this event run once for each scene.
let eventUiScene = this.uiScene ? this : this.gameManager.gameEngine.uiScene;
this.eventsManager.emitSync('reldens.createPreload', this, eventUiScene);
if(this.uiScene){
this.createUiScene();
}
this.createPlayerAnimations(sc.get(this.gameManager.playerData, 'avatarKey', GameConst.IMAGE_PLAYER));
this.createArrowAnimation();
}
createUiScene()
{
// @NOTE: the events here run only once over all the game progress.
this.eventsManager.emitSync('reldens.beforeCreateUiScene', this);
// @TODO - BETA - Replace all different DOM references and standardize with the game engine driver.
this.createPlayerBox();
this.createTargetUi();
this.createSceneLabelBox();
this.createControlsBox();
this.createInstructionsBox();
this.createMiniMap();
this.createSettingsUi();
this.eventsManager.emitSync('reldens.createUiScene', this);
}
createSettingsUi()
{
let settingsConfig = this.getUiConfig('settings');
if(!settingsConfig.enabled){
return;
}
this.settingsUi = new SettingsUi();
this.settingsUi.createSettings(settingsConfig, this);
}
createMiniMap()
{
let minimapConfig = this.getUiConfig('minimap');
if(!minimapConfig.enabled){
return;
}
this.minimapUi = new MinimapUi();
this.minimapUi.createMinimap(minimapConfig, this);
}
createInstructionsBox()
{
let instConfig = this.getUiConfig('instructions');
if(!instConfig.enabled){
return;
}
this.instructionsUi = new InstructionsUi();
this.instructionsUi.createInstructions(instConfig, this);
}
createControlsBox()
{
let controlsUi = this.getUiConfig('controls');
if(!controlsUi.enabled){
return;
}
if(this.useJoystick){
this.elementsUi['controls'] = this.createUi('joystick', controlsUi);
return this.joystick.registerJoystickController();
}
this.elementsUi['controls'] = this.createUi('controls', controlsUi);
return this.registerControllers(this.elementsUi['controls']);
}
createUi(key, uiConfig)
{
return this.createContent(key, uiConfig.uiX, uiConfig.uiY);
}
createContent(key, x, y)
{
return this.add.dom(x, y).createFromCache(key);
}
createSceneLabelBox()
{
let sceneLabelUi = this.getUiConfig('sceneLabel');
if(!sceneLabelUi.enabled){
return;
}
this.elementsUi['sceneLabel'] = this.createUi('sceneLabel', sceneLabelUi);
}
createTargetUi()
{
let targetUi = this.getUiConfig('uiTarget');
if(!targetUi.enabled){
return;
}
this.uiTarget = this.createUi('uiTarget', targetUi);
let closeButton = this.uiTarget.getChildByProperty('className', 'close-target');
closeButton.addEventListener('click', () => {
this.gameManager.gameEngine.clearTarget();
});
}
createPlayerBox()
{
let playerBox = this.getUiConfig('playerBox');
if(!playerBox.enabled){
return;
}
this.elementsUi['playerBox'] = this.createUi('playerBox', playerBox);
let logoutButton = this.elementsUi['playerBox'].getChildByProperty('id', 'logout');
logoutButton?.addEventListener('click', () => {
this.gameManager.forcedDisconnection = true;
// @TODO - BETA - Move this into an event on the firebase plugin.
if(this.gameManager.firebase.isActive){
this.gameManager.firebase.app.auth().signOut();
}
this.gameManager.gameDom.getWindow().location.reload();
});
}
getUiConfig(uiName, newWidth, newHeight)
{
let {uiX, uiY} = this.getUiPosition(uiName, newWidth, newHeight);
return {enabled: this.gameManager.config.getWithoutLogs('client/ui/'+uiName+'/enabled'), uiX, uiY}
}
getUiPosition(uiName, newWidth, newHeight)
{
if('' === uiName){
uiName = 'default';
}
let uiConfig = this.gameManager.config.getWithoutLogs('client/ui/'+uiName, {});
let uiX = sc.get(uiConfig, 'x', 0);
let uiY = sc.get(uiConfig, 'y', 0);
if(this.gameManager.config.get('client/ui/screen/responsive')){
let rX = sc.get(uiConfig, 'responsiveX', false);
let rY = sc.get(uiConfig, 'responsiveY', false);
let gameContainer = this.gameManager.gameDom.getElement(GameConst.SELECTORS.GAME_CONTAINER);
if(!newWidth){
newWidth = gameContainer.offsetWidth;
}
if(!newHeight){
newHeight = gameContainer.offsetHeight;
}
uiX = false !== rX ? rX * newWidth / 100 : 0;
uiY = false !== rY ? rY * newHeight / 100 : 0;
}
return {uiX, uiY};
}
preloadPlayerDefaultSprite()
{
let fallbackImage = this.gameManager.config.get('client/players/animations/fallbackImage', 'player-base.png');
this.load.spritesheet(GameConst.IMAGE_PLAYER, '/assets/custom/sprites/'+fallbackImage, this.playerSpriteSize);
}
createPlayerAnimations(avatarKey)
{
let avatarFrames = this.gameManager.config.getWithoutLogs(
'client/players/animations/'+avatarKey+'Frames',
this.gameManager.config.get('client/players/animations/defaultFrames')
);
let availableAnimations = [{
k: avatarKey + '_' + GameConst.LEFT,
img: avatarKey,
start: avatarFrames.left.start || 3,
end: avatarFrames.left.end || 5,
repeat: -1,
hide: false
}, {
k: avatarKey + '_' + GameConst.RIGHT,
img: avatarKey,
start: avatarFrames.right.start || 6,
end: avatarFrames.right.end || 8,
repeat: -1,
hide: false
}, {
k: avatarKey + '_' + GameConst.UP,
img: avatarKey,
start: avatarFrames.up.start || 9,
end: avatarFrames.up.end || 11,
repeat: -1,
hide: false
}, {
k: avatarKey + '_' + GameConst.DOWN,
img: avatarKey,
start: avatarFrames.down.start || 0,
end: avatarFrames.down.end || 2,
repeat: -1,
hide: false
}
];
for(let anim of availableAnimations){
this.createAnimationWith(anim);
}
this.eventsManager.emitSync('reldens.createPlayerAnimations', this, avatarKey);
}
createArrowAnimation()
{
if(!this.gameManager.config.get('client/ui/pointer/show')){
return;
}
let arrowAnim = {
k: GameConst.ARROW_DOWN,
img: GameConst.ARROW_DOWN, // this is the loaded image key
start: 0,
end: 2,
repeat: 3,
rate: 6
};
this.createAnimationWith(arrowAnim);
}
createAnimationWith(anim)
{
if(this.gameManager.createdAnimations[anim.k]){
return;
}
let animationConfig = {
key: anim.k,
frames: this.anims.generateFrameNumbers(anim.img, {start: anim.start, end: anim.end}),
frameRate: sc.get(anim, 'frameRate', this.configuredFrameRate),
repeat: anim.repeat,
hideOnComplete: sc.get(anim, 'hide', true),
};
//Logger.debug('Creating animation: '+anim.k, animationConfig);
this.gameManager.createdAnimations[anim.k] = this.anims.create(animationConfig);
return this.gameManager.createdAnimations[anim.k];
}
registerControllers(controllersBox)
{
// @TODO - BETA - Controllers will be part of the configuration in the database.
this.setupDirButtonInBox(GameConst.UP, controllersBox);
this.setupDirButtonInBox(GameConst.DOWN, controllersBox);
this.setupDirButtonInBox(GameConst.LEFT, controllersBox);
this.setupDirButtonInBox(GameConst.RIGHT, controllersBox);
this.setupDefaultActionKey(controllersBox);
}
setupDefaultActionKey(controllersBox)
{
// if the default action is not specified we won't show the button:
let defaultActionKey = this.gameManager.config.get('client/ui/controls/defaultActionKey');
if(!defaultActionKey){
return;
}
let actionBox = this.createActionBox(defaultActionKey);
this.gameManager.gameDom.appendToElement('.action-buttons', actionBox);
this.setupActionButtonInBox(defaultActionKey, controllersBox);
}
createActionBox(actionKey)
{
let skillTemplate = this.cache.html.get('actionBox');
return this.gameManager.gameEngine.parseTemplate(skillTemplate, {
key: actionKey,
actionName: actionKey
});
}
setupDirButtonInBox(dir, box)
{
let btn = box.getChildByProperty('id', dir);
if(btn){
this.hold(btn, {dir: dir});
}
}
setupActionButtonInBox(action, box)
{
let actionButton = box.getChildByProperty('id', action);
if(!actionButton){
return;
}
if(this.gameManager.config.get('client/general/controls/action_button_hold')){
this.hold(actionButton, action);
return;
}
actionButton?.addEventListener('click', () => {
let currentScene = this.gameManager.activeRoomEvents.getActiveScene();
let dataSend = {
act: ActionsConst.ACTION,
target: currentScene.player.currentTarget,
type: action
};
this.gameManager.activeRoomEvents.send(dataSend);
});
}
hold(button, action)
{
button.addEventListener('mousedown', (event) => {
this.startHold(event, button, action);
});
button.addEventListener('mouseup', (event) => {
this.endHold(event, button);
});
button.addEventListener('mouseout', (event) => {
this.endHold(event, button);
});
button.addEventListener('touchstart', (event) => {
this.startHold(event, button, action);
});
button.addEventListener('touchend', (event) => {
this.endHold(event, button);
});
}
startHold(event, button, action)
{
event.preventDefault();
if(this.gameManager.config.get('client/ui/controls/opacityEffect')){
button.classList.add('button-opacity-off');
}
let currentScene = this.gameManager.activeRoomEvents.getActiveScene();
let dataSend = action;
// @TODO - BETA - Controllers will be part of the configuration in the database.
if(!sc.hasOwn(action, 'dir')){
dataSend = {
act: ActionsConst.ACTION,
target: currentScene.player.currentTarget,
type: action.type
};
}
this.gameManager.activeRoomEvents.send(dataSend);
}
endHold(event, button)
{
event.preventDefault();
if(this.gameManager.config.get('client/ui/controls/opacityEffect')){
button.classList.remove('button-opacity-off');
}
this.gameManager.activeRoomEvents.send({act: GameConst.STOP});
}
showLoadingProgressBar()
{
if(!this.gameManager.config.getWithoutLogs('client/ui/loading/show', true)){
return;
}
let Rectangle = Geom.Rectangle;
let main = Rectangle.Clone(this.cameras.main);
this.progressRect = new Rectangle(0, 0, main.width / 2, 50);
Rectangle.CenterOn(this.progressRect, main.centerX, main.centerY);
this.progressCompleteRect = Geom.Rectangle.Clone(this.progressRect);
this.progressBar = this.createGraphics();
let width = this.cameras.main.width;
let height = this.cameras.main.height;
let fontFamily = this.gameManager.config.get('client/ui/loading/font');
let loadingFontSize = this.gameManager.config.get('client/ui/loading/fontSize');
let loadingAssetsSize = this.gameManager.config.get('client/ui/loading/assetsSize');
this.loadingText = this.createText(
width / 2,
height / 2 - 50,
'Loading...',
{fontFamily, fontSize: loadingFontSize}
);
this.loadingText.setOrigin(0.5, 0.5);
this.loadingText.setFill(this.gameManager.config.get('client/ui/loading/loadingColor'));
this.percentText = this.createText(width / 2, height / 2 - 5, '0%', {fontFamily, fontSize: loadingAssetsSize});
this.percentText.setOrigin(0.5, 0.5);
this.percentText.setFill(this.gameManager.config.get('client/ui/loading/percentColor'));
this.assetText = this.createText(width / 2, height / 2 + 50, '', {fontFamily, fontSize: loadingAssetsSize});
this.assetText.setFill(this.gameManager.config.get('client/ui/loading/assetsColor'));
this.assetText.setOrigin(0.5, 0.5);
}
createText(width, height, text, styles)
{
return this.add.text(width, height, text, styles);
}
createGraphics()
{
return this.add.graphics();
}
onLoadComplete()
{
for(let child of this.children.list){
child.destroy();
}
this.loadingText.destroy();
this.assetText.destroy();
this.percentText.destroy();
this.scene.shutdown();
}
onFileProgress(file)
{
if(!this.gameManager.config.get('client/ui/loading/showAssets')){
return;
}
// @TODO - WIP - TRANSLATIONS.
this.assetText.setText('Loading '+file.key);
}
onLoadProgress(progress)
{
let progressText = parseInt(progress * 100) + '%';
this.percentText.setText(progressText);
let color = (0xffffff);
let fillColor = (0x222222);
this.progressRect.width = progress * this.progressCompleteRect.width;
this.progressBar
.clear()
.fillStyle(fillColor)
.fillRectShape(this.progressCompleteRect)
.fillStyle(color)
.fillRectShape(this.progressRect);
}
getUiElement(uiName, logError = true)
{
if(sc.hasOwn(this.elementsUi, uiName)){
return this.elementsUi[uiName];
}
if(logError){
Logger.error('UI not found.', {uiName});
}
return false;
}
}
module.exports.ScenePreloader = ScenePreloader;