Skip to content

Commit 3e2041a

Browse files
committed
Overhauled createFromObjects to make it much more useful. Fix phaserjs#3817 phaserjs#4613
1 parent 80287f6 commit 3e2041a

2 files changed

Lines changed: 180 additions & 49 deletions

File tree

src/tilemaps/Tilemap.js

Lines changed: 167 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ var Class = require('../utils/Class');
88
var DegToRad = require('../math/DegToRad');
99
var Extend = require('../utils/object/Extend');
1010
var Formats = require('./Formats');
11+
var GetFastValue = require('../utils/object/GetFastValue');
1112
var LayerData = require('./mapdata/LayerData');
1213
var Rotate = require('../math/Rotate');
1314
var SpliceOne = require('../utils/array/SpliceOne');
15+
var Sprite = require('../gameobjects/sprite/Sprite');
1416
var Tile = require('./Tile');
1517
var TilemapComponents = require('./components');
1618
var TilemapLayer = require('./TilemapLayer');
@@ -630,87 +632,188 @@ var Tilemap = new Class({
630632
},
631633

632634
/**
633-
* Creates a Sprite for every object matching the given gid in the map data. All properties from
634-
* the map data objectgroup are copied into the `spriteConfig`, so you can use this as an easy
635-
* way to configure Sprite properties from within the map editor. For example giving an object a
636-
* property of alpha: 0.5 in the map editor will duplicate that when the Sprite is created.
635+
* This method will iterate through all of the objects defined in a Tiled Object Layer and then
636+
* convert the matching results into Phaser Game Objects (by default, Sprites)
637637
*
638-
* Custom object properties not sharing names with the Sprite's own properties are copied to the
639-
* Sprite's {@link Phaser.GameObjects.Sprite#data data store}.
638+
* Objects are matched on one of 3 criteria: The Object ID, the Object GID or the Object Name.
639+
*
640+
* Within Tiled, Object IDs are unique per Object. Object GIDs, however, are shared by all objects
641+
* using the same image. Finally, Object Names are strings and the same name can be used on multiple
642+
* Objects in Tiled, they do not have to be unique.
643+
*
644+
* You set the configuration parameter accordingly, based on which type of criteria you wish
645+
* to match against. For example, to convert all items on an Object Layer with a `gid` of 26:
646+
*
647+
* ```javascript
648+
* createFromObjects(layerName, {
649+
* gid: 26
650+
* });
651+
* ```
652+
*
653+
* Or, to convert objects with the name 'bonus':
654+
*
655+
* ```javascript
656+
* createFromObjects(layerName, {
657+
* name: 'bonus'
658+
* });
659+
* ```
660+
*
661+
* Or, to convert an object with a specific id:
662+
*
663+
* ```javascript
664+
* createFromObjects(layerName, {
665+
* id: 9
666+
* });
667+
* ```
668+
*
669+
* You should only specify either `id`, `gid`, `name`, or none of them. Do not add more than
670+
* one criteria to your config. If you do not specify any criteria, then _all_ objects in the
671+
* Object Layer will be converted.
672+
*
673+
* By default this method will convert objects into `Sprite` instances, but you can override
674+
* this by providing your own class type:
675+
*
676+
* ```javascript
677+
* createFromObjects(layerName, {
678+
* gid: 26,
679+
* classType: Coin
680+
* });
681+
* ```
682+
*
683+
* This will convert all Objects with a gid of 26 into your custom `Coin` class. You can pass
684+
* any class type here, but it _must_ extend `Phaser.GameObjects.GameObject` as its base class.
685+
* Your class will always be passed 1 parameter: `scene`, which is a reference to either the Scene
686+
* specified in the config object or, if not given, the Scene to which this Tilemap belongs.
687+
*
688+
* All properties from object are copied into the Game Object, so you can use this as an easy
689+
* way to configure properties from within the map editor. For example giving an object a
690+
* property of `alpha: 0.5` in Tiled will be reflected in the Game Object that is created.
691+
*
692+
* Custom object properties that do not exist as a Game Object property are set in the
693+
* Game Objects {@link Phaser.GameObjects.GameObject#data data store}.
694+
*
695+
* You can use set a `container` property in the config. If given, the class will be added to
696+
* the Container instance instead of the Scene.
697+
*
698+
* Finally, you can provide an array of config objects, to convert multiple types of object in
699+
* a single call:
700+
*
701+
* ```javascript
702+
* createFromObjects(layerName, [
703+
* {
704+
* gid: 26,
705+
* classType: Coin
706+
* },
707+
* {
708+
* id: 9,
709+
* classType: BossMonster
710+
* },
711+
* {
712+
* name: 'lava',
713+
* classType: LavaTile
714+
* }
715+
* ]);
716+
* ```
717+
*
718+
* The signature of this method changed significantly in v3.50.0. Prior to this, it did not take config objects.
640719
*
641720
* @method Phaser.Tilemaps.Tilemap#createFromObjects
642721
* @since 3.0.0
643722
*
644-
* @param {string} name - The name of the object layer (from Tiled) to create Sprites from.
645-
* @param {(integer|string)} id - Either the id (object), gid (tile object) or name (object or
646-
* tile object) from Tiled. Ids are unique in Tiled, but a gid is shared by all tile objects
647-
* with the same graphic. The same name can be used on multiple objects.
648-
* @param {Phaser.Types.GameObjects.Sprite.SpriteConfig} spriteConfig - The config object to pass into the Sprite creator (i.e.
649-
* scene.make.sprite).
650-
* @param {Phaser.Scene} [scene=the scene the map is within] - The Scene to create the Sprites within.
723+
* @param {string} objectLayerName - The name of the Tiled object layer to create the Game Objects from.
724+
* @param {Phaser.Types.Tilemaps.CreateFromObjectLayerConfig|Phaser.Types.Tilemaps.CreateFromObjectLayerConfig[]} config - A CreateFromObjects configuration object, or an array of them.
651725
*
652-
* @return {Phaser.GameObjects.Sprite[]} An array of the Sprites that were created.
726+
* @return {Phaser.GameObjects.GameObject[]} An array containing the Game Objects that were created. Empty if invalid object layer, or no matching id/gid/name was found.
653727
*/
654-
createFromObjects: function (name, id, spriteConfig, scene)
728+
createFromObjects: function (objectLayerName, config)
655729
{
656-
if (spriteConfig === undefined) { spriteConfig = {}; }
657-
if (scene === undefined) { scene = this.scene; }
730+
var results = [];
658731

659-
var objectLayer = this.getObjectLayer(name);
732+
var objectLayer = this.getObjectLayer(objectLayerName);
660733

661734
if (!objectLayer)
662735
{
663-
console.warn('Cannot create from object. Invalid objectgroup name given: ' + name);
736+
console.warn('createFromObjects: Invalid objectLayerName given: ' + objectLayerName);
664737

665-
if (typeof layerID === 'string')
666-
{
667-
console.warn('Valid objectgroup names:\n\t' + this.getObjectLayerNames().join(',\n\t'));
668-
}
738+
return results;
739+
}
669740

670-
return null;
741+
if (!Array.isArray(config))
742+
{
743+
config = [ config ];
671744
}
672745

673746
var objects = objectLayer.objects;
674-
var sprites = [];
675747

676-
for (var i = 0; i < objects.length; i++)
748+
for (var c = 0; c < config.length; c++)
677749
{
678-
var found = false;
679-
var obj = objects[i];
750+
var singleConfig = config[c];
751+
752+
var id = GetFastValue(singleConfig, 'id', null);
753+
var gid = GetFastValue(singleConfig, 'gid', null);
754+
var name = GetFastValue(singleConfig, 'name', null);
755+
756+
var obj;
757+
var toConvert = [];
680758

681-
if (obj.gid !== undefined && typeof id === 'number' && obj.gid === id ||
682-
obj.id !== undefined && typeof id === 'number' && obj.id === id ||
683-
obj.name !== undefined && typeof id === 'string' && obj.name === id)
759+
// Sweep to get all the objects we want to convert in this pass
760+
for (var s = 0; s < objects.length; s++)
684761
{
685-
found = true;
762+
obj = objects[s];
763+
764+
if (
765+
(id === null && gid === null && name === null) ||
766+
(id !== null && obj.id === id) ||
767+
(gid !== null && obj.gid === gid) ||
768+
(name !== null && obj.name === name)
769+
)
770+
{
771+
toConvert.push(obj);
772+
}
686773
}
687774

688-
if (found)
775+
// Now let's convert them ...
776+
777+
var classType = GetFastValue(singleConfig, 'classType', Sprite);
778+
var scene = GetFastValue(singleConfig, 'scene', this.scene);
779+
var container = GetFastValue(singleConfig, 'container', null);
780+
var texture = GetFastValue(singleConfig, 'key', null);
781+
var frame = GetFastValue(singleConfig, 'frame', null);
782+
783+
for (var i = 0; i < toConvert.length; i++)
689784
{
690-
var config = Extend({}, spriteConfig, obj.properties);
785+
obj = toConvert[i];
691786

692-
config.x = obj.x;
693-
config.y = obj.y;
787+
var sprite = new classType(scene);
694788

695-
var sprite = scene.make.sprite(config);
789+
sprite.setName(obj.name);
790+
sprite.setPosition(obj.x, obj.y);
791+
sprite.setTexture(texture, frame);
696792

697-
sprite.name = obj.name;
793+
if (obj.width)
794+
{
795+
sprite.displayWidth = obj.width;
796+
}
698797

699-
if (obj.width) { sprite.displayWidth = obj.width; }
700-
if (obj.height) { sprite.displayHeight = obj.height; }
798+
if (obj.height)
799+
{
800+
sprite.displayHeight = obj.height;
801+
}
701802

702-
// Origin is (0, 1) in Tiled, so find the offset that matches the Sprite's origin.
703-
// Do not offset objects with zero dimensions (e.g. points).
803+
// Origin is (0, 1) in Tiled, so find the offset that matches the Sprites origin.
804+
// Do not offset objects with zero dimensions (e.g. points).
704805
var offset = {
705806
x: sprite.originX * obj.width,
706807
y: (sprite.originY - 1) * obj.height
707808
};
708809

709-
// If the object is rotated, then the origin offset also needs to be rotated.
810+
// If the object is rotated, then the origin offset also needs to be rotated.
710811
if (obj.rotation)
711812
{
712813
var angle = DegToRad(obj.rotation);
814+
713815
Rotate(offset, angle);
816+
714817
sprite.rotation = angle;
715818
}
716819

@@ -722,23 +825,38 @@ var Tilemap = new Class({
722825
sprite.setFlip(obj.flippedHorizontal, obj.flippedVertical);
723826
}
724827

725-
if (!obj.visible) { sprite.visible = false; }
828+
if (!obj.visible)
829+
{
830+
sprite.visible = false;
831+
}
726832

833+
// Set properties the class may have, or setData those it doesn't
727834
for (var key in obj.properties)
728835
{
729-
if (sprite.hasOwnProperty(key))
836+
if (sprite[key] !== undefined)
837+
{
838+
sprite[key] = obj.properties[key];
839+
}
840+
else
730841
{
731-
continue;
842+
sprite.setData(key, obj.properties[key]);
732843
}
844+
}
733845

734-
sprite.setData(key, obj.properties[key]);
846+
if (container)
847+
{
848+
container.add(sprite);
849+
}
850+
else
851+
{
852+
scene.add.existing(sprite);
735853
}
736854

737-
sprites.push(sprite);
855+
results.push(sprite);
738856
}
739857
}
740858

741-
return sprites;
859+
return results;
742860
},
743861

744862
/**
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @typedef {object} Phaser.Types.Tilemaps.CreateFromObjectLayerConfig
3+
* @since 3.50.0
4+
*
5+
* @property {number} [id] - A unique Object ID to convert.
6+
* @property {number} [gid] - An Object GID to convert.
7+
* @property {string} [name] - An Object Name to convert.
8+
* @property {Phaser.GameObjects.GameObject} [classType=Phaser.GameObjects.Sprite] - A custom class type to convert the objects in to.
9+
* @property {Phaser.Scene} [scene] - A Scene reference, passed to the Game Objects constructors.
10+
* @property {Phaser.GameObjects.Container} [container] - Optional Container to which the Game Objects are added.
11+
* @property {(string|Phaser.Textures.Texture)} [key] - Optional key of a Texture to be used, as stored in the Texture Manager, or a Texture instance.
12+
* @property {(string|integer)} [frame] - Optional name or index of the frame within the Texture.
13+
*/

0 commit comments

Comments
 (0)