Jump to content

Downscaling


rich
 Share

Recommended Posts

You can scale a game down for sure. Here is the method I use:

 

I have a file I call Boot.ts which sets the game up, here is an example from a recent BBC game:

/// <reference path="../../../phaser/Phaser/Game.ts" />/// <reference path="../../../phaser/Phaser/State.ts" />/// <reference path="Preloader.ts" />module SarahAndDuck {    export class Boot extends Phaser.State {        constructor(game: Phaser.Game) {            super(game);            this.game.stage.scaleMode = Phaser.StageScaleMode.SHOW_ALL;            this.game.stage.disableVisibilityChange = true;            this.game.input.maxPointers = 1;            this.game.stage.disablePauseScreen = true;            this.game.stage.scale.minWidth = 480;            this.game.stage.scale.minHeight = 260;            this.game.stage.scale.maxWidth = 1024;            this.game.stage.scale.maxHeight = 672;            this.game.stage.scale.pageAlignHorizontally = true;            if (this.game.device.android && this.game.device.chrome == false)            {                this.game.stage.scaleMode = Phaser.StageScaleMode.EXACT_FIT;                this.game.stage.scale.maxIterations = 1;            }        }        public preload() {            this.load.image('title', 'assets/1024/title.jpg');            this.load.image('loaderFull', 'assets/1024/loader-full.png');            this.load.image('loaderEmpty', 'assets/1024/loader-empty.png');            this.load.image('orientation', 'assets/1024/orientation.jpg');            this.load.image('cbeebies', 'assets/1024/cbeebies-logo.png');        }        public create() {            this.game.stage.enableOrientationCheck(true, false, 'orientation');            this.game.switchState(SarahAndDuck.Preloader);        }    }}function boot() {    var sarahandduck = new Phaser.Game(this, null, 1024, 672);    sarahandduck.switchState(SarahAndDuck.Boot);}window.onload = function() {	boot();}

What this does is create a game at 1024 x 672 in size (iPad resolution basically) but that will scale down quite happily, to a minimum of 480x260. It also disables the pause screen and visibility change monitor (not needed on mobile) and aligns the game in the middle of the page. Finally it loads up a few assets which are used to create the loading progress bar and background in my Preloader.ts class.

Link to comment
Share on other sites

Oh and in case you are wondering here is what my Preloader.ts looks like:

/// <reference path="../../../phaser/Phaser/Game.ts" />/// <reference path="../../../phaser/Phaser/State.ts" />/// <reference path="MainMenu.ts" />/// <reference path="Sound.ts" />module SarahAndDuck {    export class Preloader extends Phaser.State {        constructor(game: Phaser.Game) {            super(game);        }        public loaderFull: Phaser.Sprite;        public loaderEmpty: Phaser.Sprite;        public preload() {            this.add.sprite(0, 0, 'title');            this.add.sprite(430, 550, 'cbeebies');            this.loaderEmpty = this.add.sprite(315, 460, 'loaderEmpty');            this.loaderEmpty.crop = new Phaser.Rectangle(0, 0, this.loaderEmpty.width, this.loaderEmpty.height);            this.loaderEmpty.name = 'loaderEmpty';            this.loaderFull = this.add.sprite(315, 460, 'loaderFull');            this.loaderFull.crop = new Phaser.Rectangle(0, 0, 0, this.loaderFull.height);            this.loaderFull.name = 'loaderFull';            this.load.atlas('ui', 'assets/1024/ui.png', 'assets/1024/ui.json');            this.load.image('help', 'assets/1024/help.jpg');            this.load.image('paused', 'assets/1024/paused.png');            this.load.image('background', 'assets/1024/background.jpg');            this.load.image('frameSmall', 'assets/1024/frame-small.png');            this.load.image('frameLarge', 'assets/1024/frame-large.png');            this.load.image('welldone', 'assets/1024/welldone.png');            //  Puzzle "Thumbnails"            this.load.image('puzzle1', 'assets/1024/puzzle1_full.jpg');            this.load.image('puzzle2', 'assets/1024/puzzle2_full.jpg');            this.load.image('puzzle3', 'assets/1024/puzzle3_full.jpg');            this.load.image('puzzle4', 'assets/1024/puzzle4_full.jpg');            this.load.image('puzzle5', 'assets/1024/puzzle5_full.jpg');            this.load.image('puzzle6', 'assets/1024/puzzle6_full.jpg');            //  Puzzle "Selection Page Frames"            this.load.image('puzzleFrame1', 'assets/1024/puzzle1_select.png');            this.load.image('puzzleFrame2', 'assets/1024/puzzle2_select.png');            this.load.image('puzzleFrame3', 'assets/1024/puzzle3_select.png');            this.load.image('puzzleFrame4', 'assets/1024/puzzle4_select.png');            this.load.image('puzzleFrame5', 'assets/1024/puzzle5_select.png');            this.load.image('puzzleFrame6', 'assets/1024/puzzle6_select.png');            this.load.audio('sound', ['assets/audio/jigsaw.m4a', 'assets/audio/jigsaw.mp3', 'assets/audio/jigsaw.ogg']);            this.load.onFileComplete.add(this.fileLoaded, this);        }        public fileLoaded(progress: number) {            this.loaderEmpty.crop.left = (395 / 100) * progress;            this.loaderFull.crop.width = (395 / 100) * progress;        }        public create() {            SarahAndDuck.Sound.init(this.game);            this.game.switchState(SarahAndDuck.MainMenu);        }    }}

Most of this file is obviously just a list of assets for the Loader, but the fileLoaded function is the bit that displays the progress bar. It works by using the crop value of a sprite to limit how much of the sprite is rendered without distorting the shape. So effectively acting like a mask. loaderEmpty is cropped from the left, and loaderFull is cropped from the right. The graphics are attached to make it more clear.

 

post-1-0-57974800-1377423023.png

post-1-0-22730600-1377423024.png

 

Link to comment
Share on other sites

Thats pretty much biggest problem for me - no idea how to handle it with Phaser.

According to this thread:

http://www.html5gamedevs.com/topic/1112-what-is-the-best-resolution-for-a-html5-game/

320x480 is best resolution to develop for, however I would much more prefer to do 960x640, and go down from there.

 

Problem is - I have no idea how to :)

I tried to find example in test suite for this, but nothing there on matter.

 

Alternatively - should I make game in both of those resolutions and use prefered one to gain speed boost? So for example if w/h would be lower than retina, then use non-retina assets.

Link to comment
Share on other sites

Sorry I replied in another thread, so have moved my posts here (which is why they appear above your original post!)

 

No problem, thanks for very fast and detailed reply :)

Ive edited my post with additional question - should i worry about downscaled game performance from iphone 4 resolution on iphone 3? Will it hit hard?

Link to comment
Share on other sites

Wow on top of that I quite dont understand how preloader works :)

Since there is no embeddding like in flash, how do you access those loading images without loading them first?

add.sprite(315, 460, 'loaderEmpty');

Does that work like "poor mans" embedding? It basically hangs executing rest of the script until image is downloaded then resumed from that point doing rest of the script (doing actual concurrent loading that doesnt make browser go blank screen because it cant proceed without asset)

Link to comment
Share on other sites

Yup totally correct - it loads in a couple of tiny images used for the preloader and then switches to the Preloader state.

 

As for performance - it depends on the game type. Sometimes scaling down hits performance a lot and sometimes you don't notice it at all. Most of our games these days are made at "high" resolution and then scaled down unless they require lots of scrolling / things moving, then we do a low res build as well.

Link to comment
Share on other sites

Rich im wondering - since your game has:

this.game.stage.scale.maxWidth = 1024;
this.game.stage.scale.maxHeight = 672;

 

How does it upscale beyond this? Is StageScaleMode.SHOW_ALL the magic here?

Also im bit puzzled why is there EXACT_FIT on android devices - those have very different resolutions, wont it result in distortion of images due to different aspect ratio?

 

Im sorry, its just that scaling to various devices seem like problematic task. I would like to reposition buttons myself via code to one of 5 anchors (corners and middle of screen), and scale art as much as possible, showing a bit more of gameplay or less in worst case rather than have blackbars on either side of screen.

Link to comment
Share on other sites

For this specific game we didn't want the graphics to scale beyond what they were designed at (1024 x 672) hence the max limit. On higher resolutions the game will have borders.

 

EXACT_FIT was set only for non-Chrome Android browsers, because the stock Android browser is so frigging terrible we found this helped things out quite a bit in this specific case. You probably don't need it.

Link to comment
Share on other sites

Ok, understood, once again makes perfect sense :)

Ive spent whole day on familiarizing myself with workflow and im pretty happy with results although:

 

Cant figure out how to approach multi resolution development that doesnt end up with black bars like SHOW_ALL will do. I would love to scale game to the max possible height, and just show more of the width so it would loose aspect ratio but wouldnt result with black bars.

 

Im sorry if my questions are starting to get annoying. I had this figured out with action script but workflow here is quite different and it isnt making it easier to adjust ideas i've developed in past.

 

 

EDIT:

Ok so far so good - Ive come up with this equation

var w = window.innerWidth;var h = window.innerHeight;var s = h / 640;var diffW = (w - (960 * s)) / svar game = new Phaser.Game(this, null, 960 + diffW, 640);

Should I put it somewhere so if game gets rescaled by user, rotated or something it wont get messed up ? I guess width/height that are passed as arguments are game.stage.width and game.stage.height values.

Link to comment
Share on other sites

Cant figure out how to approach multi resolution development that doesnt end up with black bars like SHOW_ALL will do. I would love to scale game to the max possible height, and just show more of the width so it would loose aspect ratio but wouldnt result with black.

Did you try EXACT_FIT ? I rhink it does just that.

Link to comment
Share on other sites

Could you clarify what you're trying to do? Do you want the canvas to take up ALL available pixel space? I.e. if the resolution is 1024x672 then you want a canvas sized to that? And if the game is then run on a device at 480x320 should the canvas be shrunk to that size? The way it works at the moment is that it creates a fixed size canvas (the size given in the Phaser.Game constructor) and then uses CSS to alter the width/height of the canvas for the device. EXACT_FIT does that without caring about the aspect ratio (based on the given size in the constructor) where-as SHOW_ALL sets the CSS width/height but maintains aspect ratio. So if you've started the game with a ratio that doesn't quite fit the device it will letter box it (either at the top or down the sides depending on available screen space).

 

The problem with the canvas not being a fixed size is that you then need to control sprite placement carefully yourself, i.e. a sprite placed at 500px X may appear in one screen but not a smaller one. However I think what I'll do is add a 4th scale mode that does just this and then it's up to your code to work out the best placement for the objects, perhaps a few helper functions like "right-align" could be useful here.

Link to comment
Share on other sites

Yeah that's what I thought. Phaser doesn't support this, sorry. It's not actually as simple as just "show more game world". You'd need to scale ALL in-game graphics as well. For example a logo designed to fill a 480x320 screen would look tiny on a tablet, so it'd need scaling up. I guess there would need to be some kind of internal scale factor that is applied to all graphics and coordinates and then you still need the ability to scale objects on-top of this as well. So almost as if the game doesn't use pixel values for positioning at all, but more like some arbitrary value (meters? inches?) like you usually find in 3D packages.

 

It would certainly be a powerful solution, but is incredibly hard to implement well imho.

Link to comment
Share on other sites

Yeah that's what I thought. Phaser doesn't support this, sorry. It's not actually as simple as just "show more game world". You'd need to scale ALL in-game graphics as well. For example a logo designed to fill a 480x320 screen would look tiny on a tablet, so it'd need scaling up. I guess there would need to be some kind of internal scale factor that is applied to all graphics and coordinates and then you still need the ability to scale objects on-top of this as well. So almost as if the game doesn't use pixel values for positioning at all, but more like some arbitrary value (meters? inches?) like you usually find in 3D packages.

 

It would certainly be a powerful solution, but is incredibly hard to implement well imho.

 

So far Im having luck with using that equation I posted yesterday. After Im done I might as well post full code of utilities package I will create. 

Done this in flash already and its VERY messy and specific use-case only. It works best with games that are horizontal scroll titles. Probably could adjust it to support vertical as well but honestly - its not day to day use type of scaling.

 

Would it be possible to get some signal hook after all engine resizing has been done? Pre and Post resize would be incredible to have to. I would just put some update function in state to reposition buttons by myself after scale has been handled.

Link to comment
Share on other sites

for some reason, the following code:

if (this.game.device.android && this.game.device.chrome == false){   this.game.stage.scaleMode = Phaser.StageScaleMode.EXACT_FIT;   this.game.stage.scale.maxIterations = 1;}

Gives weird results on my Android phone (stock browser): the game starts fine, if I rotate it in landscape mode it shows the OrientationScreen correctly, but when I rotate it back to portrait screen the game doesn't scale well to the screen, it becomes bigger than the screen. Removing this code makes the game work fine.

Link to comment
Share on other sites

  • 2 weeks later...
  • 6 months later...

Just as a warning to future readers of this thread, it looks like "switchState" has been removed from the API, you should use "state.start" instead...

I just lost an hour to that thinking that there was sth. wrong with my way of extending the state prototype but i could find no reference to switchState in the source code, so ....

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

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