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.

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.

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.

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.