www.webdeveloper.com
Results 1 to 7 of 7

Thread: Your opinions on my Game Loop and Code Organization

  1. #1
    Join Date
    Jun 2014
    Location
    in a while loop
    Posts
    6

    Your opinions on my Game Loop and Code Organization

    Hello all, brand new to the forums. I read the "Read First" post and hopefully I'm not starting off bad. I'm developing a JavaScript/HTML5 game for fun, but wasn't sure if my code implements good practices.

    I'll try to condense what I have in order to make this post shorter. Just a little overview to help out hopefully:
    • Create Namespaces. I've only provided one in this post.
    • canvases[] and canvasCache (private vars):

      - One is an array for storing one or more canvases.

      -The other I use to cache the canvas element when I create a new one in order to avoid the garbage collector. I turn it back to null before the createCanvas function is done. Perhaps this is overkill since I won't create new divs or canvases during runtime.

      I've considered eliminating the array and creating a function that gets the canvas or div when needed.

    • timeStamp: For exactly that. I use performance.now since it's a lot more accurate, but I also provide a fallback for browsers that don't support it.
    • Game.run: is called when I want to start the loop. No need to get into details here. Unless it can be optimized
    • Game.createCanvas: I feel more comfortable creating elements via code instead of markup.
    • Game.getBody, getBrowserWidth, getBrowserHeight: I read it's more efficient creating a temporary reference of document.body before creating a new canvas or div. I assume calling getBrowserWidth/Height is better than creating a variable I won't use as much.


    Code:
    ;(function()
    {
    	//NAMESPACES
    	window.Game = {};
    
    	var canvases = [];			// One, or more canvases stored in the array for (hopefully) quick access
    	var canvasCache = null;		// I use this to temporary store a new canvas I'm creating, and before the function ends, I make this var null
    	
    	Game.timestamp = function () {
    		return window.performance && window.performance.now ? window.performance.now() : new Date().getTime();
    	}
    
    	var now;
    	var deltaTime = 0;
    	var last = Game.timestamp();
    	var step = 1/60;
    
    //---------------------------------------------------------------------------
     	Game.run  = function (options) {
    		now = Game.timestamp();
    		deltaTime = deltaTime + Math.min(1, (now-last) /1000);
    		while(deltaTime > step) {
    			deltaTime = deltaTime - step;
    		}
    		console.log('This is looping!');
    		requestAnimationFrame(Game.run);
    	}
     //---------------------------------------------------------------------------
    
    	Game.createCanvas = function (id,width,height,x,y,color) {
    		canvasCache = document.createElement('canvas');
    		canvasCache.style.position 	         = 'absolute';
    		canvasCache.id 				 = id;
    		canvasCache.style.background        = color;
    		canvasCache.width 			 = width;
    		canvasCache.height 			 = height;
    		canvasCache.style.left 		         = x + 'px';
    		canvasCache.style.top                   = y + 'px';
    		Game.getBody().appendChild(canvasCache);
    		canvases.push(canvasCache);
    		canvasCache = null;
    	}
    
    //---------------------------------------------------------------------------
    
    	Game.getBody 			= function()  { return document.body;      }
    	Game.getBrowserWidth 	        = function()  { return window.innerWidth;  }
    	Game.getBrowserHeight 	= function()  { return window.innerHeight; }
    
    }());
    Hopefully this was't too long. I'm also trying to find a nice way to store the context of the canvas within the Game namespace. Maybe making a private var and creating a public function to get it?

    Thanks!

  2. #2
    Join Date
    Mar 2007
    Location
    localhost
    Posts
    2,346
    an infinite loop...

    Code:
    while(true){
    
    // run this code 4eva
    
    
    }
    or

    Code:
    do{
    
    
    }while(true);
    Is that what you want? Also why are you using an anon function?
    Yes, I know I'm about as subtle as being hit by a bus..(\\.\ Aug08)
    Yep... I say it like I see it, even if it is like a baseball bat in the nutz... (\\.\ Aug08)
    I want to leave this world the same way I came into it, Screaming, Incontinent & No memory!
    I laughed that hard I burst my colostomy bag... (\\.\ May03)
    Life for some is like a car accident... Mine is like a motorway pile up...

    Problems with Vista? :: Getting Cryptic wid it. :: The 'C' word! :: Whois?

  3. #3
    Join Date
    Jun 2014
    Location
    in a while loop
    Posts
    6
    Thanks for the quick response. Regarding the Anonymous function, it's a way I can give vars in several js files their own local scope. Global variables are still shared among files. At least that's what I've read. In production I'd put everything in one file. Minimized.

    A while loop would block the UI thread, and most modern browsers support requestAnimationFrame which will turn into the standard for animation on the web. The loop already works perfectly it also implements a fallback to setTimer.

    I wanted to know if this organization can use optimization or it's nice the way it is. As far as I know, it looks okay. But who knows, putting it out there for further opinions.


    Quote Originally Posted by \\.\ View Post
    an infinite loop...

    Code:
    while(true){
    
    // run this code 4eva
    
    
    }
    or

    Code:
    do{
    
    
    }while(true);
    Is that what you want? Also why are you using an anon function?

  4. #4
    Join Date
    May 2014
    Posts
    897
    I wouldn't attach game() to window, you shouldn't need to do that given what you're doing with it.

    Little tip, if you are declaring a bunch of VAR in a row, you only need to say VAR once -- you can then comma delimit the list.

    The delta you are using of aiming for 60fps as your average is going to have problems in browsers that don't support window.performance; when it drops through to that Date.getTime() you're going to be having that function return the same time multiple times in a row, as the Date functions timer granularity is way down at 36.4ms on most browsers. (which of course is why we have Performance in the first place). You might want to run some sort of granularity check to make sure you aren't drawing frames that don't update because of the low timer granularity (which is below 30fps). I'd suggest dropping your desired 1:1 rate (step) to 24. It runs faster, great, and it will reduce the number of systems that will run at a slower playrate thanks to falling back on getTime to nil.

    That said, it's nice to see someone doing it properly, separating playrate from framerate.

    Oh, and because you're going to use document and window so much, this cute trick:

    (function(d,w) {
    })(document,window);

    Can not only save you some typing, it will actually run a hair faster since as an interpreted language, less code == faster, and shorter variable names == faster lookups.

    ... and yeah, @nogDog if you don't release scripting execution, nothing gets drawn -- EVER. That's why EVERY javascript animation has to use setTimeout, setInterval, requestAnimationFrame, or something similar to actually be usable... hence all white(true) will do is send the browser off to never-never land, effectively locking it up until (if you are in a good browser) it comes up with the message about the script taking too long to run and asking if you want to kill it.

    WAIT -- if using requestAnimationFrame, the only browsers that support it also by definition support Performance -- so there's no reason to have a fallback to Date.gettime --- or is there some sort of polyfill for that we're not seeing?

    I'd consider simply seeing if both requestAnimationFrame and window.performance exist, and if they don't simply bomb out with an error and lose the attempts to have fallbacks... Well, unless you REALLY care about Safari in which case you'd still need the webkitRequestAnimationFrame crap and have no window.performance; Even before Chrome forked off into Blink, the Safari builds of webkit have been such horrible code-rot lagging behind Chrome they've made IE 10+ look good on stuff like this.
    Java is to JavaScript as Ham is to Hamburger.

  5. #5
    Join Date
    May 2014
    Posts
    897
    Oh, also I'm not sure I'd be making the canvas APO and fixed size. Generally with Canvas I like to add a window.resize handler (that I also call at startup) to scale everything as needed.

    See my crappy little demo I made before window.performance even existed:
    http://www.deathshadow.com/canvasDemoRun

    That tries to scale to fit the window while preserving aspect.

    ... and yeah, I prefer creating CANVAS from the scripting because it's a scripting only element that to be frank, has no business even having a HTML tag in the first place. Scripting off fallback is NOSCRIPT's job, no support for the scripting is scripting's job.

    Just another of those things people call HTML 5 that isn't, or at the very least shouldn't be.
    Java is to JavaScript as Ham is to Hamburger.

  6. #6
    Join Date
    Jun 2014
    Location
    in a while loop
    Posts
    6
    Hey Shadow thanks for the great answer. You're right about the vars, I should have just used commas. Thanks for the tip.

    I actually made my previous version re-size based on the browser width/height so it takes up the browser viewing area. window.resize would fire and resize everything. Well, you already know this Were you suggesting the use of it because of performance or an aesthetic opinion?

    I checked out your demo and I don't think it's crappy. The water animation was pretty cool and the boats are floating nicely. Are they "floating" based on the water or independently?

    Code:
    (function(d,w) {
    })(document,window);  // THANKS FOR THIS TIP :)
    I'm going to remove window.performance. After your post, I went ahead and read up on it at MDN , and I have a feeling it's better to use it for debugging. In fact, according to the article, Safari completely doesn't support it. Our beloved IE only supports it in version 10.0.

    WAIT -- if using requestAnimationFrame, the only browsers that support it also by definition support Performance -- so there's no reason to have a fallback to Date.gettime --- or is there some sort of polyfill for that we're not seeing?
    Ooops sorry for not including the Polyfill. I'm using the famous Paul Irish solution:

    Code:
    window.requestAnimationFrame = function() 
    {
    	return window.requestAnimationFrame 	||
    		window.webkitRequestAnimationFrame 	||
    		window.mozRequestAnimationFrame 	||
    		window.msRequestAnimationFrame 		||
    		window.oRequestAnimationFrame 		||
    		function(f) { 
    			window.setTimeout(f,1000/60); }
    }();
    What if I do the same thing for window.performance? As in:

    Code:
    window.performance = window.performance || {};
    performance.now = (function()
    {
    	return 	performance.now 		||
    			performance.mozNow 		||
    			performance.msNow		||
    			performance.oNow		||
    			performance.webkitNow	||
    			function () { return new Date().getTime();};
    })();
    By the way, I checked out the rest of your site. You write DOS and Commadore64 based games? That's pretty awesome man.


    Quote Originally Posted by deathshadow View Post
    Oh, also I'm not sure I'd be making the canvas APO and fixed size. Generally with Canvas I like to add a window.resize handler (that I also call at startup) to scale everything as needed.

    See my crappy little demo I made before window.performance even existed:
    http://www.deathshadow.com/canvasDemoRun

    That tries to scale to fit the window while preserving aspect.

    ... and yeah, I prefer creating CANVAS from the scripting because it's a scripting only element that to be frank, has no business even having a HTML tag in the first place. Scripting off fallback is NOSCRIPT's job, no support for the scripting is scripting's job.

    Just another of those things people call HTML 5 that isn't, or at the very least shouldn't be.

  7. #7
    Join Date
    May 2014
    Posts
    897
    Quote Originally Posted by Infinite Loop View Post
    Were you suggesting the use of it because of performance or an aesthetic opinion?
    More a usability issue -- I've seen a few too many canvas games that are annoying to try and play because they're stuck in a little tiny window (you'll see flash games on sites similarly afflicted) or worse, too big for the display I'm on.


    Quote Originally Posted by Infinite Loop View Post
    The water animation was pretty cool and the boats are floating nicely. Are they "floating" based on the water or independently?
    Independently, but on purpose. It tricks the brain into seeing more waves than are actually drawn. Trick I picked up back in the '80's working on true parallax depth of field scrolling -- A great example is the ground in the SMS version of Choplifter. If you moved the enemy tanks with the ground tile, it actually looks wrong so it gets it's own sideways scroll rate in-between the tile-row in front of it and the tile-row behind it.

    Quote Originally Posted by Infinite Loop View Post
    Ooops sorry for not including the Polyfill. I'm using the famous Paul Irish solution:
    Like most of his solutions I wonder if he even understands the languages he's writing for... See that garbage he did with the endless stupid malfing IE CC around the HTML tag crap that he came up with that damned near every framework pisses on websites with. REALLY not a fan of anything of his.

    I mean, setting self to self? Would that ONE if statement REALLY hurt that much? Much less there is no such thing as msRequestAnimationFrame -- never even existed -- and of course setTimeout just doesn't work at 16.6~ms (1000/60), as the minimum across browsers hovers between 30ms and 36.4ms -- so sending that low a timeout is never going to work right.

    Quote Originally Posted by Infinite Loop View Post
    What if I do the same thing for window.performance?
    I'd actually handle that a bit differently if I were to go that route. I'd probably set my own function name instead of recycling, but make it an alias of the ones that exist... THOUGH, Performance.now only has a -webkit prefix, none of the other ones have ever bothered having it.

    Code:
    var now = window.performance ? (
    	Performance.webkitNow ||
    	Performance.now
    ) : function() { return new Date().getTime(); };
    Quote Originally Posted by Infinite Loop View Post
    By the way, I checked out the rest of your site. You write DOS and Commadore64 based games? That's pretty awesome man.
    Thanks. I didn't get the memo.

    I find writing code for fun on the older narrower targets makes me a better programmer when I have the endless resources of today. It makes you think more, and when you're done it feels like way more of an accomplishment.

    Sad part being in many ways writing DOS games is simpler and more powerful than what JS can do today... admittedly much of that is the dreadful state of AUDIO in browsers, which is what made me shelve that CANVAS demo which was originally going to be "Missile Command on Steroids".
    Java is to JavaScript as Ham is to Hamburger.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles