Jump to content
This forum will be closing down. Please move to the respective dedicated project forums.

8k world size, how to crop renderer to a new canvas?


QuinTRON
 Share

Recommended Posts

Hi Team,

I'm looking to increase my world from 2000px2 => 8000px2+ (maybe even 12k if it works out) 
I haven't been successful in finding a way I could crop/clone so to speak a rectangle within the main app.renderer object to my other viewport canvas.

//Proposed canvas setup (pseudo setup):
app_canvas = {
   styles: {
      width: "8000px",
      height: "8000px",
      display: "none"
   }
};

viewport_canvas = {
   styles: {
      width: window.innerWidth,
      height: window.innerHeight
   }
};

/*******************************
*
* Proposed render logic (pseudo):
*
********************************
**
** While rendering... 
** get the coordinates of my camera... 
** clone the texture of app_canvas 
** Plot the cloned texture into viewport_canvas
**
********************************/


  1. Is this possible?
  2. Is there a better way to do this? 


I am aware of the other threads talking about culling techniques but I'm willing to keep that conversation to the side and focus on this topic.

Thanks

Link to comment
Share on other sites

Do you want to make a giant scr

eenshot, or do you want to render part of stage? I dont understand :(

The first one is "renderer.extract.getCanvas()" , the second one is just how pixi works. We map center of the screen (position) to the center of camera (pivot)

stage.position.set(renderer.screen.width/2, renderer.screen.height/2);
stage.pivot.set(cameraX, cameraY);

 

Link to comment
Share on other sites

Interesting.

Sorry for my stupid questions but does this mean by setting:

app.renderer.width = window.innerWidth; 
app.renderer.height = window.innerHeight;

-Then graphics "rendering" will only be processed over this area, depending on where my position & pivot is on the app.stage?

Link to comment
Share on other sites

Haha this is all kind of fail anyway because I cannot make my world any larger than 4096 as that is the largest the HTML canvas will go.
Any larger than that it just zooms/scales into the app.stage.

Is there anything I can do to make my world (html canvas) larger without it scaling? 

Link to comment
Share on other sites

Unless I've missed something, you seem to be over-complicating the matter. @ivan.popelyshev's most recent reply is the way to do it. No giant canvas is needed.

// Create an application with the renderer at a reasonable size
const app = new PIXI.Application(1366, 768);

// Create an entity and add it to the stage
const myThing = new PIXI.Sprite(someTexture);
app.stage.addChild(myThing);

// Set its position to whatever you want relative to app.stage's position
myThing.position.set(8000, 500);

// Move app.stage so that myThing is visible in the viewport
app.stage.position.set(-8000, -500);

(Edit: Sorry about the fucked up syntax highlighting. This forum doesn't seem to apply it properly half the time, even with repeated attempts.)

Hope that helps :)

Link to comment
Share on other sites

Hi @Sambrosia & @ivan.popelyshev

Yeah, I can see straight away where I've gone wrong. 
I was setting my renderer the size of the entire world as opposed to what I truly cared for (the clients viewport size).

This has clarified a few things for me; I really appreciate your help guys! :)

Link to comment
Share on other sites

@QuinTRON

There's another thing people who are moving from web don't know:

The first-class citizens of PIXI containers are transforms ("position", "rotation", "scale") and textures, and that's what you have to manipulate. "width" and "height" are calling for "getLocalBounds()" which is heavy method, its calculated based on children, getting or settings them have consequences! If you need current size of container, use "getBounds()", and if you want to set width or height you have to know how it works: it actually changes "scale".

Link to comment
Share on other sites

I've got the biggest grin on my face right now! :D
I cant believe these simple tricks provide such a powerful experience! 

I have read, read and read as many pixi.js documentation and other threads but it still was not evident enough for me what the renderer truly was. 
Maybe as a suggestion the pixi-documentation pages could be further detailed? (Unless I am the only person)

What I am doing now is creating a larger rectangle around my camera to check if sprites need to be rendered or not. 

Link to comment
Share on other sites

Well, you can set "renderable=false" for those sprites which are outside the camera, that will be basic culling. Juts create a rectangle, pass it to getBounds() for every sprite, check if they are inside the screen.

But it might be that your culling will be to inefficient and its better to let everything draw. Invisibile pixels are cheap after all.

Link to comment
Share on other sites

Thanks, I intend to use renderable=false;

I have just tried running the game with 100 bots and it was laggy.

Here is what I intend to do:
 

//
// 1 - Setup draw bounds per frame
//

function getDrawBounds(obj)
{
    // @obj = player x,y coordinates (the same coordinates the camera uses)
    // @clientViewPort.drawBoundWidth = 1.5x the clients viewport width

	return {
		x: parseInt(obj.x - clientViewPort.drawBoundWidth),
		y: parseInt(obj.y - clientViewPort.drawBoundHeight),
		xx: parseInt(obj.x + clientViewPort.drawBoundWidth),
		yy: parseInt(obj.y + clientViewPort.drawBoundHeight)
	};
}

// Set overflow bounds for your player
player.bounds = getDrawBounds(player);


//
// 2 - Per frame: check if the other player is in your draw bounds
//

function inBounds(p, b)
{
    // @p = point to check
    // @b = in boundary

    return p.x >= b.vpx && p.x <= b.vpxx && p.y >= b.vpy && p.y <= b.vpyy;
}

// GAME LOOP
// ...
if (!inBounds(thisHero, player.bounds)) {
	thisHero.renderPlayerSprites(false);
} else {
	thisHero.renderPlayerSprites(true);
}
// ...

 

Link to comment
Share on other sites

You create 100 instances of objects every frame, right? Don't do it. Create bounds one time and then update them every frame.

If that doesnt help:

"player" is better to be a class and not just plain object. Add "this.bounds=new PIXI.Bounds()" or "this.bounds=new MyShinyBounds()" in its constructor. If you don't understand why am I asking that, read ftp://91.193.236.10/pub/docs/linux-support/programming/JavaScript/[O`Reilly] - JavaScript. The Definitive Guide, 6th ed. - [Flanagan].pdf

Link to comment
Share on other sites

Ok, I have implemented the above code with slight modifications, incorporating your feedback.

I have now added 100 bots in my 8000x8000 world and its running very smooth :)

// This is now in the players class
// I call this method every 2nd frame (as it is unnecessary to update it every frame)
// I can now 'seamlessly' see other players renderable states toggling true/false

this.setRenderBounds = function()
{
	this.bounds.x = parseInt(this.x - clientViewPort.drawBoundWidth);
	this.bounds.y = parseInt(this.y - clientViewPort.drawBoundHeight);
	this.bounds.xx = parseInt(this.x + clientViewPort.drawBoundWidth);
	this.bounds.yy = parseInt(this.y + clientViewPort.drawBoundHeight);
};

I've noticed the App.Ticker() function uses quite a lot of processing ~10%. 
I'm curious what this does, considering I already use RequestAnimationFrame() to animate my game?
Shouldn't I use 1 or the other? 

Thanks

Link to comment
Share on other sites

In Chrome's Developer Tools => Profiles => Record Javascript CPU Profile
I notice the Ticker._tick reference is everywhere.

'render' is my games requestAnimationFrame function.
When you say '... its the same RAF...' does that mean Ticker is listening to my RAF or is it instantiating a new RAF?

Thanks in advance! 

hookem-profile-snapshot_16-02-2017.png.20f1c5680f92ede9cf7cc7c56b0d349e.png

Link to comment
Share on other sites

I'm requesting frames maximum of 1000/60.
Idle time looks like ~20-30% of the total

My structure is basically this:

  1. Initialise world
    1. create app(),
    2. generate textures and sprites...
    3. plot sprites onto the world
    4. game can now be rendered!
  2. RAF render()
    1. request a new frame (requestAnimationFrame(render))
    2. update the game state
    3. draw updates
    4. send client inputs to the server
    5. ... repeat
  3. on socket messages()
    1. Process inputs from the server

Does this mean I could get more FPS if I only use one RAF?
If so, what do you advise?

I have also attached the CPU profile (Profile 2) dump if you needed more information.

hookem-profile-16-02-2017-2.png.512243d13f554f9360e282afc29000c8.png

CPU-20170216T193712.cpuprofile

Link to comment
Share on other sites

I recommend to try add your stuff to "app.ticker" instead. But I don't think it will affect much :(

But network and game updates, are you sure we need 60FPS network? Update of sprite coords and update of game state are two different things, one must be at 60FPS for good animation but the other will be better on 10-20FPS, like most of multiplayer browser games. Linear interpolation helps a lot :)

 

So , in 8.5 seconds time, 2.25 spend on UI (divs and such, "program"), and 1.1 on js updates and render. That's not bad at all!

Just remember that 100% are all spent CPU resources, it doesnt include "idle" time. The more idle time, the better :) Percents are there only to determine which part is worse than others.

Link to comment
Share on other sites

I've learnt a lot form this conversation! 

I will raise a few cards on my project wall to:

  1. Move my games RAF => app.ticker
  2. Implement game interpolation
    1. I imagine doing this by moving objects according to their velocity * last frame time difference
  3. Then only will I reduce the amount of network packets to the server by at least 1/2

I will update this thread with on the above 3 points.

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.

Guest
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.

Loading...
 Share

  • Recently Browsing   0 members

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