mirror of
https://github.com/photonstorm/phaser
synced 2024-12-24 12:03:36 +00:00
481 lines
14 KiB
JavaScript
481 lines
14 KiB
JavaScript
/**
|
|
* @author Richard Davey <rich@photonstorm.com>
|
|
* @author Kestrel Moon Studios <creature@kestrelmoon.com>
|
|
* @copyright 2016 Photon Storm Ltd and Kestrel Moon Studios
|
|
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
|
|
*/
|
|
|
|
/**
|
|
* Creature is a custom Game Object used in conjunction with the Creature Runtime libraries by Kestrel Moon Studios.
|
|
*
|
|
* It allows you to display animated Game Objects that were created with the [Creature Automated Animation Tool](http://www.kestrelmoon.com/creature/).
|
|
*
|
|
* Note 1: You can only use Phaser.GameObject.Creature objects in WebGL enabled games. They do not work in Canvas mode games.
|
|
*
|
|
* Note 2: You must use a build of Phaser that includes the CreatureMeshBone.js runtime and gl-matrix.js, or have them
|
|
* loaded before your Phaser game boots.
|
|
*
|
|
* See the Phaser custom build process for more details.
|
|
*
|
|
* By default the Creature runtimes are NOT included in any pre-configured version of Phaser.
|
|
*
|
|
* So you'll need to do `grunt custom` to create a build that includes them.
|
|
*
|
|
* @class Phaser.GameObject.Creature
|
|
* @extends PIXI.DisplayObjectContainer
|
|
* @extends Phaser.Component.Core
|
|
* @extends Phaser.Component.Angle
|
|
* @extends Phaser.Component.AutoCull
|
|
* @extends Phaser.Component.BringToTop
|
|
* @extends Phaser.Component.Destroy
|
|
* @extends Phaser.Component.FixedToCamera
|
|
* @extends Phaser.Component.LifeSpan
|
|
* @extends Phaser.Component.Reset
|
|
* @constructor
|
|
* @param {Phaser.Game} game - A reference to the currently running game.
|
|
* @param {number} x - The x coordinate of the Game Object. The coordinate is relative to any parent container this Game Object may be in.
|
|
* @param {number} y - The y coordinate of the Game Object. The coordinate is relative to any parent container this Game Object may be in.
|
|
* @param {string|PIXI.Texture} key - The texture used by the Creature Object during rendering. It can be a string which is a reference to the Cache entry, or an instance of a PIXI.Texture.
|
|
* @param {string} mesh - The mesh data for the Creature Object. It should be a string which is a reference to the Cache JSON entry.
|
|
* @param {string} [animation='default'] - The animation within the mesh data to play.
|
|
*/
|
|
Phaser.GameObject.Creature = function (game, x, y, key, mesh, animation) {
|
|
|
|
if (animation === undefined) { animation = 'default'; }
|
|
|
|
/**
|
|
* @property {number} type - The const type of this object.
|
|
* @readonly
|
|
*/
|
|
this.type = Phaser.CREATURE;
|
|
|
|
if (!game.cache.checkJSONKey(mesh))
|
|
{
|
|
console.warn('Phaser.GameObject.Creature: Invalid mesh key given. Not found in Phaser.Cache');
|
|
return;
|
|
}
|
|
|
|
var meshData = game.cache.getJSON(mesh);
|
|
|
|
/**
|
|
* @property {Creature} _creature - The Creature instance.
|
|
* @private
|
|
*/
|
|
this._creature = new Creature(meshData);
|
|
|
|
/**
|
|
* @property {CreatureAnimation} animation - The CreatureAnimation instance.
|
|
*/
|
|
this.animation = new CreatureAnimation(meshData, animation, this._creature);
|
|
|
|
/**
|
|
* @property {CreatureManager} manager - The CreatureManager instance for this object.
|
|
*/
|
|
this.manager = new CreatureManager(this._creature);
|
|
|
|
/**
|
|
* @property {number} timeDelta - How quickly the animation advances.
|
|
* @default
|
|
*/
|
|
this.timeDelta = 0.05;
|
|
|
|
if (typeof key === 'string')
|
|
{
|
|
var texture = new PIXI.Texture(game.cache.getBaseTexture(key));
|
|
}
|
|
else
|
|
{
|
|
var texture = key;
|
|
}
|
|
|
|
/**
|
|
* @property {PIXI.Texture} texture - The texture the animation is using.
|
|
*/
|
|
this.texture = texture;
|
|
|
|
PIXI.DisplayObjectContainer.call(this);
|
|
|
|
this.dirty = true;
|
|
this.blendMode = Phaser.blendModes.NORMAL;
|
|
|
|
/**
|
|
* @property {Phaser.Point} creatureBoundsMin - The minimum bounds point.
|
|
* @protected
|
|
*/
|
|
this.creatureBoundsMin = new Phaser.Point();
|
|
|
|
/**
|
|
* @property {Phaser.Point} creatureBoundsMax - The maximum bounds point.
|
|
* @protected
|
|
*/
|
|
this.creatureBoundsMax = new Phaser.Point();
|
|
|
|
var target = this.manager.target_creature;
|
|
|
|
/**
|
|
* @property {Float32Array} vertices - The vertices data.
|
|
* @protected
|
|
*/
|
|
this.vertices = new Float32Array(target.total_num_pts * 2);
|
|
|
|
/**
|
|
* @property {Float32Array} uvs - The UV data.
|
|
* @protected
|
|
*/
|
|
this.uvs = new Float32Array(target.total_num_pts * 2);
|
|
|
|
/**
|
|
* @property {Uint16Array} indices
|
|
* @protected
|
|
*/
|
|
this.indices = new Uint16Array(target.global_indices.length);
|
|
|
|
for (var i = 0; i < this.indices.length; i++)
|
|
{
|
|
this.indices[i] = target.global_indices[i];
|
|
}
|
|
|
|
/**
|
|
* @property {Uint16Array} colors - The vertices colors
|
|
* @protected
|
|
*/
|
|
this.colors = new Float32Array([1, 1, 1, 1]);
|
|
|
|
this.updateRenderData(target.global_pts, target.global_uvs);
|
|
|
|
this.manager.AddAnimation(this.animation);
|
|
this.manager.SetActiveAnimationName(animation, false);
|
|
|
|
Phaser.Component.Core.init.call(this, game, x, y);
|
|
|
|
};
|
|
|
|
Phaser.GameObject.Creature.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
|
|
Phaser.GameObject.Creature.prototype.constructor = Phaser.GameObject.Creature;
|
|
|
|
Phaser.Component.Core.install.call(Phaser.GameObject.Creature.prototype, [
|
|
'Angle',
|
|
'AutoCull',
|
|
'BringToTop',
|
|
'Destroy',
|
|
'FixedToCamera',
|
|
'LifeSpan',
|
|
'Reset'
|
|
]);
|
|
|
|
Phaser.GameObject.Creature.prototype.preUpdateInWorld = Phaser.Component.InWorld.preUpdate;
|
|
Phaser.GameObject.Creature.prototype.preUpdateCore = Phaser.Component.Core.preUpdate;
|
|
|
|
/**
|
|
* Automatically called by World.preUpdate.
|
|
*
|
|
* @method Phaser.GameObject.Creature#preUpdate
|
|
* @memberof Phaser.GameObject.Creature
|
|
*/
|
|
Phaser.GameObject.Creature.prototype.preUpdate = function () {
|
|
|
|
if (!this.preUpdateInWorld())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
this.manager.Update(this.timeDelta);
|
|
|
|
this.updateData();
|
|
|
|
return this.preUpdateCore();
|
|
|
|
};
|
|
|
|
/**
|
|
*
|
|
*
|
|
* @method Phaser.GameObject.Creature#_initWebGL
|
|
* @memberof Phaser.GameObject.Creature
|
|
* @private
|
|
*/
|
|
Phaser.GameObject.Creature.prototype._initWebGL = function (renderSession) {
|
|
|
|
// build the strip!
|
|
var gl = renderSession.gl;
|
|
|
|
this._vertexBuffer = gl.createBuffer();
|
|
this._indexBuffer = gl.createBuffer();
|
|
this._uvBuffer = gl.createBuffer();
|
|
this._colorBuffer = gl.createBuffer();
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.DYNAMIC_DRAW);
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, this.colors, gl.STATIC_DRAW);
|
|
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
|
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
|
|
|
|
};
|
|
|
|
/**
|
|
* @method Phaser.GameObject.Creature#_renderWebGL
|
|
* @memberof Phaser.GameObject.Creature
|
|
* @private
|
|
*/
|
|
Phaser.GameObject.Creature.prototype._renderWebGL = function (renderSession) {
|
|
|
|
// If the sprite is not visible or the alpha is 0 then no need to render this element
|
|
if (!this.visible || this.alpha <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
renderSession.spriteBatch.stop();
|
|
|
|
// init! init!
|
|
if (!this._vertexBuffer)
|
|
{
|
|
this._initWebGL(renderSession);
|
|
}
|
|
|
|
renderSession.shaderManager.setShader(renderSession.shaderManager.stripShader);
|
|
|
|
this._renderCreature(renderSession);
|
|
|
|
renderSession.spriteBatch.start();
|
|
|
|
};
|
|
|
|
/**
|
|
* @method Phaser.GameObject.Creature#_renderCreature
|
|
* @memberof Phaser.GameObject.Creature
|
|
* @private
|
|
*/
|
|
Phaser.GameObject.Creature.prototype._renderCreature = function (renderSession) {
|
|
|
|
var gl = renderSession.gl;
|
|
|
|
var projection = renderSession.projection;
|
|
var offset = renderSession.offset;
|
|
var shader = renderSession.shaderManager.stripShader;
|
|
|
|
renderSession.blendModeManager.setBlendMode(this.blendMode);
|
|
|
|
// Set uniforms
|
|
gl.uniformMatrix3fv(shader.translationMatrix, false, this.worldTransform.toArray(true));
|
|
gl.uniform2f(shader.projectionVector, projection.x, -projection.y);
|
|
gl.uniform2f(shader.offsetVector, -offset.x, -offset.y);
|
|
gl.uniform1f(shader.alpha, this.worldAlpha);
|
|
|
|
if (!this.dirty)
|
|
{
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
|
|
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices);
|
|
gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
// Update the uvs
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer);
|
|
gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
|
|
// Check if a texture is dirty..
|
|
if (this.texture.baseTexture._dirty[gl.id])
|
|
{
|
|
renderSession.renderer.updateTexture(this.texture.baseTexture);
|
|
}
|
|
else
|
|
{
|
|
// Bind the current texture
|
|
gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]);
|
|
}
|
|
|
|
// Don't need to upload!
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
|
|
}
|
|
else
|
|
{
|
|
this.dirty = false;
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
|
|
gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
// Update the uvs
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.DYNAMIC_DRAW);
|
|
gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
|
|
// Check if a texture is dirty
|
|
if (this.texture.baseTexture._dirty[gl.id])
|
|
{
|
|
renderSession.renderer.updateTexture(this.texture.baseTexture);
|
|
}
|
|
else
|
|
{
|
|
gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]);
|
|
}
|
|
|
|
// Don't need to upload!
|
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
|
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
|
|
}
|
|
|
|
gl.drawElements(gl.TRIANGLES, this.indices.length, gl.UNSIGNED_SHORT, 0);
|
|
|
|
};
|
|
|
|
/**
|
|
* @method Phaser.GameObject.Creature#updateCreatureBounds
|
|
* @memberof Phaser.GameObject.Creature
|
|
* @private
|
|
*/
|
|
Phaser.GameObject.Creature.prototype.updateCreatureBounds = function () {
|
|
|
|
// Update bounds based off world transform matrix
|
|
var target = this.manager.target_creature;
|
|
|
|
target.ComputeBoundaryMinMax();
|
|
|
|
this.creatureBoundsMin.set(target.boundary_min[0], -target.boundary_min[1]);
|
|
this.creatureBoundsMax.set(target.boundary_max[0], -target.boundary_max[1]);
|
|
|
|
this.worldTransform.apply(this.creatureBoundsMin, this.creatureBoundsMin);
|
|
this.worldTransform.apply(this.creatureBoundsMax, this.creatureBoundsMax);
|
|
|
|
};
|
|
|
|
/**
|
|
* @method Phaser.GameObject.Creature#updateData
|
|
* @memberof Phaser.GameObject.Creature
|
|
* @private
|
|
*/
|
|
Phaser.GameObject.Creature.prototype.updateData = function () {
|
|
|
|
var target = this.manager.target_creature;
|
|
|
|
var read_pts = target.render_pts;
|
|
var read_uvs = target.global_uvs;
|
|
|
|
this.updateRenderData(read_pts, read_uvs);
|
|
this.updateCreatureBounds();
|
|
|
|
this.dirty = true;
|
|
|
|
};
|
|
|
|
/**
|
|
* @method Phaser.GameObject.Creature#updateRenderData
|
|
* @memberof Phaser.GameObject.Creature
|
|
* @private
|
|
*/
|
|
Phaser.GameObject.Creature.prototype.updateRenderData = function (verts, uvs) {
|
|
|
|
var target = this.manager.target_creature;
|
|
|
|
var pt_index = 0;
|
|
var uv_index = 0;
|
|
|
|
var write_pt_index = 0;
|
|
|
|
for (var i = 0; i < target.total_num_pts; i++)
|
|
{
|
|
this.vertices[write_pt_index] = verts[pt_index];
|
|
this.vertices[write_pt_index + 1] = -verts[pt_index + 1];
|
|
|
|
this.uvs[uv_index] = uvs[uv_index];
|
|
this.uvs[uv_index + 1] = uvs[uv_index + 1];
|
|
|
|
pt_index += 3;
|
|
uv_index += 2;
|
|
|
|
write_pt_index += 2;
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* Sets the Animation this Creature object will play, as defined in the mesh data.
|
|
*
|
|
* @method Phaser.GameObject.Creature#setAnimation
|
|
* @memberof Phaser.GameObject.Creature
|
|
* @param {string} key - The key of the animation to set, as defined in the mesh data.
|
|
*/
|
|
Phaser.GameObject.Creature.prototype.setAnimation = function (key) {
|
|
|
|
this.manager.SetActiveAnimationName(key, true);
|
|
|
|
};
|
|
|
|
/**
|
|
* Plays the currently set animation.
|
|
*
|
|
* @method Phaser.GameObject.Creature#play
|
|
* @memberof Phaser.GameObject.Creature
|
|
* @param {boolean} [loop=false] - Should the animation loop?
|
|
*/
|
|
Phaser.GameObject.Creature.prototype.play = function (loop) {
|
|
|
|
if (loop === undefined) { loop = false; }
|
|
|
|
this.loop = loop;
|
|
|
|
this.manager.SetIsPlaying(true);
|
|
this.manager.RunAtTime(0);
|
|
|
|
};
|
|
|
|
/**
|
|
* Stops the currently playing animation.
|
|
*
|
|
* @method Phaser.GameObject.Creature#stop
|
|
* @memberof Phaser.GameObject.Creature
|
|
*/
|
|
Phaser.GameObject.Creature.prototype.stop = function () {
|
|
|
|
this.manager.SetIsPlaying(false);
|
|
|
|
};
|
|
|
|
/**
|
|
* @name Phaser.GameObject.Creature#isPlaying
|
|
* @property {boolean} isPlaying - Is the _current_ animation playing?
|
|
*/
|
|
Object.defineProperty(Phaser.GameObject.Creature.prototype, 'isPlaying', {
|
|
|
|
get: function() {
|
|
|
|
return this.manager.GetIsPlaying();
|
|
|
|
},
|
|
|
|
set: function(value) {
|
|
|
|
this.manager.SetIsPlaying(value);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
/**
|
|
* @name Phaser.GameObject.Creature#loop
|
|
* @property {boolean} loop - Should the _current_ animation loop or not?
|
|
*/
|
|
Object.defineProperty(Phaser.GameObject.Creature.prototype, 'loop', {
|
|
|
|
get: function() {
|
|
|
|
return this.manager.should_loop;
|
|
|
|
},
|
|
|
|
set: function(value) {
|
|
|
|
this.manager.SetShouldLoop(value);
|
|
|
|
}
|
|
|
|
});
|