/**
* Модуль, отвечающий за расчет и установку размеров контейнера игры и ее масштаба.
* Создает сетку по размеру карт для расположения элементов игры.
* @class
* @extends {Phaser.ScaleManager}
* @param {object} [options] Опции
* @param {Game} options.game=game игра
* @param {width} options.width=0 текущая ширина игры для Phaser.ScaleManager
* @param {height} options.height=0 текущая высота игры для Phaser.ScaleManager
* @param {number} options.density=4 сколько клеток умещается в карте по одной оси
* @param {number} options.thickness=1 ширина линий сетки для дебага
* @param {boolean} options.debug=false нужно ли выводить дебаг информацию
* @param {number} options.minColsLandscape минимальное число колонок сетки в горизонтальном режиме
* @param {number} options.minRowsLandscape минимальное число строк сетки в горизонтальном режиме
* @param {number} options.minColsPortrait минимальное число колонок сетки в вертикальном режиме
* @param {number} options.minRowsPortrait минимальное число строк сетки в вертикальном режиме
* @see {@link http://phaser.io/docs/2.6.2/Phaser.ScaleManager.html}
*/
var ScaleManager = function(options){
this.options = mergeOptions(this.getDefaultOptions(), options);
Phaser.ScaleManager.call(this, this.options.game, this.options.width, this.options.height);
this._minColsLandscape = this.options.minColsLandscape;
this._minRowsLandscape = this.options.minRowsLandscape;
this._minColsPortrait = this.options.minColsPortrait;
this._minRowsPortrait = this.options.minRowsPortrait;
this._cellRelationThreshold = this.options.cellRelationThreshold;
/**
* Сколько клеток умещается в карте по одной оси.
* @type {number}
*/
this.density = this.options.density;
/**
* Отступ сетки от левого верхнего угла `{x, y}`.
* @type {object}
*/
this.gridOffset = {x: 0, y:0};
/**
* Количество колонок сетки.
* @type {number}
*/
this.numCols = 0;
/**
* Количество строк сетки.
* @type {number}
*/
this.numRows = 0;
/**
* Ширина сетки.
* @type {number}
*/
this.gridWidth = 0;
/**
* Высота сетки.
* @type {number}
*/
this.gridHeight = 0;
/**
* Ширина сетки.
* @type {number}
*/
this.cellWidth = 0;
/**
* Высота сетки.
* @type {number}
*/
this.cellHeight = 0;
/**
* Отношение кол-ва клеток по горизонтали к кол-ву клеток по вертикали.
* @type {Number}
*/
this.cellRelation = 0;
/**
* Ширина линий сетки для дебага.
* @type {number}
*/
this._thickness = this.options.thickness;
this.scaleMultiplier = gameOptions.get('game_scale');
/**
* Нужно ли выводить дебаг информацию.
* @type {boolean}
* @see {@link ScaleManager#toggleDebugMode}
* @see {@link ScaleManager#drawDebug}
*/
this.inDebugMode = this.options.debug;
/**
* Текстура дебаг сетки.
* @type {PIXI.Texture}
*/
this._gridTexture = null;
/**
* Дебаг сетка.
* @type {Phaser.TileSprite}
*/
this._debugGrid = null;
/**
* Группа спрайтов, подсвечивающих клетки, возвращенные из `{@link ScaleManager#at}`,
* если сетка в режиме дебага.
* @type {external:Phaser.Group}
*/
this._highlights = null;
/**
* Дебаг рамка.
* @type {Phaser.Graphics}
*/
this._border = null;
/**
* Был ли совершен переход из\в полный экран.
* Сообщает игре, что не нужно дебаунсить обновление позиций элементов.
* @type {Boolean}
*/
this.fullScreenModeChanged = false;
};
extend(ScaleManager, Phaser.ScaleManager);
/**
* Получить опции по умолчанию (см. {@link ScaleManager|ScaleManager options}).
* @return {object} Опции по умолчанию.
*/
ScaleManager.prototype.getDefaultOptions = function(){
return {
game: null,
width: 0,
height: 0,
density:4, // плотность сетки (масштаб - 1:density)
thickness: 1, // толщина линий сетки для дебага
debug: false,
minColsLandscape: 28,
minRowsLandscape: 20,
minColsPortrait: 25,
minRowsPortrait: 25,
cellRelationThreshold: 2.47
};
};
/**
* Расчитывает и устанавливает размер контейнера игры,
* перерисовывает сетку.
*/
ScaleManager.prototype.updateGameSize = function(){
this.fullScreenModeChanged = false;
this._calculateScreenSize();
this.setGameSize(this.game.screenWidth, this.game.screenHeight);
};
/**
* Расчитывает размеры игры.
*/
ScaleManager.prototype._calculateScreenSize = function(reduceMinHeight){
this.cellWidth = Math.round(skinManager.skin.width/this.density);
this.cellHeight = Math.round(skinManager.skin.height/this.density);
var container;
if(this.isFullScreen){
container = {width: window.innerWidth, height: window.innerHeight};
}
else{
container = document.getElementById(game.parent).getBoundingClientRect();
}
var width = container.width/window.devicePixelRatio*this.scaleMultiplier,
height = container.height/window.devicePixelRatio*this.scaleMultiplier,
widthRel = (width/this.cellWidth)/(height/this.cellHeight),
minWidth, minHeight;
if(widthRel >= 1.15){
if(reduceMinHeight){
minHeight = (this._minRowsLandscape - 2)*this.cellHeight;
}
else{
minHeight = this._minRowsLandscape*this.cellHeight;
}
minWidth = this._minColsLandscape*this.cellWidth;
this.game.isRawLandscape = true;
}
else{
minWidth = this._minColsPortrait*this.cellWidth;
minHeight = this._minRowsPortrait*this.cellHeight;
this.game.isRawLandscape = false;
}
if(width*(minHeight/minWidth) > height){
minWidth = 0;
}
else{
minHeight = 0;
}
var diffWidth = minWidth - width,
diffHeight = minHeight - height,
multWidth = width/minWidth,
multHeight = height/minHeight;
var screenWidth = Math.max(width, minWidth);
var screenHeight = Math.max(height, minHeight);
if(diffWidth > 0){
screenHeight /= multWidth;
}
if(diffHeight > 0){
screenWidth /= multHeight;
}
this._calculateGridSize(screenWidth, screenHeight);
var cellRelation = this.cellRelation = this.numCols/this.numRows;
if(!reduceMinHeight && cellRelation >= this._cellRelationThreshold){
this._calculateScreenSize(true);
return;
}
if(this.inDebugMode){
console.log('====== Screensize =======');
console.log(
'width:', width,
'height:', height,
'relation:', widthRel
);
console.log(
'diffWidth:', diffWidth,
'diffHeight:', diffHeight
);
console.log(
'multWidth:', multWidth,
'multHeight:', multHeight
);
console.log('====== Gridsize ======');
console.log(
'numCols:', this.numCols,
'numRows:', this.numRows
);
console.log(
'cell:', this.cellWidth, 'x', this.cellHeight
);
console.log('cell relation:', cellRelation);
}
this.game.screenWidth = screenWidth;
this.game.screenHeight = screenHeight;
};
/**
* Расчитывает размеры сетки.
* @param {number} screenWidth ширина игры
* @param {number} screenHeight высота игры
*/
ScaleManager.prototype._calculateGridSize = function(screenWidth, screenHeight){
var width = this.cellWidth,
height = this.cellHeight;
var offset = this.gridOffset = {
x: Math.round(screenWidth%width/2),
y: Math.round(screenHeight%height)
};
this.numCols = Math.floor(screenWidth/width);
this.numRows = Math.floor(screenHeight/height);
this.gridWidth = screenWidth - offset.x*2;
this.gridHeight = screenHeight - offset.y*2;
};
/**
* Возвращает координаты ячейки.
* @param {number} [col=0] колонка ячейки
* @param {number} [row=0] строка ячейки
* @param {number} [offsetX=0] отступ слева
* @param {number} [offsetY=0] отступ сверху
*
* @return {object} Координаты `{x, y}`
*/
ScaleManager.prototype.cellAt = function(col, row, offsetX, offsetY){
if(typeof col != 'number' || isNaN(col)){
col = 0;
}
if(typeof row != 'number' || isNaN(row)){
row = 0;
}
if(!offsetX){
offsetX = 0;
}
if(!offsetY){
offsetY = 0;
}
var x = col*this.cellWidth + this.gridOffset.x ,
y = row*this.cellHeight + this.gridOffset.y ;
if(this._highlights){
var highlight = this.game.add.sprite(0, 0, this._gridTexture);
this._highlights.add(highlight);
highlight.tint = 0x2DD300;
highlight.position.x = x;
highlight.position.y = y;
this.game.world.bringToTop(this._highlights);
}
return {x: x + offsetX, y: y + offsetY};
};
/**
* Переключает вывод дебаг информации.
*/
ScaleManager.prototype.toggleDebugMode = function(){
this.inDebugMode = !this.inDebugMode;
gameOptions.set('debug_grid', this.inDebugMode);
gameOptions.save();
this.drawDebugGrid();
ui.setDebugButtonText('grid', 'Grid', this.inDebugMode);
};
/**
* Рисует сетку для дебага.
* @param {object} offset отступ от края `{x, y}`
* @param {number} width ширина
* @param {number} height высота
*/
ScaleManager.prototype.drawDebugGrid = function(){
if(this._border){
this._border.destroy();
this._border = null;
}
if(this._debugGrid){
this._debugGrid.destroy();
this._debugGrid = null;
}
if(this._highlights){
this._highlights.destroy(true);
this._highlights = null;
}
if(!this.inDebugMode){
return;
}
var offset = this.gridOffset,
width = this.cellWidth,
height = this.cellHeight;
var screenWidth = this.game.screenWidth,
screenHeight = this.game.screenHeight,
debugGrid = this.game.make.graphics(0, 0),
thickness = this._thickness;
// debugGrid.lineStyle(thickness, 0x2BC41D, 1);
debugGrid.lineStyle(thickness, 0xffffff, 1);
debugGrid.drawRect(0, 0, width-thickness, height-thickness);
this._gridTexture = debugGrid.generateTexture();
this._debugGrid = this.game.add.tileSprite(0, 0, screenWidth, screenHeight, this._gridTexture);
this._debugGrid.alpha = 0.3;
this._highlights = this.game.add.group();
this._debugGrid.tilePosition = offset;
var x = offset.x,
y = offset.y,
// color = 0xC10BAC,
color = 0x000000,
alpha = 1;
var border = this._border = this.game.add.graphics(0, 0);
border.lineStyle(y, color, alpha);
border.moveTo(0, y/2 - thickness/2);
border.lineTo(screenWidth, y/2 - thickness/2);
border.lineStyle(x, color, alpha);
border.moveTo(screenWidth - x/2 + thickness/2, 0);
border.lineTo(screenWidth - x/2 + thickness/2, screenHeight);
// border.lineStyle(y, color, alpha);
// border.moveTo(screenWidth, screenHeight - y/2 + thickness/2);
// border.lineTo(0,screenHeight - y/2 + thickness/2);
border.lineStyle(x, color, alpha);
border.moveTo(x/2 - thickness/2, screenHeight);
border.lineTo(x/2 - thickness/2,0);
ui.background.add(this._debugGrid);
ui.background.add(this._border);
};
ScaleManager.prototype.toggleFullScreen = function(){
this.fullScreenModeChanged = true;
if (this.isFullScreen){
ui.cornerButtons.getByName('fullscreen').label.frame = 0;
this.stopFullScreen();
}
else{
ui.cornerButtons.getByName('fullscreen').label.frame = 1;
this.startFullScreen();
}
};