Use a physics joint on two GK Entities, springing off from the 2d iOS book

From 2d iOS, we learn how to make entities using components and display them on the scene. This includes in some cases making some entities children of others. I gave this a go and after a while found it not too hard to do. Taking it up a notch I wonder how to join entities and where the best place is to do that in the code.

My Example: You create two entities that have sprite components. I’m imagining maybe a car as the parent node and a wheel as the child entity. Once you get this working you could conceivably reuse the code to do another wheel or several if you want a big truck!

Once you make a VehicleEntity and a TireEntity as its child, (I learned this right out of the book) you give them physicsbodies, set their rotation and gravity properties. Then you are left with the decision of where to create the jointPin. I chose to make it part of the Component that makes the TireEntity a child of the VehicleEntity. Now it just has to be added to the scene somehow and that is where I got stuck.

My Work!

  1. Creating the VehicleEntity
  2. Creating the TireEntity
  3. Creating an AxleComponent to bring them together.

1.
Creating my VehicleEntity just like in the book:

import GameplayKit
import SpriteKit

enum VehicleType: String {
case SportsCar = “SportsCar”
//room for more cars later

//some variables to help locate the position the wheels need to be placed
var frontAxleVector: CGFloat {
switch self {
case SportsCar: return 50.0
}
}

var rearAxleVector: CGFloat {
    switch self {
    case SportsCar: return 50.0

    }
}

}

class VehicleEntity: GKEntity {
let veclType: VehicleType
var spriteComponent: SpriteComponent!
init(veclType: VehicleType) {
self.veclType = veclType
super.init()
let size: CGSize
switch veclType {
case .SportsCar:
size = CGSizeMake(200, 75)
//add more vehicles for fun here later
}
let textureAtlas = SKTextureAtlas(named: veclType.rawValue)
let defaultTexture = textureAtlas.textureNamed(“Driving__01.png”)

    spriteComponent = SpriteComponent(entity: self, texture: defaultTexture, size: size)
    addComponent(spriteComponent)
   
    
    let vehiclePhysicsBody = SKPhysicsBody(rectangleOfSize: size)
    vehiclePhysicsBody.dynamic = true
    vehiclePhysicsBody.allowsRotation = true
    
    //add categorybitmask here see page 592
    spriteComponent.node.physicsBody = vehiclePhysicsBody
    
    axleComponent = AxleComponent(veclType: veclType, parentNode:    spriteComponent.node)
    addComponent(axleComponent)

}

2.
Now for the TireEnitity: Again just like in the book with the addition of physicsbodies

import SpriteKit
import GameplayKit

class TireEntity: GKEntity {

var spriteComponent: SpriteComponent!

init(veclType: VehicleType) {
    super.init()
    //let testSize = CGSize(width: 100, height: 100)
    let texture = SKTexture(imageNamed: "\(veclType.rawValue)Wheel")
    spriteComponent = SpriteComponent(entity: self, texture: texture, size: texture.size())
    addComponent(spriteComponent)
    
    let physicsBody = SKPhysicsBody(circleOfRadius: texture.size().width/2)
    physicsBody.dynamic = true
    physicsBody.allowsRotation = true
    physicsBody.affectedByGravity = true
    spriteComponent.node.physicsBody = physicsBody    
}

}

3.
And now an AxleComponent to help bring the VehicleEntity and the TireEntity together and create the pinJoint:

import SpriteKit
import GameplayKit

class AxleComponent: GKComponent {
let veclType: VehicleType
let parentNode: SKNode
let rearAxle: SKPhysicsJointPin

init(veclType: VehicleType, parentNode: SKNode) {
    self.veclType = veclType
    self.parentNode = parentNode

    let wheel = TireEntity(veclType: veclType)
    let wheelNode = wheel.spriteComponent.node
    wheelNode.position = CGPointMake(-50.0, 0.0)

/*at some point I will ave to go back and do the vector math and use the variables I saved in the vehicle entity to calculate the wheelNode.position correctly… pythagorean fun here I come! */
wheelNode.zPosition = 1
parentNode.addChild(wheelNode)

    let wheelPhysicsBody = wheelNode.physicsBody
    let vehicle = VehicleEntity(veclType: veclType)
    let vehicleNode = vehicle.spriteComponent.node
    let vehiclePhysicsBody = vehicleNode.physicsBody
    
    let anchorPoint = CGPointZero
    let rearAxle = SKPhysicsJointPin.jointWithBodyA(vehiclePhysicsBody!, bodyB: wheelPhysicsBody!, anchor: anchorPoint)     

//rinse and repeat for the frontAxle
}
}

So that’s it, I just don’t know where and how to call the addJoint(rearAxle). Normally you just call scene.physicsWorld.addJoint(rearAxle) but its not that straight forward here, or I’ve gotten so wrapped up in the details that I’ve forgotten something obvious. What do you think?