2013-04-22 00:53:24 +00:00
|
|
|
/// <reference path="../Game.ts" />
|
|
|
|
/// <reference path="../geom/Quad.ts" />
|
2013-04-23 14:15:34 +00:00
|
|
|
/// <reference path="ScrollRegion.ts" />
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Phaser - ScrollZone
|
|
|
|
*
|
|
|
|
* Creates a scrolling region of the given width and height from an image in the cache.
|
2013-04-23 14:15:34 +00:00
|
|
|
* The ScrollZone can be positioned anywhere in-world like a normal game object, re-act to physics, collision, etc.
|
|
|
|
* The image within it is scrolled via ScrollRegions and their scrollSpeed.x/y properties.
|
2013-04-22 00:53:24 +00:00
|
|
|
* If you create a scroll zone larger than the given source image it will create a DynamicTexture and fill it with a pattern of the source image.
|
|
|
|
*/
|
|
|
|
|
|
|
|
module Phaser {
|
|
|
|
|
|
|
|
export class ScrollZone extends GameObject {
|
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* ScrollZone constructor
|
|
|
|
* Create a new <code>ScrollZone</code>.
|
|
|
|
*
|
|
|
|
* @param game {Phaser.Game} Current game instance.
|
|
|
|
* @param key {string} Asset key for image texture of this object.
|
|
|
|
* @param x {number} X position in world coordinate.
|
|
|
|
* @param y {number} Y position in world coordinate.
|
2013-05-04 16:18:45 +00:00
|
|
|
* @param [width] {number} width of this object.
|
|
|
|
* @param [height] {number} height of this object.
|
2013-05-04 11:59:59 +00:00
|
|
|
*/
|
2013-04-23 14:15:34 +00:00
|
|
|
constructor(game: Game, key:string, x: number = 0, y: number = 0, width?: number = 0, height?: number = 0) {
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
super(game, x, y, width, height);
|
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
this.regions = [];
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
if (this._game.cache.getImage(key))
|
|
|
|
{
|
|
|
|
this._texture = this._game.cache.getImage(key);
|
2013-04-23 14:15:34 +00:00
|
|
|
this.width = this._texture.width;
|
|
|
|
this.height = this._texture.height;
|
|
|
|
|
|
|
|
if (width > this._texture.width || height > this._texture.height)
|
|
|
|
{
|
|
|
|
// Create our repeating texture (as the source image wasn't large enough for the requested size)
|
|
|
|
this.createRepeatingTexture(width, height);
|
|
|
|
this.width = width;
|
|
|
|
this.height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a default ScrollRegion at the requested size
|
|
|
|
this.addRegion(0, 0, this.width, this.height);
|
|
|
|
|
|
|
|
// If the zone is smaller than the image itself then shrink the bounds
|
|
|
|
if ((width < this._texture.width || height < this._texture.height) && width !== 0 && height !== 0)
|
|
|
|
{
|
|
|
|
this.width = width;
|
|
|
|
this.height = height;
|
|
|
|
}
|
|
|
|
|
2013-04-22 00:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Texture of this object.
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
private _texture;
|
2013-05-20 05:21:12 +00:00
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* If this zone is larger than texture image, this will be filled with a pattern of texture.
|
|
|
|
* @type {DynamicTexture}
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
private _dynamicTexture: DynamicTexture = null;
|
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Local rendering related temp vars to help avoid gc spikes.
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
private _dx: number = 0;
|
2013-05-20 05:21:12 +00:00
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Local rendering related temp vars to help avoid gc spikes.
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
private _dy: number = 0;
|
2013-05-20 05:21:12 +00:00
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Local rendering related temp vars to help avoid gc spikes.
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
private _dw: number = 0;
|
2013-05-20 05:21:12 +00:00
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Local rendering related temp vars to help avoid gc spikes.
|
|
|
|
* @type {number}
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
private _dh: number = 0;
|
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Current region this zone is scrolling.
|
|
|
|
* @type {ScrollRegion}
|
|
|
|
*/
|
2013-04-23 14:15:34 +00:00
|
|
|
public currentRegion: ScrollRegion;
|
2013-05-20 05:21:12 +00:00
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Array contains all added regions.
|
|
|
|
* @type {ScrollRegion[]}
|
|
|
|
*/
|
2013-04-23 14:15:34 +00:00
|
|
|
public regions: ScrollRegion[];
|
2013-05-20 05:21:12 +00:00
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Flip this zone vertically? (default to false)
|
|
|
|
* @type {boolean}
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
public flipped: bool = false;
|
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Add a new region to this zone.
|
|
|
|
* @param x {number} X position of the new region.
|
|
|
|
* @param y {number} Y position of the new region.
|
|
|
|
* @param width {number} Width of the new region.
|
|
|
|
* @param height {number} Height of the new region.
|
2013-05-04 16:18:45 +00:00
|
|
|
* @param [speedX] {number} x-axis scrolling speed.
|
|
|
|
* @param [speedY] {number} y-axis scrolling speed.
|
2013-05-04 11:59:59 +00:00
|
|
|
* @return {ScrollRegion} The newly added region.
|
|
|
|
*/
|
2013-04-23 14:15:34 +00:00
|
|
|
public addRegion(x: number, y: number, width: number, height: number, speedX?:number = 0, speedY?:number = 0):ScrollRegion {
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-04-23 18:24:16 +00:00
|
|
|
if (x > this.width || y > this.height || x < 0 || y < 0 || (x + width) > this.width || (y + height) > this.height)
|
|
|
|
{
|
|
|
|
throw Error('Invalid ScrollRegion defined. Cannot be larger than parent ScrollZone');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
this.currentRegion = new ScrollRegion(x, y, width, height, speedX, speedY);
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
this.regions.push(this.currentRegion);
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
return this.currentRegion;
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
}
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Set scrolling speed of current region.
|
|
|
|
* @param x {number} X speed of current region.
|
|
|
|
* @param y {number} Y speed of current region.
|
|
|
|
*/
|
2013-04-23 14:15:34 +00:00
|
|
|
public setSpeed(x: number, y: number) {
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
if (this.currentRegion)
|
|
|
|
{
|
|
|
|
this.currentRegion.scrollSpeed.setTo(x, y);
|
|
|
|
}
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-04-23 18:24:16 +00:00
|
|
|
return this;
|
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
}
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Update regions.
|
|
|
|
*/
|
2013-04-23 14:15:34 +00:00
|
|
|
public update() {
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
for (var i = 0; i < this.regions.length; i++)
|
|
|
|
{
|
|
|
|
this.regions[i].update(this._game.time.delta);
|
|
|
|
}
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Check whether this zone is visible in a specific camera rectangle.
|
|
|
|
* @param camera {Rectangle} The rectangle you want to check.
|
|
|
|
* @return {boolean} Return true if bound of this zone intersects the given rectangle, otherwise return false.
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
public inCamera(camera: Rectangle): bool {
|
2013-05-04 11:59:59 +00:00
|
|
|
|
2013-04-22 00:53:24 +00:00
|
|
|
if (this.scrollFactor.x !== 1.0 || this.scrollFactor.y !== 1.0)
|
|
|
|
{
|
2013-05-20 05:21:12 +00:00
|
|
|
this._dx = this.frameBounds.x - (camera.x * this.scrollFactor.x);
|
|
|
|
this._dy = this.frameBounds.y - (camera.y * this.scrollFactor.x);
|
|
|
|
this._dw = this.frameBounds.width * this.scale.x;
|
|
|
|
this._dh = this.frameBounds.height * this.scale.y;
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
return (camera.right > this._dx) && (camera.x < this._dx + this._dw) && (camera.bottom > this._dy) && (camera.y < this._dy + this._dh);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-20 05:21:12 +00:00
|
|
|
return camera.intersects(this.frameBounds, this.frameBounds.length);
|
2013-04-22 00:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Render this zone object to a specific camera.
|
|
|
|
* @param camera {Camera} The camera this object will be render to.
|
|
|
|
* @param cameraOffsetX {number} X offset of camera.
|
|
|
|
* @param cameraOffsetY {number} Y offset of camera.
|
|
|
|
* @return Return false if not rendered, otherwise return true.
|
|
|
|
*/
|
2013-04-22 00:53:24 +00:00
|
|
|
public render(camera: Camera, cameraOffsetX: number, cameraOffsetY: number) {
|
|
|
|
|
|
|
|
// Render checks
|
2013-04-24 01:48:03 +00:00
|
|
|
if (this.visible == false || this.scale.x == 0 || this.scale.y == 0 || this.alpha < 0.1 || this.cameraBlacklist.indexOf(camera.ID) !== -1 || this.inCamera(camera.worldView) == false)
|
2013-04-22 00:53:24 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alpha
|
|
|
|
if (this.alpha !== 1)
|
|
|
|
{
|
2013-05-17 05:49:43 +00:00
|
|
|
var globalAlpha = this.context.globalAlpha;
|
|
|
|
this.context.globalAlpha = this.alpha;
|
2013-04-22 00:53:24 +00:00
|
|
|
}
|
|
|
|
|
2013-05-20 05:21:12 +00:00
|
|
|
this._dx = cameraOffsetX + (this.frameBounds.topLeft.x - camera.worldView.x);
|
|
|
|
this._dy = cameraOffsetY + (this.frameBounds.topLeft.y - camera.worldView.y);
|
|
|
|
this._dw = this.frameBounds.width * this.scale.x;
|
|
|
|
this._dh = this.frameBounds.height * this.scale.y;
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
// Apply camera difference
|
|
|
|
if (this.scrollFactor.x !== 1.0 || this.scrollFactor.y !== 1.0)
|
|
|
|
{
|
|
|
|
this._dx -= (camera.worldView.x * this.scrollFactor.x);
|
|
|
|
this._dy -= (camera.worldView.y * this.scrollFactor.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rotation - needs to work from origin point really, but for now from center
|
|
|
|
if (this.angle !== 0 || this.flipped == true)
|
|
|
|
{
|
2013-05-17 05:49:43 +00:00
|
|
|
this.context.save();
|
|
|
|
this.context.translate(this._dx + (this._dw / 2), this._dy + (this._dh / 2));
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
if (this.angle !== 0)
|
|
|
|
{
|
2013-05-17 05:49:43 +00:00
|
|
|
this.context.rotate(this.angle * (Math.PI / 180));
|
2013-04-22 00:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this._dx = -(this._dw / 2);
|
|
|
|
this._dy = -(this._dh / 2);
|
|
|
|
|
|
|
|
if (this.flipped == true)
|
|
|
|
{
|
2013-05-17 05:49:43 +00:00
|
|
|
this.context.scale(-1, 1);
|
2013-04-22 00:53:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this._dx = Math.round(this._dx);
|
|
|
|
this._dy = Math.round(this._dy);
|
2013-04-23 14:15:34 +00:00
|
|
|
this._dw = Math.round(this._dw);
|
|
|
|
this._dh = Math.round(this._dh);
|
2013-04-22 00:53:24 +00:00
|
|
|
|
2013-04-23 14:15:34 +00:00
|
|
|
for (var i = 0; i < this.regions.length; i++)
|
2013-04-22 00:53:24 +00:00
|
|
|
{
|
2013-04-23 14:15:34 +00:00
|
|
|
if (this._dynamicTexture)
|
|
|
|
{
|
2013-05-17 05:49:43 +00:00
|
|
|
this.regions[i].render(this.context, this._dynamicTexture.canvas, this._dx, this._dy, this._dw, this._dh);
|
2013-04-23 14:15:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-17 05:49:43 +00:00
|
|
|
this.regions[i].render(this.context, this._texture, this._dx, this._dy, this._dw, this._dh);
|
2013-04-23 14:15:34 +00:00
|
|
|
}
|
2013-04-22 00:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (globalAlpha > -1)
|
|
|
|
{
|
2013-05-17 05:49:43 +00:00
|
|
|
this.context.globalAlpha = globalAlpha;
|
2013-04-22 00:53:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-05-04 11:59:59 +00:00
|
|
|
/**
|
|
|
|
* Create repeating texture with _texture, and store it into the _dynamicTexture.
|
|
|
|
* Used to create texture when texture image is small than size of the zone.
|
|
|
|
*/
|
2013-04-23 14:15:34 +00:00
|
|
|
private createRepeatingTexture(regionWidth: number, regionHeight: number) {
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
// Work out how many we'll need of the source image to make it tile properly
|
2013-04-23 14:15:34 +00:00
|
|
|
var tileWidth = Math.ceil(this._texture.width / regionWidth) * regionWidth;
|
|
|
|
var tileHeight = Math.ceil(this._texture.height / regionHeight) * regionHeight;
|
2013-04-22 00:53:24 +00:00
|
|
|
|
|
|
|
this._dynamicTexture = new DynamicTexture(this._game, tileWidth, tileHeight);
|
|
|
|
|
|
|
|
this._dynamicTexture.context.rect(0, 0, tileWidth, tileHeight);
|
|
|
|
this._dynamicTexture.context.fillStyle = this._dynamicTexture.context.createPattern(this._texture, "repeat");
|
|
|
|
this._dynamicTexture.context.fill();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|