Sunday, December 4, 2011
DDTe4 Hours 16 to 18 Optimization
After creating the game, it became clear to me that there are more efficient ways of implementing the game other than using a grid like I did but as I have a short time-limit on the creation of the game, these faster implementations are out of the question. Still, there is some time left for doing an optimization pass. One problem that a lot of programmers have is the desire to prematurely optimize code. While the desire to write efficient code is a good desire, spending a large amount of time on a piece of code that has minimal impact on the performance of the final product is not a good way of spending your time. This is why tools like the profiler that is included in FireBug is such a great feature. The profiler tracks how many times and how much time is spent in every function that is executed while the profiler is running. This lets you know what parts of your program is taking the most time.
In the case of the life game, the code that spent the most time executing due to the huge number of times it was called was the getCell function. The problem with this function is that it needs to support calls outside of the proper bounds in order to properly support the borders. That said, the bounds should only be out by 1 in any given direction which means that if the grid size was slightly bigger and the border was computed along the edges every iteration then we could greatly simplify the getCell function.
To handle this change, the grid size was increased by 2 in both directions, with 1,1 being the top corner internally, though externally 0,0 will be the coordinate passed to get the data. This may not be intuitive, but the downside to optimization is that it can make the code a bit more complicated. The getCell function, on the other hand, becomes a very simple single line of code: return this.grid[y+1][x+1];
This means that if -1 is passed, it goes to the extra bottom or left row and passing the size of the grid as a coordinate will get the extra bottom or right row. To properly fill these rows, the setBorder function has been enhanced. It will fill the border rows and columns with the appropriate data. To make sure the data is correct, it is called at the start of every iteration. To finish up my first optimization pass, the countNeighbors and countCancer functions were quickly optimized by unrolling the loops and replacing the call to getCell with directly obtained cell data as a single line of code is easy to inline.
In JavaScript, there are no explicit types for variables. Variables get converted into whatever type is needed for the current operation. The problem is that this does not always work as planned leading to some real interesting bugs that would not appear in typed languages. In my case, I was using a value from a combo box. The value was a number, but because it is from an html control it's value is stored as a string. When it was passed to my function, 2 gets added to it. The problem is that JavaScript did not convert the string into a number then add two to it, but instead it converted the number into a string and appended it to the string. This resulted in "32" + 2 = "322" which is way off. I solved this bug by flooring the input value forcing it into a number, but finding the bug was a huge problem due to the fact that the code seemed correct (and in a typed language would have been correct). Thank you FireBug.
After fixing the bug and running the profiler again, the getCell, countNeighbors and countCancer drastically dropped in execution time. This optimization pass improved the speed of the simulation quite a bit. The game is quite fun to play with though I am sure there are many features people may want. I can't really think of any features that can be implemented in the few hours left within the allotted development time. For that reason, I am considering the game done. Still, if there is enough interest and suggestions, an enhanced version is something that I would certainly consider working on.
Sunday, November 27, 2011
DDTe4 Hours 13 to 15 - Cancer
This is the third (the first two parts were released last week) of a four part article covering the creation of my implementation of Conway's Game of Life. This week I am adding Cancer to the game.
I am not really sure why I decided to add cancer to the game of life. Perhaps it is my strange way of mourning over the loss of my mother or perhaps all the research into cancer that inspired me to create my own version of Conway's Game of Life was still in the back of my mind when I realized that I still had plenty of time to work on the project and add new features.
In the real world there are a number of causes for cancer but ultimately it comes down to either mutation or cell damage. I am limiting the simulation to only one of the two causes for cancer. For simulation purposes, mutation happens with newly formed cells. These are the ones that appear when an empty cell is surrounded by three (and only 3) living cells. Cell Damage is what happens to aging cells so is applied to any cell that is over 10 generations old. The mutation or damage is determined purely through randomness with an odds variable indicating how likely the cancer starting is. The odds value is a floating point number between 0 and 1 just like the numbers provided by the random number generator making the check simple as it is just seeing if the random number is less than the odds.
The problem with using random numbers in a simulation is that it makes it impossible to re-create the cancer. This problem can be solved by the fact that the random numbers are not random but are instead pseudo-random and the sequence of random numbers is repeatable if the original seed number is known. JavaScript doesn't let you seed the random number generator, so to do this you would have to find or write your own random number generator. For such a short time limit on this project, however, that is not realistic so cancer in this simulation will be unpredictable like it is in the real world.
This leads to the problem of how to deal with the growth of the cancer. There are three growth modes in the game. The mode you want real cancer growing in is benign which is simply no growth. Spreading mode is a slower growing form of cancer in which cells that are about to die but that are next to cancer will become cancerous. Growing mode is the evil mode where the cancer will grow into any dead cells next to it.
My initial tests had the simulation treating cancer cells as if they were dead cells. This was the ideal way from a coding perspective to implement the cancer as no drastic changes to the core simulation engine were needed. However, when I watched the cancer progress it just did not have the correct feel. It simply did not seem to grow properly. I altered the code to treat cancer as being alive and ran the simulation again. The results were almost exactly what I was looking for. I simply loved the results of both spreading modes.
From a performance perspective, there was a bit of a hit from the cancer, but not an overly dramatic hit until the cancer started to grow. The hit from the growing cancer is simply the drawing problem that was discussed in the previous article. Too many cells on the screen causes the rendering code to constantly change the drawing color and the HTML 5 canvas has an extremely inefficient way of setting colors.
Having the growth of cancer slow down the simulation is not that big of a concern, but with at least one more hour that I would like to put into this project spending some time speeding up the overall simulation would be a worthwhile endeavor.
I am not really sure why I decided to add cancer to the game of life. Perhaps it is my strange way of mourning over the loss of my mother or perhaps all the research into cancer that inspired me to create my own version of Conway's Game of Life was still in the back of my mind when I realized that I still had plenty of time to work on the project and add new features.
In the real world there are a number of causes for cancer but ultimately it comes down to either mutation or cell damage. I am limiting the simulation to only one of the two causes for cancer. For simulation purposes, mutation happens with newly formed cells. These are the ones that appear when an empty cell is surrounded by three (and only 3) living cells. Cell Damage is what happens to aging cells so is applied to any cell that is over 10 generations old. The mutation or damage is determined purely through randomness with an odds variable indicating how likely the cancer starting is. The odds value is a floating point number between 0 and 1 just like the numbers provided by the random number generator making the check simple as it is just seeing if the random number is less than the odds.
The problem with using random numbers in a simulation is that it makes it impossible to re-create the cancer. This problem can be solved by the fact that the random numbers are not random but are instead pseudo-random and the sequence of random numbers is repeatable if the original seed number is known. JavaScript doesn't let you seed the random number generator, so to do this you would have to find or write your own random number generator. For such a short time limit on this project, however, that is not realistic so cancer in this simulation will be unpredictable like it is in the real world.
This leads to the problem of how to deal with the growth of the cancer. There are three growth modes in the game. The mode you want real cancer growing in is benign which is simply no growth. Spreading mode is a slower growing form of cancer in which cells that are about to die but that are next to cancer will become cancerous. Growing mode is the evil mode where the cancer will grow into any dead cells next to it.
My initial tests had the simulation treating cancer cells as if they were dead cells. This was the ideal way from a coding perspective to implement the cancer as no drastic changes to the core simulation engine were needed. However, when I watched the cancer progress it just did not have the correct feel. It simply did not seem to grow properly. I altered the code to treat cancer as being alive and ran the simulation again. The results were almost exactly what I was looking for. I simply loved the results of both spreading modes.
From a performance perspective, there was a bit of a hit from the cancer, but not an overly dramatic hit until the cancer started to grow. The hit from the growing cancer is simply the drawing problem that was discussed in the previous article. Too many cells on the screen causes the rendering code to constantly change the drawing color and the HTML 5 canvas has an extremely inefficient way of setting colors.
Having the growth of cancer slow down the simulation is not that big of a concern, but with at least one more hour that I would like to put into this project spending some time speeding up the overall simulation would be a worthwhile endeavor.
Sunday, November 20, 2011
DDTe4 Hours 1 to 6 - The Basics of Life
When my mother went to the hospital and discovered that she had cancer, I spent some time researching the subject. Perhaps not as much time as I would have normally spent when researching a topic that strikes my interest, but enough to discover what a truly evil disease it is. Essentially, cancer is when a cell not only decides it does not want to die (I can’t blame it for that), but then starts reproducing replacing otherwise health cells. Thinking of the reproduction of cells got me thinking of Conway’s Game of Life. This is a zero player game as the game essentially follows a number of simple rules. The fun comes from setting up the world and watching it evolve.
There are a lot of features that I would like my implementation of life to support, and will implement as many features as I can within the 16-24 hours of development time allocated to this project, but the first step is to get the simulation running.
The first thing that has to be taken into account with life is the grid. I wanted to have a flexible size of grid but the key question of dealing with the grid is that in theory, the grid is suppose to be infinite. This is not necessarily realistic so the issue becomes how to deal with borders. I decided to support three different types of borders. Always dead, Always alive, and wrap-around.
The border issue makes the getCell function that I wrote for grabbing a cell a bit complicated as it has to see if the desired cell is within the bounds. If not, it then has to figure out how to deal with it, with wrap-around being a bit complex as it has to convert the passed coordinates into valid coordinates. All this condition testing has me concerned about performance, but I figure if it proves to be an issue I can do some optimization later.
Iterations of the game use the existing grid to spawn the new grid so the LifeGrid class actually creates two grids. The current grid and the old grid. Because the getCell function which I am using uses the current grid, the new grid is created in the old grid space and then the two grids are swapped. For each tile in the grid, the number of alive tiles surrounding it are counted. The rules of life are then applied and we know what the cell is going to be in the next iteration. The rules are fairly simple:
1 - If there are less than two neighbors, a living cell dies of loneliness.
2 - If there are more than three neighbors, a living cell dies of over-crowding.
3 - If there are exactly three cells, an empty (dead) cell becomes a living cell (newborn).
Because of some of the features that I know I will want in the future are dependant on knowing the age of the cell, the age is adjusted as well for each iteration. The LifeGridViewer right now simply draws the cells in red for dead and green for alive. This will change soon, however.
DDTe4 Hours 7 to 12 - Controlling Life
With the game functional, the next step is to implement controls that allow the user to modify the game. While the controls that I implemented could have been completed quicker, I found myself spending a lot longer testing the game then was absolutely necessary as there is just something fascinating about watching the simulation.
Before it is possible to watch a simulation, the simulation must first be animated. In the case of Life, this is simply a matter of displaying consecutive iterations automatically. In browsers, there are two ways of handling the timing. You can set an interval which calls a function after at least the specified time interval has expired. This happens repeatedly until the interval is stopped. For a bit more control, there are timeouts, which work just like intervals except they only call the function once.
To control the animation, a small set of controls are needed. For this game I opted to use html controls that appear below the game display. This is largely due to the fact that the controls are more for options and the real joy comes from watching the display. For the animation, a combo-box is used to allow for different playback speeds, the play button which will become a pause button when clicked, and a single step button for those people who want to analyze the progress of the simulation.
Once the animation was working and tested, adding more control over the colors became my next challenge. I wanted the ability to see the aging of the cells but also wanted the more traditional monochromatic style of display. To allow for these, I decided to use a color set approach where an array of colors are used to determine what is shown for different ages and states for the cells. By setting all the ages to the same color you can create a monochromatic style display. I created a large number of color sets so players should be able to find a color scheme they like.
With a more colorful display finished, controls over the size of the display and whether or not to show borders were added. As different sized grids were already implemented in the core game classes, this was very simple to implement. However, when the simulation was ran at a higher resolution, the speed slowdown was quite significant. Running the firebug profiling tool showed the problem was with the display code.
This had me confused as the display of the simulation is remarkably simple as all it is doing is drawing a large number of rectangles. These should be drawn exceedingly fast. As I looked over the code to see if I did anything stupid, it dawned on me that the color was changing for every rectangle. This shouldn't be a big issue, and with most graphics API's it would not be a problem. However, the Canvas API uses the DOM color model which is string based. This means that for every color change, the string gets converted into a number. The overhead for all this string processing is very high.
At this point, I was banging my head trying to figure out a way of speeding things up without resorting to the lower level canvas ImageData API. While this API gives you access to the raw color data, it would be a lot of work to implement. Then it dawned on me that most frames consist mostly of long-dead cells. Instead of drawing every cell, I really only need to draw the living and recently killed cells. By blanking the display and drawing only the living cells, the speed of the simulation increased dramatically.
The final feature that I knew I must have before I could consider this project releasable would be the ability to manually add cells to the display. This was handled by simply converting the mouse click to a tile coordinate and setting that tile to alive.
With this done, the project is in a releasable state, but I still have at least four hours to invest into this project so the question is what to work on next? More optimization would be nice to speed things up a bit more, but for some reason the idea of adding cancer came to my mind.
Sunday, November 13, 2011
DDTe3 Final Thoughts
This was a really interesting episode to create, as the huge number of articles covering it’s creation clearly shows. Game-play wise, however, I am not as sure. While the individual games are enjoyable for a short-term play, I am not entirely sure there is a long-term play value to the games. To solve this problem, I plan on having a future puzzle gallery project which will let players select the picture to play with whichever game they are interested in. I would also like to add new features such as options to control how the grid is shown, and to give randomly generated images. Additional features such as game timers and move counters may also be added. I am really sure how long it will be before this enhanced version will be created (nor do I know how many releases it will take to get to the final version of the puzzle gallery game) but it is certainly something I will be working on.
Will I do another challenge like this again in the future? As the amount of time I have to devote to the Blazing Games site is being reduced in favour of larger scale games, such a challenge does make some sense. I think, however, if I do such a challenge again it would probably be done slightly different. What I think I would do is create a single game in a 16-24 hour period with as many bells and whistles as can be created within the time limit and then the following episode would add as many variations of the base game as can be created in a 24 hour development period. This would give me both the quality that I would like while also giving me a large number of releases. I would probably switch to a weekly release schedule while all the sub-episodes were released. If there were eight variants like there was for this release it would still result in a couple months for only a 24 hour work period which could be handy if a bigger project is heading into some type of crunch time.
Eight games in 24 hours is still quite impressive. A large reason that such a feat is possible has to do with how much software development tools and environments have improved. I suppose I would be able to develop a couple of games in under 24 hours using basic back when the Commodore 64 was my computer. Assembly language I would be lucky to finish a single game and then only if I was able to rely on code from earlier assembly language projects.
When you get right down to it, JavaScript is the basic of our time, with C++ being the modern equivalent to assembly language. While it is possible to still write in assembly language, the time requirements of writing in assembly language are simply not worth the speed and size benefits that it brings. I still think that it is worth learning assembly language if only to understand what the compiler is actually doing.
Sunday, November 6, 2011
DDTe3 Hours 22 to 23 - A Distorted Game
Sorry for missing last week, but I was condo-sitting for my aunt. This is a continuation of my series of articles about the creation of the multi-game Dozen Days of Tiles episode 3 where I tried to create as many games as I could in 24 hours. This part concludes the development of the final (and my personal favorite) game in the episode.
In earlier games created this episode, the game data (model) was separate from the display (view) with the interaction between the two handled by the game (controller). Having three separate classes allowed for a lot more reuse as the model class was used in all seven of the other games and there were only two view classes shared by the seven games. As time is running out and there will not be any other games based of of the radically different model that this game uses for arranging the tiles, I am combining the controller and the model into a single game class. The entire game code is so small that it really doesn’t matter and if fact creating multiple classes to do things properly is overkill. In fact, despite trying to cut back on the amount of code I post and instead try to focus more on the much more important theory, I am going to post all of the code in the game class.
The constructor stores the image and splitting information. It then sets up the root tile, which is the size of the whole puzzle and contains the whole image. This tile is what gets broken apart to form the final puzzle. An array to hold all the puzzle pieces is created and we call the routine to scramble the board. Since this routine is only ever called once, it could have been placed in the constructor but to make the code a bit more readable (as if such a small program has that problem) it is in a separate function.
PuzzleGallery.DistortionPuzzleGame = function(id, w, h, img, clip, splits)
{
this.supr = new BGLayers.Layer(id, clip.width, clip.height);
BGLayers.inheritProperties(this, this.supr);
this.split = splits;
this.image = img;
this.clip = clip;
this.rootTile = new PuzzleGallery.DistortionTile(id, img, clip, clip.width, clip.height, 10);
this.rootTile.setTileListener(this);
this.tileList = new Array();
this.tileList.push(this.rootTile);
this.selectedTile = null;
this.addChild(this.rootTile, new BGLayers.Rectangle(0,0,w,h));
this.scramble();
}
The heart of the game is handling clicking on tiles. This is very simple as all we do is see if a tile has been clicked on already. If it has not been, the tile gets marked as the selected tile and it’s highlight is turned on. If there is a selected tile then we swap the clipping region of both the tiles and un-highlight the selected tile then we clear the selected tile variable so a new selection can be made. That is all the logic needed to handle the game.
PuzzleGallery.DistortionPuzzleGame.prototype.onTileClick = function(t)
{
if (this.selectedTile == null) {
this.selectedTile = t;
this.selectedTile.setHighlighted(true);
} else {
t.swapClips(this.selectedTile);
this.selectedTile.setHighlighted(false);
this.selectedTile = null;
}
this.addDirty(null);
}
The heart of the game is the scrambling as it also breaks apart the picture. The number of splits passed to the constructor is what controls the number of split passes that the scrambler goes through. In theory, each split doubles the number of tiles in the game, but as there are occasionally tiles that are too small to split further, this is not always the case. One the clips that make up the final puzzle are ready, we loop through the list of pieces and let it know that the true clipping region is it’s current clipping region. Finally, we swap the pieces around. The number of swaps is the split size times the number of tiles to make sure that the puzzle is not straightforward swapping of tiles.
PuzzleGallery.DistortionPuzzleGame.prototype.scramble = function()
{
// breaking up picture
var child, cntr, listLen, cntrList;// = this.rootTile.split();
for (cntr = 0; cntr < this.split; ++cntr) {
listLen = this.tileList.length;
for (cntrList = 0; cntrList < listLen; ++cntrList) {
child = this.tileList[cntrList].split();
if (child != null)
this.tileList.push(child);
}
}
// marking correct clips
listLen = this.tileList.length;
for (cntrList = 0; cntrList < listLen; ++cntrList) {
this.tileList[cntrList].setTrueClip();
}
// scrambling puzzle
var swap;
for (cntr = 0; cntr < this.split; ++cntr) {
for (cntrList = 0; cntrList < listLen; ++cntrList) {
swap = Math.floor(Math.random() * listLen)
this.tileList[cntrList].swapClips(this.tileList[swap]);
}
}
}
That is the entire game and with about half an hour left is where we end this episode. But that may not be the end of the puzzle gallery. Next week I will have one final article on the topic of this game where I discuss possible future plans.
Sunday, October 23, 2011
DDTe3 Hours 19 to 21 A distorted Tile
The distortion puzzle is a game I had created before but have never released on Blazing Games. The idea is that the game is made up of a broken up images where the boxes that make up the image are varying sizes. The part of the image that is shown in each tile is scaled to the size of the tile making for a distorted version of the image. While the game is essentially the original picture puzzle game, the effect of the distortion makes the game much more challenging than a regular picture puzzle game.
The key problem with this game is that the game board is no longer a grid. This means that the tiles will need to be handled differently then the other grid-based games. Likewise, the display is not as simple as the image being displayed in the tile may be distorted. This means that it is a good idea to create a special tile for dealing with the tiles in the distortion puzzle.
Having a hex tile that handled borders was much more convenient then the approach used with the grid games, so I decided to take this approach with the distortionTile. As the rendering and management of the tile is pretty much the same as the hex tile except for the shape I will not go into much detail about that aspect of this class. The focus instead will be on the two key aspects of this class. These are the clip and splitting.
The clip is kind of complex as there are two clips that make up this tile. The first clip is the true clip which is set once all the splitting has been done. If the current clip is the same as the true clip than the tile is in the correct place. The current clip is what gets swapped and is used to determine what is drawn.
Splitting tiles is a special situation as it is what is used to generate the puzzle for the game. To prevent too small of tiles, there are restrictions on how big a tile has to be in order to be split. The split is always done along the longest side, though in hind-site this is probably unnecessary and even more distorted puzzles could be generated by removing this restriction. The split line is then randomly generated but will always be somewhere within the 60% of the middle of the side. The rational for doing this is to prevent super-slim slices within the puzzle as those are hard for the player to deal with both in figuring out what is in the slice and in clicking on the slice.
PuzzleGallery.DistortionTile.prototype.split = function()
{
var child;
var temp;
var tempRect = new BGLayers.Rectangle(this._logicalPosition);
var childRect = new BGLayers.Rectangle(this._logicalPosition);
var childClip = new BGLayers.Rectangle(this._clip);
if (Math.max(this._clip.width, this._clip.height) < (this.thickness*5))
return null;
temp = Math.random() * .6 + .2;
if (this._clip.width >= this._clip.height) {
this._clip.width = Math.floor(temp * this._clip.width);
tempRect.width = Math.floor(temp * tempRect.width);
childRect.x += tempRect.width;
++childRect.x;
childRect.width -= tempRect.width;
childClip.x += this._clip.width;
childClip.width -= this._clip.width;
} else {
this._clip.height = Math.floor(temp * this._clip.height);
tempRect.height = Math.floor(temp * tempRect.height);
childRect.y += tempRect.height;
++childRect.y;
childRect.height -= tempRect.height;
childClip.y += this._clip.height;
childClip.height -= this._clip.height;
}
this.adjustPosition(tempRect);
child = new PuzzleGallery.DistortionTile(this.id, this._image, childClip, childRect.width, childRect.height, this.thickness);
child.setTileListener(this.listener);
this.parent.addChild(child, childRect);
return child;
}
This leaves us with two things that need to be done to have a full game. We need the actual game manager and we need a class to display the puzzle. Both those will be discussed next time.
The key problem with this game is that the game board is no longer a grid. This means that the tiles will need to be handled differently then the other grid-based games. Likewise, the display is not as simple as the image being displayed in the tile may be distorted. This means that it is a good idea to create a special tile for dealing with the tiles in the distortion puzzle.
Having a hex tile that handled borders was much more convenient then the approach used with the grid games, so I decided to take this approach with the distortionTile. As the rendering and management of the tile is pretty much the same as the hex tile except for the shape I will not go into much detail about that aspect of this class. The focus instead will be on the two key aspects of this class. These are the clip and splitting.
The clip is kind of complex as there are two clips that make up this tile. The first clip is the true clip which is set once all the splitting has been done. If the current clip is the same as the true clip than the tile is in the correct place. The current clip is what gets swapped and is used to determine what is drawn.
Splitting tiles is a special situation as it is what is used to generate the puzzle for the game. To prevent too small of tiles, there are restrictions on how big a tile has to be in order to be split. The split is always done along the longest side, though in hind-site this is probably unnecessary and even more distorted puzzles could be generated by removing this restriction. The split line is then randomly generated but will always be somewhere within the 60% of the middle of the side. The rational for doing this is to prevent super-slim slices within the puzzle as those are hard for the player to deal with both in figuring out what is in the slice and in clicking on the slice.
PuzzleGallery.DistortionTile.prototype.split = function()
{
var child;
var temp;
var tempRect = new BGLayers.Rectangle(this._logicalPosition);
var childRect = new BGLayers.Rectangle(this._logicalPosition);
var childClip = new BGLayers.Rectangle(this._clip);
if (Math.max(this._clip.width, this._clip.height) < (this.thickness*5))
return null;
temp = Math.random() * .6 + .2;
if (this._clip.width >= this._clip.height) {
this._clip.width = Math.floor(temp * this._clip.width);
tempRect.width = Math.floor(temp * tempRect.width);
childRect.x += tempRect.width;
++childRect.x;
childRect.width -= tempRect.width;
childClip.x += this._clip.width;
childClip.width -= this._clip.width;
} else {
this._clip.height = Math.floor(temp * this._clip.height);
tempRect.height = Math.floor(temp * tempRect.height);
childRect.y += tempRect.height;
++childRect.y;
childRect.height -= tempRect.height;
childClip.y += this._clip.height;
childClip.height -= this._clip.height;
}
this.adjustPosition(tempRect);
child = new PuzzleGallery.DistortionTile(this.id, this._image, childClip, childRect.width, childRect.height, this.thickness);
child.setTileListener(this.listener);
this.parent.addChild(child, childRect);
return child;
}
This leaves us with two things that need to be done to have a full game. We need the actual game manager and we need a class to display the puzzle. Both those will be discussed next time.
Sunday, October 16, 2011
DDTe3 Hour 18 - Hex Sliding Puzzle
I have decided to switch back to posting my entries here on Sunday evenings. I was actually thinking of dropping this blog and just posting to Google+, but figured that this has a bit more permanence then G+ posts do. This article continues my series on Dozen Days of Tiles episode 3, where I created 8 games in 24 hours. This entry covers the creation of my hex sliding puzzle.
Originally, I was not thinking about doing a hex-based sliding puzzle as realistically you can not slide hexes as they form a really nicely locked pattern. Puzzle games do not necessarily have to reflect reality, so after thinking about it for a while, I figured that this would be an interesting game to develop. After playing the finished version of the game, I am quite glad that I did as it is actually a really fun variation of the sliding puzzle.
The hard part to creating this game is in dealing with the sliding. A hex grid can be thought of as a three-axis system, but that is only partially true. While the Z axis does exist, it is dependent on the X axis and the Y axis. This means that manipulating the Z axis means that you are actually changing the X and Y axis. This got me thinking that if I just move along both the X and Y axis at the same time, things should work. Here is the new version of the sliding code.
PuzzleGallery.HexSlidingPuzzleGame.prototype.moveSlider = function(p)
{
var tempX,tempY;
var hp = new PuzzleGallery.HexPoint();
hp.setPointFromGrid(p.x, p.y);
while ((this.slider.x != hp.x) || (this.slider.y != hp.y)) {
tempX = this.slider.getGridX();
tempY = this.slider.getGridY();
if (this.slider.x > hp.x) {
this.slider.translateX(-1);
} else if (this.slider.x < hp.x) {
this.slider.translateX(1);
}
if (this.slider.y > hp.y) {
this.slider.translateY(-1);
} else if (this.slider.y < hp.y) {
this.slider.translateY(1);
}
this.puzzle.swapPuzzlePieces(tempX, tempY, this.slider.getGridX(), this.slider.getGridY());
};
this.view.update();
}
When trying to see if this method works, sliding along the proper axis works fine but if a shift is not axis-aligned, the results were a bit strange. The quick solution to this problem is to simply limit sliding to axis-aligned slides, which is what the game is going to do anyways. I do not like stop-gap solutions but prefer when possible to know why things are not working. This problem actually was simple enough to figure out, as the strange results come from moves that are positive or negative along both the X and Y axis. Movement along the proper Z axis always results in opposite mathematical operations being applied to X and Y.
While I could probably special case the sliding of positive or negative X/Y combos, I really wanted to get this game finished in under an hour so I would have more time for the next game as it is a fairly complex game. As I would not be able to rely on sliding to random points as I did with the original sliding puzzle, my quick and dirty solution was to simply increase the amount of random slides five-fold calling the sliding through the axis-checking onTileClicked method.
The next (and as it turned out final) game in this series is still not the rotation puzzle but something never released on the Blazing Games site. The development on that game will start being covered next week.
Originally, I was not thinking about doing a hex-based sliding puzzle as realistically you can not slide hexes as they form a really nicely locked pattern. Puzzle games do not necessarily have to reflect reality, so after thinking about it for a while, I figured that this would be an interesting game to develop. After playing the finished version of the game, I am quite glad that I did as it is actually a really fun variation of the sliding puzzle.
The hard part to creating this game is in dealing with the sliding. A hex grid can be thought of as a three-axis system, but that is only partially true. While the Z axis does exist, it is dependent on the X axis and the Y axis. This means that manipulating the Z axis means that you are actually changing the X and Y axis. This got me thinking that if I just move along both the X and Y axis at the same time, things should work. Here is the new version of the sliding code.
PuzzleGallery.HexSlidingPuzzleGame.prototype.moveSlider = function(p)
{
var tempX,tempY;
var hp = new PuzzleGallery.HexPoint();
hp.setPointFromGrid(p.x, p.y);
while ((this.slider.x != hp.x) || (this.slider.y != hp.y)) {
tempX = this.slider.getGridX();
tempY = this.slider.getGridY();
if (this.slider.x > hp.x) {
this.slider.translateX(-1);
} else if (this.slider.x < hp.x) {
this.slider.translateX(1);
}
if (this.slider.y > hp.y) {
this.slider.translateY(-1);
} else if (this.slider.y < hp.y) {
this.slider.translateY(1);
}
this.puzzle.swapPuzzlePieces(tempX, tempY, this.slider.getGridX(), this.slider.getGridY());
};
this.view.update();
}
When trying to see if this method works, sliding along the proper axis works fine but if a shift is not axis-aligned, the results were a bit strange. The quick solution to this problem is to simply limit sliding to axis-aligned slides, which is what the game is going to do anyways. I do not like stop-gap solutions but prefer when possible to know why things are not working. This problem actually was simple enough to figure out, as the strange results come from moves that are positive or negative along both the X and Y axis. Movement along the proper Z axis always results in opposite mathematical operations being applied to X and Y.
While I could probably special case the sliding of positive or negative X/Y combos, I really wanted to get this game finished in under an hour so I would have more time for the next game as it is a fairly complex game. As I would not be able to rely on sliding to random points as I did with the original sliding puzzle, my quick and dirty solution was to simply increase the amount of random slides five-fold calling the sliding through the axis-checking onTileClicked method.
The next (and as it turned out final) game in this series is still not the rotation puzzle but something never released on the Blazing Games site. The development on that game will start being covered next week.
Friday, October 7, 2011
DDTe3 Hour 17 - Hex Spin Puzzle
This is a continuation of my series on the creation of Dozen Days of Tiles episode 3 games on the Blazing Games site. While the other episodes in the Dozen Days series were about the creation of a game in under 24 hours, this episode is a challenge to see how many simple games can be created in under 24 hours. While this article covers the creation of the hex spin game, it is heavily dependent on the material covered in previous posts.
The next game to create this “day” is the hex-based variation of the spin puzzle. Because of the nature of the hex grid, the spin is a fairly natural operation. The spin, when looked at from a hex map perspective as figure 1 shows, is a very simple operation. Of course, using the grid coordinates that we are storing the hex in would make doing this procedure very tricky to code but by using the hex coordinate system that was discussed in an earlier article this can be a very easy piece of code to write.
Converting between the two coordinate systems is easy enough to do and could be done right in the spinning code, I have a third hex game in mind so it might be better off to put the conversion and translation of hex coordinates into it’s own class, which I called HexPoint. This class has methods for converting between the two coordinate systems as well as for translating (moving) the hex point along the x, y and z axis. The z axis is tied to the other two so manipulating the z axis actually adjusts both the x and y axis as the following code snippet shows.
PuzzleGallery.HexPoint.prototype.translateZ = function(adj)
{
this.y = this.y + adj;
this.x = this.x - adj;
}
The HexSpinPuzzle game is essentially the SpinPuzzle game but with a hex grid so the only code that really needs to be written to create this game is a spin methods. Because I am “borrowing” code from SpinPuzzle which itself was borrowed from TwistPuzzle, the method to perform the spin action is called performTwist. While the logic behind the spin is the same as with the two grid games, the implementation is a bit more complex due to the need to work with two different coordinate systems. While at first glance the code may seem complex, it is remarkably simple and took very little time to write. Essentially, all we are doing is defining a pair of hex coordinates which represent the tiles that are to be manipulated. We start by finding the coordinates of the starting point. I am using the y-1 hex coordinate, though any hex that circles the hex tile that was clicked on could have been chosen for the starting point. As with the regular twist and spin puzzles, we need to save this to a temporary variable as this tile is going to be replaced. The coordinate is saved in a second HexPoint and the original point is translated to the position of the tile that will be shifted into the original point. Becuse of the point chosen to start at, the order of the translations are x+1, y+1, z+1, x-1, and y-1. The final z-1 translation would take us back to the start so instead of doing that translation we instead use the temp value. After each translation, the tile at that location is copied to the previous position.
PuzzleGallery.HexSpinPuzzleGame.prototype.performTwist = function(p)
{
var hp1 = new PuzzleGallery.HexPoint();
var hp2 = new PuzzleGallery.HexPoint();
hp1.setPointFromGrid(p.x, p.y);
hp1.translateY(-1);
hp2.moveTo(hp1.x, hp1.y);
var temp = this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY());
hp1.translateX(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateY(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateZ(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateX(-1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateY(-1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
// hp1.translateZ(-1);
this.puzzle.setPuzzlePiece(hp2.getGridX(), hp2.getGridY(), temp);
this.view.update();
}
With this done the game is ready. The next hex game should be fairly simple to write and will probably leave me with enough time to create an eighth game.
The next game to create this “day” is the hex-based variation of the spin puzzle. Because of the nature of the hex grid, the spin is a fairly natural operation. The spin, when looked at from a hex map perspective as figure 1 shows, is a very simple operation. Of course, using the grid coordinates that we are storing the hex in would make doing this procedure very tricky to code but by using the hex coordinate system that was discussed in an earlier article this can be a very easy piece of code to write.
figure 1 - Hex Spin |
Converting between the two coordinate systems is easy enough to do and could be done right in the spinning code, I have a third hex game in mind so it might be better off to put the conversion and translation of hex coordinates into it’s own class, which I called HexPoint. This class has methods for converting between the two coordinate systems as well as for translating (moving) the hex point along the x, y and z axis. The z axis is tied to the other two so manipulating the z axis actually adjusts both the x and y axis as the following code snippet shows.
PuzzleGallery.HexPoint.prototype.translateZ = function(adj)
{
this.y = this.y + adj;
this.x = this.x - adj;
}
The HexSpinPuzzle game is essentially the SpinPuzzle game but with a hex grid so the only code that really needs to be written to create this game is a spin methods. Because I am “borrowing” code from SpinPuzzle which itself was borrowed from TwistPuzzle, the method to perform the spin action is called performTwist. While the logic behind the spin is the same as with the two grid games, the implementation is a bit more complex due to the need to work with two different coordinate systems. While at first glance the code may seem complex, it is remarkably simple and took very little time to write. Essentially, all we are doing is defining a pair of hex coordinates which represent the tiles that are to be manipulated. We start by finding the coordinates of the starting point. I am using the y-1 hex coordinate, though any hex that circles the hex tile that was clicked on could have been chosen for the starting point. As with the regular twist and spin puzzles, we need to save this to a temporary variable as this tile is going to be replaced. The coordinate is saved in a second HexPoint and the original point is translated to the position of the tile that will be shifted into the original point. Becuse of the point chosen to start at, the order of the translations are x+1, y+1, z+1, x-1, and y-1. The final z-1 translation would take us back to the start so instead of doing that translation we instead use the temp value. After each translation, the tile at that location is copied to the previous position.
PuzzleGallery.HexSpinPuzzleGame.prototype.performTwist = function(p)
{
var hp1 = new PuzzleGallery.HexPoint();
var hp2 = new PuzzleGallery.HexPoint();
hp1.setPointFromGrid(p.x, p.y);
hp1.translateY(-1);
hp2.moveTo(hp1.x, hp1.y);
var temp = this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY());
hp1.translateX(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateY(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateZ(1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateX(-1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
hp1.translateY(-1);
this.puzzle.setPuzzlePiece(
hp2.getGridX(), hp2.getGridY(),
this.puzzle.getPuzzlePiece(hp1.getGridX(), hp1.getGridY()));
hp2.moveTo(hp1.x, hp1.y);
// hp1.translateZ(-1);
this.puzzle.setPuzzlePiece(hp2.getGridX(), hp2.getGridY(), temp);
this.view.update();
}
With this done the game is ready. The next hex game should be fairly simple to write and will probably leave me with enough time to create an eighth game.
Thursday, September 29, 2011
DDTe3 Hour 15 - 16 Hex Puzzle Game
My series of posts on the creation of Dozen Days of Tiles episode 3 (Puzzle Gallery) continues with the creation of the hex puzzle game. This builds on the theory and code from the last couple of posts so please read those first.
With the HexTile class complete, the next step is to actually display the puzzle. The display of a hex grid is a bit more complicated then displaying a regular tile grid. If you draw a rectangle on a piece of hex graph paper, you will notice that you will be clipping half a hex on each end. This means that the width of a hex-tile is equivalent to the width of the display divided by the half a hex more than the number of desired tiles in the row. The height of a hex -tile is even more confusing to calculate. Because the rows of hexes overlap, the height of a row is essentially less than the height of a tile. When determining the tile height, it is best to think of each row (except the last) being ¾ of the height of a tile.
var halfWidth = Math.floor(clip.width / (puzzle.puzzleWidth * 2 + 1));
var quarterHeight = Math.floor(clip.height / (puzzle.puzzleHeight * 3 + 1));
this.tileWidth = halfWidth * 2;
this.tileHeight = quarterHeight * 4;
Laying out the tiles is pretty much the same as laying out a grid, except that every other row is offset by half a tile. Unlike the grid based games, the border is kind of important here as bits of the image are cut out by the irregular shape of the board. The border is drawn the same as it was in the original BasePuzzleView class except that the top and bottom extend a quarter of a tile into the board and the left and right borders extend half a tile into the board.
With the puzzle drawing properly, we now have the problem that the board is drawn in it’s solved state. Moving the hex tiles around is a bit trickier and I was about to write code to calculate the placement of a hex when I realized that I would be looping through them all anyway. By using the Puzzle value to determine which hex goes in which screen location, the update code was only marginally different from the original update code.
The final challenge, which I cheated on, is the click handling. Instead of properly determining which hex was clicked on, I assumed that most people are going to be clicking near the middle of a hex anyway so went with the much simpler bounding box. I may do proper checks later but for now the method is good enough.
With the click support added, creating the first puzzle was simply a matter of copying the original PicturePuzzle Class and changing BasePuzzleView to HexPuzzleView where necessary. With this done, the first hex based puzzle is done and it is time to start on the next one.
With the HexTile class complete, the next step is to actually display the puzzle. The display of a hex grid is a bit more complicated then displaying a regular tile grid. If you draw a rectangle on a piece of hex graph paper, you will notice that you will be clipping half a hex on each end. This means that the width of a hex-tile is equivalent to the width of the display divided by the half a hex more than the number of desired tiles in the row. The height of a hex -tile is even more confusing to calculate. Because the rows of hexes overlap, the height of a row is essentially less than the height of a tile. When determining the tile height, it is best to think of each row (except the last) being ¾ of the height of a tile.
figure 1 - Hex Clip |
var halfWidth = Math.floor(clip.width / (puzzle.puzzleWidth * 2 + 1));
var quarterHeight = Math.floor(clip.height / (puzzle.puzzleHeight * 3 + 1));
this.tileWidth = halfWidth * 2;
this.tileHeight = quarterHeight * 4;
Laying out the tiles is pretty much the same as laying out a grid, except that every other row is offset by half a tile. Unlike the grid based games, the border is kind of important here as bits of the image are cut out by the irregular shape of the board. The border is drawn the same as it was in the original BasePuzzleView class except that the top and bottom extend a quarter of a tile into the board and the left and right borders extend half a tile into the board.
With the puzzle drawing properly, we now have the problem that the board is drawn in it’s solved state. Moving the hex tiles around is a bit trickier and I was about to write code to calculate the placement of a hex when I realized that I would be looping through them all anyway. By using the Puzzle value to determine which hex goes in which screen location, the update code was only marginally different from the original update code.
The final challenge, which I cheated on, is the click handling. Instead of properly determining which hex was clicked on, I assumed that most people are going to be clicking near the middle of a hex anyway so went with the much simpler bounding box. I may do proper checks later but for now the method is good enough.
With the click support added, creating the first puzzle was simply a matter of copying the original PicturePuzzle Class and changing BasePuzzleView to HexPuzzleView where necessary. With this done, the first hex based puzzle is done and it is time to start on the next one.
Friday, September 23, 2011
DDTe3 Hour 12 - 14 Hex Tile
This is a continuation of my series of articles on the creation of Dozen Days of Tiles episode 3. In this part, we continue developing the hex code by creating a hex-shaped image clipping tile.
As I don’t already have any existing classes for drawing masked shapes, a new class is going to need to be created for drawing the hex tile. This new class works very similarly to the existing ImageLayer class, but with a bit more drawing complexity. Overridding the ImageLayer class does not make sense as the drawing code is going to have to be replaced.
Clipping in the HTML5 canvas is a bit tricky. The important thing to remember about clipping is that you MUST save the state of the canvas before setting a clipping region and restore the state of the canvas once you are done. The canvas does not let you create a new clipping region larger than the existing region. Each successive clip results in a ever-shrinking drawable region. I personally would have used a additive/subtractive model for building a clipping layer, but that is not what we currently have to work with.
Drawing the hex tile then consists of saving the canvas state, creating a hex path (outPath) for the tile, clipping the canvas using the path, drawing the tile as a rectangle, then restoring the canvas state. As I was doing all this drawing work anyway, I started thinking that perhaps I should combine the drawing of the hex with the drawing of the highlight/border. Adding the setup/management methods of the TileBorder class to the HexTile class was simple as these classes for just set up variables. The hard part would be drawing them, and this was actually not overly difficult.
My first thought was to use a clipping approach as was done with the drawing of the image. This thought only lasted a few second as I quickly realized that instead of drawing a transparent rectangle over a clipping path, I could just draw a transparent color using the path. By creating the inner bounds of the border, I would also have the path needed for drawing the highlight color. With inner and outer hexes, it is possible to create the border path. As explained in the previous post, the border has to reverse the order of the inner path points as the winding order of the lines in the path determine the fill area. With the outer and inner hex path, this is very simple to do.
for (var cntr = 0; cntr < 7; ++cntr) {
this.borderPath[cntr] = this.outPath[cntr];
this.borderPath[13-cntr] = this.inPath[cntr];
}
this.borderPath[14] = this.outPath[6];
The next step then is to create a hex view. That, along with the first hex game, is what we will be looking at next.
As I don’t already have any existing classes for drawing masked shapes, a new class is going to need to be created for drawing the hex tile. This new class works very similarly to the existing ImageLayer class, but with a bit more drawing complexity. Overridding the ImageLayer class does not make sense as the drawing code is going to have to be replaced.
Clipping in the HTML5 canvas is a bit tricky. The important thing to remember about clipping is that you MUST save the state of the canvas before setting a clipping region and restore the state of the canvas once you are done. The canvas does not let you create a new clipping region larger than the existing region. Each successive clip results in a ever-shrinking drawable region. I personally would have used a additive/subtractive model for building a clipping layer, but that is not what we currently have to work with.
Drawing the hex tile then consists of saving the canvas state, creating a hex path (outPath) for the tile, clipping the canvas using the path, drawing the tile as a rectangle, then restoring the canvas state. As I was doing all this drawing work anyway, I started thinking that perhaps I should combine the drawing of the hex with the drawing of the highlight/border. Adding the setup/management methods of the TileBorder class to the HexTile class was simple as these classes for just set up variables. The hard part would be drawing them, and this was actually not overly difficult.
My first thought was to use a clipping approach as was done with the drawing of the image. This thought only lasted a few second as I quickly realized that instead of drawing a transparent rectangle over a clipping path, I could just draw a transparent color using the path. By creating the inner bounds of the border, I would also have the path needed for drawing the highlight color. With inner and outer hexes, it is possible to create the border path. As explained in the previous post, the border has to reverse the order of the inner path points as the winding order of the lines in the path determine the fill area. With the outer and inner hex path, this is very simple to do.
for (var cntr = 0; cntr < 7; ++cntr) {
this.borderPath[cntr] = this.outPath[cntr];
this.borderPath[13-cntr] = this.inPath[cntr];
}
this.borderPath[14] = this.outPath[6];
The next step then is to create a hex view. That, along with the first hex game, is what we will be looking at next.
Thursday, September 15, 2011
DDTe3 Hours 11 Drawing Hexes
In order to manipulate hex-shaped images, masks are going to have to be used. In canvas parlance, clipping regions are the proper term. Clipping is one of the ugliest parts of the canvas API, as it uses a shrinking region logic. You have to save the canvas state before setting up the region, set up the region, do the clipping based drawing, then restore the state of the canvas. Thankfully clipping is powerful enough to allow paths to be used to create a clipping region. This means that if we can create a simple hex-drawing function, that hex can be used as a clipping shape for creating hex-shaped puzzle pieces.
Actually, instead of drawing a hex, creating an array of points is more useful, especially when it comes time to creating the border. The hex, when you look at it, really only has a small number of important numbers that need to be calculated. Figure 1 shows the special points that are needed to create the hex and listing 1 shows the function used for creating the array of points.
function buildHexPath(rect, pathlist)
{
var path = pathlist;
// make sure path list of points contains proper number of points
if (path == null)
path = new Array();
while (path.length < 7)
path.push(new BGLayers.Point());
while (path.length > 7)
path.pop();
var halfx = rect.x + rect.width / 2;
var x2 = rect.x + rect.width;
var y1a = rect.y + rect.height / 4;
var y1b = rect.y + 3 * rect.height / 4;
var y2 = rect.y + rect.height;
path[0].x = rect.x;
path[0].y = y1a;
path[1].x = halfx;
path[1].y = rect.y;
path[2].x = x2;
path[2].y = y1a;
path[3].x = x2;
path[3].y = y1b;
path[4].x = halfx;
path[4].y = y2;
path[5].x = rect.x;
path[5].y = y1b;
path[6].x = rect.x;
path[6].y = y1a;
return path;
}
The hex can now be drawn, but to create a border we need a pair of hexes. My first attempt to create a border hex was to create an inner hex and an outer hex and join the two together. This did not work as expected. If you look at figure 2, the first hex is the normal hex. The second hex is suppose to be the border. My immediate reaction was that the fill method didn’t support complex polygons. This isn’t that surprising of a limitation so I quickly wrote my plan B implementation.
The third hex in this figure was created by drawing each segment of the hex separately. This was done in a similar way to the first attempt at creating a border. A outer hex and an inner hex are created and then the points are looped through and combined to create six separate polygons.
function drawHexBorder(ctx, rect, pct)
{
var outpath = buildHexPath(rect, null);
var wadj = rect.width * pct;
var hadj = rect.height * pct;
var inpath = buildHexPath(new BGLayers.Rectangle(rect.x+wadj, rect.y+hadj, rect.width - wadj-wadj, rect.height - hadj-hadj),null);
for(var cntr = 0; cntr < 6; ++cntr) {
ctx.beginPath();
ctx.moveTo(outpath[cntr].x,outpath[cntr].y);
ctx.lineTo(outpath[cntr+1].x,outpath[cntr+1].y);
ctx.lineTo(inpath[cntr+1].x,inpath[cntr+1].y);
ctx.lineTo(inpath[cntr].x,inpath[cntr].y);
ctx.lineTo(outpath[cntr].x,outpath[cntr].y);
ctx.closePath();
ctx.fill();
}
}
Once this was done I decided to spend a little bit of time researching how the cavas fill was suppose to work as I was positive that I had seen some drawings that had holes in it. After a few minutes of research (about the same amount of time it took me to write plan-b) I finally stumbled upon the winding rule for filling. It appears that the direction of the edge lines are used as part of determining of the points that are filled. While I have played with a number of fill algorithms, I have never actually implemented a winding algorithm but it does mean that by reversing the order of the points in the inner hexagon, the fill should work properly. This would allow the drawing of the border as a single drawing operation which should be more efficient.
Actually, instead of drawing a hex, creating an array of points is more useful, especially when it comes time to creating the border. The hex, when you look at it, really only has a small number of important numbers that need to be calculated. Figure 1 shows the special points that are needed to create the hex and listing 1 shows the function used for creating the array of points.
figure 1 |
function buildHexPath(rect, pathlist)
{
var path = pathlist;
// make sure path list of points contains proper number of points
if (path == null)
path = new Array();
while (path.length < 7)
path.push(new BGLayers.Point());
while (path.length > 7)
path.pop();
var halfx = rect.x + rect.width / 2;
var x2 = rect.x + rect.width;
var y1a = rect.y + rect.height / 4;
var y1b = rect.y + 3 * rect.height / 4;
var y2 = rect.y + rect.height;
path[0].x = rect.x;
path[0].y = y1a;
path[1].x = halfx;
path[1].y = rect.y;
path[2].x = x2;
path[2].y = y1a;
path[3].x = x2;
path[3].y = y1b;
path[4].x = halfx;
path[4].y = y2;
path[5].x = rect.x;
path[5].y = y1b;
path[6].x = rect.x;
path[6].y = y1a;
return path;
}
The hex can now be drawn, but to create a border we need a pair of hexes. My first attempt to create a border hex was to create an inner hex and an outer hex and join the two together. This did not work as expected. If you look at figure 2, the first hex is the normal hex. The second hex is suppose to be the border. My immediate reaction was that the fill method didn’t support complex polygons. This isn’t that surprising of a limitation so I quickly wrote my plan B implementation.
figure 2 |
The third hex in this figure was created by drawing each segment of the hex separately. This was done in a similar way to the first attempt at creating a border. A outer hex and an inner hex are created and then the points are looped through and combined to create six separate polygons.
function drawHexBorder(ctx, rect, pct)
{
var outpath = buildHexPath(rect, null);
var wadj = rect.width * pct;
var hadj = rect.height * pct;
var inpath = buildHexPath(new BGLayers.Rectangle(rect.x+wadj, rect.y+hadj, rect.width - wadj-wadj, rect.height - hadj-hadj),null);
for(var cntr = 0; cntr < 6; ++cntr) {
ctx.beginPath();
ctx.moveTo(outpath[cntr].x,outpath[cntr].y);
ctx.lineTo(outpath[cntr+1].x,outpath[cntr+1].y);
ctx.lineTo(inpath[cntr+1].x,inpath[cntr+1].y);
ctx.lineTo(inpath[cntr].x,inpath[cntr].y);
ctx.lineTo(outpath[cntr].x,outpath[cntr].y);
ctx.closePath();
ctx.fill();
}
}
Once this was done I decided to spend a little bit of time researching how the cavas fill was suppose to work as I was positive that I had seen some drawings that had holes in it. After a few minutes of research (about the same amount of time it took me to write plan-b) I finally stumbled upon the winding rule for filling. It appears that the direction of the edge lines are used as part of determining of the points that are filled. While I have played with a number of fill algorithms, I have never actually implemented a winding algorithm but it does mean that by reversing the order of the points in the inner hexagon, the fill should work properly. This would allow the drawing of the border as a single drawing operation which should be more efficient.
Thursday, September 8, 2011
DDTe3 Hex theory
This article continues my series of articles on the creation of Dozen Days of Tiles episode 3. In this episode instead of creating a game in under 24 hours of development time, I am instead seeing how many games I can create in 24 hours. The previous articles covered the creation of the first four games in this episode. This article takes a look at hex grids and the theory used behind the next three games in this episode.
The fifth game in this game in a day (24 hours development time, not real time) is still not my rotation puzzle game. Instead, I am going to do a hex based version of the image puzzle.While this play mode may be original to the Blazing Games site, it is not the first time I have done this game. When I was playing around with the Android SDK, I developed this play mode. Instead of breaking the puzzle up into a grid, the puzzle is broken up into hexes on a hex map.
If you are into tabletop strategy or role-playing games, you are probably already familiar to hex maps. For these games, hex maps have a huge advantage over grids in that you do not have to deal with diagonals. This may not sound like a big deal, but moving diagonally lets you travel a bit more than 1.4 times further than if you travel horizontally or vertically. For image puzzles, it adds a bit more challenge to the puzzle as more thought is required to place the pieces.
Using a hex grid seems scary the first time you approach developing one, but as you look at it, things really are not that complicated. The first issue is how to represent the data. I originally solved this problem when I looked at an offset-tiled ceiling and immediately realized how the pattern was similar to that of a hex map. Figure 1 shows the two side by side.
The nice thing about the offset map is that it is easy to represent the map by simply using a grid. Depending on the type of things you are planning on doing, there may be no issues at all. Where there is a problem is when you start adding things on top of the map and have to start moving them around and looking around the map. The x direction is fine, but any type of y manipulation is problematic as the grid shifts around. One solution to this problem is to properly align the y axis as shown in figure 2. Notice that there is a third axis, labeled Z. This is not really a separate axis as it’s value is dependent on the value of the X and Y axis so it can be easily calculated.
This seems like a good idea but has the problem of having a skewed layout. Storing such a hex map means either having to have negative coordinates or having a lot of unused storage as the map size and positioning of things is adjusted to allow for a positive only layout. A better solution is to use the offset-grid format for storing the hex map but then convert to axis-aligned coordinates when doing any type of traversal of the grid. This translation can be done as follows:
hex_x = x - Math.floor(y/2);
hex_y = y;
hex_z = -hex_x - hex_y;
By having both the offset_tile coordinates for a logical grid-based storage and manipulation of the data as well as hex coordinates for navigating the hex-grid, the hex map becomes fairly easy to work with. The best part is that because the offset grid works the same as a normal grid, the BasePuzzleModel does not need to be changed in order to use it for hex-based puzzle games. What does need to be changed, however, is the BasePuzzleView. Before we can create the HexPuzzleView class, however, we will need to first figure out how to draw hexes. That, of course, will be next week.
The fifth game in this game in a day (24 hours development time, not real time) is still not my rotation puzzle game. Instead, I am going to do a hex based version of the image puzzle.While this play mode may be original to the Blazing Games site, it is not the first time I have done this game. When I was playing around with the Android SDK, I developed this play mode. Instead of breaking the puzzle up into a grid, the puzzle is broken up into hexes on a hex map.
If you are into tabletop strategy or role-playing games, you are probably already familiar to hex maps. For these games, hex maps have a huge advantage over grids in that you do not have to deal with diagonals. This may not sound like a big deal, but moving diagonally lets you travel a bit more than 1.4 times further than if you travel horizontally or vertically. For image puzzles, it adds a bit more challenge to the puzzle as more thought is required to place the pieces.
Using a hex grid seems scary the first time you approach developing one, but as you look at it, things really are not that complicated. The first issue is how to represent the data. I originally solved this problem when I looked at an offset-tiled ceiling and immediately realized how the pattern was similar to that of a hex map. Figure 1 shows the two side by side.
figure 1 |
figure 2 |
This seems like a good idea but has the problem of having a skewed layout. Storing such a hex map means either having to have negative coordinates or having a lot of unused storage as the map size and positioning of things is adjusted to allow for a positive only layout. A better solution is to use the offset-grid format for storing the hex map but then convert to axis-aligned coordinates when doing any type of traversal of the grid. This translation can be done as follows:
hex_x = x - Math.floor(y/2);
hex_y = y;
hex_z = -hex_x - hex_y;
By having both the offset_tile coordinates for a logical grid-based storage and manipulation of the data as well as hex coordinates for navigating the hex-grid, the hex map becomes fairly easy to work with. The best part is that because the offset grid works the same as a normal grid, the BasePuzzleModel does not need to be changed in order to use it for hex-based puzzle games. What does need to be changed, however, is the BasePuzzleView. Before we can create the HexPuzzleView class, however, we will need to first figure out how to draw hexes. That, of course, will be next week.
Thursday, September 1, 2011
DDTe3 Hour 10 - Spin Puzzle
The spin puzzle is similar to the twist puzzle except that the tiles surrounding the tile clicked on are the ones that move counterclockwise. As with the previous puzzle, this one was very quick to implement. In fact, this game was finished in under half an hour!
The spinning mechanism is very similar to the twist mechanism but more so. To make it easer to get my coordinates straight, I took a piece of paper and created a 3x3 grid and wrote the offsets in the grid as the following table demonstrates.
Instead of the 4 way swap that was implemented for the twist puzzle, this game will use a 8 way swap.
PuzzleGallery.SpinPuzzleGame.prototype.performTwist = function(p)
{
var temp = this.puzzle.getPuzzlePiece(p.x-1, p.y-1);
this.puzzle.setPuzzlePiece(p.x-1, p.y-1, this.puzzle.getPuzzlePiece(p.x, p.y-1));
this.puzzle.setPuzzlePiece(p.x, p.y-1, this.puzzle.getPuzzlePiece(p.x+1, p.y-1));
this.puzzle.setPuzzlePiece(p.x+1, p.y-1, this.puzzle.getPuzzlePiece(p.x+1, p.y));
this.puzzle.setPuzzlePiece(p.x+1, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y+1));
this.puzzle.setPuzzlePiece(p.x+1, p.y+1, this.puzzle.getPuzzlePiece(p.x, p.y+1));
this.puzzle.setPuzzlePiece(p.x, p.y+1, this.puzzle.getPuzzlePiece(p.x-1, p.y+1));
this.puzzle.setPuzzlePiece(p.x-1, p.y+1, this.puzzle.getPuzzlePiece(p.x-1, p.y));
this.puzzle.setPuzzlePiece(p.x-1, p.y, temp);
this.view.update();
}
Finally, the click had to make sure the position clicked on can spin and the scrambling method had to be adjusted to insure the coordinates are valid. With those simple changes, another game has been completed. My next game in this challenge will be a bit more complex as it will not only require a new view class be created, but also a new coordinate system though surprisingly the BasePuzzleModel will remain unchanged!
The spinning mechanism is very similar to the twist mechanism but more so. To make it easer to get my coordinates straight, I took a piece of paper and created a 3x3 grid and wrote the offsets in the grid as the following table demonstrates.
-1,-1 | 0,-1 | 1,-1 |
-1,0 | * | 1,0 |
-1,1 | 0,1 | 1,1 |
Instead of the 4 way swap that was implemented for the twist puzzle, this game will use a 8 way swap.
PuzzleGallery.SpinPuzzleGame.prototype.performTwist = function(p)
{
var temp = this.puzzle.getPuzzlePiece(p.x-1, p.y-1);
this.puzzle.setPuzzlePiece(p.x-1, p.y-1, this.puzzle.getPuzzlePiece(p.x, p.y-1));
this.puzzle.setPuzzlePiece(p.x, p.y-1, this.puzzle.getPuzzlePiece(p.x+1, p.y-1));
this.puzzle.setPuzzlePiece(p.x+1, p.y-1, this.puzzle.getPuzzlePiece(p.x+1, p.y));
this.puzzle.setPuzzlePiece(p.x+1, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y+1));
this.puzzle.setPuzzlePiece(p.x+1, p.y+1, this.puzzle.getPuzzlePiece(p.x, p.y+1));
this.puzzle.setPuzzlePiece(p.x, p.y+1, this.puzzle.getPuzzlePiece(p.x-1, p.y+1));
this.puzzle.setPuzzlePiece(p.x-1, p.y+1, this.puzzle.getPuzzlePiece(p.x-1, p.y));
this.puzzle.setPuzzlePiece(p.x-1, p.y, temp);
this.view.update();
}
Finally, the click had to make sure the position clicked on can spin and the scrambling method had to be adjusted to insure the coordinates are valid. With those simple changes, another game has been completed. My next game in this challenge will be a bit more complex as it will not only require a new view class be created, but also a new coordinate system though surprisingly the BasePuzzleModel will remain unchanged!
Thursday, August 25, 2011
DDTe3 Hour 9 Twist puzzle
While it has been a while since the last post in this series due to a family tragedy, I am now back to posting weekly and am continuing my series of articles on the creation of Dozen Days of Tiles episode 3. This is a game in a day challenge in which instead of developing a game in under 24 hours (development time) I am instead seeing how many games can be created in 24 hours of development time. Today the creation of the twist puzzle is covered.
The twist puzzle takes a 2x2 block of tiles and rotates them counter-clockwise. The only new game mechanic revolves around the rotation of tiles, which can be handled using existing BasePuzzleModel classes. There are no changes needed to the view class making this is a very quick project.
The game mechanic that needs to be implemented is a performTwist method. This could be done using three swaps as outlined in the following pseudo-code:
swap x,y with x+1,y
swap x+1,y with x+1,y+1
swap x+1,y+1 with x,y+1
However this results in six tile moves. Because I already knew which game I was going to develop right after this one was finished, I decided to use a more efficient four-way swap as the next game in the series would be better able to utilize this code. Having long-term plans is always nice, even if they don't come to fruition they are giving you a path to follow.
PuzzleGallery.TwistPuzzleGame.prototype.performTwist = function(p)
{
var temp = this.puzzle.getPuzzlePiece(p.x, p.y);
this.puzzle.setPuzzlePiece(p.x, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y));
this.puzzle.setPuzzlePiece(p.x+1, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y+1));
this.puzzle.setPuzzlePiece(p.x+1, p.y+1, this.puzzle.getPuzzlePiece(p.x, p.y+1));
this.puzzle.setPuzzlePiece(p.x, p.y+1, temp);
this.view.update();
}
This still leaves the problem that tiles along the right and bottom edges are not valid to click on so the onTileClick callback method has to be slightly changed.
PuzzleGallery.TwistPuzzleGame.prototype.onTileClick = function(p)
{
if (( p.x < (this.puzzle.puzzleWidth-1)) && (p.y < (this.puzzle.puzzleHeight-1)))
this.performTwist(p);
}
The game scrambling likewise needs to be changed. As with the sliding puzzle game, a scramble method that randomly selects a valid tile and performs a twist on that tile is all that was needed.
PuzzleGallery.TwistPuzzleGame.prototype.scramble = function()
{
var p = new BGLayers.Point();
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h * 10;
for (var cntr = 0; cntr < n; ++cntr) {
p.x = Math.floor(Math.random() * (w-1));
p.y = Math.floor(Math.random() * (h-1));
this.performTwist(p);
}
}
While I try to focus on writing about the theory behind the code and try only to show the relevant bits of code, almost all the code that I wrote is in this article. Still, finishing a game in well under an hour (though I am still counting the time as an hour to simplify my time-keeping) is great.
The twist puzzle takes a 2x2 block of tiles and rotates them counter-clockwise. The only new game mechanic revolves around the rotation of tiles, which can be handled using existing BasePuzzleModel classes. There are no changes needed to the view class making this is a very quick project.
The game mechanic that needs to be implemented is a performTwist method. This could be done using three swaps as outlined in the following pseudo-code:
swap x,y with x+1,y
swap x+1,y with x+1,y+1
swap x+1,y+1 with x,y+1
However this results in six tile moves. Because I already knew which game I was going to develop right after this one was finished, I decided to use a more efficient four-way swap as the next game in the series would be better able to utilize this code. Having long-term plans is always nice, even if they don't come to fruition they are giving you a path to follow.
PuzzleGallery.TwistPuzzleGame.prototype.performTwist = function(p)
{
var temp = this.puzzle.getPuzzlePiece(p.x, p.y);
this.puzzle.setPuzzlePiece(p.x, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y));
this.puzzle.setPuzzlePiece(p.x+1, p.y, this.puzzle.getPuzzlePiece(p.x+1, p.y+1));
this.puzzle.setPuzzlePiece(p.x+1, p.y+1, this.puzzle.getPuzzlePiece(p.x, p.y+1));
this.puzzle.setPuzzlePiece(p.x, p.y+1, temp);
this.view.update();
}
This still leaves the problem that tiles along the right and bottom edges are not valid to click on so the onTileClick callback method has to be slightly changed.
PuzzleGallery.TwistPuzzleGame.prototype.onTileClick = function(p)
{
if (( p.x < (this.puzzle.puzzleWidth-1)) && (p.y < (this.puzzle.puzzleHeight-1)))
this.performTwist(p);
}
The game scrambling likewise needs to be changed. As with the sliding puzzle game, a scramble method that randomly selects a valid tile and performs a twist on that tile is all that was needed.
PuzzleGallery.TwistPuzzleGame.prototype.scramble = function()
{
var p = new BGLayers.Point();
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h * 10;
for (var cntr = 0; cntr < n; ++cntr) {
p.x = Math.floor(Math.random() * (w-1));
p.y = Math.floor(Math.random() * (h-1));
this.performTwist(p);
}
}
While I try to focus on writing about the theory behind the code and try only to show the relevant bits of code, almost all the code that I wrote is in this article. Still, finishing a game in well under an hour (though I am still counting the time as an hour to simplify my time-keeping) is great.
Thursday, August 18, 2011
Adjusting Blazing Games Plans
Sorry for the long delay between posts. I will continue my series on the creation of Dozen Days of Tiles episode 3 next week as this week I am going to discuss the changes I am making to Blazing Games. With the added responsibilities that have come after my mother's death, I have been forced to rethink my plans for Blazing Games. This may be a good thing if I can stick to my new plans, but as I have a habit of falling back to my old way of doing things only time will tell. If you have visited the Blazing Games site, you may already know that I am switching the updating of the site to every other week. Quite frankly, once a month is just not often enough for what I want to do yet weekly is just too frequent. The games and open source releases that will appear on the site will be smaller games for the time being as I am going to start focusing on one large scale game at a time and that large scale game is going to be small enough that I should be able to complete it in a reasonable period of time. To prevent other people from stealing my work, sneak previews of my bigger project will either be older builds of the game or will have large chunks of the content omitted.
Right now Blazing Games is more of a hobby that just happens to earn enough to cover it's costs, unless you count my time in which case the books would be well into the red right now. Now that there are some, albeit a small number, of indies who are making a lot of money and many more who are making a living off of their creations, it is probably time that I focus on turning my hobby into a real business. While I happen to be in a good position at the moment, my mother's bout with cancer has been a brick to the back of the head reminder about how quickly things can change.
My spare-time playing around with the creation of a larger scale game (and my own Fantasy Combat game Engine) has taught me how much different it is developing a large scale game than the simple games I tend to have on my site. This has caused me to rethink my plans for my first larger game and break the development of the larger game down into a number of smaller games that will lead to the final game. As Blazing Games simply does not have enough visitors to justify exclusivity to the larger games, I am going to be experimenting with releasing the game on various game portals as well as experimentation with porting the games to the various phone platforms and their respective stores.
I do plan on continuing my open sourcing of older games from my site, but some of my favourite games will be upgraded and enhanced. Some of the tools I am developing for my larger scale projects will be released as open source as will some of the libraries that I am developing. Full games will probably continue to use the GPL license while libraries will use the far-less restrictive MIT license.
While the site will be updated every other week, this blog will be returning to a weekly release again, if only so I can get caught up with my making of DDT series. While I do hope I can turn Blazing Games into a real company, I know the odds are against me. Still, it is worth a try and right now I have the motivation, it is just a matter of finding enough of that elusive thing called "time".
Right now Blazing Games is more of a hobby that just happens to earn enough to cover it's costs, unless you count my time in which case the books would be well into the red right now. Now that there are some, albeit a small number, of indies who are making a lot of money and many more who are making a living off of their creations, it is probably time that I focus on turning my hobby into a real business. While I happen to be in a good position at the moment, my mother's bout with cancer has been a brick to the back of the head reminder about how quickly things can change.
My spare-time playing around with the creation of a larger scale game (and my own Fantasy Combat game Engine) has taught me how much different it is developing a large scale game than the simple games I tend to have on my site. This has caused me to rethink my plans for my first larger game and break the development of the larger game down into a number of smaller games that will lead to the final game. As Blazing Games simply does not have enough visitors to justify exclusivity to the larger games, I am going to be experimenting with releasing the game on various game portals as well as experimentation with porting the games to the various phone platforms and their respective stores.
I do plan on continuing my open sourcing of older games from my site, but some of my favourite games will be upgraded and enhanced. Some of the tools I am developing for my larger scale projects will be released as open source as will some of the libraries that I am developing. Full games will probably continue to use the GPL license while libraries will use the far-less restrictive MIT license.
While the site will be updated every other week, this blog will be returning to a weekly release again, if only so I can get caught up with my making of DDT series. While I do hope I can turn Blazing Games into a real company, I know the odds are against me. Still, it is worth a try and right now I have the motivation, it is just a matter of finding enough of that elusive thing called "time".
Friday, July 29, 2011
DDTe3 Hour 8 - Sliding Puzzle
My mother went from improving to a very rapid decline and passed away July 29th at 1:05AM. She meant the world to me and will be greatly missed. While I posted a game on BlazingGames.com this week as the game ready to post, I will be taking a few week break from posting new material. I am many weeks ahead on this blog for material so may still post the weekly articles here but I can not guarantee this. Here is the continuation of my How Many Games can I Develop in 24 hours challenge.
Creating the Sliding Puzzle game is fairly straightforward as the only real game mechanic that needs to be implemented is the slider. The slider is simply the bottom right-most tile set to be highlighted with the highlight color being near-opaque. The reason for making it near-opaque instead of fully-opaque is that I felt the game would be better if you knew what part of the image the slider represented but it had to be dark enough that it was obviously the slider. Creating the slider, then, required very little code.
this.slider = new BGLayers.Point(tw-1, th-1);
this.view.setTileHighlight(tw-1, th-1, true);
this.view.setColors("rgb(100,0,100)", "green", "red", .5, .9);
With the slider on the board, the only other major game-play mechanic became moving the slider around. I decided that the best way to implement the movement of the slider would be to simply take a point that represents where the slider is to be moved to and then move the slider horizontally until it is at the proper x location and then vertically until it is at the proper y location.
PuzzleGallery.SlidingPuzzleGame.prototype.moveSlider = function(p)
{
this.view.setTileHighlight(this.slider.x, this.slider.y, false);
while (this.slider.x < p.x) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x+1, this.slider.y);
++this.slider.x;
};
while (this.slider.x > p.x) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x-1, this.slider.y);
--this.slider.x;
};
while (this.slider.y < p.y) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x, this.slider.y+1);
++this.slider.y;
};
while (this.slider.y > p.y) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x, this.slider.y-1);
--this.slider.y;
};
this.view.setTileHighlight(this.slider.x, this.slider.y, true);
this.view.update();
}
This made implementing the mouse very easy as you simply call the moveSlider function with the point passed by the onTileClick call that BasePuzzleView makes when a tile is clicked. While having both horizontal and vertical movement at once was nice, after playing the game I worried that it might be too confusing to the player so altered the onTileClick function to only allow the slider to move when the move was only horizontal or vertical.
The other thing I was worried about is that the scrambling of the puzzle was not based on the game-play mechanic. While I am positive that this shouldn’t matter and that any scrambled puzzle should be solvable, I decided not to take any chances and wrote my own Sliding Puzzle Game scrambling function. This simply moves the slider around by randomly selecting points on the puzzle and calling the moveSlider function using that point.
PuzzleGallery.SlidingPuzzleGame.prototype.scramble = function()
{
var p = new BGLayers.Point();
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h * 10;
for (var cntr = 0; cntr < n; ++cntr) {
p.x = Math.floor(Math.random() * w);
p.y = Math.floor(Math.random() * h);
this.moveSlider(p);
}
}
And with that done, we have finished a second game. For the third game, however, I am not going to go with the rotation puzzle but have a different sort of twist in mind.
Creating the Sliding Puzzle game is fairly straightforward as the only real game mechanic that needs to be implemented is the slider. The slider is simply the bottom right-most tile set to be highlighted with the highlight color being near-opaque. The reason for making it near-opaque instead of fully-opaque is that I felt the game would be better if you knew what part of the image the slider represented but it had to be dark enough that it was obviously the slider. Creating the slider, then, required very little code.
this.slider = new BGLayers.Point(tw-1, th-1);
this.view.setTileHighlight(tw-1, th-1, true);
this.view.setColors("rgb(100,0,100)", "green", "red", .5, .9);
With the slider on the board, the only other major game-play mechanic became moving the slider around. I decided that the best way to implement the movement of the slider would be to simply take a point that represents where the slider is to be moved to and then move the slider horizontally until it is at the proper x location and then vertically until it is at the proper y location.
PuzzleGallery.SlidingPuzzleGame.prototype.moveSlider = function(p)
{
this.view.setTileHighlight(this.slider.x, this.slider.y, false);
while (this.slider.x < p.x) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x+1, this.slider.y);
++this.slider.x;
};
while (this.slider.x > p.x) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x-1, this.slider.y);
--this.slider.x;
};
while (this.slider.y < p.y) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x, this.slider.y+1);
++this.slider.y;
};
while (this.slider.y > p.y) {
this.puzzle.swapPuzzlePieces(this.slider.x, this.slider.y, this.slider.x, this.slider.y-1);
--this.slider.y;
};
this.view.setTileHighlight(this.slider.x, this.slider.y, true);
this.view.update();
}
This made implementing the mouse very easy as you simply call the moveSlider function with the point passed by the onTileClick call that BasePuzzleView makes when a tile is clicked. While having both horizontal and vertical movement at once was nice, after playing the game I worried that it might be too confusing to the player so altered the onTileClick function to only allow the slider to move when the move was only horizontal or vertical.
The other thing I was worried about is that the scrambling of the puzzle was not based on the game-play mechanic. While I am positive that this shouldn’t matter and that any scrambled puzzle should be solvable, I decided not to take any chances and wrote my own Sliding Puzzle Game scrambling function. This simply moves the slider around by randomly selecting points on the puzzle and calling the moveSlider function using that point.
PuzzleGallery.SlidingPuzzleGame.prototype.scramble = function()
{
var p = new BGLayers.Point();
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h * 10;
for (var cntr = 0; cntr < n; ++cntr) {
p.x = Math.floor(Math.random() * w);
p.y = Math.floor(Math.random() * h);
this.moveSlider(p);
}
}
And with that done, we have finished a second game. For the third game, however, I am not going to go with the rotation puzzle but have a different sort of twist in mind.
Thursday, July 21, 2011
DDTe3 Hour 7 - Making a Slider
As mentioned last post, to make it easier to remember to post, I am going to post the blog at the same time I update Blazing Games. This week I am continuing my series of articles on the creation of Dozen Days of Tiles episode 3 which is an as many games as I can develop in under 24 hours of development time challenge. So far the picture puzzle game has been created so development on a sliding puzzle has just started.
After finishing the first game, most of the work is now present that additional games should be able to be created quickly. The second game that I have in mind is a sliding puzzle. To get the functionality needed to create the game, a slider has to be moved around the game board. This can be handled by swapping pieces so no additional features need to be added to the base puzzle model. However, there needs to be a visible slider on the screen so some extensions will need to be added to the base model view class.
While thinking about how to actually add the tile, my first thought was to simply make the highlight as the tile. As clicking on a tile will cause the slider to move, no highlight is needed for this game so all the work is already done. The only downside to this approach is that it would require a more-solid highlight but since I want to add the ability to change the border and highlight colors anyway, the slider would be essentially free. Another route that I could have taken would be to simply add an ability to grab a tiles display position so I could simply add a sprite over-top of the board.
To allow the tile border and highlight colors to be changed, a setColors function was added to the TileBorder class. The class uses both colors and alpha values as I had decided when creating the HighlightBlock class to keep the alpha value separate from the color. My thoughts at the time were that it allows for alpha effects to be implemented much easier and has the side benifit that normal color labels (such as red or blue) can then be used rather than requiring the use of the rgba() function to specify colors.
Finally, in the BaseModelView class, a set colors class was added which simply calls the setColor class for every border in the view.
PuzzleGallery.BasePuzzleView.prototype.setColors = function(col, ccol, ecol, ba, ha)
{
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h;
for (var indx = 0; indx < n; ++indx) {
this.tileBorders[indx].setColors(col, ccol, ecol, ba, ha);
}
this.addDirty(null);
}
We now have everything needed to create a slider so the next step is to create a sliding puzzle game.
After finishing the first game, most of the work is now present that additional games should be able to be created quickly. The second game that I have in mind is a sliding puzzle. To get the functionality needed to create the game, a slider has to be moved around the game board. This can be handled by swapping pieces so no additional features need to be added to the base puzzle model. However, there needs to be a visible slider on the screen so some extensions will need to be added to the base model view class.
While thinking about how to actually add the tile, my first thought was to simply make the highlight as the tile. As clicking on a tile will cause the slider to move, no highlight is needed for this game so all the work is already done. The only downside to this approach is that it would require a more-solid highlight but since I want to add the ability to change the border and highlight colors anyway, the slider would be essentially free. Another route that I could have taken would be to simply add an ability to grab a tiles display position so I could simply add a sprite over-top of the board.
To allow the tile border and highlight colors to be changed, a setColors function was added to the TileBorder class. The class uses both colors and alpha values as I had decided when creating the HighlightBlock class to keep the alpha value separate from the color. My thoughts at the time were that it allows for alpha effects to be implemented much easier and has the side benifit that normal color labels (such as red or blue) can then be used rather than requiring the use of the rgba() function to specify colors.
Finally, in the BaseModelView class, a set colors class was added which simply calls the setColor class for every border in the view.
PuzzleGallery.BasePuzzleView.prototype.setColors = function(col, ccol, ecol, ba, ha)
{
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
var n = w * h;
for (var indx = 0; indx < n; ++indx) {
this.tileBorders[indx].setColors(col, ccol, ecol, ba, ha);
}
this.addDirty(null);
}
We now have everything needed to create a slider so the next step is to create a sliding puzzle game.
Sunday, July 17, 2011
DDTe3 Hours 5 to 6 The Picture Puzzle Game
My mother is still in the hospital, which is at least part of the reason I missed posting this last week. I am thinking about updating this blog the same time that I update the Blazing Games site, but kind of want to keep them separate to emphasis the fact that they are separate things. The few people who actually read this probably already realize this and combining the posting dates may make things easier so don't be surprised if the blog starts being updated late Thursday nights (PST). This is continuing the development of Dozen Days of Tiles episode 3 which is a how many games can I develop in 24 hours challenge instead of the usual developing a game in under 24 hours challenge.
With the puzzle displaying, we are most of the way to a playable picture puzzle game. The only issue remaining that must be solved is input. The mouse input is handled by the BasePuzzleView class by calling a listener function. As this listener function can be set by any of the games, it is not game dependent. Instead, the function that gets called is what holds the game-play logic.
The information that the game needs to know is what tile was selected. There are a number of ways this information can be passed, but the most universally useful way is simply to indicate the row and column that was selected as any other information can be derived from that knowledge. Determining this is a bit more problematic as BGLayers passes real mouse positions not logical ones. This conversion from real to logical coordinates is something that BGLayers probably should have functions to handle but it does not. Still, this is very easy to calculate as it is essentially just a scaling calculation.
var rp = this.findRealPosition();
var lx = (x - rp.x) * (this._logicalSize.width / rp.width);
var ly = (y - rp.y) * (this._logicalSize.height / rp.height);
var p = new BGLayers.Point(Math.floor((lx - this.tileLeft) / this.tileWidth),
Math.floor((ly - this.tileTop) / this.tileHeight));
The game logic to handle the click simply stores the first tile clicked on as the selector and the second click swaps the two tiles. At this point we have a playable game but three problems immediately come to mind. First, there is no visible way of knowing what tile was selected. Second, it isn't always obvious where the tiles are. Third, there is no indication about which tiles are correct or not. The second and third problems can be solved by adding a border that has an optional hint capability. But instead of just having a border, why not add a highlight feature to the border as well and get a hat-trick. For those of you not familiar with Hockey, a hat-trick is when a player scores three goals in a single game.
The TileBorder class simply consists of the four borders and the highlight. The class holds 3 colors one highlight color, one correct color and one incorrect color. The correctness is handled by a setCorrect(b) function that sets the border colors to the correct color if passed true and to the error color if passed false. The highlight is set to the highlight color and is initially invisible but can be turned on (or off again) by calling the setHighlight function.
In my first attempt of implementing this, the borders were just layer classes but I discovered that the rgba colors were not working. This was obviously because the layers by default are solid. Unfortunately, setting them to transparent has the side effect of not drawing the background color making them invisible. This makes sense as the layers are placeholders that draw a background color if necessary and if the layer isn't solid then no background is needed. A new class, the HightlightBlock, was quickly created to draw a solid block. Instead of using rgba colors for transparency, I instead opted for a separate alpha channel. While not utilized yet, it opens the possibility of alternating the transparency without having to worry about the color.
The tile borders are then added to the BasePuzzleView class after the tiles are created so that the borders will always be above the tiles. The update method then adds a single line to it's update loop:
this.tileBorders[indx].setCorrect(tile == indx);
This line sets the correctness color of the border. With that we have a fully playable game. One game down and at least another 3 to go.
With the puzzle displaying, we are most of the way to a playable picture puzzle game. The only issue remaining that must be solved is input. The mouse input is handled by the BasePuzzleView class by calling a listener function. As this listener function can be set by any of the games, it is not game dependent. Instead, the function that gets called is what holds the game-play logic.
The information that the game needs to know is what tile was selected. There are a number of ways this information can be passed, but the most universally useful way is simply to indicate the row and column that was selected as any other information can be derived from that knowledge. Determining this is a bit more problematic as BGLayers passes real mouse positions not logical ones. This conversion from real to logical coordinates is something that BGLayers probably should have functions to handle but it does not. Still, this is very easy to calculate as it is essentially just a scaling calculation.
var rp = this.findRealPosition();
var lx = (x - rp.x) * (this._logicalSize.width / rp.width);
var ly = (y - rp.y) * (this._logicalSize.height / rp.height);
var p = new BGLayers.Point(Math.floor((lx - this.tileLeft) / this.tileWidth),
Math.floor((ly - this.tileTop) / this.tileHeight));
The game logic to handle the click simply stores the first tile clicked on as the selector and the second click swaps the two tiles. At this point we have a playable game but three problems immediately come to mind. First, there is no visible way of knowing what tile was selected. Second, it isn't always obvious where the tiles are. Third, there is no indication about which tiles are correct or not. The second and third problems can be solved by adding a border that has an optional hint capability. But instead of just having a border, why not add a highlight feature to the border as well and get a hat-trick. For those of you not familiar with Hockey, a hat-trick is when a player scores three goals in a single game.
The TileBorder class simply consists of the four borders and the highlight. The class holds 3 colors one highlight color, one correct color and one incorrect color. The correctness is handled by a setCorrect(b) function that sets the border colors to the correct color if passed true and to the error color if passed false. The highlight is set to the highlight color and is initially invisible but can be turned on (or off again) by calling the setHighlight function.
In my first attempt of implementing this, the borders were just layer classes but I discovered that the rgba colors were not working. This was obviously because the layers by default are solid. Unfortunately, setting them to transparent has the side effect of not drawing the background color making them invisible. This makes sense as the layers are placeholders that draw a background color if necessary and if the layer isn't solid then no background is needed. A new class, the HightlightBlock, was quickly created to draw a solid block. Instead of using rgba colors for transparency, I instead opted for a separate alpha channel. While not utilized yet, it opens the possibility of alternating the transparency without having to worry about the color.
The tile borders are then added to the BasePuzzleView class after the tiles are created so that the borders will always be above the tiles. The update method then adds a single line to it's update loop:
this.tileBorders[indx].setCorrect(tile == indx);
This line sets the correctness color of the border. With that we have a fully playable game. One game down and at least another 3 to go.
Monday, July 4, 2011
DDTe3 Hours 2 to 4 Drawing the Puzzle
As my Mother is still in the hospital, I am quite thankful that I have been writing my development articles as the games were written so I am months ahead of schedule when it comes to material that is ready to post. If only I could remember to post things on time :). This series was interrupted by a couple of weeks to celebrate the release of Duke Nukem Forever and to take a brief look at my ImageAtlas library but now we continue by developing the core classes that will allow me to create a lot of games really quickly.
The BasePuzzleView class has the job of displaying the puzzle. This puzzle is drawn from an image that is passed into this class. To make the game as flexible as possible, I want to be able to use only part of an image. This makes it easier to work with images that only have a partially usable portion. More important, at least in my situation, it makes it possible to maintain the proper aspect ratio for an image that is a different size than the canvas the game is going to be played in. While it is certainly possible to make the canvas a proportional size to the image being used, I like to keep my canvas a constant size. As my BGLayers library already has a rectangle class, it is simple enough to pass in a clipping region. Finally, we need the model class being displayed. With this information we have the constructor for our class.
When I started to write this class, two ways of implementing it came immediately to my mind. One way would be to have the class do all the bitmap manipulation itself when drawing. The other would be to have the class made up of a bunch of child ImageLayers that hold all the pieces of the puzzle. The first method removes a lot of overhead from having a lot of layers on the display list at a cost of a very difficult rendering process. While more efficient, speed probably is not going to be an issue whatsoever with any of the games that make up this project, so the easier to implement child path is the one I decided to go with.
The first step I then went on to implement was determining if borders were necessary. My old-school thinking was that tiles should be integers which means that it is possible for there to be borders. I was not thinking that the view is a layer that uses logical coordinates and is going to be scaled and that partial pixels are already handled by BGLayers. This is a weird lack of thinking as I am taking advantage of how BGLayers uses logical coordinates by setting the size of the layer to the size of the clipping region. Still, this is a fairly simple problem to solve. The tile size is determined by dividing width and height of the clipped image by the number of columns and rows of the puzzle. This is rounded down so the borders width is simply the width of the image clip minus the width of the tiles multiplied by the number of columns in the puzzle. Likewise the height of the borders is simply the height of the image clip minus the hight of the tiles multiplied by the number of rows in the puzzle.
The size of the individual borders is half the size of the border. If the border is an odd size, one border needs to be a pixel bigger than the other border for whatever orientation the border represents (top/bottom or left/right). The easiest way of doing this is to make the first border the total size of the borders divided by two rounded down and the other border being equal to the size of both the borders minus the size of the first border. This way of dealing with splitting odd integers is a handy trick to remember if you have to deal with integers a lot. Using integers was something that use to be important to graphics programming (when floating point numbers were thought to be evil due to how slow non-hardware accelerated floating point was) but is not so much the case anymore.
Once the borders have been created, it is very easy to lay out the tiles as the following code segment clearly shows.
indx = 0;
for (cntrR = 0; cntrR < puzzle.puzzleHeight; ++cntrR) {
for (cntrC = 0; cntrC < puzzle.puzzleWidth; ++cntrC) {
this.tiles[indx] = new BGLayers.ImageLayer("tile"+indx, img);
rect = new BGLayers.Rectangle(left + this.tileWidth * cntrC,
top + this.tileHeight * cntrR,
this.tileWidth, this.tileHeight);
this.tiles[indx].setClip(rect);
this.addChild(this.tiles[indx], rect);
++indx;
}
}
The only problem is that the tiles are laid out in the proper order, not in the order reflected in the current state of the puzzle data. This problem had me stumped for a second or two, but then I realized that all I needed to do was move the tiles to the position they are supposed to be in. As this is something that happens every time the puzzle data changes, an update function was created to deal with this task.
PuzzleGallery.BasePuzzleView.prototype.update = function()
{
var cntrR, cntrC, indx, tile;
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
indx = 0;
for (cntrR = 0; cntrR < h; ++cntrR) {
for (cntrC = 0; cntrC < w; ++cntrC) {
tile = this.puzzle.getPuzzlePiece(cntrC, cntrR);
this.tiles[tile].moveTo( this.tileLeft + cntrC * this.tileWidth,
this.tileTop + cntrR * this.tileHeight);
this.tileBorders[indx].setCorrect(tile == indx);
++indx;
}
}
this.addDirty(null);
}
The best part is that to make the tiles animate to their new position, I can simply create an animateTo function within the BGLayers library and have all the work done for me. I don't know if I will have time to do this within the 24 hours alloted to this project, but it is certainly something that I want to add to the BGLayers library eventually.
Now that we have the puzzle being displayable, we need to get on with creating a game. That, as you have already guessed, will be covered next week.
The BasePuzzleView class has the job of displaying the puzzle. This puzzle is drawn from an image that is passed into this class. To make the game as flexible as possible, I want to be able to use only part of an image. This makes it easier to work with images that only have a partially usable portion. More important, at least in my situation, it makes it possible to maintain the proper aspect ratio for an image that is a different size than the canvas the game is going to be played in. While it is certainly possible to make the canvas a proportional size to the image being used, I like to keep my canvas a constant size. As my BGLayers library already has a rectangle class, it is simple enough to pass in a clipping region. Finally, we need the model class being displayed. With this information we have the constructor for our class.
When I started to write this class, two ways of implementing it came immediately to my mind. One way would be to have the class do all the bitmap manipulation itself when drawing. The other would be to have the class made up of a bunch of child ImageLayers that hold all the pieces of the puzzle. The first method removes a lot of overhead from having a lot of layers on the display list at a cost of a very difficult rendering process. While more efficient, speed probably is not going to be an issue whatsoever with any of the games that make up this project, so the easier to implement child path is the one I decided to go with.
The first step I then went on to implement was determining if borders were necessary. My old-school thinking was that tiles should be integers which means that it is possible for there to be borders. I was not thinking that the view is a layer that uses logical coordinates and is going to be scaled and that partial pixels are already handled by BGLayers. This is a weird lack of thinking as I am taking advantage of how BGLayers uses logical coordinates by setting the size of the layer to the size of the clipping region. Still, this is a fairly simple problem to solve. The tile size is determined by dividing width and height of the clipped image by the number of columns and rows of the puzzle. This is rounded down so the borders width is simply the width of the image clip minus the width of the tiles multiplied by the number of columns in the puzzle. Likewise the height of the borders is simply the height of the image clip minus the hight of the tiles multiplied by the number of rows in the puzzle.
The size of the individual borders is half the size of the border. If the border is an odd size, one border needs to be a pixel bigger than the other border for whatever orientation the border represents (top/bottom or left/right). The easiest way of doing this is to make the first border the total size of the borders divided by two rounded down and the other border being equal to the size of both the borders minus the size of the first border. This way of dealing with splitting odd integers is a handy trick to remember if you have to deal with integers a lot. Using integers was something that use to be important to graphics programming (when floating point numbers were thought to be evil due to how slow non-hardware accelerated floating point was) but is not so much the case anymore.
Once the borders have been created, it is very easy to lay out the tiles as the following code segment clearly shows.
indx = 0;
for (cntrR = 0; cntrR < puzzle.puzzleHeight; ++cntrR) {
for (cntrC = 0; cntrC < puzzle.puzzleWidth; ++cntrC) {
this.tiles[indx] = new BGLayers.ImageLayer("tile"+indx, img);
rect = new BGLayers.Rectangle(left + this.tileWidth * cntrC,
top + this.tileHeight * cntrR,
this.tileWidth, this.tileHeight);
this.tiles[indx].setClip(rect);
this.addChild(this.tiles[indx], rect);
++indx;
}
}
The only problem is that the tiles are laid out in the proper order, not in the order reflected in the current state of the puzzle data. This problem had me stumped for a second or two, but then I realized that all I needed to do was move the tiles to the position they are supposed to be in. As this is something that happens every time the puzzle data changes, an update function was created to deal with this task.
PuzzleGallery.BasePuzzleView.prototype.update = function()
{
var cntrR, cntrC, indx, tile;
var w = this.puzzle.puzzleWidth;
var h = this.puzzle.puzzleHeight;
indx = 0;
for (cntrR = 0; cntrR < h; ++cntrR) {
for (cntrC = 0; cntrC < w; ++cntrC) {
tile = this.puzzle.getPuzzlePiece(cntrC, cntrR);
this.tiles[tile].moveTo( this.tileLeft + cntrC * this.tileWidth,
this.tileTop + cntrR * this.tileHeight);
this.tileBorders[indx].setCorrect(tile == indx);
++indx;
}
}
this.addDirty(null);
}
The best part is that to make the tiles animate to their new position, I can simply create an animateTo function within the BGLayers library and have all the work done for me. I don't know if I will have time to do this within the 24 hours alloted to this project, but it is certainly something that I want to add to the BGLayers library eventually.
Now that we have the puzzle being displayable, we need to get on with creating a game. That, as you have already guessed, will be covered next week.
Tuesday, June 28, 2011
Flash Image Atlas Animation System. Why?
This was suppose to be posted on Sunday, but with my mother going into the hospital, I kind of forgot about posting it. Sorry for the delay.
As part of my larger project, I have decided to develop my own animation system. As this larger project is currently being done in Flash, which is essentially an animation system with a powerful programming language tacked on to it, this may seem redundant. If I knew for sure that the project was going to be exclusively done in Flash, it would be. The truth is that I may end up having to port the game to other devices. While Flash is sort of runnable on portable devices, the performance currently isn't quite there. If, when my game is in a near finished state, the game runs fine on the target devices then there is no issue. However, this is not necessarily going to be the case so I have been looking into what would be involved in porting a game by creating a native version for certain devices.
OpenGL ES is pretty much the standard for all the devices I am thinking about targeting. While studying OpenGL one common optimization that comes highly recommended is to combine the textures that one is using into something called an image atlas. As it turns out, an image atlas is a more advanced version of image strips (aka sprite strips) and image grids (aka image sheets or sprite sheets). Image strips/sheets are what I was using for my Java games so I am well versed in the technique.
A lot of the artwork for my larger-scale game is bitmap graphics so creating a library that allows for an image atlas to drive an animation would be convenient and make porting easier. Spending a development week or two to get this functionality is really not much of a loss while the benefits are potentially great. I define a development week to be 40 hours which is a typical work week in Canada. As my work on the large scale game is part time, it may take two or three weeks in real world time for a development week. I plan on porting it to HTML 5 and possibly other platforms. Not too long ago I created a simple image atlas class for my HTML 5 JavaScript graphics library so an HTML 5 port so the HTML 5 version should be fairly quick to develop. This will give me a common set of components that will make it much easier to switch between platforms. While I personally believe that Flash will be around for a while, having an easy path to other platforms doesn't hurt.
In fact, with Microsoft not supporting Web GL in IE 9, any web-based will have to use a plug-in such as the upcoming Flash 11 to support 3D graphics in a cross-platform way. While Microsoft is claiming security issues (WebGL is fundementally far more secure than Microsoft's Active X which is still in IE), I hear that in Windows 8 there will be browser support for accessing Direct X 11. Since Direct X is essentially a less-secure version of Open GL (what WebGL is based on) I am wondering what Microsoft's true motivations for not supporting WebGL are. Still, I see the future of 3D on the web being Flash. Ideally it will be a WebGL with fallback to Flash future but more likely it will be just Flash with paid iOS apps for Apple users. Thanks Microsoft.
As part of my larger project, I have decided to develop my own animation system. As this larger project is currently being done in Flash, which is essentially an animation system with a powerful programming language tacked on to it, this may seem redundant. If I knew for sure that the project was going to be exclusively done in Flash, it would be. The truth is that I may end up having to port the game to other devices. While Flash is sort of runnable on portable devices, the performance currently isn't quite there. If, when my game is in a near finished state, the game runs fine on the target devices then there is no issue. However, this is not necessarily going to be the case so I have been looking into what would be involved in porting a game by creating a native version for certain devices.
OpenGL ES is pretty much the standard for all the devices I am thinking about targeting. While studying OpenGL one common optimization that comes highly recommended is to combine the textures that one is using into something called an image atlas. As it turns out, an image atlas is a more advanced version of image strips (aka sprite strips) and image grids (aka image sheets or sprite sheets). Image strips/sheets are what I was using for my Java games so I am well versed in the technique.
A lot of the artwork for my larger-scale game is bitmap graphics so creating a library that allows for an image atlas to drive an animation would be convenient and make porting easier. Spending a development week or two to get this functionality is really not much of a loss while the benefits are potentially great. I define a development week to be 40 hours which is a typical work week in Canada. As my work on the large scale game is part time, it may take two or three weeks in real world time for a development week. I plan on porting it to HTML 5 and possibly other platforms. Not too long ago I created a simple image atlas class for my HTML 5 JavaScript graphics library so an HTML 5 port so the HTML 5 version should be fairly quick to develop. This will give me a common set of components that will make it much easier to switch between platforms. While I personally believe that Flash will be around for a while, having an easy path to other platforms doesn't hurt.
In fact, with Microsoft not supporting Web GL in IE 9, any web-based will have to use a plug-in such as the upcoming Flash 11 to support 3D graphics in a cross-platform way. While Microsoft is claiming security issues (WebGL is fundementally far more secure than Microsoft's Active X which is still in IE), I hear that in Windows 8 there will be browser support for accessing Direct X 11. Since Direct X is essentially a less-secure version of Open GL (what WebGL is based on) I am wondering what Microsoft's true motivations for not supporting WebGL are. Still, I see the future of 3D on the web being Flash. Ideally it will be a WebGL with fallback to Flash future but more likely it will be just Flash with paid iOS apps for Apple users. Thanks Microsoft.
Sunday, June 19, 2011
Thoughts on Forever
I am going to delay my series of articles on the creation of episode 3 of Dozen Days of Tiles for a couple of weeks so I can touch on a couple of other topics. The big news in computer gaming (and to a lesser extent video gaming) circles is the release of Duke Nukem Forever (DNF). The reviews have been more negative than positive. Some of the negative reviews are negative because of the games play mechanics and other game play issues. These are fine and I consider them valid criticism. Other reviewers are those people that incorrectly think the game should be better because it took so long to develop. These people annoy me because the development time for DNF has nothing to do with its quality. There are a large number of reasons for this, but lets just look at the top three reasons.
First of all, the number of years a project is in development is not related to the development years of a project. A development year is one person working full time on a project for a year. If I spend 4 years working on a game and a team of 4 perfectly coordinated developers worked 1 year on the same type of game, the amount of time spent developing the two games is the same. My game should not be better because it took 4 times as long to develop because it didn't. Therefore, looking at the development time of a game strictly based on the number of years it has been in development is just stupid.
Second, the game changed game engines and major subsystems multiple times during development. This is not something that can be considered lightly as porting code from one platform to another is going to take a good chunk of time. In some cases, you may even need to spend a good chunk of time to recreate functionality if the features of the new engine are different. This is why very few games change their underlying engine mid-stream.
Finally, a huge part of the repeated delays of the game was a result of playing catchup. Many programmers, myself included, have worked on projects that have a moving goalpost. What happens is that you have your initial specifications and you work hard to reach these. Months before reaching the goal there is a review of the project and the big-wig decides that things have changed so new specifications are created requiring major changes to the existing code so the project is delayed and just before the project is finished, the big-wig shows up again and ... repeat until either the big-wig or the project (or both) are dead. DNF was clearly caught in the trap of trying to stay ahead of the game market. Every time it started getting near completion, enough time had passed that the game was no longer meeting the cutting edge requirements of management so the game would be delayed to allow time to catch up with the rest of the industry.
This is similar to what has happened with my Coffee Quest 5 project, the difference being that CQ5 has not been in development for all this time. My problem with CQ5 was more of a wanting a browser based game that would be able to use technology that simply was not available in browsers. The few times I did start on the project, it was quickly put on ice again as the technology simply wasn't there. While there were some Java 3D libraries, they simply did not work well within the browser as I discovered when a huge number of people had issues running CQGL. I had considered porting Coffee Quest to Flash and use PaperVision, but found that it had issues and Flash Player 10 was going to have some limited 3D support. So I waited for Flash Player 10 only to discover that the 3D effects had major sorting issues. Now there is the upcoming Mole-Hill version of Flash in beta as well as Web GL so the possibility of finally developing CQ5 is in my mind again.
Had I not had unrealistic expectations for the speed of browser development, I probably would have just enhanced my existing ray-caster or possibly even developed a simple software 3D library and released CQ5 many years ago. Sadly, I had Hardware 3D in the back of my mind and CQ5 ended up on the back-burner as I waited for Adobe or browser venders to finally put proper 3D into browsers. Something that really should have happened a decade ago but still hasn't happened.
While DNF may suck, I wonder how much of it has to do with overly high expectations and how much has to do with poor game play. I won't know the answer to that question until I see a copy of DNF in the bargain bin, as going by the reviewers I trust the game is not worth full price (and probably not worth bargain bin prices either but I am curious).
First of all, the number of years a project is in development is not related to the development years of a project. A development year is one person working full time on a project for a year. If I spend 4 years working on a game and a team of 4 perfectly coordinated developers worked 1 year on the same type of game, the amount of time spent developing the two games is the same. My game should not be better because it took 4 times as long to develop because it didn't. Therefore, looking at the development time of a game strictly based on the number of years it has been in development is just stupid.
Second, the game changed game engines and major subsystems multiple times during development. This is not something that can be considered lightly as porting code from one platform to another is going to take a good chunk of time. In some cases, you may even need to spend a good chunk of time to recreate functionality if the features of the new engine are different. This is why very few games change their underlying engine mid-stream.
Finally, a huge part of the repeated delays of the game was a result of playing catchup. Many programmers, myself included, have worked on projects that have a moving goalpost. What happens is that you have your initial specifications and you work hard to reach these. Months before reaching the goal there is a review of the project and the big-wig decides that things have changed so new specifications are created requiring major changes to the existing code so the project is delayed and just before the project is finished, the big-wig shows up again and ... repeat until either the big-wig or the project (or both) are dead. DNF was clearly caught in the trap of trying to stay ahead of the game market. Every time it started getting near completion, enough time had passed that the game was no longer meeting the cutting edge requirements of management so the game would be delayed to allow time to catch up with the rest of the industry.
This is similar to what has happened with my Coffee Quest 5 project, the difference being that CQ5 has not been in development for all this time. My problem with CQ5 was more of a wanting a browser based game that would be able to use technology that simply was not available in browsers. The few times I did start on the project, it was quickly put on ice again as the technology simply wasn't there. While there were some Java 3D libraries, they simply did not work well within the browser as I discovered when a huge number of people had issues running CQGL. I had considered porting Coffee Quest to Flash and use PaperVision, but found that it had issues and Flash Player 10 was going to have some limited 3D support. So I waited for Flash Player 10 only to discover that the 3D effects had major sorting issues. Now there is the upcoming Mole-Hill version of Flash in beta as well as Web GL so the possibility of finally developing CQ5 is in my mind again.
Had I not had unrealistic expectations for the speed of browser development, I probably would have just enhanced my existing ray-caster or possibly even developed a simple software 3D library and released CQ5 many years ago. Sadly, I had Hardware 3D in the back of my mind and CQ5 ended up on the back-burner as I waited for Adobe or browser venders to finally put proper 3D into browsers. Something that really should have happened a decade ago but still hasn't happened.
While DNF may suck, I wonder how much of it has to do with overly high expectations and how much has to do with poor game play. I won't know the answer to that question until I see a copy of DNF in the bargain bin, as going by the reviewers I trust the game is not worth full price (and probably not worth bargain bin prices either but I am curious).
Sunday, June 12, 2011
DDTe3 Hour 1 Planning and the Puzzle Model
For the third episode of Dozen Days of Tiles, my series where I develop games with a particular theme in under 24 hours of development time, I decided to twist the concept of developing a game in a day and instead trying to develop as many games as I can within the 24 hours. I know that while the work is done in 24 hours, because the work is spread out over multiple days, it is not the same as if I did the work in a single day. Having done the Dozen Days of Dice series as game in a day stints, I know that after twelve hours of coding the mind starts working against you. That said, finding a solid day to work on something is increasingly more difficult and can be easily interrupted even if such a rare block of time can be found. I also want to document my experience in the form of these blog posts. I do not count the time I spend writing these posts towards the 24 hours but I am trying to write the posts shortly after I put in a programming stint so the thought process at the time is preserved.
Part of the reason for the desire to create multiple games for this episode is directly related to the return of a weekly format for Blazing Games. While the weekly format is more iterative than it has been in the past, allowing for games to evolve into more complex games over time, I still prefer having a buffer of material so that if a larger third-party project interrupts my site work, the schedule will not need to be adjusted.
Creating multiple games in a 24 hour period leaves the question what set of games are tile related, and have similar enough game mechanics that the work on one can be utilized in allowing the related games to be created. At the same time, I am looking at some of the older games on the Blazing Games site and am trying to figure out what should be done with them. The Flash games can be enhanced as Flash is going to be around for a while yet. The Java games, sadly, are in a more precarious position so consideration should be made towards porting them to HTML5. Looking at some of the Java games that I have done, I noticed my picture puzzle series of games. These are simple enough games that I don't need to port the games at all but can instead re-write them from scratch without loosing that much time. In fact, with all the knowledge that I have gained over the years, I should be able to get the core picture puzzle game functional very quickly.
With the game in mind, it is time to start on the project. While having a client-model-view architecture is probably a bit of overkill for this series, it doesn't hurt so I will start by creating the model. This class is being called BasePuzzleModel in the project.
The model creates a two-dimensional array to hold the grid. In JavaScript, 2D arrays are created by making an array of arrays. The model could have also simply created a single array the size of the width times the height of the grid and mathematically determined the position of the tile. I chose to go with the the two-dimensional approach because that way the internal structure of the grid more closely matches the problem being solved. Still, as the tiles are then assigned linear values to represent their proper position, in hindsight going with a single dimensional array would have been easier and just as logical. As I write this, I am only 6 hours into the project and could change things but as the internal structure of the model is theoretically hidden from the classes that use it there would be no point changing it.
As briefly explained in the paragraph above, each tile is assigned an index value that is linear based on the row and column. The index is equal to the row * the width of the puzzle plus the column. By having the linear sequence of tile values, it is possible to easily determine if the puzzle is correct by simply seeing if the tiles are in order. Some simple convenience functions were created for manipulating the puzzle and within an hour we have the model up and running. The functions added were getPuzzlePiece(x,y), setPuzzlePiece(x,y, n), swapPuzzlePieces(x1,y1,x2,y2), scrambleBoard() and checkWin(). These are all fairly straightforward so I won’t delve into the details of these.
The next phase is to turn the model into something visible. The obvious class for this job would be something called the BasePuzzleView, which we will look at next week.
Part of the reason for the desire to create multiple games for this episode is directly related to the return of a weekly format for Blazing Games. While the weekly format is more iterative than it has been in the past, allowing for games to evolve into more complex games over time, I still prefer having a buffer of material so that if a larger third-party project interrupts my site work, the schedule will not need to be adjusted.
Creating multiple games in a 24 hour period leaves the question what set of games are tile related, and have similar enough game mechanics that the work on one can be utilized in allowing the related games to be created. At the same time, I am looking at some of the older games on the Blazing Games site and am trying to figure out what should be done with them. The Flash games can be enhanced as Flash is going to be around for a while yet. The Java games, sadly, are in a more precarious position so consideration should be made towards porting them to HTML5. Looking at some of the Java games that I have done, I noticed my picture puzzle series of games. These are simple enough games that I don't need to port the games at all but can instead re-write them from scratch without loosing that much time. In fact, with all the knowledge that I have gained over the years, I should be able to get the core picture puzzle game functional very quickly.
With the game in mind, it is time to start on the project. While having a client-model-view architecture is probably a bit of overkill for this series, it doesn't hurt so I will start by creating the model. This class is being called BasePuzzleModel in the project.
The model creates a two-dimensional array to hold the grid. In JavaScript, 2D arrays are created by making an array of arrays. The model could have also simply created a single array the size of the width times the height of the grid and mathematically determined the position of the tile. I chose to go with the the two-dimensional approach because that way the internal structure of the grid more closely matches the problem being solved. Still, as the tiles are then assigned linear values to represent their proper position, in hindsight going with a single dimensional array would have been easier and just as logical. As I write this, I am only 6 hours into the project and could change things but as the internal structure of the model is theoretically hidden from the classes that use it there would be no point changing it.
As briefly explained in the paragraph above, each tile is assigned an index value that is linear based on the row and column. The index is equal to the row * the width of the puzzle plus the column. By having the linear sequence of tile values, it is possible to easily determine if the puzzle is correct by simply seeing if the tiles are in order. Some simple convenience functions were created for manipulating the puzzle and within an hour we have the model up and running. The functions added were getPuzzlePiece(x,y), setPuzzlePiece(x,y, n), swapPuzzlePieces(x1,y1,x2,y2), scrambleBoard() and checkWin(). These are all fairly straightforward so I won’t delve into the details of these.
The next phase is to turn the model into something visible. The obvious class for this job would be something called the BasePuzzleView, which we will look at next week.
Subscribe to:
Posts (Atom)