ChubbRck

How to zoom out from center of game.world?

Recommended Posts

Hi there,

 

I'm trying to zoom out the entire game world from the center.. unfortunately I see no method for the camera for zooming out so I'm scaling the game.world directly with

this.game.world.scale.setTo(0.5, 0.5);

Unfortunately, this scales around the top left of the screen. I've tried setting the anchor on the game.world as well as the pivot to the center of the world or the center of the stage to no avail. Is it possible to achieve what I'm trying to do?

 

Thanks for any thoughts - 

 

Nick

Share this post


Link to post
Share on other sites

The camera doesn't support zooming natively right now - I'm afraid if you want this functionality you're going to have to code it yourself. It is of course possible but not without some understanding of the maths and techniques involved. You may want to Google for other frameworks that support this and have a go at replicating the way their cameras work, or wait for it to be supported in Phaser (which I'm sure it will eventually!).

 

Phaser is influenced by Flixel, a Flash AS3 library which has advanced cameras, so maybe it could be interesting to work out how that works?

Share this post


Link to post
Share on other sites

Thanks for the thoughts, lewster - 

 

Do you know if it is possible to scale the world around the center point? I know cameras in Phaser don't support zooming yet, but as a workaround I was hoping to scale the entire game.world. I just can't figure out how to set its anchor, origin, pivot, or whichever is needed.

 

Nick

Share this post


Link to post
Share on other sites

Eureka! This does actually work - example here: http://jsfiddle.net/lewster32/NMNJ7/ - added some rudimentary clipping too.

 

CAVEAT: Until body alignment with pivot is fixed in Phaser, this method will not work with collision. The issue is that Phaser's body positioning does not take into account pivot correctly.

Share this post


Link to post
Share on other sites

i can not manage to get the zoom out around the exact center point of the camera it has at the moment i invoke the zoom..  do you have an idea?

 

i have a world with different objects.. most of the time the camera follows the object... when i zoom out i want the camera to zoom out from the objects coordinates..  it always zooms out from the upper left corner and that looks very bad..

 

thank you !

Share this post


Link to post
Share on other sites

What I do in update() is apply the zoom to world.scale and calculate the new position based on the object's world position. The non-offset part of the value is scaled with world.scale, but not the point of focus (camCenter = offset within the camera view of the object you want to follow). I tween this.worldScale and this takes care of everything else: 

 

         var new = new Phaser.Point(this.math.interpolateFloat(this.lastCamPos.x, this.followedObject.x, this.camfollowfactor), this.math.interpolateFloat(this.lastCamPos.y, this.followedObject.y, this.camFollowFactor));         new.copy(this.lastCamPos);         this.world.scale.setTo(this.worldScale);         new.x = new.x * this.worldScale - this.camCenter.x;        new.y = new.y * this.worldScale - this.camCenter.y;         this.camera.setPosition(new.x, new.y);          

Share this post


Link to post
Share on other sites

puhh.. thank you for your input.. unfortunately i can not make sense out of your code or apply it to mine...  my camera jumps around and centers on whatever points it likes - just not the one point that was in the middle of the screen the moment i started the zoom... :(

 

just out of interest..  what is the camfollowfactor and where to you define lastcampos ?

Share this post


Link to post
Share on other sites

You should set camCenter to half your game width and height (or wherever in your view the object you are following is); lastCamPos is set right there in the code - you could probably do it with sprite.body.data.previousPosition as well. Cam follow factor is how much the camera lags behind, i currently have it set to 0.1 

Share this post


Link to post
Share on other sites

i just don't get it...   i can't think straight anymore..

 

i deleted everything in the game to make a clean showcase 

 http://test.xapient.net/phaser/springtest/indexzoom.html

 

you can zoom in/out with the letters A and O   and then grab the map with the mouse and move it around .. 

you will see that the camera zooms out from somewhere in the upper left corner and that this point constantly changes with the zoom level.. so the camera is moving around like crazy..

 

if you find some time to read the code (only one function is important where all the magic (not) happens)  :  i would very much appreciate it .. thank you!

 

i just want the camera to constantly focus on the exact middle of the view..  i don't care if it goes out of bounds to do this...

 

function updateLevelstatus(){    //desktop zoom    if (game.input.keyboard.isDown(Phaser.Keyboard.A) && (mapSizeMaxCurrent < mapSizeMax)) {mapSizeMaxCurrent += 16;}    else if (game.input.keyboard.isDown(Phaser.Keyboard.O) && (mapSizeMaxCurrent > worldwidth )) {  mapSizeMaxCurrent -= 16;    }    mapSizeMaxCurrent = Phaser.Math.clamp(mapSizeMaxCurrent, worldwidth , mapSizeMax); //prevent odd scalefactors - set a minimum and maximum scale value    worldScale = mapSizeMaxCurrent/mapSizeMax;    if (mapSizeMaxCurrent < mapSizeMax  ){        zoomed=true;        stageGroup.scale.set(worldScale);        currentBounds = new Phaser.Rectangle(0, 0, mapSizeX*worldScale, mapSizeY*worldScale);        game.camera.bounds=currentBounds; // update bounds to the actual size for the camera so it cannot move outside    }else{       currentBounds = new Phaser.Rectangle(0, 0, mapSizeX, mapSizeY);       game.camera.bounds=currentBounds;  // keep camera in bounds        if (stageGroup.scale.x != 1) {            zoomed=false;             stageGroup.scale.set(1);        }    }    if(zoomed === false){ }   else {         if(game.input.activePointer.isDown && !game.input.pointer2.isDown){   //move around the world            if (oldcamera) { game.camera.x += oldcamera.x - game.input.activePointer.position.x; game.camera.y += oldcamera.y - game.input.activePointer.position.y; }            oldcamera = game.input.activePointer.position.clone();        }        else {            oldcamera = null;           }    }}

Share this post


Link to post
Share on other sites

Here's my function that zooms in/out on the mouse pointer's current location. Perhaps passing in the center of the world in your application could work?

I'm adding all my sprites to a "scaler" group to help simulate zooming and I have an initial size of my world stored in this.mapWidth, this.mapHeight.

 

Light.Game.prototype.zoom = function(delta) {  var oldScale = this.scaler.scale.x;  // We always scale both co-ordinates equally.  var scale = oldScale + delta;  // Don't zoom out if the whole world is visible (clip it right on the edge).  scale = Math.max(scale, game.camera.view.width / this.mapWidth);  scale = Math.max(scale, game.camera.view.height / this.mapHeight);  var scaleCoef = scale / oldScale;  var scaledMouseX = game.input.mousePointer.worldX * scaleCoef;  var scaledMouseY = game.input.mousePointer.worldY * scaleCoef;  var deltaMouseX = scaledMouseX - game.input.mousePointer.worldX;  var deltaMouseY = scaledMouseY - game.input.mousePointer.worldY;  this.scaler.scale.set(scale);  game.world.width = scale * this.mapWidth;  game.world.height = scale * this.mapHeight;  game.camera.setBoundsToWorld();  game.camera.focusOnXY(      game.camera.view.centerX + deltaMouseX,      game.camera.view.centerY + deltaMouseY);};

Share this post


Link to post
Share on other sites

@wayfinder :   what do you mean with "here"  ? the link seems to work for me and zooming in and out too ? 

 

btw.  thx for your contributions ..  you helped me to figure out what i need to do..

 

i needed to store the actual camera center in a variable.  the trick was to store its value relative to the current world scale size

 

 

 

here is the code to zoom I/O and pan:

 

variables explanation:

worldwidth (canvas size x) 

mapSizeMaxCurrent (current size of the zoomed map in pixels - its always the smaller side of the map to avoid black bars later)

mapSizeMax (initial size of the smaller side of the map)

mapSizeX (map width)

mapSizeY (map height)

worldScale (current scale factor)

function updateLevelstatus(){    // zoom in/out with a/o    if (game.input.keyboard.isDown(Phaser.Keyboard.A) && (mapSizeMaxCurrent < mapSizeMax)) { mapSizeMaxCurrent += 32; }    else if (game.input.keyboard.isDown(Phaser.Keyboard.O) && (mapSizeMaxCurrent > worldwidth )) { mapSizeMaxCurrent -= 32; }    mapSizeMaxCurrent = Phaser.Math.clamp(mapSizeMaxCurrent, worldwidth , mapSizeMax);     worldScale = mapSizeMaxCurrent/mapSizeMax;    stageGroup.scale.set(worldScale);  // scales my stageGroup (contains all objects that shouldbe scaled)    if(game.input.activePointer.isDown && !game.input.pointer2.isDown){   //move around the world        if (oldcamera) {             game.camera.x += oldcamera.x - game.input.activePointer.position.x;             game.camera.y += oldcamera.y - game.input.activePointer.position.y;         }        oldcamera = game.input.activePointer.position.clone();        // store current camera position (relative to the actual scale size of the world)        rescalefactorx = mapSizeX / (mapSizeX * worldScale); // multiply by rescalefactor to get original world value        rescalefactory = mapSizeY / (mapSizeY * worldScale);        currentcamerapositionX = game.camera.view.centerX*rescalefactorx;        currentcamerapositionY = game.camera.view.centerY*rescalefactory;    }    else { //center camera on the point that was in the center of the view atm the zooming started        oldcamera = null;        if (!currentcamerapositionX){ // if not set yet (never zoomed)            currentcamerapositionX = game.camera.view.centerX;            currentcamerapositionY = game.camera.view.centerY;        }        followx = currentcamerapositionX*worldScale;        followy = currentcamerapositionY*worldScale;        game.camera.focusOnXY(followx, followy);    }}

and here is the example demo:

 http://test.xapient.net/phaser/springtest/indexzoom.html

 

:D  :ph34r:

Share this post


Link to post
Share on other sites

this is browser related.. if you open the debug tools it will seach for a .map file to map everything in the minimized version..

this is no showstopper at all.. just ignore it .. it has no influence on the demo..

 

zoom in or out with the letters A and O  and then use the mouse to move the world around..   i just tried the link and it works as intended

Share this post


Link to post
Share on other sites

Edit: Worked it out. If I multiply my world x and y positions by (1 / myZoom) it works! e.g.  for a zoom of .5 (zoomed out)

Edit 2: This was not a good idea in the end, please read the posts below.

newX = game.input.mousePointer.worldX * (1 / 0.5);newY = game.input.mousePointer.worldY * (1 / 0.5);

Eureka! This does actually work - example here: http://jsfiddle.net/lewster32/NMNJ7/ - added some rudimentary clipping too.

 

CAVEAT: Until body alignment with pivot is fixed in Phaser, this method will not work with collision. The issue is that Phaser's body positioning does not take into account pivot correctly.

 

Hi lewster32, I've been attempting to write a kind of SimCity game. I'm successfully drawing roads and panning around the game area. Unlike your example here, I'm just panning with the camera, and not touching pivot. However, when I start trying to zoom, the gameworld position doesn't update, and the road draws in the wrong place. Is this to do with your "CAVEAT" above? Or are you aware of a fancy way to translate word position with the zoom factor?

 

I've forked your fiddle here: http://jsfiddle.net/cvcqutgf/ and added mouse cursor debug;

 

If you hover your mouse over the stage, and pan/zoom around, you'll see that the world co-ordinates don't update (If you were just to move the camera without pivot they would). However, like I said my issue is the co-ordinates when zooming. Are you able to shed any light on this for me?

 

Cheers,

Share this post


Link to post
Share on other sites

Thanks NETANEL, I found the way I did it above was not great, and after some more research found this example on Stack Overflow: https://dl.dropboxusercontent.com/u/23574503/pixitests/index.html, Stack link

http://stackoverflow.com/questions/29035084/zoom-to-cursor-position-pixi-js

 

I liked this for its simplicity and ended up implementing this way, using a group and not altering the world like you've suggested. But I did not touch the pivot. The only issue now is that I can drag the main group off the boundary of the world. But it's not that big a deal at this stage in my development. I'm really only at prototyping phase. If I like your suggested method (to be seen) I will implement it though.

Share this post


Link to post
Share on other sites

This code allows you to zoom out, then center the camera to a desired point.

var zoomFactor = 0.5;
var cameraFocusX = 100;
var cameraFocusY = 200;

game.world.scale.setTo(zoomFactor);
game.camera.focusOnXY(cameraFocusX * game.world.scale.x, cameraFocuzY * game.world.scale.y);

If you want to zoom out from the center, set

var cameraFocusX = game.world.width / 2;
var cameraFocusY = game.world.height / 2;

EDIT:

Have in mind that after you zoom in/out (scale up/down the world),

sprite.collideWorldBounds = true;

will not work correctly. Also, if you want to get mouse X, Y coordinates based on world, instead of

var mouseWorldX = game.input.worldX;
var mouseWorldY = game.input.worldY;

you should use

var mouseWorldX = game.input.worldX / game.world.scale.x;
var mouseWorldY = game.input.worldY / game.world.scale.y;

However, sprite.events.onInputOver.add(callback) will work correctly whatever the world scale

Share this post


Link to post
Share on other sites

Hey guys! Just digging around in the source code and I think I found this in Camera.js:

   scale: {

        enumerable: true,

        get: function ()
        {
            return this.transform._scaleX;
        },

        set: function (value)
        {
            this.transform._scaleX = value;
            this.transform._scaleY = value;
            this.transform.dirty = true;
            this.transform.updateCache();
        }

    },

    scaleX: {

        enumerable: true,

        get: function ()
        {
            return this.transform._scaleX;
        },

        set: function (value)
        {
            this.transform._scaleX = value;
            this.transform.dirty = true;
            this.transform.updateCache();
        }

    },

But even though this doesn't range from a point. The camera itself is what is scaling, so whatever location it is at should be the place scaled. So how does that work, is this the solution to all of our problems? Let me know what you think, I can be an idiot sometimes and not notice crap.

Share this post


Link to post
Share on other sites
On 6/14/2014 at 5:40 PM, lewster32 said:

Eureka! This does actually work - example here: http://jsfiddle.net/lewster32/NMNJ7/ - added some rudimentary clipping too.

 

CAVEAT: Until body alignment with pivot is fixed in Phaser, this method will not work with collision. The issue is that Phaser's body positioning does not take into account pivot correctly.

Thanks @lewster32, i tried your idea and have some zooming working in the beginnings of a game.

When might body alignment with pivot be fixed in Phaser, as i'll need collision detection.  Or even better, when might native camera zooming appear in Phaser?

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.