Jump to content

preload entity object layers on Tiled, load in game later


Recommended Posts



I find Tiled incredibly convenient for entity placement, in addition to tilemapping obviously. 

My game requirements are to load NPCs at different quests. I'm aware you can easily add new Entities via code like this:

me.game.world.addChild(new MySprite());

But I'd rather define all the objects directly in Tiled, then render them with an option. Renderable offers the ability to setOpacity, but it doesn't seem to affect the visibility of the sprite.

Moreover, I'd rather just have it not be there, but have its space saved on the map ready to load it.

How can I best accomplish this? Perhaps I can create a spawn point object class and assign it an NPC ID?

game.FriendlyNPC = game.NPCEntity.extend({
    init: function(x, y, settings) {
        this._super(game.NPCEntity, "init", [x, y, settings]);


Screen Shot 2018-05-18 at 12.03.14 AM.png



Ended up using Spawn Entity location to spawn the NPC there

		let spawnEntity = me.game.world.getChildByProp('spawnID', 1)[0];

		var obj = {
			poolID : 'FriendlyNPC',
			x : spawnEntity.pos.x,
			y : spawnEntity.pos.y,
			data : {
				width: 16,
				height : 16,
				framewidth : 16,
				frameheight : 16

		var newEntity = me.pool.pull(obj.poolID, obj.x, obj.y, obj.data);
		newEntity.z = 44;


Link to comment
Share on other sites

What kind of events would trigger the entities to "actually load"? Would it be something that just happens nondeterministically, or when loading the map with certain state? If the latter, I would probably lean toward using a copy of the map with the various different states. I know this won't work for every situation, but it's definitely the easiest to implement.

For a longer-term solution, you might consider using the object layers supported by Tiled. IIRC, you can change the visibility (on/off, but melonJS just uses it to set the entity opacity to 0) and melonJS won't render invisible layers. But the entity would still be active and needs to be "disabled" or else it will continue to be updated and will be included in collision detection tests, etc.

One idea that just came to me is that each object layer can be implemented as a me.Container, if you pass options.flatten=false to me.levelDirector.loadLevel. In short, the most naïve approach is to grab the container reference by the layer's name in the options.onLoaded callback, then remove it from the scene and store it somewhere for later until you need it again. It might look something like this:

me.levelDirector.loadLevel('my_map', {
  flatten: false,
  onLoaded: () => {
    // Save an array of every layer named 'quest' to a global object
    game.quest_layers = me.game.world.getChildByName('quest');

    // Remove all of the quest layers from the scene
    game.quest_layers.forEach((layer) => {
      me.game.world.removeChild(layer, true); // The second arg preserves the layer

setTimeout(() => {
  // ... Some time passes and we can trigger the quest entities to appear
  // We'll just use a random layer index for illustration ...
  let x = Math.floor(Math.random() * game.quest_layers.length);

  // Remove the layer from the global array, and add it to the scene
  let layer = game.quest_layers.splice(x, 1);
}, 5000);

This is super simplified. A more complex implementation might take layers by multiple names, and store them in a hash map, or even iterate the entire world container looking for invisible containers... There's a lot that can be done to customize it, but the takeaway is that it's desirable to remove children from the scene graph, and add them back in later. And this can be done with the optional keepalive argument when removing children.

That might be a good place to start, anyway. Hope it helps.

Link to comment
Share on other sites

  • 3 weeks later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

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