haelix

Tilemap & Offscreen Enemies Questions

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!

 

Share this post


Link to post
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
    });
}

 

Share this post


Link to post
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.

Share this post


Link to post
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

Share this post


Link to post
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);
            }
        }
    });
}

 

Share this post


Link to post
Share on other sites

after discussion with a colleague and after I read some articles then most likely finite state machine approach will be much better.. and in update function I will check only those which are supposed to be updated..

Share this post


Link to post
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
}

 

Share this post


Link to post
Share on other sites

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.

Guest
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.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.