Sponsored By

Featured Blog | This community-written post highlights the best of what the game industry has to offer. Read more like it on the Game Developer Blogs.

Simple mechanics, complex puzzle creation - Part 3: Fun challenges

Now that we can check for level correctness and create fair challenges, we try to implement "fun" rules in Skiddy's editor.

Andrea Baldiraghi, Blogger

November 2, 2016

15 Min Read

In part 1, we defined our game building blocks and mechanics and observed the exponential growth of possible game states and level complexity. In part 2, we found a way to verify our levels as to guarantee the 3 basic rules of our game (no dead ends, with and without max-combo, a no-combo solution can’t be shorter than a combo one) and we assigned a 3-star rating system for our correct levels.

Our final goal though is to create fair, fun and interesting challenges, and a correct level only satisfies the fairness constraint so we are going to try and define additional rules to improve our rating system and highlight the fun and interesting components of a level.

These rules must represent the feedback from playtesting sample levels both by the designer and players with different levels of experience in videogames. They must try to define “fun” and ‘interesting” while staying consistent with the communication we are creating between the game and the player through our mechanics and levels sequence. Let’s see an example of the content of this communication.

Silent tutorial, natural learning

Skiddy has a total of 12 worlds. The first contains only red Skiddies. The next 4 worlds present a single new object each. Following worlds will combine these objects, creating even more complex puzzles.

The first few levels of each world act as a “silent tutorial” to guide players toward a natural learning of each new object’s properties, understanding through playing.

We can see this in the progression of the first 4 levels of World 1:

Level 1 - The minimum playable level: 2 Skiddies to get max combo, an empty plane and one exit

Level 2 - The plane is not a rectangle, there can be static obstacles

Level 3 - There can be more than one exit.
Vertical symmetry makes left and right solutions equivalent

Level 4 - We can’t clear single Skiddies but we can still break the max-combo with 2 double combos

These sequence of 4 simple levels subtly teaches a lot of game mechanics, but we can go one level further and analyze the moves we are allowed to make in a couple of easy levels to see how the “natural learning” idea works within a single board.


Level 1-1, we learn how to get medals and break the combo

We can’t move up, so we immediately reduce the choice to three directions to limit a beginner’s confusion. After noticing the bottom exit, usually our first instinct is to go down, in this way we clear 1 Skiddy in 1 move. We are left with another lonely one to bounce around and clear the level in at least 2 more moves. We get no medals, but we learn that it’s ok to clear Skiddies one by one. Now we want to get some medals so we try again, doing something different. If we move either left or right, we get the 2 Skiddies stuck together and in this level, there is no way of separating them. Whichever way we move now we will end up with a combo. On the left side, we can go down and clear the level in only 2 moves. This is the minimum and will net us all 3 medals. On the right side, we can either go down-left-down or back left and down, so we clear the level in 4 or 3 moves (typically 4 because on first instinct we generally tend to not backtrack). We learn the difference between combo only (1 medal) and combo in minimum moves (3 medals).

This level also shows how a simple change creates problematic results.

If we move the bottom exit to the middle, we change two things:

  1. There would be no way to break the combo

  2. The only way for the player to learn about the importance of minimum move would be a frustrating ping-pong left and right

Level 1-1 is a simple but comprehensive example of what we learned from our first playtest sessions and helps us defined some positive and negative characteristic of a level.

Positive:

  1. It’s my choice to break the combo. Until all same-color Skiddies are in the level I must be able to get the max combo no matter how I moved before

  2. It’s easy to break the combo if I don’t pay attention. It’s rewarding to focus on my moves

  3. Level layouts, symmetry and block placement have a meaningful purpose

Negative:

  1. Getting the max combo in less moves than it takes to break it reduces the challenge

  2. Levels that are easy to solve just randomly moving around are boring

  3. Correct levels with a feeling of random or unbalanced block placement are not interesting or visually confusing

Lets’ analyze and try to implement point no.1. in our editor.

1 Until all same-color Skiddies are in the level I must be able to get the max combo

To clarify this situation, here’s an example of a level where we break the max combo:

The perfect  solution for this level is Down, Left, Down. Starting by moving left we clear the yellow Skiddies in a combo but then it’s impossible to get the red ones in a position that will not break theirs. Even not willingly breaking any color combo, the max combo is now impossible.

 

While play-testing this became subconsciously expected and felt almost as important as not having dead ends so we decided that it was a necessary condition to get at least 3 stars in our rating system.

To track this, first we define a method (CheckCanCombo) to check if the level state related to a node can still lead to a max combo:


//this class contains all information related to our level game board.
//we can unpack all this information from the Node.Value field and recreate
//any state while traversing our tree

Class Board { 
	…

	Int NumR; //hold the initial count of red skiddies in this level
	
	List <Blocks> Moveables; //moveable blocks in this level 
		 		//(colored skiddies, crates, ice blocks, etc..)

	//checks if from this node we can still reach the max combo
	//returns 0 if can combo, 2 if cannot combo (1 is reserved for later)
	public int CheckCanCombo() {

		if (NumR > 0) { 
			int countreds = 0;    
			//count each color skiddy
			foreach (Block b in Moveables) {
				if(b.IsType(RedSkiddy)) {
                				countreds++;
			        }    		
	
//if a color has less than all items, it cannot lead to a combo, 
//0 means we can still get a combo for this color or the last block for this
//color was cleared. If it’s the last one, the node will be excluded in the 
//final check because the related node State is not set to MaxCombo            
			if (countreds > 0 && countreds != NumR) {
		               return 2;
        			}
			else return 0;
		}
	}

	…
}

Then we add a field (CanCombo) to our node class (defined in part 1 and 2) to track the result.


// A node contains information about board configuration and relations to other nodes
class Node {
	int Value;		//encodes our pieces’ layout and board score
	NodeState State;	//max-combo, ok or dead-end?
	Node[4] Child;	//the states originating form the next 4 moves
	int Index; 		//generating move(none, up, right, down, left) 
	     			//			    	-1    0   1      2     3
	Node Parent;    //state before last move, used to traverse our solution
    int Depth;		//how many moves it took to reach this node

	int CanCombo;   //tracks if the max combo is still reachable from this node
			        //0 can, 2 cannot combo (1 is reserved for later)
}

Our root is created with CanCombo = 0 as anyway all blocks are available, then whenever we create a child node from a parent node that can still reach the combo, we perform the check. The first time that we reach a node that breaks the combo, we can save the move sequence so the editor can show us where it breaks.


//creation from an existing node
	Node node = new Node(value) {
		Value = value;	
		State = DeadEnd		//we do not know if we can reach a solution
		Parent = CurrentNode;	//set the parent for solution traversal
		Index = index;		//we track the originating move
		Depth = currentNode.Depth + 1;
	 
	     if (CurrentNode.CanCombo < 2) { 
                //only if parent can reach the max combo
        		node.CanCombo = board.CheckCanCombo();       
	     }
    	     else {        		
     		//save the move sequence so we can see it in the editor
	        Board.FirstBreaker = GetFirstBreakerSolution(currentNode);
        	     }
	}

Then we define a method to check if at some point the combo was broken.


//We enumerate through all our unique nodes and check if a node that could still lead
//to the max combo (CanCombo == 0) didn’t actually lead to it (State != MaxCombo)

public bool BreakComboCheck() {
    foreach (Node n in Uniques) {
        if (n.CanCombo == 0) {
            if (!n.State == NodeState.MaxCombo)
                return false;
        }
    }
    return true;
}

And at the end of our rating check, we can add this after the DeadEnd search, together with the other conditions to get our 3 stars.


    …

	Rating = 0;

        if (!HasDeadEnds()) {
		Rating = 1;
	        bool comboUnbroken = BreakComboCheck();

		if (noCombo && withCombo) {
			Rating = 2;
                 	if (comboUnbroken) {
				if (Perfect == Moves) {
	                               	Rating = 3;
					…	
				}
		…

Thanks to the previous state propagation, this important rule was fairly easy to implement, we can move to point no.2.

2 - It’s easy to break the combo if I don’t pay attention. It’s rewarding to focus on my moves

What this means in practice is that it must never take more moves to clear a single Skiddy (or more than one but not all if we have more than 2) from one color group than it takes to get the combo for that group (as we saw in level 1-1). Let’s clarify with a negative example:

Here we can get the red combo in 1 move by going down, but it takes 2 moves to break it going right then down.

 

 

Tracking this is even easier than point one, we just need a field (SingleSkiddyOut) in our tree class and when we perform our CheckCanCombo during node creation we save our depth if necessary.


       …
	 
	   if (CurrentNode.CanCombo < 2) { //only if parent can reach the max combo
        		node.CanCombo = board.CheckCanCombo();   

       //if at this point we broke the combo, it means we cleared some but
	   //not all skiddies of a color group. We save the number of moves.
          	if (node.CanCombo == 2 && singleSkiddyOut == 0 ) {
                       SingleSkiddyOut = currentNode.Depth + 1;
            }

		…

And when we rate the board we just check if it’s greater than the number of moves it takes to get a perfect.

This simple rule improves a level’s quality a lot, so we add a 4th star to our rating.


    …

	Rating = 0;

        if (!HasDeadEnds()) {
		Rating = 1;
	        bool comboUnbroken = BreakComboCheck();

		if (noCombo && withCombo) {
			Rating = 2;
                 	if (comboUnbroken) {
				if (Perfect == Moves) {
	                               	Rating = 3;

			//breaking the combo is not harder then getting a perfect
					if (SingleSkiddyOut <= Perfect) {
		                               Rating = 4;
					}	
             …

We can move to the last point:

3 - Level layouts, symmetry and block placement have a meaningful purpose

We briefly discussed placement of static blocks in level 1-1 analysis but before we continue we need to take a look at how we introduced other obstacles in later levels.

In Level 2-1 we learn how to use a pit, a block that will stop Skiddies on their movement but can be slid over with an additional move. This can be useful to align us to an exit or to change direction mid-level.

Initially we perceive a new obstacle as a negative challenge

Our first reaction is to move away

But we find that we cannot reach the exit using walls only

We are guided back to try the new object

Discovering its properties

And we learn how to use it to solve the levels

The function of this new block, as that of any other dynamic object we will get later is to challenge the player while contributing to the level solution. It would make no sense to just have these objects around yet solving the level without interacting with them, so we track that any special block is contributing to the final solution.

We do this by checking 2 things:

  1. If we remove all the special blocks and get the same solutions, they are not contributing anything

  2. For each and every solution leading to a perfect, every special block must be interacted with (e.g.: every pit must be traversed by a Skiddy, every crate must be pushed around, etc...)

As before, we can clarify this with the example of a wrong level:

In this example, we can get a perfect solution moving Up, Left, Down, Right and Down, with both Skiddies sliding over the pit. If we remove the pit though, because of the level layout, we get the exact perfect solution as the Skiddies can use walls to stop in the correct position. This level will fail the 4th star check

 

These checks are a bit more complicated than the previous ones so we omit code for brevity but in the end if our level contains special blocks, we can check this as part of our 4th star rating.


    …

	Rating = 0;

	if (!HasDeadEnds()) {
		Rating = 1;
	        bool comboUnbroken = BreakComboCheck();

		if (noCombo && withCombo) {
			Rating = 2;
                 	if (comboUnbroken) {
				if (Perfect == Moves) {
                           	Rating = 3;
					//breaking the combo is not harder then getting a perfect
					if (factory.FirstSkiddyOut <= Perfect) {
					 	…
						//we either don’t have special blocks or thei are 
						//all used in every perfect solution
						if (!HasSpecials || UsingSpecials(factory)) {
			                   		Rating = 4;
						}	
                 …

In the final version of our editor there’s an additional 5th star for levels with a second color with only 1 Skiddy. This levels get 5 stars only if it’s possible to clear this single Skiddy in no more than 1 move after clearing the first combo. (It’s tedious to bounce around a lonely Skiddy without combo chance).  For the sake of our discussion, we don’t need to dwell on its implementation details. All levels featured in the game are 4 or 5 Stars.

We have now reached a satisfying situation, where our editor can analyze our level and, based on the game designer’s requirements, correctly determine if it respects all the required rules and rate it accordingly.

Our levels are now guaranteed to satisfy the following conditions:

  1. Without dead ends – 1 Star

  2. With and without max-combo -2 Stars

  3. The no-combo solution is always longer than a combo one

  4. It’s always possible to get the max combo regardless of the level state, unless I break it voluntarily – 3 Stars

  5.  I can always break the combo in less moves than it takes to get the perfect

  6. If there are special blocks they all contribute to the perfect solution. – 4 Stars

  7. If there’s a single Skiddy for a color, it can be cleared in 1 move after the combo for the other color – 5 stars

This removes human error in this critical (and, frankly, impossible to always verify by hand) test phase and avoids that level that appears to be good but has hidden negative characteristics not found by the designer or by human players.

We can now create levels that are fair and fun, yet we are still missing the final element to answer our initial question. Given two levels with the same elements and equal rating, what makes one better than the other? What makes an interesting level?

In the 4th and last part we will try to implement some level design rules so that our editor can help us in the creation phase and avoid testing levels that can be discarded in advance.

 

Disclaimer: As a first experience in designing/programming a video game, we are aware our methods might not be the best but they served the purpose and aided the design and the code to evolve and complement each other.  If readers have questions or suggestions regarding the subject matter and how to improve it, we at BigBangPixel would sincerely like to discuss it, so write us at [email protected]

License: Skiddy and all related assets including levels and editors are Copyright 2012 by BigBangPixel and all rights are reserved. The information published in this article can be used by anyone for non-assignable, non-transferable, non-commercial use or educational purposes.  Any other use, including any redistribution in

whole or in part, requires explicit, written permission from BigBangPixel.

Read more about:

Featured Blogs
Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like