QuinTRON Posted February 13, 2017 Share Posted February 13, 2017 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 ** ********************************/ Is this possible? 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 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 13, 2017 Share Posted February 13, 2017 That's 3 of 4k monitors, right? If you want it to show in small window, then you dont need this , neither culling. Just move the main container and render it again? I need more info about your case. Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 13, 2017 Author Share Posted February 13, 2017 Hi Ivan, thanks for getting back to me. My topic is not necessarily about 4k monitors, it is a coincidence my world size was divisible by it. I hope the attached image better describes my problem. Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 14, 2017 Share Posted February 14, 2017 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); QuinTRON 1 Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 14, 2017 Author Share Posted February 14, 2017 I only wish to render part of the stage. As you can imagine, if my world = 12,000px wide+heigh then the actual DOM Element is just too big and is laggy. Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 14, 2017 Share Posted February 14, 2017 I just gave you the code. What's the problem? Make renderer 1366x768, put elements in stage however you want, then move the stage with position&pivot. Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 14, 2017 Author Share Posted February 14, 2017 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? Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 15, 2017 Author Share Posted February 15, 2017 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? Quote Link to comment Share on other sites More sharing options...
Sambrosia Posted February 15, 2017 Share Posted February 15, 2017 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 QuinTRON 1 Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 15, 2017 Author Share Posted February 15, 2017 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! Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 15, 2017 Share Posted February 15, 2017 @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". QuinTRON 1 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 15, 2017 Share Posted February 15, 2017 Also if you use my code, you can set the scale or rotation of screen, and it will rotate around the center. That's why pivot/position combo is awesome: you are pinning two points , one on screen and one in your world. Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 15, 2017 Author Share Posted February 15, 2017 I've got the biggest grin on my face right now! 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. ivan.popelyshev 1 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 15, 2017 Share Posted February 15, 2017 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. Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 15, 2017 Author Share Posted February 15, 2017 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); } // ... Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 15, 2017 Share Posted February 15, 2017 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 Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 16, 2017 Author Share Posted February 16, 2017 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 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 16, 2017 Share Posted February 16, 2017 How did you notice it? Its actually the same requestAnimationFrame , no need to rewrite it. Also, 10% is of all the app time, not of the CPU time? Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 16, 2017 Author Share Posted February 16, 2017 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! Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 16, 2017 Share Posted February 16, 2017 How big is your time interval? How many seconds is the "idle time" in that list? Yeah. Ticker creates its own RAF. Your app is using it. Where do you call requestAnimationFrame manually? Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 16, 2017 Author Share Posted February 16, 2017 I'm requesting frames maximum of 1000/60. Idle time looks like ~20-30% of the total My structure is basically this: Initialise world create app(), generate textures and sprites... plot sprites onto the world game can now be rendered! RAF render() request a new frame (requestAnimationFrame(render)) update the game state draw updates send client inputs to the server ... repeat on socket messages() 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. CPU-20170216T193712.cpuprofile Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted February 16, 2017 Share Posted February 16, 2017 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. QuinTRON 1 Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 16, 2017 Author Share Posted February 16, 2017 I've learnt a lot form this conversation! I will raise a few cards on my project wall to: Move my games RAF => app.ticker Implement game interpolation I imagine doing this by moving objects according to their velocity * last frame time difference 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. Quote Link to comment Share on other sites More sharing options...
QuinTRON Posted February 16, 2017 Author Share Posted February 16, 2017 Re: Point 1 It was straight forward to implement. I basically replaced my RAF with app.ticker.add(); Looking at the CPU profiles it made a slight improvement of ~2% But at least I have peace of mind there is only one RAF in play, so the two wont have to battle each other... Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.