Saturday, May 2, 2015

CJAW : Swift TicTacToe Part2

This week, added some minor changes to the Tic Tac Toe Game.  Basically replaced all x,y parameters to CGPoint, and used grid size’s half width and half height in order to position the Xs and Os. Then added a reset button to clear the nodes on screen. 

To add reset button : 
In Main.Storyboard, drag and drop a button(from Object library. If you are not able to see Object library on the right bottom corner, then do View->Utilities->Show Identity Inspector to see the library) into a suitable location inside the view controller. I moved the button to bottom left corner, below a space where the grid would appear. 

If you are not able to view assistant editor, then click on View->Assistant Editor->Show Assistant Editor. This window shows the GameViewController.swift file’s code. Do a control+drag from the button to somewhere inside the class GameViewController. When prompted, chose Connection:Action ( to call a function when the button is touched), Name: OnTouch(), Type:UIButton, Event:Touch Up Inside, Arguments: Sender. This will create a function inside the  GameViewController class. This function will be called when the button is touched.

     

@IBAction func OnTouch(sender: UIButton) {
        PresentGameScene()
    }

Create a function called PresentGameScene() which would delete all existing nodes inside the GameScene, and make the view present the scene once again, fresh.

func PresentGameScene(){
        if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
            // Configure the view.
            let skView = self.view as SKView
            skView.showsFPS = true
            skView.showsNodeCount = true
            
            /* Sprite Kit applies additional optimizations to improve rendering performance */
            skView.ignoresSiblingOrder = true
            
            /* Set the scale mode to scale to fit the window */
            scene.scaleMode = .AspectFill
            
            scene.Reset();
            skView.presentScene(scene)
       }

   //Make sure to reuse the code in 

     override func viewDidLoad() {
        super.viewDidLoad()
        PresentGameScene();
 }

Now we need to implement scene.Reset(). In GameScene.swift file, implement the function

  func Reset(){
        self.removeAllChildren();
    }

That is all. It is quite simple. removeAllChildren takes care of removing all the child nodes from the game scene, and cleans the slate for fresh start.

Github link: https://github.com/swtsvn/CJAW/tree/TicTacMain/TicTac

Tuesday, April 28, 2015

CJAW: Swift Tic Tac Toe

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
                }

                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


        

Tuesday, March 24, 2015

Code Jam : Swift Physics, Joints, FieldNodes.

This week, I created something similar to pendulum, with Physics bodies, physics joints, and Field Nodes.

I say something similar, because it did not reach the exact pendulum swing that I wanted. But it is closer. If the values are tweaked a bit, it would reach the optimal pendulum swing motion. Before that I thought I would publish this post.

First create a simple empty game in Xcode for swift language.  In GameScene.swift, inside class GameScene, in didMoveToView(), add the following nodes.

/* Setup your scene here */
        let myLabel = SKLabelNode(fontNamed:"Chalkduster")
        myLabel.text = "Pendulum";
        myLabel.fontSize = 15;
        myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
        self.addChild(myLabel)

        
These lines create label node, set its font size, and mention the idea of the game.  Though the empty project is a game. This is no where closer to being a game. This is purely for experimentation and blogging purpose. 

Place the label at the center of the screen. CGRectGetMidX() is a CGGeometry function which returns center x position of the rectangle passed as the parameter. Similarly CGRectGetMidY. Csdfs


I created three main nodes. One is a rectangle which will act as the rod. A circle which will act as the bob. And an invisible circle which will act as the anchor point for the rod. It will be on the other side of the rod, on opposite end to the bob circle. 

        let rectNode = SKShapeNode(rect: CGRectMake(500,300, 5, 250))
        rectNode.strokeColor = SKColor.greenColor()
        rectNode.fillColor = SKColor.yellowColor();
        rectNode.lineWidth = 1
        let rectBody = SKPhysicsBody(rectangleOfSize: rectNode.frame.size)
        rectBody.affectedByGravity = false
        rectBody.mass  = 5
        rectBody.dynamic = true // should be dynamic
        rectNode.physicsBody = rectBody;
        self.addChild(rectNode)

This snippet creates a rectangle node positioned at 500,300. Stroke color is green, fill color is yellow. You can provide any color you want. I simply created colors to provide contrast against black background. 

Then comes the physics body. The Physics body gives movement to the node, and makes it behave in accordance with the gravity law. Collision is taken care of by the physics bodies. 

Create a rectangular physics body of the same size as that of the rectangular node. Then I made sure the physics body is not affected by gravity because, I want them to be affected only by the two Field bodies' gravitational forces. 

Let the physics body have a mass of 5.  Make sure dynamic is set to true, so that they can move with respect to the forces acting on them. 

Set the physics Body of the rectangular SKNode to the newly created physics body. Then add the node to the scene. Scene is the parent of the node. 

Similarly create circle node :
        let circleNode = SKShapeNode(circleOfRadius: 20);
        circleNode.position.x = 500;
        circleNode.position.y = 300
        circleNode.strokeColor = SKColor.greenColor()
        circleNode.fillColor = SKColor.orangeColor()
        let circleBody = SKPhysicsBody(circleOfRadius: 20)
        circleBody.affectedByGravity = rectBody.affectedByGravity
        circleBody.mass = 10
        circleBody.dynamic = true //should be dynamic
        circleNode.physicsBody = circleBody

        self.addChild(circleNode)

And create the anchor node:
  
        let AnchorNode = SKShapeNode(circleOfRadius: 25);
        AnchorNode.position.x = circleNode.position.x
        AnchorNode.position.y = circleNode.position.y + 250
        AnchorNode.alpha = 0
        AnchorNode.strokeColor = SKColor.greenColor()
        AnchorNode.fillColor = SKColor.redColor()
        let AnchorBody = SKPhysicsBody(circleOfRadius: 20)
        AnchorBody.affectedByGravity = false
        AnchorBody.dynamic = false //should be dynamic
        
        AnchorNode.physicsBody = AnchorBody
        AnchorBody.affectedByGravity = false
        self.addChild(AnchorNode)

The important points to note in the anchor node are as follows: Anchor node is invisible because I want the rod to look closer to a real pendulum. Position is same as that of the other end of the rod. It also has a body but it is not affected by gravity. It is not dynamic as well. It should stay put like a nail on the wall. It needs a physics body, in order to create a Pin joint later with the rod. Red circle is the anchor, orange is the pendulum bob.



For the sake of clarity, the red circle has an alpha of 1, and is visible. But it will be rendered transparent in the final code. 

Now that the three major nodes are created, I am going to create two Field Nodes which would act as radial gravity nodes, which means, objects would be attracted towards them and would follow a natural curve of moving towards them and moving away from them. 

I tried to create pendulum with one such node. but It did not give expected results, hence I am falling back to two nodes. 




The cyan colored circles are the Field nodes which would try to pull the bob towards them. Note: SKFieldNode is available only for iOS 8.0 and above. 

Here is the code snippet for them. 


        let GravityNode = SKFieldNode.radialGravityField()
        GravityNode.position.x = 350
        GravityNode.position.y = 290
        GravityNode.strength = 6
        GravityNode.falloff = 3.5
        

        self.addChild(GravityNode)

lAs we already know, let keyword creates a constant reference to the object, meaning, the GravityNode cannot point to any other object. The properties inside the object are editable, but not the GravityNode. 

Set the position of one of the radial gravity node on the left side of the pendulum. Set its strength to be 6, and falloff to be 3.5 . Strength is the pull strength of its gravity. FallOff is the variable which sets the exponent value which determines how much of gravitational pull the objects would feel, after a certain distance. 

Strength and falloff had to be tweaked in order to get a smooth swinging pendulum. 

Add the node to the scene. 

        let GCircleNode = SKShapeNode(circleOfRadius: 25);
        GCircleNode.position = GravityNode.position
        GCircleNode.strokeColor = SKColor.greenColor()
        GCircleNode.fillColor = SKColor.cyanColor()
        GCircleNode.alpha = 1
        self.addChild(GCircleNode)

This is a debug node which was created to show the position of the field node. This is not required to be rendered for the final run. 

Similarly create a second field node, to pull the pendulum towards the other direction. 

        let GravityNode1 = SKFieldNode.radialGravityField()
        GravityNode1.position.x = 650
        GravityNode1.position.y = GravityNode.position.y
        GravityNode1.strength = GravityNode.strength
        GravityNode1.falloff = GravityNode.falloff
        self.addChild(GravityNode1)

        
        let GCircleNode1 = SKShapeNode(circleOfRadius: 25);
        GCircleNode1.position = GravityNode1.position
        GCircleNode1.strokeColor = SKColor.greenColor()
        GCircleNode1.fillColor = SKColor.cyanColor()
        GCircleNode1.alpha = 1
        self.addChild(GCircleNode1)

Now the rod needs to be pinned to the invisible anchor node, and the bob circle needs to be pinned to the other end of the rod, in order to move in alignment  with the rod. 

        let PinJoint = SKPhysicsJointPin.jointWithBodyA(circleNode.physicsBody, bodyB: 
          rectNode.physicsBody, anchor: circleNode.position)
        
        let stickJoint = SKPhysicsJointPin.jointWithBodyA(rectNode.physicsBody, bodyB: 
          AnchorNode.physicsBody, anchor: AnchorNode.position)
        
        self.physicsWorld.addJoint(PinJoint)
        self.physicsWorld.addJoint(stickJoint)

The physics joint Pin, fixes bodyA to Body B at a certain point. This point is called anchor point. Body A is circle (bob) and body B is the rod in the first PinJoint. They are fixed at the bob's position. 

Second stickJoint(for lack of better term) joins the rod and the invisible anchor node at the anchor node's position. 

Add these two joints to the world. Now since the anchor's dynamic property is set to false, and it is not affected by gravity, It would stay put, and the rod has no other option than to stay put at that end. But the other end can move freely, and the bob circle will move whereever the other end moves because it is pinned to the rod at that point. 

Now we have a working pendulum, whose bob is being pulled equally by left and right gravity nodes. When the bob reaches the center after being pulled by right node, it will be pulled by the left one, thereby swinging from one end to the other. 




Code Jam for the week of Mar 15 2015
Project uploaded here : https://github.com/swtsvn/CJAW/tree/master/PhysicsGame

Sunday, March 8, 2015

Code Jam : Swift : Gradient and Graphics

Today I am going to enter graphics in swift, or at least the basics of it. 
In a simple view controller, ( I assume you know how to create a view controller by now, if not do refer to my previous blogs), Create a view. A view is nothing but a sub window inside a view controller. It is a subclass of UIView, and can be used to draw elements on screen. 

This week, I am going to create a bezier path with transformations, and color it with gradient color. This would be the simplest of all the graphics we can do in swift, but this is where it starts. 

In viewController.swift (or the file name you have for the main view controller), create a new class called MyView (or any other name you prefer), and subclass it to UIView.

class MyView : UIView{

Override the function drawRect().

override func drawRect(rect: CGRect) {

1. Transformations : I assume the readers know about graphics transformations. If not here are few good pages on it (http://www.cs.uic.edu/~jbell/CourseNotes/ComputerGraphics/2DTransforms.html and http://www.cs.utexas.edu/~fussell/courses/cs384g-fall2010/lectures/lecture07-Affine.pdf)
In this week, I am going to add rotation, and translation to the bezier curve. Rotation is created by Core Graphics function  CGAffineTransformMakeRotation.  cThis function creates a rotation matrix from unit matrix. The argument is angle in radians.CGAffineTransformMakeRotation is one of the methods to rotate objects on screen. The other way is to directly use CGContextRotateCTM, which rotates within a context. For this week, we will see affine transformation matrix. Eventually I will end up using context to append the transformation matrices.

 var rot = CGAffineTransformMakeRotation(CGFloat(M_PI/ 4)

The angle of rotation is 45 degrees ( Pi/4).  Then I translate the object to bring it inside the view. 


var trans = CGAffineTransformMakeTranslation(100, -150)

This creates another matrix that would translate the object by 100 units along x axis and -150 units along y axis. Since iOS coordinate system origin is at top left corner of screen, this would move the object towards right and up.

Next I am saving the current context, this is to make sure, we can restore back to the previous context after our customized changes to the current transformation matrix (CTM)

 let context = UIGraphicsGetCurrentContext()
 CGContextSaveGState(context)
UIGraphicsGetCurrentContext This function returns back a  CGContextRef of the current context ( https://developer.apple.com/library/ios/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html ) being used. Current context is nil by default. the UIView object (MyView class object in our case) pushes a valid context into the stack, making it current, to draw objects, and this happens just before calling drawRect() method. In case you are not using UIView object, then you must manually push context using UIGraphicsPushContext method. 

 CGContextConcatCTM(context, rot)
 CGContextConcatCTM(context, trans)

These lines concatenates rotation matrix, and translation matrix to the existing matrix of the context. The order is important. These lines would first rotate the object then translate. 

2. Bezier Curve : Next is to draw a bezier curve (  http://web.iitd.ac.in/~hegde/cad/lecture/L13_Bezi ercurve.pdf ) . To create the curve programmatically. I am creating a rectangle with a circle at its bottom to look similar to a pendulum but not exactly one. This would include two bezier paths inside one. 

First create the rectangle path. 
  var bezierPath = UIBezierPath();
  let r = CGRectInset(rect, rect.size.width * 0.475, rect.size.height * 0.05)
  var rpath = UIBezierPath(roundedRect: r, cornerRadius: 60.0)
      
Create a new UIBezierPath, then create a rounded rectangle by using CGRectInset with rectangle as the view’s rectangle itself, and the roundness to reduce the width by a lot, but height by a small fraction, so that a long slender rectangle is created. Then create a bezier path using the provided easy API UIBezierPath instead of creating your own control points using  addLineToPoint or addCurveToPoint functions. 

Then create another bezier path that would create a circle. 
let newrect = CGRectMake(20, 105, 250  , 250)
let h = CGRectInset(newrect, newrect.size.width * 0.3, newrect.size.width * 0.3)
var headpath = UIBezierPath(ovalInRect: h);
let rad = 20.0
        
This creates another rectangle that would position the circle at the bottom part of the rectangle that I already created. CGRectInset is used to create circle with this rectangle. UIBezierPath is used to create bezier path. using ovalInRect parameter. 

 rpath.appendPath(headpath)
 bezierPath.appendPath(rpath);
 bezierPath.addClip()

Add headpath to rpath ( circle to rectangle), then append that combined path to the main empty bezierPath. Then do addClip(). This method intersects the shape with current clipping region of the graphics context. This method is important to create the gradient color filling to the path. 

3. Gradient filling:

 let colorspace = CGColorSpaceCreateDeviceRGB()
 let g1 = UIColor(red: 0.5, green: 0.2, blue: 0.8, alpha: 1)
 let g2 = UIColor(red: 1, green: 0.6, blue: 0.2, alpha: 1
 let gc : CFArray = [g1.CGColor, g2.CGColor, UIColor.blueColor().CGColor, UIColor.redColor().CGColor]
 let gl : [CGFloat] = [0, 0.3,0.5,1]
 let gra = CGGradientCreateWithColors(colorspace, gc, gl)
       
 CGContextDrawLinearGradient(context, gra, CGPointMake(self.bounds.width/2, self.bounds.height - 20), CGPointMake(self.bounds.width / 2, 20), 0)

First create device dependent RGB color space by using CGColorSpaceCreateDeviceRGB . This is important to set the colors for the gradient. 
Create two colors g1 and g2, and setup 4 colors for the gradient to change from. Then create color array using 4 colors (g1, g2, blue, red). Create coordinates array, which specifies where the color should change. This is again an array of 4 elements. 
Then create gradient with colors and coordinates. using CGGradientCreateWithColors . Then draw gradient colors. Since we already clipped using addClip, the gradient colors will be applied to the bezier path. 

 CGContextDrawLinearGradient(context, gra, CGPointMake(self.bounds.width/2, self.bounds.height - 20), CGPointMake(self.bounds.width / 2, 20), 0)
       
 CGContextRestoreGState(context)

CGContextDrawLinearGradient is used to draw the gradient colors to the bezier shapes.  The third and fourth parameters are CGPoints that define the coordinates for starting and ending points.  CGContextRestoreGState is used to restore the context that was used before we saved it and changed it. 
For a simple project like this one, saving and restoring might not be necessary. But it is required for complex ones with multiple objects to be rendered on the screen. 

The final rendered view looks like this :

The viewController.swift code :


import UIKit

class MyView : UIView{
   
override func drawRect(rect: CGRect) {
       
       
       
       
// 1. transformations
        var rot = CGAffineTransformMakeRotation(CGFloat(M_PI) / 4)
       
var trans = CGAffineTransformMakeTranslation(100, -150)
       
       
let context = UIGraphicsGetCurrentContext()
       
CGContextSaveGState(context)
       
CGContextConcatCTM(context, rot)
       
CGContextConcatCTM(context, trans)
       
   
       
//bezier path
        var bezierPath = UIBezierPath();
       
       
let r = CGRectInset(rect, rect.size.width * 0.475, rect.size.height * 0.05)
       
var rpath = UIBezierPath(roundedRect: r, cornerRadius: 60.0)
      
       
       
let newrect = CGRectMake(20, 105, 250  , 250)
       
let h = CGRectInset(newrect, newrect.size.width * 0.3, newrect.size.width * 0.3)
       
var headpath = UIBezierPath(ovalInRect: h);
       
let rad = 20.0
     
        rpath.
appendPath(headpath)
   
       
        bezierPath.
appendPath(rpath);
        bezierPath.
addClip()
      
       
//gradient
        let colorspace = CGColorSpaceCreateDeviceRGB()
       
let g1 = UIColor(red: 0.5, green: 0.2, blue: 0.8, alpha: 1)
       
let g2 = UIColor(red: 1, green: 0.6, blue: 0.2, alpha: 1)
       
let gc : CFArray = [g1.CGColor, g2.CGColor, UIColor.blueColor().CGColor, UIColor.redColor().CGColor]
       
let gl : [CGFloat] = [0, 0.3,0.5,1]
       
       
let gra = CGGradientCreateWithColors(colorspace, gc, gl)
       
       
CGContextDrawLinearGradient(context, gra, CGPointMake(self.bounds.width/2, self.bounds.height - 20), CGPointMake(self.bounds.width / 2, 20), 0)
       
       
CGContextRestoreGState(context)
    
    }
}


class MyViewController: UIViewController{
  
   
   
let myview = MyView(frame: CGRectMake( 10, 100, 300, 300))
   
@IBOutlet var colorLabel: UILabel!
   
override func viewDidLoad() {
       
super.viewDidLoad()
       
// Do any additional setup after loading the view, typically from a nib.
        view.addSubview(myview);
    }

   
override func didReceiveMemoryWarning() {
       
super.didReceiveMemoryWarning()
       
// Dispose of any resources that can be recreated.
    }
}




Error & Solution : If you get a blank screen instead of the main view controller, and an error in the debug window stating "perhaps the designated entry point is not set?”, then it means there is no initial view controller for the story board. Select the storyboard->then the navigation controller or the view controller that you want as the first screen -> attributes inspector -> check the “Set as initial view controller” option. It should be enabled.

Code Jam for the week of Mar 1 2015