My original plans for this weekend were to start working on the first episode of Dozen Days of Tiles. I still am up in the air as whether I should start with my Mah Jongg effort or if Sudoku would be the better starting project. Sadly, neither have been started as Steam has their Thanksgiving sale going on and one of the games on sale (92% off) was an indie story pack that contained a game I wanted. Since the pack was less than the cost of the single game, I grabbed the pack and a game called Recettear caught my eye. It was different enough that I figured I would install it on my windows machine and try it out for a few hours. The game was so enjoyable that I am writing this post about it since it ate up my DDT time.
You play the game as a young girl named Recette. Your father ran off to become an adventurer and left you in debt. To pay off your debt, the fairy Tear is helping you turn your house into a store. Because the town you live in is a haven for adventurers, it is an item shop. While you can buy items wholesale, the fun of the game comes from hiring adventurers and then going into a dungeon to "acquire" the items so you can sell them for a 100% profit.
The game is surprisingly addictive. The only real complaint that I have about the game so far is the weekly payment. It is a skewed payment scheme where the first payment is 10000, the second 30000, the third 80000, the fourth 200000 and a final payment that I haven't seen yet but from the progression would guess 500000. While the idea here from a designers perspective is to keep the game challenging, I think the game would have been more enjoyable if the debt could be paid off at a slower pace. When I screwed up and was not able to make the 200000 payment, I discovered that instead of having to go back to an earlier save and replay the week the game would automatically restart you on day 2 but with all your stock and experience. Still, I think a better approach would have been to tie the expansion of the store to the debt. As each chunk of debt was paid off (minimum payment perhaps but small enough so game could be played leisurely) a store upgrade would start causing the loan to start again.
Still, for a low cost indie game, this is quite a fun title. My recommendation, however, is not to start on this game if you have other things to do as like many strategy games this game has a one-more-turn syndrome that causes hours to mysteriously vanish into the game.
Sunday, November 28, 2010
Sunday, November 14, 2010
DDT project starting
A few years ago I started the Dozen Days Pentalogy. This was planned to be a set of 5 series of a dozen small games. Each game in the series would be developed in a day. I originally started this project after hearing about a game in a day competition. As a lot of the games on Blazing Games were developed with a very short time-frame, this seemed right up my ally. The first series of games were developed in Flash and actually done in a day. This was not very easy to schedule and things like family problems made it harder for me to justify locking myself up for a day. For that reason, the second series was set up to be a maximum development time of 24 hours which could be spread out so I could work on it whenever I had a few hours to spare. This was done in Flex, which is a more code oriented variant of Flash (it produces the same swf files that Flash does) as I felt it was more open to being open-sourced as the tools were freely available while Flash Professional is very expensive. The last two episodes of the second season, however, were my attempt at moving to HTML 5.
It is now time for me to start on the third series of games. The remaining categories that I plan on covering are Tiles, Cards, and Board. All three are interesting and are the type of games that should be able to be created in a short period of time. Still, my current interest in Sudoku and Mah-Jongg means that I have decided that the third series is going to be tile-based games.
There are going to be a few changes on how I create these games. First, I am going to use my BGLayers library and develop the game using HTML 5 (no big surprise here). Second, while the time limit will be 24 hours, this will only apply to work on the code. As I finish up a block of work on a project, I plan on writing a detailed post about the work. The time spent writing these articles will not count towards the time-limit of the game. I will, essentially, be developing the game "live on the Blazing Games Development Blog" though may get a few weeks ahead of the articles if I am on a roll and can put the time in. Finally, some of the games may be broken into two or three separate games. For instance, Sudoku will have a player project which will be separate from a generator project.
I hope the few of you who actually read this will find this interesting.
It is now time for me to start on the third series of games. The remaining categories that I plan on covering are Tiles, Cards, and Board. All three are interesting and are the type of games that should be able to be created in a short period of time. Still, my current interest in Sudoku and Mah-Jongg means that I have decided that the third series is going to be tile-based games.
There are going to be a few changes on how I create these games. First, I am going to use my BGLayers library and develop the game using HTML 5 (no big surprise here). Second, while the time limit will be 24 hours, this will only apply to work on the code. As I finish up a block of work on a project, I plan on writing a detailed post about the work. The time spent writing these articles will not count towards the time-limit of the game. I will, essentially, be developing the game "live on the Blazing Games Development Blog" though may get a few weeks ahead of the articles if I am on a roll and can put the time in. Finally, some of the games may be broken into two or three separate games. For instance, Sudoku will have a player project which will be separate from a generator project.
I hope the few of you who actually read this will find this interesting.
Sunday, November 7, 2010
Animating the Canvas part 10: Cleaning up the Dirt
Creating a library is a bit different type of programming than normal application creation. When you are creating a class for an application, the only thing you have to be concerned about is that it meets the needs of your application. When creating a library, you have the extra burden that not only must your class do what it is suppose to do but it has to be flexible enough and bullet proof enough to be used by other people who are unrelated to your project. Lack of protected and private variables, as well as the namespace issues, makes creating a library in JavaScript more challenging. My goal today is to go over BGLayers and try to clean it up so it will be useful to others. At this point I highly doubt anybody is actually using my library (other than myself) so I don't have to worry about backwards compatibility. The biggest part of this effort will be to make protected variables more obvious so other programmers will know when they are messing with a variable they shouldn't be. From my brief examination of other JavaScript projects, I have noticed that the underscore is often used to indicate a protected variable. This is common enough and the underscore is distinct enough that it should be adequate to act as a warning to people wanting to modify variables directly. It's not the best solution but it is easy enough of a change.
The Dimension and Point classes don't have any changes necessary. The Rectangle class does have a bit of confusion in it. The contains function is for points while the containsRect is for rectangles. This could be confusing and result in someone using contains with a rectangle parameter and never getting proper results back. To eliminate this possible problem, I am changing contains to containsPoint. To make it even friendlier, both of the contains functions will take advantage of different parameter sets so point and rectangle objects can be passed to the respective functions as well as raw coordinates.
The layers class is where we have a lot of variables that should be private. The logical size of the layer is used to determine the real position so changing it outside of the class will not be noticed resulting in incorrect results. As there currently is no way of altering this, a changeSize function will be created. The logical position variable is similar, but already has multiple functions that modify it so the only new function needed here is a getPosition function. The real position, children and dirty rectangle variables are already adequately handled with functions. The solid variable, on the other hand, is really layer dependent and should not even be seen by the user. Visibility, though, is important so a setVisible function will be added. The only variables left "visible" to the user then are the background color and id. I suppose changing the background color should force a redraw so I will add a setBackgroundColor function and make it protected as well.
Finally, for the ImageLayer class, both the clip and image variables should probably be protected. I debated if it was wise to allow changing the image but ultimately decided there was little harm in allowing it so a setImage function has been added.
With this bit of cleaning up, I think that BGLayers is good enough for now. Certainly, as I am using the library internally, it will have enhancements added to it over time so expect the occasional article about new features in the future. As for future posts, I want to focus on the creation of games so have decided that this blog will be used as a detailed journal for the development of a number of future BlazingGames.com games. More on that next week. The source for the BGLayers library can be found at http://www.blazinggames.com/other/openLibrary/html5Libs.
The Dimension and Point classes don't have any changes necessary. The Rectangle class does have a bit of confusion in it. The contains function is for points while the containsRect is for rectangles. This could be confusing and result in someone using contains with a rectangle parameter and never getting proper results back. To eliminate this possible problem, I am changing contains to containsPoint. To make it even friendlier, both of the contains functions will take advantage of different parameter sets so point and rectangle objects can be passed to the respective functions as well as raw coordinates.
The layers class is where we have a lot of variables that should be private. The logical size of the layer is used to determine the real position so changing it outside of the class will not be noticed resulting in incorrect results. As there currently is no way of altering this, a changeSize function will be created. The logical position variable is similar, but already has multiple functions that modify it so the only new function needed here is a getPosition function. The real position, children and dirty rectangle variables are already adequately handled with functions. The solid variable, on the other hand, is really layer dependent and should not even be seen by the user. Visibility, though, is important so a setVisible function will be added. The only variables left "visible" to the user then are the background color and id. I suppose changing the background color should force a redraw so I will add a setBackgroundColor function and make it protected as well.
Finally, for the ImageLayer class, both the clip and image variables should probably be protected. I debated if it was wise to allow changing the image but ultimately decided there was little harm in allowing it so a setImage function has been added.
With this bit of cleaning up, I think that BGLayers is good enough for now. Certainly, as I am using the library internally, it will have enhancements added to it over time so expect the occasional article about new features in the future. As for future posts, I want to focus on the creation of games so have decided that this blog will be used as a detailed journal for the development of a number of future BlazingGames.com games. More on that next week. The source for the BGLayers library can be found at http://www.blazinggames.com/other/openLibrary/html5Libs.
Monday, November 1, 2010
Animating the Canvas part 9: Getting Dirty Quicker
When I was first starting to learn to program, I was told three steps to follow in order to create good programs. The first step is to get your program running. The second step is to get it running correctly. The final step, which is often not needed, is to get it running fast. In the old days (the 1990's) programmers were more concerned with speed (100MHz was fast!) so a lot of programmers would optimize their code before the program was even running. Often, the optimizations used would make their code messier making it harder to actually get the program running correctly or at all.
The big trick to optimizing is simply the knowledge that in the normal course of running only a small percentage of the code being ran is responsible for the bulk of the time. If you can find the parts of your program that most of the executing time is taking place in, you can optimize those areas and gain a fair bit of speed. Tools like FireBug make this very easy as they have tools that do the tracking for you.
Once you know what code needs to be fixed, the key question becomes how to speed it up. My advice would be to learn Assembly language (aka Machine code). While you may never need to use it, which is unfortunate as it is great fun to code in, knowing what the machine is actually doing at a low level will give you a much greater appreciation for what is going on with your program. Another technique, which I don't do as much as I should, is to simply use the debugger to single step through the function in question. This can give you a huge insight into what is going on.
BGLayers have two parts that need focus on. First, is the adding of dirty rectangles. Next is the rendering of things. The addDirty function is relatively minor CPU wise, but during my discovery at how poor Canvas Clipping is I noticed a lot of Rectangles were being created needlessly and wanted to reduce this. Creating a new instance of an object has some overhead to it so avoiding doing so will speed things up. Right at the start of addDirty, a new instance of a rectangle is created. This was done to support null parameters which add the entire layer, but when you consider that the function will call the same function until the parent is reached, this can be very inefficient.
The problem is that a new instance of the rectangle passed has to be created as it has to be altered to assure it is pixel aligned. While this alteration is minor but could muck up the rectangle if it is used by unrelated parts of the program. When we start clipping the dirty rectangle we use recursion to call the function causing many unnecessary rectangles to be created. The solution is to eliminate the recursion. This is easily done by simply having an array with a list of rectangles that need to be clipped. Initially there is only the initial rectangle in this list. If it is clipped, new rectangles get added to the list instead of having to call addDirty. This eliminates the recursion.
With these simple but major changes, the program is run and no noticeable difference in run time. Well, at least I know there will be less garbage collection. My point about not optimizing where there is no need has proven itself as I wasted almost an hour for no gain. Still, I am happier with the code as recursion has been eliminated making the code nicer.
Next, we try to speed up the part that is taking up over two-thirds of the cycles in my tests. Namely the draw self function. This again leads me back to ancient times (the 90's) when the big bugaboo in graphics programming was drawing pixels multiple times per frame. In those times, accelerated graphics cards were hit or miss and accessing video memory was costly. Things have changed today but eliminating unnecessary drawing is still a good idea. In fact, this was planned from the beginning and is why there is a solid variable to let the renderer know if a layer is solid. Anything underneath a solid layer is not going to be seen so if the portion being drawn is contained within the solid layer, only that layer and any layers above it need to be drawn. This is done in the render function, which the drawSelf function is called from. The rendering code has been changed to only call drawSelf if no solid layers contain the bounds being rendered.
for (cntr = this.children.length - 1; cntr >= 0; --cntr) {
if ((this.children[cntr].solid) && (this.children[cntr].findRealPosition().containsRect(bounds))) {
startDraw = cntr;
break;
}
}
if (startDraw == -1) {
this.drawSelf(ctx, bounds);
startDraw = 0;
}
for (cntr = startDraw; cntr < this.children.length; ++cntr)
this.children[cntr].render(ctx, bounds);
That simple change has a drastic effect on performance. DrawSelf now accounts for less than half of the drawing time. The next step will be to make the API friendlier. The code for this post is located at http://www.blazinggames.com/other/openLibrary/html5Libs.
The big trick to optimizing is simply the knowledge that in the normal course of running only a small percentage of the code being ran is responsible for the bulk of the time. If you can find the parts of your program that most of the executing time is taking place in, you can optimize those areas and gain a fair bit of speed. Tools like FireBug make this very easy as they have tools that do the tracking for you.
Once you know what code needs to be fixed, the key question becomes how to speed it up. My advice would be to learn Assembly language (aka Machine code). While you may never need to use it, which is unfortunate as it is great fun to code in, knowing what the machine is actually doing at a low level will give you a much greater appreciation for what is going on with your program. Another technique, which I don't do as much as I should, is to simply use the debugger to single step through the function in question. This can give you a huge insight into what is going on.
BGLayers have two parts that need focus on. First, is the adding of dirty rectangles. Next is the rendering of things. The addDirty function is relatively minor CPU wise, but during my discovery at how poor Canvas Clipping is I noticed a lot of Rectangles were being created needlessly and wanted to reduce this. Creating a new instance of an object has some overhead to it so avoiding doing so will speed things up. Right at the start of addDirty, a new instance of a rectangle is created. This was done to support null parameters which add the entire layer, but when you consider that the function will call the same function until the parent is reached, this can be very inefficient.
The problem is that a new instance of the rectangle passed has to be created as it has to be altered to assure it is pixel aligned. While this alteration is minor but could muck up the rectangle if it is used by unrelated parts of the program. When we start clipping the dirty rectangle we use recursion to call the function causing many unnecessary rectangles to be created. The solution is to eliminate the recursion. This is easily done by simply having an array with a list of rectangles that need to be clipped. Initially there is only the initial rectangle in this list. If it is clipped, new rectangles get added to the list instead of having to call addDirty. This eliminates the recursion.
With these simple but major changes, the program is run and no noticeable difference in run time. Well, at least I know there will be less garbage collection. My point about not optimizing where there is no need has proven itself as I wasted almost an hour for no gain. Still, I am happier with the code as recursion has been eliminated making the code nicer.
Next, we try to speed up the part that is taking up over two-thirds of the cycles in my tests. Namely the draw self function. This again leads me back to ancient times (the 90's) when the big bugaboo in graphics programming was drawing pixels multiple times per frame. In those times, accelerated graphics cards were hit or miss and accessing video memory was costly. Things have changed today but eliminating unnecessary drawing is still a good idea. In fact, this was planned from the beginning and is why there is a solid variable to let the renderer know if a layer is solid. Anything underneath a solid layer is not going to be seen so if the portion being drawn is contained within the solid layer, only that layer and any layers above it need to be drawn. This is done in the render function, which the drawSelf function is called from. The rendering code has been changed to only call drawSelf if no solid layers contain the bounds being rendered.
for (cntr = this.children.length - 1; cntr >= 0; --cntr) {
if ((this.children[cntr].solid) && (this.children[cntr].findRealPosition().containsRect(bounds))) {
startDraw = cntr;
break;
}
}
if (startDraw == -1) {
this.drawSelf(ctx, bounds);
startDraw = 0;
}
for (cntr = startDraw; cntr < this.children.length; ++cntr)
this.children[cntr].render(ctx, bounds);
That simple change has a drastic effect on performance. DrawSelf now accounts for less than half of the drawing time. The next step will be to make the API friendlier. The code for this post is located at http://www.blazinggames.com/other/openLibrary/html5Libs.
Subscribe to:
Posts (Atom)