Jump to content

Responsive scene


Recommended Posts

Im trying to make app that will work fine on any screen. That means any resolution and any aspect ratio. I have canvas that fill 100% width and height of viewport. Problem is that renderer has absolute dimensions and it fits to canvas. Its fine when aspect ratio is same, but view is deformed on different ratios - and I dont want that.


I have managed to make something that tentatively holds shape, but is far from looking same on any screen. I will describe my approach here and would be happy if you will tell me about yours. Or some best practices, if there are any. So, here is what I have done:


  1. I set size of renderer same as viewport (window.innerWidth and window.innerHeight)
  2. I have some default project size as base (1280 x 900) as reference frame for absolute positioning and scaling
  3. I have percentage of width and height, so I can place items relatively on screen
  4. Sprites are placed on scene both relatively (x% from top and left) and absolutely (most time x% + number of pixels). Absolute positioning is there because there was problem to fit sprites near each other and not overlap them
  5. Sprites are anchored in center (0.5, 0.5)
  6. Sprite size is modified by mean of width and height of viewport compared to project base size (viewport of 1280 x 900 is same as project original size, so modifier is 1. 900 x 1280 would be 1 too. 640 x 900 would be 0.75, because width is 0.5 and height is 1...)
  7. It is not a problem if something goes off screen on left/right, but scene should cover full view, so no "white spaces" or letterbox anywhere.

I may upload example, but its experiment of everything about pixi, so there is shitload of other things that have nothing to do with this issue and would be pain to remove that, so I hope my description is sufficient.


When I look at this after few days, its quite complicated and it should be more simple... I hope. Worst problem I see is fitting sprites in different aspect ratios proportionally without breaking composition of scene. My current solution is just breaking composition little bit.


So, what is better way to do this?

Link to comment
Share on other sites

I'm not exactly sure what you're getting at, it sounds like you want it to look *exactly* the same on any screen, but that just isnt going to work, if I resize my browser to 1000x1000 its never going to look the same as viewport of 1280x800.


If you just want to scale up or down then pixi containers have a scale attribute.


Other wise, dont worry too much about your viewport and just have your world render and the viewport simply reveals and restricts your game world. By that, I mean that a 600x600 viewport sees a square of the world, whilst a 1000x600 shows the same square plus the parts of your world to the left and right (or just left, or just right, however you like).


For one-screen games this is more complicated but you simply cant make a 'square' scene fit onto a rectangular stage without letterboxing or stretch/squish.


It sounds like you're vastly over-complicating things.

Link to comment
Share on other sites

Overcomplicating things - that is my big curse :)


Show 600x600 of 1000x600 world is fine. But how do I do that? If I let renderer fit canvas and canvas is 100% of viewport, it just deforms it contents (so, it squish 1000x600 to be 600x600 instead of cropping).

Link to comment
Share on other sites

I think the problem you might be having is converting world co-ords into screen coords, but PIXI can do most of this for you.


This is the only example I've got publicly that might help explain it. The code can be found here, although this is library code, the example code can be found here.


The example just draws stars on to a pixi container, each star having an `x` and `y` coordinate in world space. The only slight confusion here is that I've shifted the container so that when you load the page world 0,0 is centralised on the page. If you use the arrow keys to move around then you’re moving your world coordinates, with the container shifting in the opposite direction to give the illusion of movement. So, for example, you move 10 units to the right and the star position is still 0,0, although it appears on-screen at -10,0. As I'm shifting the container I dont much care about that star's screen x,y, all I care about is its world transform. As you scroll more stars are created (and destroyed, well, they are just moved but pretend its creation/destruction), but I dont worry about their screen coords, I work out where my viewport is (trivial as I move my 'player' location with each keypress) and I draw a star on the edge, for example, if I've moved my 'player' to 200,200 and the screen is 1000 px wide then my new star will end up at 700,200 (200 + 1000 / 2 as my 0,0 is centralised and not top-left).


A star drawn at 0,0 will always be drawn at 0,0 on the PIXI container element, the window viewport dictates how much of that container (I call it a stage, its analogous with the older PIXI implementation of a stage container) I can actually see. If I didnt have many elements then I'd just draw them all, even if they are off-canvas but its normally fairly easy to check which ones are in and out of the viewport (you can get the container position, and the window dimensions easily, its just pesky zoom/scale that complicates things, but, not every case has that concern anyway).


In that example I create a canvas based on the window dimensions, I then create the renderer to match the canvas/window dimensions. The "stage" container is then created and positioned before adding my starfield class, which simply adds its 'master' container to the stage and then adds all the stars it needs to its master container.


If my game world was just one screen that should fit into the screen and ( i.e. my 'stage' container is a fixed size ) and the window dimensions do not match that size, then I guess I'd consider scaling the stage, but, I'd scale to the same value in each dimension and stop when one dimensions hits the edges i.e. you'd get a letterbox or a sideways letterbox depending on how the world and screen dimensions match up.


I hope that helps, I'm still not sure I'm 100% on helping with your question.

Link to comment
Share on other sites

Thanks for your solution. Starfield helped me sort some things up. Now I have some idea, lets see how it ends...



Actually, are you after a squish/stretch like Ermins Adventure?


The author has released their source code

Nope, this is exactly what Im trying to avoid. Lets say I want window into game world that always contain as much as possible, while rest of the world is over the corner, if it doesnt fit with current aspect ratio.

Link to comment
Share on other sites

Well, seems I got it. Just not sure if there is no better way to do it.


Trick is to compose squere scene (1000x1000 in my case) and then modify renderer width or height according to canvas size. Canvas is by css set to be 100% width and height of window. See renderer setting:

	// viewport dimensions	var baseWidth = Math.floor(window.innerWidth);	var baseHeight = Math.floor(window.innerHeight);		// scene dimensions	var projectedWidth = 1000;	var projectedHeight = 1000;	// viewport aspect ratio	var aspectRatio = baseWidth / baseHeight;	// renderer acctual dimensions	var rendererWidth = projectedWidth * aspectRatio;	var rendererHeight = projectedHeight;	renderer = PIXI.autoDetectRenderer(rendererWidth, rendererHeight, {backgroundColor : 0x446276, view: document.getElementById("stage")});

Second important thing is to center containers, so x 0 is in middle of viewport. Found that part tricky, because changing container.position.x had no effect. But changing pivot works (just hope it doesnt screw up something else):

container.pivot.x = rendererWidth / -2

Then I can place any sprite relatively to center of screen (on x axis, y is always 0-1000, so there is no need to center it). Values greater than 0 are on right, lower than 0 are on left from center. Resizing is taken care of by pixi and everything is scaled proportionaly, because canvas and renderer aspect ratios are same.


So, this way scene is always centered, no matter of screen size or aspect ratio, everything is proportional and everybody happy. Im bit afraid about pivot point, but right now, it seems it works...


EDIT: it is better to change container.position. See posts bellow

Link to comment
Share on other sites

I'm sure I found some problem with the pivot method, maybe something to do with adding children to the container, maybe, I forget exactly what it was now.


I'm not sure why

container.position.set( projectedWidth / 2, projectedHeight / 2 ) // or using rendererWidth and rendererHeight

doesnt work to centralise the <0,0> point. Its what I use here by translating by an offset (which is just half the width/height to get to the middle).


Also, why 


When is `innerHeight` and innerWidth` anything other than an integer?



Glad you've got things working how you need though! Good work!

Link to comment
Share on other sites

Aha, I was trying to set container.position.x directly. By set method it works just fine. Seems directly accesed position.x havent changed at all, I just havent realized why, because no error was thrown. This should save me of some problems, thanks!


About Math.floor, I had some issues with float given by some browser. Half-pixels or something like that. Cant recall more details.


EDIT: Oh, crap. Position adjusts just y, x is still 0. Strange...

Edited by OnGe
Link to comment
Share on other sites

Well, I have found where is the problem with position. It was somewhere between keyboard and chair. I have feature that move view according to mouse drag. So it overwriten any change to position I made. So, I had towrap everything in another container and center this one.


So, there is no problem in changing position of container.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

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