I am going to delay the planned installment of Animating the Canvas this week. While I have made a lot of progress on the code and thought that I had the rest of this series finished, when using the code within my Tarot project, some bugs were uncovered. While I could continue the series anyway, as the planned topic for today would not have been related to the issue at hand, I have decided instead to take a brief break and discus testing.
Testing and debugging are an important part of programming. The testing requirements largely depend on the project. Being old-school, I tend to use my brain to do the bulk of my debugging. I try and think like the computer to figure out where the problem is and then isolate and solve the problem. I find this approach much faster than the second level of debugging, namely using a debugger. Firefox, thankfully, has an incredible debugger called firebug. Apple has pretty much cloned this tool for Safari. Still, as someone who uses multiple operating systems, I like the fact that Firefox is everywhere so tend to use that browser for my preliminary testing. Single stepping through a program can be very time-consuming but for some bugs it is a necessity.
The big trend now is something called unit testing. It is an approach that is really good and is something that I should be doing more of but as most my projects are small I don't. The idea here is that you write your tests before you write your code. The tests are usually written using some type of testing framework in mind. Because the tests are all automated, you simply need to run the tests before checking in code. The advantage to using this technique is that you know when you are done as all of your tests are successful. For game development, this is only a partial solution. You can test the subsystems that make up the game, but are still going to need human testing for a lot of the testing.
While unit testing is not the silver bullet a lot of people think, the automated tests do help you make progress if you have written them. If you have not and are debugging things, unit tests can still prove useful. Once you have isolated a bug, or started writing testing code to help find the bug, you will have automated tests that make sure you do not re-introduce the bug in the future. While I am sure there are countless JavaScript testing frameworks available, creating one is very simple. Here is the one I wrote after discovering my issues with the BGLayers library I am writing:
function addTestResult(group, desc, result)
{
var testTable = document.getElementById('testTable');
var rRow = testTable.insertRow(1);
var resText;
if ( result)
resText = 'Test Passed';
else
resText = 'Test Failed';
rRow.innerHTML = ''+group+''+desc+''+resText+'';
}
Yes, I could have searched out a much better one online, but was simply too lazy to. My own "framework" only took a few minutes to write. I am sure that as I continue to focus more on writing JavaScript, especially as I start larger projects, finding a better library for unit testing will make sense. For now, my simple test function is adequate for my needs.
Sunday, September 26, 2010
Sunday, September 19, 2010
Animating the Canvas part 5: Layers of Paint
Last week we covered the positioning of layers and how to get the real position of the layer. This week we are actually going to draw. To make this class very easy to extend, the drawing of the layer is broken into two separate functions. The drawSelf function simply draws the contents of the layer. No care is given to any children the layer may have. By doing this, we can isolate the drawing of the layer (if any) from dealing with children. This function takes a bounds parameter which indicates which portion of the layer needs to be drawn. The function first looks to see if the bounds that are being drawn are actually part of this layer. This is done by adding a new function to the Rectangle class: intersects(rect). This is a very simple function that tests if two rectangles intersect with each other. Still, a lot of people seem to find the test confusing so lets go over it in detail:
First we want to make sure that the passed rectangle is not left of the class rectangle. This is done by taking the class rectangles' x2 coordinate and comparing it to the passed rectangles' x coordinate. If x is greater than x2 is then obviously there can be no overlap so the condition will fail.
if ( (this.x < (rect.x + rect.width)) &&
Next, we know that the passed rectangle is not to left of the class rectangle so we are now seeing if it is to the right of the rectangle. This can be done by seeing if the class rectangles' x2 coordinate is greater than the passed rectangles' x coordinate.
( (this.x + this.width) > rect.x) &&
At this point we know that there is potentially intersection along the x axis so we now need to examine the y axis. This is essentially the same as above except we are checking for top and bottom instead of left and right.
(this.y < (rect.y + rect.height)) &&
( (this.y + this.height) > rect.y) )
return true;
else
return false;
If there is some overlap, we want to get that overlap so a getIntersection function is added to the rectangle to perform this task. It is simply the interior most bounds so no detailed explanation should be necessary.
Once we know what portion needs to be drawn, we simply draws a rectangle in the colour that is contained in the backgroundColor property. Overridden classes may need to do more work to figure out what needs to be drawn and to insure that things are drawn within the clip, you may actually need to formalize the bounds by using canvas clipping operations. It may be a good idea to set a clipping region no matter what as the browser probably has very efficient clipping support so there should be very little overhead.
The other function used for drawing is the render function. This is a very simple function that simply calls the drawSelf function passing the bounds it was passed and then calls the render function for all of the children that belong to this layer.
There is one additional function for painting the display. The renderDirty function is a convenience function that simply calls render for each rectangle in the list of dirty rectangles. This function will be discussed in a later part as while have a functional system right now, the dirty rectangle management needs to be overhauled to eliminate overlap. We will be starting on this work in the next part.
First we want to make sure that the passed rectangle is not left of the class rectangle. This is done by taking the class rectangles' x2 coordinate and comparing it to the passed rectangles' x coordinate. If x is greater than x2 is then obviously there can be no overlap so the condition will fail.
if ( (this.x < (rect.x + rect.width)) &&
Next, we know that the passed rectangle is not to left of the class rectangle so we are now seeing if it is to the right of the rectangle. This can be done by seeing if the class rectangles' x2 coordinate is greater than the passed rectangles' x coordinate.
( (this.x + this.width) > rect.x) &&
At this point we know that there is potentially intersection along the x axis so we now need to examine the y axis. This is essentially the same as above except we are checking for top and bottom instead of left and right.
(this.y < (rect.y + rect.height)) &&
( (this.y + this.height) > rect.y) )
return true;
else
return false;
If there is some overlap, we want to get that overlap so a getIntersection function is added to the rectangle to perform this task. It is simply the interior most bounds so no detailed explanation should be necessary.
Once we know what portion needs to be drawn, we simply draws a rectangle in the colour that is contained in the backgroundColor property. Overridden classes may need to do more work to figure out what needs to be drawn and to insure that things are drawn within the clip, you may actually need to formalize the bounds by using canvas clipping operations. It may be a good idea to set a clipping region no matter what as the browser probably has very efficient clipping support so there should be very little overhead.
The other function used for drawing is the render function. This is a very simple function that simply calls the drawSelf function passing the bounds it was passed and then calls the render function for all of the children that belong to this layer.
There is one additional function for painting the display. The renderDirty function is a convenience function that simply calls render for each rectangle in the list of dirty rectangles. This function will be discussed in a later part as while have a functional system right now, the dirty rectangle management needs to be overhauled to eliminate overlap. We will be starting on this work in the next part.
Sunday, September 12, 2010
Animating the Canvas part 4: Laying out Layers
As I am partially writing these classes for use with November's Tarot release, I am a lot further in the code than I would be if I was just working on this code Sunday afternoons (which is the plan for this blog from now on). I have been packaging up the source as it has reached logical development points but it will be a while before this series of articles catches up with the work. The source code is located at http://www.blazinggames.com/other/openLibrary/html5Libs.
With primitives started it is now time to get to the real code and start implementing the layers class. This class will be a base class for all of the other elements that get added to the canvas. The problem with this is that JavaScript does not currently support superclasses or inheritance. This is something that may come to a future version of JavaScript (ECMAScript version 6 unless it gets delayed like it did when such features were in ECMAScript version 4) but for now we have to manually perform the inheritance. While some browsers support a technique known as prototype chaining by exposing the __proto__ property, this is not always the case so manually copying the properties must be done for browser compatibility. A simple function can handle this making creating subclasses much easier, though at a bit of cost in efficiency and memory.
BGLayers.inheritProperties = function(child, supr)
{
for (var property in supr) {
if (typeof child[property] == "undefined")
child[property] = supr[property];
}
}
The layers are loosely based on the layer classes that I created for Dozen Days of Words Episode 12: Morse Code but with the addition of dirty rectangle support and switching from absolute positions to relative positioning. Relative positioning adds a lot more flexibility for animation as any given layer only has to worry about it's position relative to it's parent. For this reason, a layer can be created with a width and a height which can, with the exception of the root (stage) layer, be any size as scaling will be done when the component is rendered onto the canvas.
The logical and real positions of the layer is dependent on the parent. This means that there should only be a single parent for a layer, though layers can have multiple children. This means that when you add a child to a layer, that child is being assigned a new parent. If it already has a parent that parent is told that the child is being removed and the new parent becomes the parent. The addChild, removeChild, and setParent functions handle all this work. Note that these functions take advantage of the addDirty function to let the old and new parents know which part of the display has changed.
The addDirty function handles our dirty rectangle list, but at the moment is far from complete as I was more concerned with getting the code functional. Currently the addDirty function simply adds the dirty rectangle, expressed in real canvas coordinates, to the root layer. The root layer is simply the layer which does not have a parent. To find the layer, the parent is called until there is no parent. Right now no effort is being made to cull the list to eliminate overdrawing. This feature will be added in the future.
While for internal work the real size and location of the layer is not that important, for marking dirty rectangles and rendering them knowing the real location becomes vital. This is where the findRealPosition function comes into play. As this is such an important function, lets go over it in detail.
First, to speed things up, we don't want to constantly re-calculate this so we have a flag that lets us know if the real position is known and if so, we return the already calculated position. This means that when the logical position or parent layer position changes the flag has to be set to false so when the final code is put together the logical position information may be marked protected (sadly, there is no such thing as protected variables in JavaScript yet, so we have to go on the honour system).
if (this.realPositionKnown)
return this.realPosition;
If this is the root layer then it's logical position and size are the real thing. If it is not, then we need to get the real thing by getting the parent's real position by calling this function on the parent. If the parent is not the root layer it will call it's parent and so on until the real position can be determined.
var parentPos = this.logicalPosition;
var w = this.logicalSize.width;
var h = this.logicalSize.height;
if (this.parent != null) {
parentPos = this.parent.findRealPosition();
w = this.parent.logicalSize.width;
h = this.parent.logicalSize.height;
}
Knowing the real position of the parent then gives us the information we need to find our real position. This is done by determining how big we are logically compared to how big of an area we are in our parent's eyes. This results in scaling factors.
var scaleX = parentPos.width / w;
var scaleY = parentPos.height / h;
With the scaling factors known, we can simply calculate the position by multiplying the logical coordinates by the scale and adding the parent's position.
this.realPosition.x = parentPos.x + this.logicalPosition.x * scaleX;
this.realPosition.y = parentPos.y + this.logicalPosition.y * scaleY;
this.realPosition.width = this.logicalPosition.width * scaleX;
this.realPosition.height = this.logicalPosition.height * scaleY;
this.realPositionKnown = true;
return this.realPosition;
Now we know where to draw things, the next step is to actually implement the rendering of things which we will do next week.
With primitives started it is now time to get to the real code and start implementing the layers class. This class will be a base class for all of the other elements that get added to the canvas. The problem with this is that JavaScript does not currently support superclasses or inheritance. This is something that may come to a future version of JavaScript (ECMAScript version 6 unless it gets delayed like it did when such features were in ECMAScript version 4) but for now we have to manually perform the inheritance. While some browsers support a technique known as prototype chaining by exposing the __proto__ property, this is not always the case so manually copying the properties must be done for browser compatibility. A simple function can handle this making creating subclasses much easier, though at a bit of cost in efficiency and memory.
BGLayers.inheritProperties = function(child, supr)
{
for (var property in supr) {
if (typeof child[property] == "undefined")
child[property] = supr[property];
}
}
The layers are loosely based on the layer classes that I created for Dozen Days of Words Episode 12: Morse Code but with the addition of dirty rectangle support and switching from absolute positions to relative positioning. Relative positioning adds a lot more flexibility for animation as any given layer only has to worry about it's position relative to it's parent. For this reason, a layer can be created with a width and a height which can, with the exception of the root (stage) layer, be any size as scaling will be done when the component is rendered onto the canvas.
The logical and real positions of the layer is dependent on the parent. This means that there should only be a single parent for a layer, though layers can have multiple children. This means that when you add a child to a layer, that child is being assigned a new parent. If it already has a parent that parent is told that the child is being removed and the new parent becomes the parent. The addChild, removeChild, and setParent functions handle all this work. Note that these functions take advantage of the addDirty function to let the old and new parents know which part of the display has changed.
The addDirty function handles our dirty rectangle list, but at the moment is far from complete as I was more concerned with getting the code functional. Currently the addDirty function simply adds the dirty rectangle, expressed in real canvas coordinates, to the root layer. The root layer is simply the layer which does not have a parent. To find the layer, the parent is called until there is no parent. Right now no effort is being made to cull the list to eliminate overdrawing. This feature will be added in the future.
While for internal work the real size and location of the layer is not that important, for marking dirty rectangles and rendering them knowing the real location becomes vital. This is where the findRealPosition function comes into play. As this is such an important function, lets go over it in detail.
First, to speed things up, we don't want to constantly re-calculate this so we have a flag that lets us know if the real position is known and if so, we return the already calculated position. This means that when the logical position or parent layer position changes the flag has to be set to false so when the final code is put together the logical position information may be marked protected (sadly, there is no such thing as protected variables in JavaScript yet, so we have to go on the honour system).
if (this.realPositionKnown)
return this.realPosition;
If this is the root layer then it's logical position and size are the real thing. If it is not, then we need to get the real thing by getting the parent's real position by calling this function on the parent. If the parent is not the root layer it will call it's parent and so on until the real position can be determined.
var parentPos = this.logicalPosition;
var w = this.logicalSize.width;
var h = this.logicalSize.height;
if (this.parent != null) {
parentPos = this.parent.findRealPosition();
w = this.parent.logicalSize.width;
h = this.parent.logicalSize.height;
}
Knowing the real position of the parent then gives us the information we need to find our real position. This is done by determining how big we are logically compared to how big of an area we are in our parent's eyes. This results in scaling factors.
var scaleX = parentPos.width / w;
var scaleY = parentPos.height / h;
With the scaling factors known, we can simply calculate the position by multiplying the logical coordinates by the scale and adding the parent's position.
this.realPosition.x = parentPos.x + this.logicalPosition.x * scaleX;
this.realPosition.y = parentPos.y + this.logicalPosition.y * scaleY;
this.realPosition.width = this.logicalPosition.width * scaleX;
this.realPosition.height = this.logicalPosition.height * scaleY;
this.realPositionKnown = true;
return this.realPosition;
Now we know where to draw things, the next step is to actually implement the rendering of things which we will do next week.
Sunday, September 5, 2010
Animating the Canvas Part 3: Getting Primitive
Before I get to the actual article, I will briefly point out that Dozen Days of Words episode 12: Morse Code has been posted on the site and while I never had the time to get dirty rectangles implemented in it, it does use a primitive layers system. In fact, if you are running it on Internet Explorer using excanvas you can visibly see how dirty rectangles could dramatically improve things. This is not noticeable on browsers that support the canvas tag.
As is often the case, before we can get to the good stuff, we need to build the foundation. As this project is going to require a bunch of classes and JavaScript, at least current implementations of it, is not really designed for such a thing we need to think about the best way of handling classes. Everything in JavaScript is thrown into a global namespace which can lead to problems. Looking at how other JavaScript libraries have handled the problem, I am going to follow the same route and put all my classes into a single object which is essentially equivalent to packages in Java or ActionScript.
This is actually very easy to do and to my surprise, it poses no problems for using the prototype variable in class creation. The one disadvantage to this technique is that you are putting the entire library into the package. Two ways around this is to break the library up into separate files that can be individually included, or to use a utility like Google's closure compiler. Setting up the package is simple:
var BGLayers = new Object();
With the "package" set up, it is time to get some of the primitives out of the way. The obvious most primitive graphic objects are the point and dimension. Both of these classes are essentially just structures but they are handy to have.
BGLayers.Point = function(x,y)
{
this.x = x;
this.y = y;
}
BGLayers.Dimension = function(w,h)
{
this.width = w;
this.height = h
}
The next class is a bit more complicated but is important as it is really the heart of this engine. No, not the layers class (we will start on that next week) but the lowly Rectangle. The question is how to handle the construction of the rectangle as I would like support for a valid empty rectangle, a clone constructor that takes a Rectangle as the sole parameter and copies it, and a Rectangle that lets you specify the four parameters.
Java and ActionScript support multiple constructors and functions by basing which function gets called on the parameters used. JavaScript doesn't do this yet. So how does one have multiple constructors for something like the Rectangle class? This is where I get to play around a bit with JavaScript. Researching this subject I discovered that functions have a arguments variable that holds the parameters. While arguments is not technically an Array object, it does have a length and can be accessed like an array. By using the length, the three different constructors can be combined into a single constructor function as follows:
BGLayers.Rectangle = function(x, y, w, h)
{
if (arguments.length == 1) { // clone rectangle
this.x = x.x;
this.y = x.y;
this.width = x.width;
this.height = x.height;
} else if (arguments.length == 4) { // parametrized rectangle
this.x = x;
this.y = y;
this.width = w;
this.height = h;
} else { // default to empty rectangle
this.x = 0;
this.y = 0;
this.width = 0;
this.height = 0;
}
}
I have noticed that I am starting to get a bit code-heavy. I want to focus more on the concepts and less on raw code, so I am thinking that for future posts I will link to the source file and just focus on the most relevant code while having an overview of the additional code. This has the added advantage of get through a lot more material and there is a lot of material that I want to cover here. As the Layers class is rather huge, I suspect that it will require more than one post to cover everything in it. Once we get that out of the way we can get to the animation part.
As is often the case, before we can get to the good stuff, we need to build the foundation. As this project is going to require a bunch of classes and JavaScript, at least current implementations of it, is not really designed for such a thing we need to think about the best way of handling classes. Everything in JavaScript is thrown into a global namespace which can lead to problems. Looking at how other JavaScript libraries have handled the problem, I am going to follow the same route and put all my classes into a single object which is essentially equivalent to packages in Java or ActionScript.
This is actually very easy to do and to my surprise, it poses no problems for using the prototype variable in class creation. The one disadvantage to this technique is that you are putting the entire library into the package. Two ways around this is to break the library up into separate files that can be individually included, or to use a utility like Google's closure compiler. Setting up the package is simple:
var BGLayers = new Object();
With the "package" set up, it is time to get some of the primitives out of the way. The obvious most primitive graphic objects are the point and dimension. Both of these classes are essentially just structures but they are handy to have.
BGLayers.Point = function(x,y)
{
this.x = x;
this.y = y;
}
BGLayers.Dimension = function(w,h)
{
this.width = w;
this.height = h
}
The next class is a bit more complicated but is important as it is really the heart of this engine. No, not the layers class (we will start on that next week) but the lowly Rectangle. The question is how to handle the construction of the rectangle as I would like support for a valid empty rectangle, a clone constructor that takes a Rectangle as the sole parameter and copies it, and a Rectangle that lets you specify the four parameters.
Java and ActionScript support multiple constructors and functions by basing which function gets called on the parameters used. JavaScript doesn't do this yet. So how does one have multiple constructors for something like the Rectangle class? This is where I get to play around a bit with JavaScript. Researching this subject I discovered that functions have a arguments variable that holds the parameters. While arguments is not technically an Array object, it does have a length and can be accessed like an array. By using the length, the three different constructors can be combined into a single constructor function as follows:
BGLayers.Rectangle = function(x, y, w, h)
{
if (arguments.length == 1) { // clone rectangle
this.x = x.x;
this.y = x.y;
this.width = x.width;
this.height = x.height;
} else if (arguments.length == 4) { // parametrized rectangle
this.x = x;
this.y = y;
this.width = w;
this.height = h;
} else { // default to empty rectangle
this.x = 0;
this.y = 0;
this.width = 0;
this.height = 0;
}
}
I have noticed that I am starting to get a bit code-heavy. I want to focus more on the concepts and less on raw code, so I am thinking that for future posts I will link to the source file and just focus on the most relevant code while having an overview of the additional code. This has the added advantage of get through a lot more material and there is a lot of material that I want to cover here. As the Layers class is rather huge, I suspect that it will require more than one post to cover everything in it. Once we get that out of the way we can get to the animation part.
Subscribe to:
Posts (Atom)