Jump to content

[Help!] createFromObjects doesn't copy my object's custom properties


Scalemail Ted
 Share

Recommended Posts

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

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)1805035252_ScreenShot2018-05-10at1_54_08AM.thumb.png.a33d13d6c284c80767b9859c0b627f1b.png

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.

327443585_ScreenShot2018-05-10at1_52_04AM.thumb.png.5b741798b4a7d3742f38194c0ce97dba.png

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

2075572215_ScreenShot2018-05-10at1_52_59AM.thumb.png.2dca305881f6081fbd0e730b1d19e9fb.png

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

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) :

2047323856_ScreenShot2018-05-10at10_30_14AM.png.27c604ddfe35f255d763f272946069f6.png

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

  • Scalemail Ted changed the title to createFromObjects and tile's Object Layer properties

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 by Scalemail Ted
grammar
Link to comment
Share on other sites

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

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

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...