Jump to content

Tilemap & Offscreen Enemies Questions


haelix
 Share

Recommended Posts

I had a few questions about Tilemap's implementation and some general questions about having a player walk around a top-down 2d "overworld" and having enemies hundreds of pixels offscreen that the player would eventually walk near.

Question 1: Using Tiled to generate a tilemap, is there a maximum size that you can generate using Phaser.Tilemap? I've read 2048x2048 are limits for some mobile devices for an actual "tilesheet" or images, but is there any max size for the map you can generate in Tiled and use in Phaser? 

Question 2: Does the Tilemap implementation render tiles only in the viewport or maybe a tile or two "offscreen" as a buffer? It doesn't render the entire map and layers? Are offscreen tiles receiving update events (ex: if a tile had its own water animation) or are only the in-viewport tiles receiving update calls?

Question 3: Assuming my "Enemy" class on update just walks back and forth until it "spots" the Player, when initializing the tilemap, should I be creating/adding my Enemy classes and placing them way offscreen outside the viewport at initialization and they wont take update/moving/rendering until they're in the viewport? Or should I be listening to viewport xy changes and "spawn" enemies as they walk into the viewport?  While the player is moving, are the Enemies actually moving around or do they not start getting those update events until they're inside the viewport? Basically, do Sprites added to a tilemap layer but off screen exist and are able to do things or do they have to be in the viewport for the tilemap to update them?

I've found several examples of how to build Tilemap levels platforming and such, but when it's used in this context with other actors existing as children of a tilemap layer, I haven't found much. Anyone know of any good examples of this?

Thanks!

 

Link to comment
Share on other sites

Interested in points 2 and 3 as well..

If we talk about point 3 then its probably worth to mention that in my case I created concept map in Tiled with just grass and stones plus 3 objects.. everything is handled by createFromObjects function and all these 3 objects are added to the same group.. I need to loop through them in create function and sadly also in update function.. however two of the objects share same sprite and they have same gid and one of those two is off screen.. when they are added by createFromObjects function autoCull parameter is set to true.. forEach function loops through that one as well anyway.. 
it would mean that all objects (enemies or whatever) are added in the beginning and are updated all the time if this approach is used..

probably there is another approach with which not all objects in group are updated when update function is called but didnt find it yet

EDIT: I guess sprite.inCamera property can help
EDIT2: in this example http://phaser.io/examples/v2/tilemaps/create-from-objects question mark and exit "tiles" disappear when they are off screen.. move slowly and you will see that once camera view passes the middle of tile it just go invisible

This is what I mean

function preload() {
    game.load.atlas('terrain', 'resources/images/terrain/terrain.png', 'resources/images/terrain/terrain.json', Phaser.Loader.TEXTURE_ATLAS_JSON_HASH);
    game.load.atlas('characters', 'resources/images/characters/characters.png', 'resources/images/characters/characters.json', Phaser.Loader.TEXTURE_ATLAS_JSON_HASH);

    game.load.tilemap('staticMap', 'resources/map/map.json', null, Phaser.Tilemap.TILED_JSON);
}


function create() {
    // Create map
    var map = game.add.tilemap('staticMap');
    map.addTilesetImage('terrain', 'terrain');

    // Create layers
    grass = map.createLayer('Grass');
    stones = map.createLayer('Stones');

    // Create characters group
    charactersGroup = game.add.group();
    charactersGroup.enableBody = true;

    // Create characters
    // Two of the objects have same gid but different names
    map.createFromObjects('Characters', 11, 'characters', 'jim/walk/down/01', true, false, charactersGroup);
    map.createFromObjects('Characters', 47, 'characters', 'bob/walk/down/01', true, true, charactersGroup);

    // Initialize character
    charactersGroup.forEach(function (character) {
        // some setup
        // here all 3 objects are available
    });
}


function update() {
    charactersGroup.forEach(function (character) {
        // random moving code
        // again all 3 objects are updated
    });
}

 

Link to comment
Share on other sites

It looks like TilemapLayer tries to render only relevant/visible portions. But any Sprites follow Phaser's normal rules: they update unless exists=false, animate unless visible=false. So your enemies will behave the same whether they're in viewport or not.

Link to comment
Share on other sites

I have set condition in my update function so it checks if sprite/character is in viewport.. 

but still I dont like the idea of looping through all characters in an update function just to check if they are inCamera and to get them moving

Link to comment
Share on other sites

I am starting to think that this whole approach is not correct.. it can get pretty slow if there are many NPCs

In create function I set loop so NPC checks every 5 seconds if its in camera view and moving.. if in camera view but standing then it generates random point where to go (can be off screen) and sets isMoving flag to true.. Then in update function I check (in every frame) for isMoving flag and if its true then NPC starts traversing the generated path (array of points)

Whole idea is that every 5 seconds I can set character to isMoving state and update function will start moving NPC on next call.. I added simple code with comments so you can imagine what I mean

 

function create() {
    // Every 5 seconds check if character is in viewport and moving
    // If yes and not moving then get random path where to go
    game.time.events.loop(5000, function () {
        if(character.inCamera) {
            if (!characters[character.name].isMoving) {
                // Here we generate path for character (pathfinding)
                // And set isMoving flag to true
                getPath(character);
            }
        }
    }, this);
}

function update() {
    charactersGroup.forEach(function (character) {
        // Stop character from physical movement
        character.body.velocity.set(0);

        if(character.inCamera) {
            // If character has isMoving flag set to true (set by getPath func) then traverse path
            if (characters[character.name] && characters[character.name].isMoving) {
                // Move to next tile in path array
                // Last tile set isMoving flag to false
                traversePath(character);
                playAnimation(character);
            }
        }
    });
}

 

Link to comment
Share on other sites

as I said.. I will use finite state machine for NPCs

in general I will have an object or any kind of "grouping functionality" where I keep data about my NPCs.. for example if I have two states "walk" and "idle" I will need to do physical update of position only for those NPCs which are in "walk" state.. in separate function/class I will be handling state change and viewport checks

 

something like this

function create () {
    // create NPCs
    // init state machine
}


function update () {
    // forEach of to be updated NPCs do something
    group.forEach(function (npc) {
        // move to x,y
    }
}


function stateMachine (npcs) {
    // for each of npcs check if in viewport
    // set the state and
    // assign to "group" or do something else
}

 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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