Add Tiled animation support to TilemapLayer.

This commit is contained in:
Ben Richards 2024-08-19 12:28:27 +12:00
parent 1a45ac8eea
commit 16abedf87b
4 changed files with 189 additions and 1 deletions

View file

@ -329,6 +329,26 @@ var TilemapLayer = new Class({
* @since 3.0.0
*/
/**
* The time elapsed since timer initialization.
* This drives the animation of the texture.
*
* @name Phaser.Tilemaps.TilemapLayer#timeElapsed
* @type {number}
* @since 3.90.0
*/
this.timeElapsed = 0;
/**
* Whether the animation timer is paused.
*
* @name Phaser.Tilemaps.TilemapLayer#timePaused
* @type {boolean}
* @since 3.90.0
* @default false
*/
this.timePaused = false;
this.setTilesets(tileset);
this.setAlpha(this.layer.alpha);
this.setPosition(x, y);
@ -339,6 +359,23 @@ var TilemapLayer = new Class({
this.initPostPipeline(false);
},
// Overrides Game Object method
addedToScene: function ()
{
this.scene.sys.updateList.add(this);
},
// Overrides Game Object method
removedFromScene: function ()
{
this.scene.sys.updateList.remove(this);
},
preUpdate: function (time, delta)
{
this.updateTimer(time, delta);
},
/**
* Populates the internal `tileset` array with the Tileset references this Layer requires for rendering.
*
@ -1488,6 +1525,63 @@ var TilemapLayer = new Class({
return this.tilemap.worldToTileXY(worldX, worldY, snapToFloor, point, camera, this);
},
/**
* Pauses or resumes the animation timer for this game object.
*
* @method Phaser.Tilemaps.TilemapLayer#setTimerPaused
* @since 3.90.0
* @param {boolean} [paused] - Pause state (`true` to pause, `false` to unpause). If not specified, the timer will unpause.
* @return {this} This game object.
*/
setTimerPaused: function (paused)
{
this.timePaused = !!paused;
return this;
},
/**
* Reset the animation timer for this game object.
*
* @method Phaser.Tilemaps.TilemapLayer#resetTimer
* @since 3.90.0
* @param {number} [ms=0] - The time to reset the timer to.
* @return {this} This game object.
*/
resetTimer: function (ms)
{
if (ms === undefined) { ms = 0; }
this.timeElapsed = ms;
return this;
},
/**
* Update the timer for this game object.
* This is called automatically by the preUpdate method.
* The timer drives the animation of the texture.
*
* Override this method to create more advanced time management,
* or set it to a NOOP function to disable the timer update.
* If you want to control animations with a tween or input system,
* disabling the timer update could be useful.
*
* @method Phaser.Tilemaps.TilemapLayer#updateTimer
* @since 3.90.0
* @param {number} time - The current time in milliseconds.
* @param {number} delta - The time since the last update, in milliseconds.
* @return {this} This game object.
*/
updateTimer: function (time, delta)
{
if (!this.timePaused)
{
this.timeElapsed += delta;
}
return this;
},
/**
* Destroys this TilemapLayer and removes its link to the associated LayerData.
*

View file

@ -63,6 +63,8 @@ var TilemapLayerWebGLRenderer = function (renderer, src, drawingContext)
var submitterNode = src.customRenderNodes.Submitter || src.defaultRenderNodes.Submitter;
var transformerNode = src.customRenderNodes.Transformer || src.defaultRenderNodes.Transformer;
var timeElapsed = src.timeElapsed;
for (var i = 0; i < tileCount; i++)
{
var tile = renderTiles[i];
@ -74,7 +76,14 @@ var TilemapLayerWebGLRenderer = function (renderer, src, drawingContext)
continue;
}
var tileTexCoords = tileset.getTileTextureCoordinates(tile.index);
var tileIndex = tileset.getAnimatedTileId(tile.index, timeElapsed);
if (tileIndex === null)
{
continue;
}
var tileTexCoords = tileset.getTileTextureCoordinates(tileIndex);
var tileWidth = tileset.tileWidth;
var tileHeight = tileset.tileHeight;

View file

@ -194,6 +194,20 @@ var Tileset = new Class({
* @since 3.0.0
*/
this.texCoordinates = [];
/**
* The number of frames above which a tile is considered to have
* many animation frames. This is used to optimize rendering.
* If a tile has fewer frames than this, frames are searched using
* a linear search. If a tile has more, frames are searched using
* a binary search.
*
* @name Phaser.Tilemaps.Tileset#animationSearchThreshold
* @type {number}
* @since 3.90.0
* @default 64
*/
this.animationSearchThreshold = 64;
},
/**
@ -269,6 +283,61 @@ var Tileset = new Class({
);
},
/**
* Returns the ID of the tile to use, given a base tile and time,
* according to the tile's animation properties.
*
* If the tile is not animated, this method returns the base tile ID.
*
* @method Phaser.Tilemaps.Tileset#getAnimatedTileId
* @since 3.90.0
* @param {number} tileIndex - The unique id of the tile across all tilesets in the map.
* @param {number} milliseconds - The current time in milliseconds.
* @return {?number} The tile ID to use, or null if the tile is not contained in this tileset.
*/
getAnimatedTileId: function (tileIndex, milliseconds)
{
if (!this.containsTileIndex(tileIndex)) { return null; }
var animData = this.getTileData(tileIndex);
if (!(animData && animData.animation)) { return tileIndex; }
milliseconds = milliseconds % animData.animationDuration;
var anim = animData.animation;
var frame = null;
// Binary search.
var low = 0;
var high = anim.length - 1;
var mid = 0;
var startTime = 0;
while (low <= high)
{
mid = (low + high) >>> 1;
frame = anim[mid];
startTime = frame.startTime;
if (startTime <= milliseconds && startTime + frame.duration > milliseconds)
{
return frame.tileid + this.firstgid;
}
if (startTime < milliseconds)
{
low = mid + 1;
}
else
{
high = mid - 1;
}
}
return null;
},
/**
* Returns the texture coordinates (UV in pixels) in the Tileset image for the given tile index.
* Returns null if tile index is not contained in this Tileset.

View file

@ -96,6 +96,22 @@ var ParseTilesets = function (json)
(datas[tile.id] || (datas[tile.id] = {})).type = tile.type;
}
}
// Sum up animation length.
for (var tileId in datas)
{
var animData = datas[tileId].animation;
if (animData)
{
var animTime = 0;
for (var j = 0; j < animData.length; j++)
{
animData[j].startTime = animTime;
animTime += animData[j].duration;
}
datas[tileId].animationDuration = animTime;
}
}
}
if (Array.isArray(set.wangsets))