Scalemail Ted Posted May 10, 2018 Share Posted May 10, 2018 I am using createFromObjects (Link to API) to create a collection of Sprites from the object layer imported from a Tiled JSON file. I have successfully created the collection of sprites, however, I seem to be missing some critical data from these newly created Sprite objects. The original JSON tile data has a 'properties' field containing a unique key_id for each particular 'key' tile which appears to not copy over with this method invocation. Is there a way to get these 'properties' values from the object layer into each of the new Sprite objects? Link to comment Share on other sites More sharing options...
Scalemail Ted Posted May 10, 2018 Author Share Posted May 10, 2018 So according to the documentation createFromObjects is suppose to copy over the 'properties' attributes from the map data Quote Creates a Sprite for every object matching the given gid in the map data. All properties from the map data objectgroup are copied into the `spriteConfig`, so you can use this as an easy way to configure Sprite properties from within the map editor. For example giving an object a property of alpha: 0.5 in the map editor will duplicate that when the Sprite is created. So I dug into the source code for createFromObjects and inserted some logging to see the config data before making a sprite and after. You can see in my screenshot, that I added some console.logs on lines 71802 and 71804 in phaser.js, where respecitvely I console.log(config) and then console.log(sprite) The resulting output in my console for the config object is shown below. You can clearly see that the 'properties' attribute of key_id is there. But when I display the resulting Sprite object constructed from that config object, it does not have either a key_id attribute or a properties field Am I missing something simple? Shouldn't the key_id be an attribute in this new Sprite object? Link to comment Share on other sites More sharing options...
Scalemail Ted Posted May 10, 2018 Author Share Posted May 10, 2018 So, I've delved deeper into this rabbit hole, tracing into the source code for the methods responsible for constructing the Sprite objects. As can be seen in the previous post, on line 71803 in createFromObjects each Sprite object is constructed by invoking the factory method this.scene.make.sprite(config) where the config object that is passed contains the following attributes: {key, frame, key_id, x , y}. Note that the key_id is inserted into the config object via the Extend( {}, config, obj.properties ), where key_id is defined within the properties field of obj. So tracing back into the make.sprite method using a config object as an argument (link to source) : There is an invocation to the method GetAdvancedValue passing 'key', and 'frame' to get the corresponding values from the config object and then a new Sprite object is instantiated using as the parameter list: scene object, x, y, key, and frame. Then a call to BuildGameObject (link to code) is made, where the config object is passed to it. [Note: This method is too large to directly post so I've linked it]. It appears the keys that BuildGameObject explicitly seeks to define within the created gameObject are: x, y, depth, flipX, flipY, scale, scrollFactor, rotation, angle, alpha, origin, scalemode, blendmode, visible, add. So as best as I can tell the factory method used to create Sprite objects from a configuration object ignores all other fields besides the ones explicitly listed above, thus my key_id attribute is never added into the Sprite object. Is this a correct understanding of the sequence of calls? If so, is there a way to have additional attributes in the config object to be added to the Sprite object? Or more precisely, how can I get the key_id (within properties) to get added into the resultant Sprite object when importing from a Object Layer (via Tiled JSON)? Link to comment Share on other sites More sharing options...
Scalemail Ted Posted May 11, 2018 Author Share Posted May 11, 2018 (edited) I found a Phaser 3 lab example using createFromObjects: https://labs.phaser.io/edit.html?src=src\game objects\tilemap\static\create from objects.js However, it does not cover my use case as this example's Object Layer's properties object strictly contains an 'alpha' field, which is one of the keys that is explicitly checked by the BuildGameObject method, as stated in my previous post. (Link to example's JSON, where the only property defined in object layer is alpha) Is there example code for the Phaser 3 createFromObjects method where the properties object includes some non-graphics biased data, such as some event-triggering property. Or is this not an intended use case for the Phaser 3 createFromObject method? In Phaser 2, it appears that Sprites would inherit all of the 'properties' defined within the Object Layer, because it does the following for-loop (link to Phaser 2 source code) : Quote for (var property in obj.properties) { group.set(sprite, property, obj.properties[property], false, false, 0, true); } Is there a reason why it appears that Phaser 3's createFromObject seems to omit this? If so, is there a known alternative to produce a similar result as Phaser 2's createFromObject method? Edited May 11, 2018 by Scalemail Ted grammar Link to comment Share on other sites More sharing options...
wkd-aine Posted May 14, 2018 Share Posted May 14, 2018 I'm updating a game from Phaser 2 to Phaser 3 and needed this functionality, I grabbed the createFromObjects function from Phaser2 and updated it as below to add the props.data from the JSON to the new sprite object. I'm also adding my own Custom class like you used to be able to do with Phaser 2 as well, but you should be able to see that and pull it out fairly easily. I just added this to a scene helper file I have, I didn't update the core library in anyway and am currently using 3.7.1 function createFromObjects( scene, name, id, customClass, spriteConfig) { if( spriteConfig == undefined ) spriteConfig = {} var objectLayer = scene.map.getObjectLayer(name); if (!objectLayer) { console.warn('Cannot create from object. Invalid objectgroup name given: ' + name); return; } var objects = objectLayer.objects; var sprites = []; for (var i = 0; i < objects.length; i++) { var found = false; var obj = objects[i]; if (obj.gid !== undefined && typeof id === 'number' && obj.gid === id || obj.id !== undefined && typeof id === 'number' && obj.id === id || obj.name !== undefined && typeof id === 'string' && obj.name === id) { found = true; } if (found) { var config = Object.assign(spriteConfig, obj.properties); config.x = obj.x; config.y = obj.y; let sprite if( customClass != undefined ) { sprite = new customClass( config ) } else { sprite = scene.make.sprite( config ) } sprite.name = obj.name; if (obj.width) { sprite.displayWidth = obj.width; } if (obj.height) { sprite.displayHeight = obj.height; } // Origin is (0, 1) in Tiled, so find the offset that matches the Sprite's origin. var offset = { x: sprite.originX * sprite.displayWidth, y: (sprite.originY - 1) * sprite.displayHeight }; // If the object is rotated, then the origin offset also needs to be rotated. if (obj.rotation) { var angle = DegToRad(obj.rotation); Rotate(offset, angle); sprite.rotation = angle; } if (obj.flippedHorizontal !== undefined || obj.flippedVertical !== undefined) { sprite.setFlip(obj.flippedHorizontal, obj.flippedVertical); } if (!obj.visible) { sprite.visible = false; } sprites.push(sprite); } } return sprites; } And the function is called like below: createFromObjects( scene, 'objects', 200, Reward, { scene: scene } ) Good luck Link to comment Share on other sites More sharing options...
Scalemail Ted Posted May 16, 2018 Author Share Posted May 16, 2018 Thanks wkd-aine, this is a similar solution to what I had done, but yours is more elegant by just overriding the createFromObjects method. I had originally created a helper function within the scene to add the properties into my objects after they had been grouped, so i was iterating over all the elements twice >_<: addPropertiesToObject( gid, objGroup ) { var props = this.map.filterObjects('objects', (obj) => {if (obj.gid === gid) return obj} ) for (var index in objGroup) { Object.assign( objGroup[index], props[index].properties ); } } Link to comment Share on other sites More sharing options...
Recommended Posts