Pages

Friday, December 16, 2011

Match-3 in Construct 2: part one

Gosh, quite a lot has been happening with Construct 2 since I last posted. The addition of a WebGL renderer speeds games up considerably, Scirra now features an Arcade on their site where you can submit your C2-made treasures and the custom plugin development is basically exploding. That's just to mention a few highlights.

Certainly a good time to come back and do some more blogging. And what's better than a tutorial to brush up on those rusty C2-skills of yours?

One of my more notable achievements with Construct Classic surely was the Match-3 tutorial, which quite a few people seemed to find useful. Since there's always interest in this kind of puzzle games, I decided to put a little effort into creating a similar guide for Construct 2. And here are the humble beginnings:


The key to a working Match-3 game is in any case a two dimensional array. So let's start with adding an array object, set its width and height to the desired dimensions of your playfield. In this case I chose 6x6.



For our game blocks we obviously do need a sprite too. The easiest way to do this is to simply use the frames of the sprite. Import each individual block as a frame of the same animation and set the animation speed to 0. For this example I'm dealing with four different block types.


Now that we have added all the objects we need, it's time to go to the event sheet and add a few global variables. First we need a starting position for our playfield, which is the position where the first block will be drawn. Add two global variables 'startx' and 'starty' for that purpose. Also very important for the project would be the grid size. To have some spacing between the 64x64 blocks I added a global variable 'grid' with a value of 80.


To have the game blocks actually showing up on screen, we do need to use the 'For each element'-loop of the array object. Set it to loop through all XY elements. Add an 'Create object'-action and set it to create the block sprite at the following position:

X: startx + Array.CurX * grid
Y: starty + Array.CurY * grid

So there's a bit of very simplistic math for you. Remember that the array loop starts with the element (0,0), which is the top left position, then goes through each column from left to right. So the last element in the loop will be the bottom right with the index of (5,5).


Test-run the game and you should see a grid of 6x6 game blocks appearing. So far so good.

The more tricky part now is to create the playfield randomized, but in a manner that at no point there are three or more blocks matched up horizontally or vertically.

A method I like is to use a string variable, which represents the range of possible game blocks. In this example we use four different blocks, which means four frames, which results in a string 'rand' of "0123". Every possible frame index just added together in a string. If you had six different game blocks it would be "012345". Note that this method only works if you have ten or less different game blocks you want randomized on startup, which normally is the case.


Note that we set the actual value of the 'rand'-string anew for every iteration of the loop, because we want the same initial possibilities for every element/block.

Now we add two sub-events to compare the two previous blocks, vertically and horizontally. If two blocks prior to the one being currently looped match, the current block can't have the same value. So we remove that possibility from the string 'rand'. For this purpose Construct 2 provides a handy 'replace'-expression, so we set the variable 'rand' to:

replace(rand,str(Array.At(Array.CurX-1,Array.CurY)),"")


Note that the conditions here are actually all the 'Compare two values'-condition of the 'System'-object. One is there to check if the X/Y array index is greater than 1, cause there can't be two lower indices if it isn't. Then, as mentioned above, the last two elements will be match-checked. Some expressions of the array object come in handy here: 'Array.at', which returns the array value at any given XYZ index, and Array.CurX/CurY, which return the indices being currently looped.

After these checks we write the actual value to the array in a new sub-event, which will be randomized from the remaining possibilities. To do this effectively it is vital to learn about another expression: 'mid'.

The 'mid'-expression can return any part of a string. So for example, if you had a string "ScirraConstructTwo", the expression

mid("ScirraConstructTwo",6,9)

would return "Construct". The first parameter of the expression is the string, the second the starting index of the part and the third parameter is the number of characters you want returned. So we use this expression to return one random character of the 'rand'-string. Which actually means we set the current value of the array to:

mid(rand,int(random(len(rand))),1)

Compare it to the example above, you will see that it isn't really complicated. The confusing thing is the second parameter, the start index. Since we want a random character returned, we use the random expression with the length of the 'rand'-string as parameter. There's also the expression 'int' to make sure it will return an integer value.



What's left to do is set the frame of the sprite to the current value of the array and test the game. Give it a few spins to convince yourself that there'll never be three or more blocks matched up on startup.

Isn't it a beautiful thing? And done in just a mere five events. Not bad. But there's still a long way to go for a working Match-3 game. Expect more event magic in the second part of this tutorial. Cheers!

Download this lesson's capx file

15 comments:

  1. Nice, I'm looking forward to part two :)

    ReplyDelete
  2. Nice, waiting for part 2 of the tutorial ;)

    ReplyDelete
  3. oh dear! well where is the next part

    ReplyDelete
  4. Will there be a next part anytime soon ?

    ReplyDelete
  5. Cool tutorial, when will the next part be posted? thx for sharing though...

    ReplyDelete
  6. I see there is still interest in this tutorial, but I'm afraid I abandoned this blog for over a year now. However about half of the 2nd part already exists as a draft and I might still finish up and publish the piece.

    To point you to an alternative you can actually use right now, go and check out the following forum posts by rexrainbow:

    http://www.scirra.com/forum/bejeweled-plugins-demo_topic62447.html

    http://www.scirra.com/forum/triple-townlike-match-3-demo_topic64226.html

    http://www.scirra.com/forum/match-3-in-hex-board_topic57030.html

    ReplyDelete
    Replies
    1. Thank you for these links, and for any future second parts you do for this, as it is intrinsic to my figuring out how to do my project at hand. ;)

      Delete
  7. if i want to do 10 or more random ...what should be done?

    ReplyDelete
  8. this is the easiest and simplest tutorial i have searched but its too bad it wasnt been continued :( this could have helped me big time

    ReplyDelete
    Replies
    1. Sorry about that. In the meantime I did release a Construct 2 plugin for match-3 games. Maybe check that one out: https://www.scirra.com/forum/plugin-jmatch3_t116977

      Delete