Matoking

Changing game size to fit page

Recommended Posts

I just started using Phaser and so far I have really enjoyed using it. I, however, have one problem.

 

With the current project I'm making, I want the game to fill the element that is the parent of the game canvas. Instead of scaling the game screen, which causes the image to become stretched and anti-aliased, I want the game screen to be resized so that game area either becomes larger or smaller which allows more or less game sprites to be visible.

 

Is this possible?

Share this post


Link to post
Share on other sites

Yes, you can specify game canvas size when you create it, and I'm pretty sure you can change it on window resize event as well.

 

All you have to do is make sure your HTML BODY has 0 padding and set the game size to document.window.width and document.window.height.

Share this post


Link to post
Share on other sites

how about something like this:

<script type="text/javascript">                        // get users screen size            winW = document.body.offsetWidth;            winH = document.body.offsetHeight;                       (function () {            // set canvas to above size            var game = new Phaser.Game(winW, winH, Phaser.CANVAS, '', { preload: preload, create: create, update:update}); </script>   
        

When the game is launched the screen(browser window) height and width will grabbed and set as winH & winW, then phaser will create a canvas with the set size.

The only catch with this is if you resize the window after the game is running the canvas will stay the size that it was first created, which also makes this great for mobile devices.

 

There are a lot of ways to detect which devices and screen size your user is using, but from what it seems you are trying to do it shouldn't be needed if you use the code above.

 

 

Another simple fix would be to add a fullscreen option that will open up the game in a new window at what ever size you set it to. 

<html><head><script>function openGameWindow(){myWindow=window.open('http://www.html5gamedevs.com/topic/1637-107-progress-update/,,width=700,height=600');}</script></head><body><input type="button" value="Open window" onclick="openGameWindow()" /></body></html>

and then just set the canvas size to fit the screen.

Share this post


Link to post
Share on other sites

I probably didn't make it clear in the first post, but I want the game size to be resized even after the game has started. Since the game size seems to be set in stone after the game is started, I'm doubtful if it's doable without modifying the source code.

 

EDIT:

 

Okay, I figured out it's possible to change the screen size by making the default renderer Phaser.CANVAS and adding onresize event to body, which calls the following function.

 

It still has some minor problems, so it's not a full solution just yet. And since it essentially forces you to use canvas instead of WebGL it has quite a lot of performance implications.

 

EDIT 2:

Okay, I managed to get it to resize correctly when it's using canvas as a renderer. It would be useful if it worked with WebGL too, so I'll look into getting it to work too.

 

EDIT 3:

Alright, I figured out a solution that works with both rendering modes. Add the following line to the part where the game is started:

$(window).resize(function() { window.resizeGame(); } );

And the function in question:

function resizeGame() {var height = $(window).height();var width = $(window).width();	game.width = width;game.height = height;game.stage.bounds.width = width;game.stage.bounds.height = height;	if (game.renderType === Phaser.WEBGL){	game.renderer.resize(width, height);}}

Seems to work flawlessly, but there could be some unforeseen issues. I don't think Phaser was designed for this. :P

 

I use jQuery in the examples, but you should be able to get width and height of the window and add the onresize event handler using other methods, too.

Share this post


Link to post
Share on other sites

I tweaked this so now resizeGame looks like this:

(I use disabled AA, and window.inner* props which are better)

also the constant is different (Phaser.WEBGL == 2 not 1)

 

var resizeGame = function () {
 
  var height = window.innerHeight;
  var width = window.innerWidth;
 
  game.width = width;
  game.height = height;
  game.stage.bounds.width = width;
  game.stage.bounds.height = height;
 
  if (game.renderType === 1) {
    game.renderer.resize(width, height);
    Phaser.Canvas.setSmoothingEnabled(game.context, false);
  }
}

Share this post


Link to post
Share on other sites

I've tried my best to work this out but it doesn't seem to work for me. What am I doing wrong? My idea is to integrate it with a flexible-width Twitter's Bootstrap site.

 

This is based on the HelloPhaser example (using Phaser 2.0.3).

<!doctype html><html>  <head>    <meta charset="UTF-8" />    <title>hello phaser!</title>  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>    <script src="phaser.min.js"></script>  <script type="text/javascript">    window.onload = function() {          function resizeGame (game) {        if (game == null)          return;        var width = $(window).width();        var height = $(window).height();        game.width = width;        game.height = height;               game.stage.bounds.width = width;        game.stage.bounds.height = height;        game.world.setBounds(0, 0, width, height);        game.camera.setSize(width, height);        game.camera.setBoundsToWorld();        if (game.renderType === Phaser.WEBGL) {          game.renderer.resize(width, height);            }      }            function preload () {        game.load.image('logo', 'phaser.png');      }      function create () {        var logo = game.add.sprite(game.world.centerX, game.world.centerY, 'logo');        logo.anchor.setTo(0.5, 0.5);      }            var width = $(window).width();      var height = $(window).height();      var game = new Phaser.Game(width, height, Phaser.AUTO, 'phasercanvas', { preload: preload, create: create });      $(window).resize(function () {        resizeGame(game);      });    };  </script>  <style>    body {      margin: 0;      padding: 0;    }  </style>  </head>  <body>  <div id="phaserwrapper">    <div id="phasercanvas"></div>  </div>  </body></html>

Share this post


Link to post
Share on other sites

In case some of the other code doesn't work out as expected, I'm attaching something great and simple for Phaser 2.0.3 (by the time I'm writing this reply) at http://gamemechanicexplorer.com/ which is using Twitter's Bootstrap (what I also want to use).

function windowResize() {  // some other non-relevant code for our cause (I think)  // ...  if (game) {    game.scale.maxWidth = _EXAMPLEWIDTH;    game.scale.maxHeight = _EXAMPLEHEIGHT;    game.scale.setShowAll();    game.scale.refresh();  }}

 

Share this post


Link to post
Share on other sites

Seems the typescript definition for game.renderer is incorrect. Solved with (<any>this.game.renderer) for now.

 

In the example the game.stage.bounds is also incorrect (at least for Phaser 2.0.4).

 

Had to do something between lines  (we'll see if I need something else too, but for now it works):

 this.game.width = size.width; this.game.height = size.height; this.game.stage.width = size.width; this.game.stage.height = size.height; this.game.scale.width = size.width; this.game.scale.height = size.height; if (this.game.renderType === Phaser.WEBGL) {    (<any>this.game.renderer).resize(size.width, size.height); } // Tell ScaleManager that we have changed sizes (updates canvas styles) this.game.scale.setSize();

Share this post


Link to post
Share on other sites

I have revised my code and it needed some other additions. The game.debug seems to have off-screen canvas which needs resizing, hopefully there aren't many of these elsewhere. Revised magic:

this.game.width = size.width;this.game.height = size.height;this.game.canvas.width = size.width;this.game.canvas.height = size.height;this.game.world.setBounds(0, 0, size.width, size.height);this.game.scale.width = size.width;this.game.scale.height = size.height;this.game.camera.setSize(size.width, size.height);this.game.camera.setBoundsToWorld();// resize debug offscreen canvasif (this.game.debug.sprite) {    this.game.debug.sprite.removeStageReference();}this.game.debug.boot();(<any>this.game.renderer).resize(size.width, size.height);// Tell ScaleManager that we have changed sizesthis.game.scale.setSize();

It seems fine to call resize for both CANVAS and WEBGL renderers. Also noted that calling the game.debug.boot() would not remove the old sprite if one was already added, so we have to remove it first (maybe the boot() should be fixed regarding that). Other debug references should (correct me if I'm wrong) be GC'd automatically.

 

Hopefully this is helpful and I hope Phaser would allow this to be done easier way.

Share this post


Link to post
Share on other sites

A bit related to resizing things. I had tileSprite to fit the game size and those need to be resized as well if you don't want to stretch the image. Basically change the tileSprite width and height and then invalidate the PIXI texture:

 

this.object.width = size.width;this.object.height = size.height;// Invalidate the tile sprite textures(<any>this.object).tilingTexture = null;(<any>this.object).__tilePattern = null;

Seems to work fine and as far as I checked the PIXI code, it should trigger the texture generate on webgl and canvas properly as if the tileSprite was created freshly, except you don't have to worry adding it back to the stage/world.

 

Related offtopic: The TypeScript definition for game.make.tileSprite is incorrect. The frame parameter is not optional.

Share this post


Link to post
Share on other sites

Small warning and update to the code I posted before. the line managing the this.game.debug.sprite is slightly wrong and causes the debug sprite to be stacked on WebGL and decreasing render performance quickly (OSX, Chrome + WebGL). Revised code for that section should fix the issue:

            // resize debug offscreen canvas            if (this.game.debug.sprite) {                this.game.stage.removeChild(this.game.debug.sprite);                this.game.debug.sprite = null;                this.game.debug.textureFrame = null;                if (this.game.debug.texture) {                    this.game.debug.texture.destroy();                }                this.game.debug.texture = null;                if (this.game.debug.baseTexture) {                    this.game.debug.baseTexture.destroy();                }                this.game.debug.baseTexture = null;                this.game.debug.context = null;                this.game.debug.canvas = null;                this.game.debug.boot();            }

I'm not 100% sure if all the deinitialization code is needed as I'm not that familiar how PIXI handles the textures. This also points small issue with Phaser that calling game.debug.boot() multiple times on WebGL renderer causes sprite "leak".

Share this post


Link to post
Share on other sites

Hey guys, I've been messing around with the code above, trying to get a view working where the canvas resizes to fit the browser window when the user resizes it. I don't want to scale anything, but rather just reveal as much of the game world as possible to fit the screen.

 

I admit that it's kind of an odd use case, but would work really well for the types of games I'm trying to work on.

 

I'm running into some major problems, and I'm not sure if I'm just approaching it all wrong, but regardless, the resizing method Jouniii suggests doesn't seem to work for me at all.

 

Here is my example app:

http://mattguest.com/tmp/resize/index.html

 

It creates a game that is initially the size of the browser (this works great) and creates a tilemap. You can scroll using the arrow keys or by dragging. It takes a few seconds for the map to load, but once it's ready there will be a light grey box in all four corners of the map to make it clear where the bounds are.

 

If you don't resize the browser it all it works as expected - you can scroll to all four corners.

 

If you make the browser larger than it initially was, then the extra area doesn't get rendered (it remains black) but the camera takes the black area into account when figuring out the bounds.

 

If you make the browser smaller, then the view stops scrolling at a certain point but the camera debug info shows that the x and y position of the camera is moving, even though visually it stops updating.

 

When I inspect the page, the canvas element is being set to the correct size, and the camera debug info being printed is always correct as well. The bounds are being computed correctly, but the view is not matching what it says. It's easier to see the problem in action than to explain.

 

I'm not looking for a complete solution, I don't mind figuring it out, I'm mostly just wondering if I'm missing some basic concept of how the Phaser game world, view and camera interact. Is it just not possible to do what I'm trying to do with Phaser?

 

Here's the resize code I'm using (mostly from the above posts) In the example link I posted, this is wrapped in a timeout and invoked by the window resize event, but there doesn't seem to be any difference if I remove that complication.

function resizeGame() {    var size = {        width : window.innerWidth,        height : window.innerHeight    };    console.log('resizing to ', size.width, size.height);    Game.width = size.width;    Game.height = size.height;    Game.canvas.width = size.width;    Game.canvas.height = size.height;    Game.world.setBounds(0, 0, level.fullPixelW, level.fullPixelH);    Game.scale.width = size.width;    Game.scale.height = size.height;    if (Game.debug.sprite) {        Game.stage.removeChild(Game.debug.sprite);        Game.debug.sprite = null;        Game.debug.textureFrame = null;        if (Game.debug.texture) {            Game.debug.texture.destroy();        }        Game.debug.texture = null;        if (Game.debug.baseTexture) {            Game.debug.baseTexture.destroy();        }        Game.debug.baseTexture = null;        Game.debug.context = null;        Game.debug.canvas = null;        Game.debug.boot();    }    Game.renderer.resize(size.width, size.height);    Game.scale.setSize();    Game.camera.setSize(size.width, size.height);    Game.camera.setBoundsToWorld();    resizeTimeout = false;}

Anyway, if someone has some insight, or an example lying around of something like this working, I'd love to get more info.

 

thanks!

Share this post


Link to post
Share on other sites

jounii could you elaborate how you hooked up the resizing code with TypeScript? I'm wanting to make my game responsive to window resize as well but can't get it to work properly. Where did you place your resizing code and how are you calling it from the $(window).resize?

Share this post


Link to post
Share on other sites

jounii could you elaborate how you hooked up the resizing code with TypeScript? I'm wanting to make my game responsive to window resize as well but can't get it to work properly. Where did you place your resizing code and how are you calling it from the $(window).resize?

Better late than never.

 

Two places. state.init() and custom Phaser.Plugin postRender which looks up a "needs resizing" flag window.resize sets. Probably would change correctly, but I wanted to make sure it changes in that stage to prevent any issues.

Share this post


Link to post
Share on other sites

None of these solutions seem to work for me, on Phaser 2.3.0. The only thing I've managed to be able to do is shrink/stretch the canvas to fit the window. But I don't want shrinking/stretching, I just want the visible potion of the canvas to extend all the way to the window width on resize. It doesn't seem like it should be a difficult thing to do but I suppose 90% of Phaser games are for mobile so stuff like this is easily overlooked. 

 

Anyone have any simple solutions? You'd think something like this could/should be accomplished with one line of code. 

Share this post


Link to post
Share on other sites

Hi, I already posted this link several times here: http://sbcgamesdev.blogspot.cz/2015/04/phaser-tutorial-manage-different-screen.html

 

It is article on my blog about managing different screen sizes. My target was to avoid stretching as much as possible and also avoid letterboxing/pilars. Solution is to have small areas of image, that are visible only sometimes (depends on target device aspect). If these areas are not enough then stretching comes into play. I usually make it that I can handle iPhone to iPad aspect without stretching.

 

Solution is enclosed into separate class. Do not expect to find one line solution for such a complex problem. And while my solution works, I am happy with and use it in my games, it is not only possible solution and for some other situations there can be different ones. For example: if you have scrolling tile map - should your users see always the same portion of it or can they see more if they have wider display? Depends on game design...

Share this post


Link to post
Share on other sites

@samme thank you, seems to be by far the best solution.

Together with this it even works for the switch to fullscreen:

game.scale.fullScreenScaleMode = Phaser.ScaleManager.RESIZE

 

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.