Jump to content

Creating a mini map in Phaser?


ForgeableSum
 Share

Recommended Posts

Anyone have examples of how to do a mini map in phaser? 

 

One way I thought of doing it was to create a separate canvas element and copy the scaled down contents of the game world into it. Problem with this approach is there's no way (that I know of) to copy an entire canvas including the non-visible parts (non-visible to the window). So if the game is larger than the window size, you run into trouble. 

 

Thoughts? Appreciate any advice. 

Link to comment
Share on other sites

I would think that you could scale down the image/sprite to achieve the reduced view of the map, then you can treat it as a separate object and place items inside. Or if you create a group and place items exactly where you want them and then scale the whole group the items will remain in their exact locations. 

Link to comment
Share on other sites

Phaser is not very good at seperation of game objects and display objects. Most of the time they are the same. What you need to do is separate your game objects from display objects and then you can just have 2 display objects for the same game object. Both display objects can be sprites with a different texture and thus you can make a minimap of sorts.

Link to comment
Share on other sites

Is it a tile-based game?  I am doing it by assigning a color for each tile and drawing the minimap onto a BitmapData object.

 

In create():

// the static mapvar miniMapBmd = this.game.add.bitmapData(g_game.tileMap.width*g_game.miniMapSize, g_game.tileMap.height*g_game.miniMapSize);// g_game.miniMapSize is the pixel size in the minimap// iterate my map layersfor (l=0; l<g_game.tileMap.layers.length; l++) {   for (y = 0; y < g_game.tileMap.height; y++) {      for (x = 0; x < g_game.tileMap.width; x++) {         var tile = g_game.tileMap.getTile(x, y, l);         if (tile && g_game.tileMap.layers[l].name == 'Ground') {            // fill a pixel in the minimap            miniMapBmd.ctx.fillStyle = '#bc8d6b';            miniMapBmd.ctx.fillRect(x * g_game.miniMapSize, y * g_game.miniMapSize, g_game.miniMapSize, g_game.miniMapSize);         }         else if ... other types of tiles      }   }}g_game.miniMap = this.game.add.sprite(x, y, miniMapBmd);// dynamic bmd where I draw mobile stuff like friends and enemies g_game.miniMapOverlay = this.game.add.bitmapData(g_game.tileMap.width*g_game.miniMapSize, g_game.tileMap.height*g_game.miniMapSize);this.game.add.sprite(g_game.miniMap.x, g_game.miniMap.y, g_game.miniMapOverlay);

And then I draw dynamic stuff on the minimap in update()

g_game.miniMapOverlay.context.clearRect(0, 0, g_game.miniMapOverlay.width, g_game.miniMapOverlay.height);g_game.soldiers.forEach(function(soldier) {   g_game.miniMapOverlay.rect(Math.floor(soldier.x / TILE_SIZE) * g_game.miniMapSize, Math.floor(soldier.y / TILE_SIZE) * g_game.miniMapSize, g_game.miniMapSize, g_game.miniMapSize, color);});g_game.miniMapOverlay.dirty = true; 

Working pretty well so far for Super Combat Squadron:

CDuhQGzUkAEmNz-.png

Link to comment
Share on other sites

Sanjin, I actually had this idea. Problem is my tiles can't really be represented by a single hex. They have complicated color schemes. See screenshot:

 

GvB0Wns.png

 

 

Aside from that, they are not tiles. There is a grid system for placing static game objects (e.g. trees). However, there are also game objects which move off the grid (namely, units). Walkable terrain (e.g. roads, grass, leaves) does not conform to any grid system. Because of this, I'm thinking copying the entire canvas, scaled down, is my best (and perhaps only) option. If anyone has examples/implementations of this for a game world which doesn't fit inside the window, I'd love to see them. 

Link to comment
Share on other sites

  • 6 months later...

How was this accomplished finally in Feudal Wars?

I accomplished it with a render texture which represents the game world. I use a graphic to update units and game objects and the terrain layer is rendered every 300 milli or so. Normally you wouldn't have to update the terrain layer, because most maps are static. But my map changes in the map editor so I constantly re-render it. Works like a charm. 

 

function createMiniMap() {    miniMapContainer = game.add.group();    resolution = 2 / gameSize;    if (game.world.width > 8000) {        var renderWH = 8000;    } else {        var renderWH = game.world.width;    }    renderTexture = game.add.renderTexture(renderWH, renderWH);    renderTexture.resolution = resolution;    var cropRect = new Phaser.Rectangle(0, 0, 200, 200);    renderTexture.crop = cropRect;    var miniMapY = game.camera.view.height - (game.world.height * resolution);    var miniMapUI = game.add.image(0, 0, 'mini_map');    renderTexture.trueWidth = renderTexture.resolution * game.world.width;    renderTexture.trueHeight = renderTexture.resolution * game.world.height;    var cropRect = new Phaser.Rectangle(0, 0, renderTexture.trueWidth, renderTexture.trueHeight);    renderTexture.crop = cropRect;    var miniWidth = .075 * renderTexture.trueWidth;    var miniHeight = miniMapY - (.06 * renderTexture.trueHeight);    miniMap = game.add.sprite(miniWidth, miniHeight, renderTexture);    var padding = .241 * renderTexture.trueHeight;    miniMapUI.width = (renderTexture.trueWidth + padding);    miniMapUI.height = (renderTexture.trueHeight + padding);    miniMapUI.y = game.camera.view.height - miniMapUI.height;    miniMapUI.fixedToCamera = true;    miniMap.fixedToCamera = true;    viewRect = game.add.graphics(0, 0);    viewRect.lineStyle(1, 0xFFFFFF);    viewRect.drawRect(miniMap.x, miniMap.y, game.camera.view.width * resolution, game.camera.view.height * resolution);    unitDots = game.add.graphics(miniMap.x, miniMap.y);    unitDots.fixedToCamera = true;    var bg = game.add.graphics(0, 0);    bg.beginFill(0x000000, 1);    bg.drawRect(0, miniMapUI.y + (miniMapUI.height * .1), miniMapUI.width * .95, miniMapUI.height * .9);    bg.fixedToCamera = true;    var children = [bg, miniMap, unitDots, viewRect, miniMapUI];    miniMapContainer.addMultiple(children);}function updateUnitDots() {    unitDots.clear();    gameObjects.forEach(function(object) {        var unitMiniX = object.x * renderTexture.resolution;        var unitMiniY = object.y * renderTexture.resolution;        var objectType = object.objectType;        if (objectType == 'unit' || objectType == 'building' || objectType == 'wall') {            if (playerColors[object.player - 2] == undefined) {                // player 1                var color = '0x1331a1';            } else {                var color = playerColors[object.player - 2].color;            }            unitDots.beginFill(color);            if (objectType == 'building') {                unitDots.drawRect(unitMiniX, unitMiniY, 5, 5);            } else {                unitDots.drawEllipse(unitMiniX, unitMiniY, 1.5, 1.5);            }        } else if (objectType == 'plant') { // tree            unitDots.beginFill(0x2A4B17);            unitDots.drawEllipse(unitMiniX, unitMiniY, 2, 2);        } else {            var color = '0x666666'; // gray            unitDots.beginFill(color);            unitDots.drawRect(unitMiniX, unitMiniY, 5, 5);        }    });}

 

You can catch a glimpse of the mini map working in the game trailer

Link to comment
Share on other sites

  • 1 year later...
On 21/11/2015 at 3:49 AM, feudalwars said:

I accomplished it with a render texture which represents the game world. I use a graphic to update units and game objects and the terrain layer is rendered every 300 milli or so. Normally you wouldn't have to update the terrain layer, because most maps are static. But my map changes in the map editor so I constantly re-render it. Works like a charm. 

 


function createMiniMap() {    miniMapContainer = game.add.group();    resolution = 2 / gameSize;    if (game.world.width > 8000) {        var renderWH = 8000;    } else {        var renderWH = game.world.width;    }    renderTexture = game.add.renderTexture(renderWH, renderWH);    renderTexture.resolution = resolution;    var cropRect = new Phaser.Rectangle(0, 0, 200, 200);    renderTexture.crop = cropRect;    var miniMapY = game.camera.view.height - (game.world.height * resolution);    var miniMapUI = game.add.image(0, 0, 'mini_map');    renderTexture.trueWidth = renderTexture.resolution * game.world.width;    renderTexture.trueHeight = renderTexture.resolution * game.world.height;    var cropRect = new Phaser.Rectangle(0, 0, renderTexture.trueWidth, renderTexture.trueHeight);    renderTexture.crop = cropRect;    var miniWidth = .075 * renderTexture.trueWidth;    var miniHeight = miniMapY - (.06 * renderTexture.trueHeight);    miniMap = game.add.sprite(miniWidth, miniHeight, renderTexture);    var padding = .241 * renderTexture.trueHeight;    miniMapUI.width = (renderTexture.trueWidth + padding);    miniMapUI.height = (renderTexture.trueHeight + padding);    miniMapUI.y = game.camera.view.height - miniMapUI.height;    miniMapUI.fixedToCamera = true;    miniMap.fixedToCamera = true;    viewRect = game.add.graphics(0, 0);    viewRect.lineStyle(1, 0xFFFFFF);    viewRect.drawRect(miniMap.x, miniMap.y, game.camera.view.width * resolution, game.camera.view.height * resolution);    unitDots = game.add.graphics(miniMap.x, miniMap.y);    unitDots.fixedToCamera = true;    var bg = game.add.graphics(0, 0);    bg.beginFill(0x000000, 1);    bg.drawRect(0, miniMapUI.y + (miniMapUI.height * .1), miniMapUI.width * .95, miniMapUI.height * .9);    bg.fixedToCamera = true;    var children = [bg, miniMap, unitDots, viewRect, miniMapUI];    miniMapContainer.addMultiple(children);}function updateUnitDots() {    unitDots.clear();    gameObjects.forEach(function(object) {        var unitMiniX = object.x * renderTexture.resolution;        var unitMiniY = object.y * renderTexture.resolution;        var objectType = object.objectType;        if (objectType == 'unit' || objectType == 'building' || objectType == 'wall') {            if (playerColors[object.player - 2] == undefined) {                // player 1                var color = '0x1331a1';            } else {                var color = playerColors[object.player - 2].color;            }            unitDots.beginFill(color);            if (objectType == 'building') {                unitDots.drawRect(unitMiniX, unitMiniY, 5, 5);            } else {                unitDots.drawEllipse(unitMiniX, unitMiniY, 1.5, 1.5);            }        } else if (objectType == 'plant') { // tree            unitDots.beginFill(0x2A4B17);            unitDots.drawEllipse(unitMiniX, unitMiniY, 2, 2);        } else {            var color = '0x666666'; // gray            unitDots.beginFill(color);            unitDots.drawRect(unitMiniX, unitMiniY, 5, 5);        }    });}

 

You can catch a glimpse of the mini map working in the game trailer

I know this is old, but what does gameSize refer to when setting the value to the resolution variable?

Link to comment
Share on other sites

4 hours ago, billmo said:

I know this is old, but what does gameSize refer to when setting the value to the resolution variable?

It's the game world width/height divided by 100 (game.world.width / 100); 

I should note that my techniques for rendering a mini map have since evolved from the time of my post. I no longer render the entire terrain layer to the map every x number of milliseconds. I do that for units (anything that moves), but for the terrain, I have a simple render texture the exact size of the mini map and render the tiles (transformed to fit the scaled position and resolution/scale of the mini map) whenever a tile changes. 

However, for the purposes of most simple games, my old technique should do fine. 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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