Here is a simple TicTacToe Game in basic form. No reset button, no timer. They would follow eventually. But for now, lets look at the sprite kit example game
First I created an empty game with SpriteKit framework. The main controller class is renamed as GameViewController, which inherits from UIViewController. All the necessary code would have already been added by XCode when we created the empty game. All we need to do is display the grid and listen to user input.
This is a turn based game, so first player always takes up ‘0’ icon. In GameScene.swift file, which inherits from SKScene, override the function didMoveToView(). This function is called when this scene becomes active in the game. This becomes active when the code skView.presentScene(scene) is called in viewDidLoad function of GameViewController class.the presentScene basically brings the scene into active mode.
Next Create a background image. I downloaded a tic tac toe game grid image from online. You could do the same or create your own custom cool grid.
Background = SKSpriteNode(imageNamed: "tictacbg")
Background.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(Background)
These lines basically create a sprite node from image tictacbg, set its position to be the middle of the screen, and add the node to the game scene. Adding the child node is important because it makes sure the node is added to the root node and is visible on screen.
The image tictacbg is setup in images.xcassets/tictacbg.imageset/ (See github project link for the whole structure).
GridWidth = Background.frame.width / 3.0;
GridHeight = CGFloat(Background.frame.height) / 3.0;
BottomLeftX = Background.position.x - Background.frame.width / 2;
BottomLeftY = Background.position.y - Background.frame.height / 2;
These lines save the grid width, height, bottom left position values. This seems old school to save x,y values in two different variables. But lets have this for now. Will upgrade it soon
These variables are declared in the class like so:
var Background = SKSpriteNode()
var GridArray = [Int](count: 9, repeatedValue: 0)
var PlayerTurn : Int = 0
var GridWidth : CGFloat = 0
var GridHeight : CGFloat =0
var BottomLeftX : CGFloat = 0
var BottomLeftY : CGFloat = 0
The GridArray is used to store 1 or 0 to indicate whether a grid cell has already been marked by any user. PlayerTurn variable is used to identify whose turn it would be next.
Then in touchesBegan overridden function:
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {let location = touch.locationInNode(self)
let XIndex = Int(location.x - BottomLeftX) / Int(GridWidth);
let YIndex = Int(location.y - BottomLeftY) / Int(GridHeight);let ArrayIndex = YIndex * 3 + XIndex;
for each touch, get the touch location(locationinNode(self)), find its x index from the grid’s bottom left corner, and y index from same bottom left corner. This index indicates which column the touch was in (X) and which row the touch was in (Y). Basically it is simple math, where the distance between the touch and the corner is divided by the grid widht/height in order to get the index. 0 being the bottom most row and 2 being the top most row for Y. Similarly 0 being the left most column and 2 being the right most column for X value. Array index is calculated by the formula above, where 0 would be the bottom left most cell, 1 being the second cell on bottom row, and 2 being the third cell on bottom row, 4 being the first cell on middle row, etc.
This array index is used to access the values in the GridArray.
if(GridArray[ArrayIndex] == 0 ){
var PositionX = CGFloat(BottomLeftX) + CGFloat(XIndex) * CGFloat(GridWidth);
PositionX += CGFloat(65);
var PositionY = CGFloat(GridHeight) + CGFloat(BottomLeftY) + CGFloat(YIndex) * CGFloat(GridHeight);
PositionY -= CGFloat(65)
if(PlayerTurn == 0){
AddO(CGPoint(x: PositionX, y: PositionY));
PlayerTurn = (PlayerTurn + 1) % 2
}
else{
AddX(CGPoint(x: PositionX, y: PositionY));
PlayerTurn = (PlayerTurn + 1) % 2
}
PositionX += CGFloat(65);
var PositionY = CGFloat(GridHeight) + CGFloat(BottomLeftY) + CGFloat(YIndex) * CGFloat(GridHeight);
PositionY -= CGFloat(65)
if(PlayerTurn == 0){
AddO(CGPoint(x: PositionX, y: PositionY));
PlayerTurn = (PlayerTurn + 1) % 2
}
else{
AddX(CGPoint(x: PositionX, y: PositionY));
PlayerTurn = (PlayerTurn + 1) % 2
}
GridArray[ArrayIndex] = 1;
}
If the grid is empty, calculate the X, and Y position (center position) for the player icon. X position is calculated as : from the bottom most row’s x, move one cell width at a time, until you reach the cell that the user is touching using the code : var PositionX = CGFloat(BottomLeftX) + CGFloat(XIndex) * CGFloat(GridWidth); Then this would be the bottom left corner of that cell. Then move about 65 units to the right approximately to figure out the center of the cell.
This would be changed later to use the GridWidth.
Similarly start from bottom left corner Y, then move one cell up at a time, until you reach the cell that the user is touching using the code : var PositionY = CGFloat(GridHeight) + CGFloat(BottomLeftY) + CGFloat(YIndex) * CGFloat(GridHeight);
If it is the first player’s turn (PlayerTurn == 0), then add O sprite in that position. Remember this position is the center of the grid cell, and would be center of the icon. Then change playerTurn variable value to be 1.
If it is second player’s turn(PlayerTurn == 1), then add X sprite in that position. Then change PlayerTurn to again 0.
Set the GridArray value to be 1/true/enabled. So that next time, touching same grid will not create any new sprite.
That is all the code needed. Now during first touch 0 is displayed, next one X is displayed. It is the raw concept of tic tac toe. More will follow.
Github link :https://github.com/swtsvn/CJAW/tree/TicTacMain/TicTac