Jump to content

Pooling a large number of tiles


Gryz
 Share

Recommended Posts

I am building a tile based game with procedural generated worlds that contain a large number of tiles.

I have this working by using Phaser's Tiled integration to dynamically create tile maps, e.g.

const map = this.game.add.tilemap('world');

const tile = new Phaser.Tile(...)

map.layers[0].data = [tile, ...];

The world is represented as a matrix of tiles.

But due to memory usage, I need restrict the number of tiles using an object pool. My idea is to break the world matrix into sub-matrices, loading them into memory from disk (using web workers and IndexedDb). The tiles would be loaded into memory according to their proximity to the player as he moves through the world-- tiles close to the player, but outside of the viewport, would overwrite tiles in the object pool that are further away and outside the viewport.

My question is whether this can work with Phaser's rendering engine. I tried changing a tile's attributes after loading the map, and the new attributes seem to take effect when the screen is re-rendered when a sprite moves. My assumption is that new tiles updated in the object pool will be shown correctly when they are re-rendered after becoming visible again in the viewport.

Link to comment
Share on other sites

I use this kind of Pool (based on the work of NIKLAS BERG in http://metroid.niklasberg.se/2016/02/29/making-a-custom-pool-class-by-extending-phaser-group/)

 

My implementation is very  similar :

import { Spawnable } from 'app/phaser/spawnable'

export class Pool extends Phaser.Group {

    public sprites:Array<Phaser.Sprite>;

    constructor(game: Phaser.Game, private spriteType: typeof Spawnable, instances: number, name: string) {
        super(game, game.world, name, false, true, Phaser.Physics.ARCADE);
        this.initializePool(instances);
    }

    private initializePool(instances) {
        this.sprites = new Array();
        if (instances <= 0) {
            return;
        } // We don't need to add anything to the group
        for (var i = 0; i < instances; i++) {
            let sprite = this.add(new this.spriteType(this.game)); // Add new sprite
            sprite.poolId = i;
            this.sprites.push(sprite);
        }
    }

    public createNew(x: number, y: number, data?: Object) {
        let obj: Spawnable = this.getFirstDead(false);
        if (!obj) {
            console.log('createNew');
            obj = new this.spriteType(this.game);
            this.add(obj, true);
        }
        obj.spawn(x, y, data);
        return obj;
    }
}

//Note I had to extends de Phaser.Sprite Class
export class Spawnable extends Phaser.Sprite {

// decorator for Typescript
    constructor(game: Phaser.Game, x?: number, y?: number, texture?: string) {
        super(game, x, y, texture);
    }

    spawn(x: number, y: number, data?: any) {
        this.reset(x, y);
        this.data = data;
        this.exists = true;
        this.alive = true;
    }
}

So when i want to "kill" a pooled sprite, I just need  to hide it and flag it as dead

//initializePool
this.SomeSpritePool = new Pool(game, SomeSprite, 200, 'visibleMarker');

// pick a new Sprite
let theSomeSprite = this.SomeSpritePool.createNew(x, y)

...
// killing it
theSomeSprite.alive = false;
theSomeSprite.visible = false;

 

Link to comment
Share on other sites

  • 4 weeks later...

A follow up to this. I am rendering a large world and pooling only tile objects that need to be displayed on screen. The general idea is to keep a buffer of tiles offscreen, and reposition them in the direction the player is moving in, updating their attributes to the new tiles to be displayed.

Can this be done via update() in Phaser? This code seems to lag behind, probably because it doesn't use a time delta:

Quote

update() {

    // Get the distance that the player has moved since last frame.

    const distanceX = this.player.sprite.x - this.prevPlayerX;
    const distanceY = this.player.sprite.y - this.prevPlayerY;
    this.prevPlayerX = this.player.sprite.x;
    this.prevPlayerY = this.player.sprite.y;

    ...

    if (Math.abs(distanceX) > delta) {
        // Reposition buffer of tiles and update tile attributes
    }

}

Is the alternative to create my own time-based loop?

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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