iOS SDK: Build a Facts Game - Game Logic

Welcome back to the third and final section of our Facts Game with Sprite Kit tutorial series. This tutorial will teach you how to use the Sprite Kit framework to create a question-based facts game. It is designed for both novice and advanced users. Along the way, you will apply the Sprite Kit core.


Introduction

In this tutorial, you will program the entire game logic including the player's life, the question, and the player's answer. This tutorial series is broken up into three sections: Project Setup, Facts Interface, and Game Logic. If you haven't yet completed the second section, you can download the project and pickup exactly where we left off. Each part produces a practical result, and the sum of all parts will produce the final game. Despite the fact that each part can be read independently, for a better understanding we suggest to follow the tutorial step by step. We also included the source code for each part separately, thus providing a way to start the tutorial in any part of the series.

This is what our game will look like upon completion:

Image0
Illustration of Final Result - Facts

1. Custom Facts Class

In the last tutorial, you defined a plist file for the questions. Each question has four properties. In order to manage them, you need to create a custom class to afford that task properly. Therefore, you need to form another Objective-C class. Name it factObject and define the NSObject superclass.

Now, let's edit the header file and add the four plist properties. Each plist property has its own features:

  • The statement Id is an int.
  • The statement is a NSString.
  • The isCorrect statement is an int.
  • The additional information is a NSString.

The end result should be similar to this:

You don't need to use the implementation file (.m). We will parse the plist file to this custom class and use the values directly from the memory.


2. Facts Interface: Initialization

In the last tutorial, you defined the basic structure of the facts interface. It is now time to complete it with the logic steps. To complete this game, we need to create a question label, a customized background statement, a button that asks for another question, and a true and false interface. Those four statements translate into five properties defined in the FactsScene.h file. Once again, you can name them as you please. Our implementation is:

Now move your attention to the FactsScene.m. You need to define several objects that are used internally in the class:

  • A NSMutableArray to store the questions
  • A random value that represents a random question
  • The question identifier
  • The minimum threshold for the right questions; this threshold indicates the minimum required correct answers for the user to advance to another level. In this tutorial, you will use value seven.

Your implementation file should look like this:

It is now time to allocate a few values and begin with the logic. In the -(id) initWithSize:(CGSize)size inLevel:(NSInteger)level withPlayerLives:(int)lives method initiate the questionNumber and the totalRightQuestions. Since it is the first time you use it, the initiation is easy and can be done like:

Now it is time to use the custom class defined in the aforementioned step. Parse the plist file and use the information store in the plist to allocate and populate new factObject objects. Note that we will store each factObject object in a custom NSMutableArray already defined (statements). The complete snippet is below.

This step removes the older parsing code from the -(void) didMoveToView:(SKView *)view method. You can remove it, since you will not use it anymore.


3. Facts Interface: Logic

It is now time to focus on the logic code itself. We need to show the question to the user. However, the question is always a random choice. Start to define a rectangle to afford the question and then allocate the necessary resources for the question's text. The following snippet will help you:

Note that you will not use the SKLabelNode over the simple NSString because of a SKLabelNode limitation; it is for single-line text only. A warning will appear regarding the getRandomNumberBetween:0 to:X method. You need to declare and code it; its objective is to return a random value between two values. The next snippet will help you:

Now that you can see the question, we need to add some functionalities to the right and wrong button. Change both selectors and call a new method called: presentCorrectWrongMenu.

Additionally, define a tag for each button. The true button will be tag = 1 and the false tag = 0. These tags help you when you call the -(void)presentCorrectWrongMenu:(UIButton*)sender method to determine which button was tapped to call that same method.

The next step is to add the -(void)presentCorrectWrongMenu:(UIButton*)sender method. This method is complex and recognizes which button is tapped, adds a custom answer interface, and adds a button that calls the next question. Use the following snippet to achieve the above-mentioned topics:

A warning will appear, however do not fix it right away. First, end the method declaration. Now that you have a custom interface for the answer, you need to test the player's answer. To achieve that, you need to know which button the player tapped and the inherent question's answer. You already know this, so you only need to create a simple logic test condition. To do this, you need to test if the answer is correct or incorrect, play a sound accordingly, and proceed to the properties update. The next snippet will help you. Note that you must place it where the last snippet of code ended.

Do you remember the last warning? Now you should see several warnings. Don't worry, they're warning you that several methods are missing. We can correct that. The first method to define is the -(void)nextQuestion. As the name suggests, it calls the next question. Besides presenting a new question, it resets the timer, increments the question number, updates the current question label, removes the presented question from the array, and tests the logic needed to move to another level. The complete source code of -(void)nextQuestion is:

Note that you hard-coded the maximum questions (10) for this level and the threshold for the next level (7). Once again, a new warning will appear. No resetTimer method exists; this method only resets the maximumTime property to 60 and updates the label accordingly:

In the last tutorial, you defined the touchWillProduceASound method. However in this tutorial, you need to modify it further. The objective is to pass it a object that represents the correct or incorrect answer. Then the corresponding sound will play. The complete method is:

You still need to define the -(void)removePlayerLife method. As the name states, it tests the life of a player and acts accordingly. If the player has more than one life, a life is reduced and the inherent asset is updated or is moved to the home screen. The complete method is below.

At this point, we're nearly finished. It is now time to update the - (void)updateTimer defined in the last tutorial. This new method is responsible for updating the timer value and testing the player's life. It automatically reacts when the timer hits zero. At that time, it tests the player's life and acts accordingly. It goes to the main menu if the player's life is less than one or calls another question otherwise (decreasing the player's life). The complete snippet is below.


4. Additional Methods

Two additional methods were created: -(void)moveToHome and -(void)removeUIViews. We need to define them because we'll use them more than once. It is good practice to reuse code instead of typing it all again. The -(void)moveToHome is just a call to a SKTransition and MyScene class. The code is:

The -(void)removeUIViews removes the UIKit views from the superview. Here is what the code looks like:

Now that everything is correct, Run the project. Every time you correctly answer a question, you will see an interface similar to the next image:

Image1
Illustration of a correct answer

On the other hand, when you incorrectly answer a question, you will see an interface that looks like this:

Image2
Illustration of an incorrect answer

5. Final Improvements

There's just one more step before we're done. We need to correctly initialize the actualPlayerLevel at the level selection. Switch your attention to the MyScene.m class (the first one created by the Xcode) and let's add some lines of code. Initially, add an object of the type NSUserDefaults to the @implementation section. The following snippet will help you:

Now inside the -(void) didMoveToView:(SKView *)view, add the inherent NSUserDefaults initialization. The default value is one, so that a new player always starts a new game at Level 1. Moreover, if the player didn't achieve the minimum requisites to pass the level, it starts again at that same level. The result is below.

Several other adjustments can be made to this game. You can customize the correct answer rates for questions, animations, and transitions, or alter the landscape and portrait mode. We think that you are ready for such a task. Try to implement them on your own.


Conclusion

At the end of this Facts tutorial, you should be able to create a SpriteKit game, create and configure several SpriteKit views and actions, configure several UIKit views, use them in parallel with SpriteKit, and parse Property lists. Don't hesitate to use the comment section below for suggestions or comments. Thanks for reading!

Tags:

Comments

Related Articles