ARKit – Ball is not passing through "SCNTorus" hole - swift

I am stuck with an issue on ARKit and I need help.
I am making a little demo where I am placing a simple SCNTorus geometry in the scene and I am trying to throw a small ball (SCNSphere) into the torus hole. The problem is that the ball is bouncing in the middle rather than pass through.
There is the code for the torus:
let ring = SCNTorus(ringRadius: 0.4, pipeRadius: 0.1)
ring.ringSegmentCount = 100
let ringMaterial = SCNMaterial()
ringMaterial.diffuse.contents = UIImage(named: "art.scnassets/Ball/BeachBallColor.jpg")
ring.materials = [ringMaterial]
let ringNode = SCNNode()
ringNode.position = SCNVector3(x: location.worldTransform.columns.3.x,
y: location.worldTransform.columns.3.y + 0.8,
z: location.worldTransform.columns.3.z)
ringNode.geometry = ring
let body = SCNPhysicsBody(type: SCNPhysicsBodyType.kinematic,
shape: nil)
body.categoryBitMask = CollisionTypes.wall.rawValue
body.collisionBitMask = CollisionTypes.beachball.rawValue
// body.contactTestBitMask = CollisionTypes.beachball.rawValue
body.isAffectedByGravity = false
body.mass = 0.5
ringNode.physicsBody = body
sceneView.scene.rootNode.addChildNode(ringNode)
And for the ball :
let node = SCNNode(geometry: sphere!)
node.renderingOrder = 10
let body = SCNPhysicsBody(type: SCNPhysicsBodyType.dynamic,shape: nil)
body.categoryBitMask = CollisionTypes.beachball.rawValue
body.collisionBitMask = CollisionTypes.solid.rawValue|CollisionTypes.wall.rawValue|CollisionTypes.beachball.rawValue
// body.contactTestBitMask = CollisionTypes.fireball.rawValue|CollisionTypes.wall.rawValue
body.isAffectedByGravity = true
body.mass = 0.5
body.restitution = 0.75
body.damping = 0.1
body.friction = 0.8
node.physicsBody = body

The code you use to create the physicsbody (body type kinametic and shape nil) results in a simplified “convex hull” representation of the geometry. Simply put, the geometry you see is a torus, but the geometry used for the collision detection is not.
This line of (obj c) code is actually from one of the Apple sample code projects:
_torus.physicsBody = [SCNPhysicsBody bodyWithType:SCNPhysicsBodyTypeStatic shape:[SCNPhysicsShape shapeWithGeometry:_torus.geometry options: #{SCNPhysicsShapeTypeKey : SCNPhysicsShapeTypeConcavePolyhedron} ] ];
In other words, you need to create a static type body and a shape based on the geometry itself using the SCNPhysicsShapeTypeConcavePolyhedron key value (which only works for static bodies) to end up with a more accurate representation of the torus geometry as the physics body.
For more details see: https://developer.apple.com/documentation/scenekit/scnphysicsshape

Thanks! it work!
there is the code :
let ring = SCNTorus(ringRadius: 0.4, pipeRadius: 0.1)
ringNode.geometry = ring
let shapeOptions = [ SCNPhysicsShape.Option.type : SCNPhysicsShape.ShapeType.concavePolyhedron]
let physicShape = SCNPhysicsShape(geometry: ring, options: shapeOptions)
let body = SCNPhysicsBody(type: SCNPhysicsBodyType.kinematic,
shape: physicShape)
body.categoryBitMask = CollisionTypes.wall.rawValue
body.collisionBitMask = CollisionTypes.beachball.rawValue
body.isAffectedByGravity = false
body.mass = 0.5
ringNode.physicsBody = body

Related

SCNPhysicsShape don't allowed my car to move when apply engine force

I finally manage to create a driving car in SceneKit, using SCNPhysicsVehicle.
The following code is working fine... my car is dropped in the scene, I can apply engine force and I can steer the wheels and drive the car..
but once I activate body.physicsShape = SCNPhysicsShape(node: chassie), the car don't move anymore.
func setupVeicles(){
let chassie = loadAssetWithName(nameFile: "rc_car", nameNode: "rccarBody", type: "scn", scale: SCNVector3(1, 1, 1))
chassie.position = SCNVector3(0, 1, 0)
let body = SCNPhysicsBody.dynamic()
// WHY THIS LINE OF CODE BLOCK MY CAR TO MOVE
// body.physicsShape = SCNPhysicsShape(node: chassie)
body.categoryBitMask = BodyType.car.rawValue
body.collisionBitMask = BodyType.floor.rawValue
body.contactTestBitMask = BodyType.floor.rawValue
body.allowsResting = false
body.mass = 1
body.restitution = 0.1
body.friction = 0.5
body.rollingFriction = 0
chassie.physicsBody = body
// Load the wheel
let wheelFL = chassie.childNode(withName: "wheelLocator_FL", recursively: true)!
let wheelFR = chassie.childNode(withName: "wheelLocator_FR", recursively: true)!
let wheelBL = chassie.childNode(withName: "wheelLocator_RL", recursively: true)!
let wheelBR = chassie.childNode(withName: "wheelLocator_RR", recursively: true)!
let phywheelFL = createPhysicsVehicleWheel(wheelNode: wheelFL, position: SCNVector3(3, 1.31, 2.753))
let phywheelFR = createPhysicsVehicleWheel(wheelNode: wheelFR, position: SCNVector3(-3, 1.271, 2.753))
let phywheelBL = createPhysicsVehicleWheel(wheelNode: wheelBL, position: SCNVector3(4, 1.31, -3.566))
let phywheelBR = createPhysicsVehicleWheel(wheelNode: wheelBR, position: SCNVector3(-4, 1.31, -3.566))
physicsVehicle = SCNPhysicsVehicle(chassisBody: chassie.physicsBody!, wheels: [phywheelFL,phywheelFR,phywheelBL,phywheelBR])
self.scene.physicsWorld.addBehavior(physicsVehicle)
self.scene.rootNode.addChildNode(chassie)
}
What I don't understand is why if I activate SCNPhysicsShape the car doesn't move anymore..
This in my mind will allow me to simulate better Physics.
My floor is set like this:
func makeFloor()->SCNNode{
let geo = SCNFloor()
let matFloor = SCNMaterial()
matFloor.blendMode = .multiply
matFloor.diffuse.wrapS = .repeat
matFloor.diffuse.wrapT = .repeat
matFloor.diffuse.contents = UIImage(named: "concrete.png")
geo.materials = [matFloor]
let floor = SCNNode(geometry: geo)
let body = SCNPhysicsBody.static()
body.categoryBitMask = BodyType.floor.rawValue
body.allowsResting = false
body.restitution = 0.1
body.friction = 0.5
body.rollingFriction = 0
floor.physicsBody = body
floor.name = "floor"
return floor
}
If I deactivate SCNPhysicsShape the wheel are into the ground .. looks unrealistic..
With SCNPhysicsShape(node: chassie) applied:
without SCNPhysicsShape(node: chassie):

How does SCNIKConstraint work?

I have the following code (this can be run by replacing the standard ViewController code in the Game base project for macOS):
let scene = SCNScene()
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = NSColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
/* RELEVANT CODE BEGINS */
let boxGeo = SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0)
let boxMaterial = SCNMaterial()
boxMaterial.diffuse.contents = NSColor.gray
boxGeo.firstMaterial = boxMaterial
let boxNode = SCNNode(geometry: boxGeo)
scene.rootNode.addChildNode(boxNode)
boxNode.name = "box0"
let sphereGeo = SCNSphere(radius: 0.5)
let sphereMaterial = SCNMaterial()
sphereMaterial.diffuse.contents = NSColor.green
sphereGeo.firstMaterial = sphereMaterial
let sphereNode = SCNNode(geometry: sphereGeo)
boxNode.addChildNode(sphereNode)
sphereNode.name = "sphere0"
sphereNode.constraints = [SCNConstraint]()
let distance = SCNDistanceConstraint(target: boxNode)
distance.minimumDistance = 2.0
distance.maximumDistance = 5.0
sphereNode.constraints?.append(distance)
let ik = SCNIKConstraint.inverseKinematicsConstraint(chainRootNode: boxNode)
sphereNode.constraints?.append(ik)
let anim = CABasicAnimation(keyPath: "targetPosition.y")
anim.fromValue = -2.0
anim.toValue = 2.0
anim.duration = 1
anim.autoreverses = true
anim.repeatCount = .infinity
ik.addAnimation(anim, forKey: nil)
/* RELEVANT CODE ENDS */
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = true
scnView.showsStatistics = true
scnView.backgroundColor = NSColor.black
From what I can gather from the documentation, the animation (and yes, the scene kit view animation setting is set to both play and loop in IB) should move the sphere as close as possible to the points 2.0 and -2.0 on the y-axis by rotating the cube. However, the sphere simply stays stationary. I have also tried setting the initial position of the sphere and cube by manipulating their position vectors directly instead of via the distance constraint, but again the animation did nothing.
Additionally, I have attempted to use the distance constraint in combination with the box having a lookAt constraint to make it rotate to constantly look at the sphere - these caused the rendering of the box and sphere to completely freak out.
I feel as though maybe I am missing something in the documentation here, such as another constraint or some kind of transform matrix to setup some kind of initial value. But I have encountered some other issues with constraints, animations and skeletons that is making me begin to believe that there is either a bug or some undocumented aspects of SceneKit.
You have added the sphereNode as child of the boxNode. If you move the boxNode all childs are also moved and the constraint has no effect.

Physics Shape are not matching with Objects' shape when in contact

I have two objects and I want something to happen when they are both in contact. One object is an SCNSphere and the other one SCNCylinder. The only issue is that when I throw the ball at the cylinder, they seem to be touching even if there is a gap. If I throw it very far away then it works as expected. How can I make the contacts accurate and do lot leave any gaps? It looks like the PhysicsShape does not match my object's shape. I want it to be accurate. Any help?
My code for cylinder:
let scorer = SCNCylinder(radius: 0.02, height: 0.01)
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: "basketballSkin.png")
scorer.materials = [material]
let scorerNode = SCNNode(geometry: scorer)
scorerNode.worldPosition = SCNVector3(x: 0, y: -1.35, z: -1.4)
let physicsShapesc = SCNPhysicsShape(node: scorerNode, options:[SCNPhysicsShape.Option.type: SCNPhysicsShape.ShapeType.concavePolyhedron])
let physicsBodysc = SCNPhysicsBody(type: .static, shape: physicsShapesc)
scorerNode.physicsBody = physicsBodysc
scorerNode.physicsBody?.categoryBitMask = BodyType.scorer.rawValue
scorerNode.physicsBody?.collisionBitMask = BodyType.scorer.rawValue | BodyType.ball.rawValue
scorerNode.physicsBody?.contactTestBitMask = BodyType.scorer.rawValue | BodyType.ball.rawValue
My code for ball:
let ball = SCNSphere(radius:0.04)
// Bucketnode.scale = SCNVector3Make(0.2,0.2,0.2);
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: "basketballSkin.png")
ball.materials = [material]
let ballNode = SCNNode(geometry: ball)
ballNode.position = cameraPosition
let physicsShape = SCNPhysicsShape(node: ballNode, options:nil)
let physicsBody = SCNPhysicsBody(type: .dynamic, shape: physicsShape)
ballNode.physicsBody = physicsBody
let forceVector:Float = 2.7
ballNode.physicsBody?.applyForce(SCNVector3Make(cameraPosition.x * forceVector, cameraPosition.y * forceVector, cameraPosition.z*forceVector), asImpulse: true)
ballNode.physicsBody?.categoryBitMask = BodyType.ball.rawValue
//ballNode.physicsBody?.collisionBitMask = BodyType.ball.rawValue | BodyType.scorer.rawValue
ballNode.physicsBody?.contactTestBitMask = BodyType.ball.rawValue | BodyType.scorer.rawValue
sceneView.scene.rootNode.addChildNode(ballNode)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { // change 2 to desired number of seconds
ballNode.removeFromParentNode()
}
Taking in account the definition for the SCNPhysicsShape.ShapeType structure regards a geometry "Values for the type key specifying the level of detail that SceneKit uses when creating a physics shape based on a geometry." the option set would not probably be working as expected:
let physicsShapesc = SCNPhysicsShape(node: scorerNode, options:[SCNPhysicsShape.Option.type: SCNPhysicsShape.ShapeType.concavePolyhedron])
Besides that, how fast the ball is moving towards the bucket? the "concavePolyhedron" seems to be the most demanding type for rendering

How to use SCNAvoidOccluderConstraint (any example)

Does anyone have example of using SCNAvoidOccluderConstraint?
The only description, which I found is:
#abstract A SCNAvoidOccluderConstraint constraints place the receiver
at a position that prevent nodes with the specified category to
occlude the target.
#discussion The target node and it's children are
ignored as potential occluders.
UPDATE: Xcode 9 was officially released and still no one line in documentation.
Coming late, but here is a working example (in Python, but can easily be reproduced in Swift or ObjC). The ball with the SCNAvoidOccluderConstraint on it jumps back on its trajectory whenever the block in the middle obstructs the view to the other ball.
"""
avoid occluder demo
"""
from objc_util import *
import sceneKit as scn
import ui
import math
def dot(v1, v2):
return sum(x*y for x,y in zip(list(v1),list(v2)))
def det2(v1, v2):
return v1[0]*v2[1] - v1[1]*v2[0]
class Demo:
#classmethod
def run(cls):
cls().main()
#on_main_thread
def main(self):
main_view = ui.View()
w, h = ui.get_screen_size()
main_view.frame = (0,0,w,h)
main_view.name = 'avoid occluder demo'
scene_view = scn.View(main_view.frame, superView=main_view)
scene_view.autoresizingMask = scn.ViewAutoresizing.FlexibleHeight | scn.ViewAutoresizing.FlexibleWidth
scene_view.allowsCameraControl = True
scene_view.delegate = self
scene_view.backgroundColor = 'white'
scene_view.rendersContinuously = True
scene_view.scene = scn.Scene()
root_node = scene_view.scene.rootNode
floor_geometry = scn.Floor()
floor_node = scn.Node.nodeWithGeometry(floor_geometry)
root_node.addChildNode(floor_node)
ball_radius = 0.2
ball_geometry = scn.Sphere(radius=ball_radius)
ball_geometry.firstMaterial.diffuse.contents = (.48, .48, .48)
ball_geometry.firstMaterial.specular.contents = (.88, .88, .88)
self.ball_node_1 = scn.Node.nodeWithGeometry(ball_geometry)
self.ball_node_2 = scn.Node.nodeWithGeometry(ball_geometry)
root_node.addChildNode(self.ball_node_1)
root_node.addChildNode(self.ball_node_2)
occluder_geometry = scn.Box(0.3, 2., 15., 0.2)
occluder_geometry.firstMaterial.diffuse.contents = (.91, .91, .91)
occluder_node = scn.Node.nodeWithGeometry(occluder_geometry)
occluder_node.position = (0., 0.8, 0.)
root_node.addChildNode(occluder_node)
self.orbit_r = 10
self.omega_speed_1 = math.pi/1500
self.omega_speed_2 = 1.5*self.omega_speed_1
self.ball_node_1.position = (self.orbit_r, 0.5, 0.)
self.ball_node_2.position = (0., 0.5, self.orbit_r)
constraint = scn.AvoidOccluderConstraint.avoidOccluderConstraintWithTarget(self.ball_node_1)
self.ball_node_2.constraints = [constraint]
camera_node = scn.Node()
camera_node.camera = scn.Camera()
camera_node.position = (0.5*self.orbit_r , 0.5*self.orbit_r, 1.5*self.orbit_r)
camera_node.lookAt(root_node.position)
root_node.addChildNode(camera_node)
light_node = scn.Node()
light_node.position = (self.orbit_r, self.orbit_r, self.orbit_r)
light = scn.Light()
light.type = scn.LightTypeDirectional
light.castsShadow = True
light.shadowSampleCount = 32
light.color = (.99, 1.0, .86)
light_node.light = light
light_node.lookAt(root_node.position)
root_node.addChildNode(light_node)
main_view.present(hide_title_bar=False)
def update(self, view, atTime):
pos_1 = self.ball_node_1.presentationNode.position
pos_2 = self.ball_node_2.presentationNode.position
self.omega_1 = -math.atan2(det2((pos_1.x, pos_1.z), (1., 0.)), dot((pos_1.x, pos_1.z), (1., 0.)))
self.omega_2 = -math.atan2(det2((pos_2.x, pos_2.z), (1., 0.)), dot((pos_2.x, pos_2.z), (1., 0.)))
self.omega_1 += self.omega_speed_1
self.omega_2 += self.omega_speed_2
self.ball_node_1.position = (self.orbit_r*math.cos(self.omega_1), 0.5, self.orbit_r*math.sin(self.omega_1))
self.ball_node_2.position = (self.orbit_r*math.cos(self.omega_2), 0.5, self.orbit_r*math.sin(self.omega_2))
Demo.run()
I came across this oldie recently hoping to get more insight if this constaint could be used to solve a particular problem. Unfortunately, Apple's documentation is still atrocious so I'm leaving some more notes here for posterity.
SCNAvoidOccluderConstraint takes an SCNNode as a target. If an object obstructs the line of sight between the target node and the node that you added this constraint to, the node with the constraint will jump to the nearest point between its original position and the target to re-establish its line of sight with the target node.
In most cases, this point will be immediately on the other side of the obstructing object, so your constrained object will not move all the way through to the other side of the obstructing object; its center point will be aligned with the occluder's visible edge with respect to the target.
Furthermore, you can use a SCNNode's categoryBitMask and the constraint's occluderCategoryBitMask to exclude certain nodes from being occluders.
Here's a loose adaptation of #pulbrich 's original answer in Swift which illustrates the usage. You can paste this in the default XCode SceneKit Game project's GameViewController.swift file:
import SceneKit
import QuartzCore
class GameViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene()
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
cameraNode.look(at: SCNVector3(0,0,0))
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 0)
scene.rootNode.addChildNode(lightNode)
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = NSColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
let scnView = self.view as! SCNView
scnView.scene = scene
scnView.allowsCameraControl = true
scnView.showsStatistics = true
scnView.backgroundColor = NSColor.black
//--------------------------
let ball_radius = 0.2
let ball_geometry = SCNSphere(radius: ball_radius)
let ball_node_1 = SCNNode.init(geometry: ball_geometry)
ball_node_1.name = "b1"
let ball_node_2 = SCNNode.init(geometry:ball_geometry)
ball_node_2.name = "b2"
scene.rootNode.addChildNode(ball_node_1)
scene.rootNode.addChildNode(ball_node_2)
ball_node_1.worldPosition = SCNVector3(5, 5, 0)
ball_node_2.worldPosition = SCNVector3(5, -5, 0)
let occluder_geometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0)
let occluder_node = SCNNode.init(geometry: occluder_geometry)
scene.rootNode.addChildNode(occluder_node)
let constraint = SCNAvoidOccluderConstraint(target: ball_node_1)
ball_node_2.constraints = [constraint]
let a1 = CABasicAnimation(keyPath: "position")
a1.toValue = SCNVector3(-5,5,0)
a1.duration = 5
a1.autoreverses = true
a1.repeatCount = .infinity
ball_node_1.addAnimation(a1, forKey: "move1")
//IMPORTANT NOTE: this constraint will hose CABasicAnimation,
//but the presense of the animation will snap it back to the toValue
//vector when the target is no longer occluded
let a2 = CABasicAnimation(keyPath: "position")
a2.toValue = SCNVector3(5,-5,0)
//a2.toValue = SCNVector3(-5,-5,0)
a2.duration = 5
a2.autoreverses = true
a2.repeatCount = .infinity
ball_node_2.addAnimation(a2, forKey: "move2")
}
}

Swinging Beam that Doesn't Stop Swinging in Swift SpriteKit

I have a ios 9 spritekit game. I am adding a i-beam or a wrecking ball that should swing from a jointed rope like a pendulum. My game requires gravity and I want the beam to react to gravity and sprites that jump on the beam or hit the beam from below. When I use the following code, the beam eventually slows down and comes to rest without any interaction with other sprites. The top node in the jointed node is fixed (i.e., modeling attachment to a crane or building) I start the beam swinging by applying an impulse on the bottom node in the jointed node. I have set the friction, linear dampening, and angular dampening to 0.
What I need the beam to do prior to interacting with any sprites is to swing back and forth where the maximum height on the left swing and right swing is nearly the same throughout time. I want the beam or wrecking ball to act like its swinging from a frictionless pivot. The beam or ball doesn't go in a full circle, so I cannot use a constant angular velocity.
I tried something similar to:
Constant speed orbit around point with SKNode but neither the linear nor angular velocity is constant after the initial impulse as the beam or ball will arc up, slow down, stop at the top of the arc, and then circle back in the other direction.
let (actionSceneObjectNode, jointArray) = ActionSceneObject.createActionJointedSceneObjectAtPosition(CGPoint(x: positionX, y: positionY), ofType: actionSceneObject.type!, withImage: actionSceneObject.imageName, withActionDirection: actionSceneObject.imageDirection)
foregroundNode.addChild(actionSceneObjectNode)
if let bottomNode = actionSceneObjectNode.childNodeWithName("bottomObject") {
bottomNode.physicsBody?.applyImpulse(CGVector(dx: 50000.0, dy: 0))
}
// add the joints
for joint in jointArray {
self.physicsWorld.addJoint(joint)
}
Function
class func createActionJointedSceneObjectAtPosition(position: CGPoint, ofType type: ActionSceneObjectType, withImage imageName: String, withActionDirection actionDirection: DirectionValue) -> (ActionSceneObjectNode, [SKPhysicsJoint]) {
let node = ActionSceneObjectNode()
node.position = position
node.name = SceneObjectType.Action.rawValue
node.actionType = type
node.actionDirection = actionDirection
var jointArray = [SKPhysicsJoint]()
var sprite: SKSpriteNode
////////
// adapted from https://stackoverflow.com/questions/20811931/how-to-create-a-rope-in-spritekit
let countJointElements:Int = 3
let texture = SKTexture(imageNamed: "Rope.png")
//let textureSize = CGSize(width: texture.size().width*SceneObjectSizeScale.ActionSceneObject, height: texture.size().height*SceneObjectSizeScale.ActionSceneObject)
let topAnchor = SKSpriteNode(texture: texture, size: texture.size())
topAnchor.name = "topAnchor"
//topAnchor.position = CGPointMake(position.x, position.y) // the node holds the joint start position
topAnchor.physicsBody = SKPhysicsBody(rectangleOfSize: texture.size())
topAnchor.physicsBody?.categoryBitMask = PhysicsCategoryBitmask.None
topAnchor.physicsBody?.affectedByGravity = false
topAnchor.physicsBody?.friction = 0.0
topAnchor.physicsBody?.restitution = 1.0
topAnchor.physicsBody?.linearDamping = 0.0
topAnchor.physicsBody?.angularDamping = 0.0
topAnchor.physicsBody?.mass = 10.0
node.addChild(topAnchor)
// by default, the joints build top to bottom
for index in 0 ..< countJointElements {
let item = SKSpriteNode(texture: texture, size: texture.size())
item.name = "ropeitem_" + String(index)
item.position = CGPointMake(0, 0 - CGFloat(index+1) * item.size.height)
item.physicsBody = SKPhysicsBody(rectangleOfSize: texture.size())
item.physicsBody?.categoryBitMask = PhysicsCategoryBitmask.None
item.physicsBody?.affectedByGravity = true
item.physicsBody?.friction = 0.0
item.physicsBody?.restitution = 1.0
item.physicsBody?.linearDamping = 0.0
item.physicsBody?.angularDamping = 0.0
item.physicsBody?.mass = 10.0
node.addChild(item)
var bodyA = SKPhysicsBody()
if (index == 0)
{
bodyA = topAnchor.physicsBody!;
}
else
{
let nameString = "ropeitem_" + String(index - 1)
let nodeItem = node.childNodeWithName(nameString) as! SKSpriteNode
bodyA = nodeItem.physicsBody!
}
// needs to in terms of the physics world - the item position in the node is already negative
let joint = SKPhysicsJointPin.jointWithBodyA(bodyA, bodyB: item.physicsBody!, anchor: CGPointMake(position.x, position.y + item.position.y + item.size.height/2))
jointArray.append(joint)
}
let nameString = NSString(format: "ropeitem_%d", countJointElements - 1)
let lastLinkItem = node.childNodeWithName(nameString as String)
let bottomObject = SKSpriteNode(imageNamed: "I-Beam.png")
bottomObject.name = "bottomObject"
bottomObject.setScale(SceneObjectSizeScale.Platform)
bottomObject.position = CGPointMake(0, 0 + lastLinkItem!.position.y - lastLinkItem!.frame.size.height/2.0 - bottomObject.frame.size.height/2.0)
bottomObject.physicsBody = SKPhysicsBody(rectangleOfSize: bottomObject.size)
bottomObject.physicsBody?.categoryBitMask = PhysicsCategoryBitmask.Platform
bottomObject.physicsBody?.affectedByGravity = true
bottomObject.physicsBody?.friction = 0.0
//bottomObject.physicsBody?.restitution = 1.0
bottomObject.physicsBody?.linearDamping = 0.0
bottomObject.physicsBody?.angularDamping = 0.0
bottomObject.physicsBody?.mass = 500.0
node.addChild(bottomObject)
let jointLast = SKPhysicsJointFixed.jointWithBodyA(lastLinkItem!.physicsBody!, bodyB: bottomObject.physicsBody!, anchor: CGPointMake(position.x, position.y + bottomObject.position.y + bottomObject.frame.size.height/2.0))
jointArray.append(jointLast)
///////
///////
sprite = SKSpriteNode(imageNamed: imageName)
//sprite.setScale(SceneObjectSizeScale.ActionSceneObject)
node.sprite = sprite
//node.addChild(sprite)
node.physicsBody = SKPhysicsBody(texture: texture, size: sprite.size)
node.physicsBody!.categoryBitMask = PhysicsCategoryBitmask.None
switch actionDirection {
case .Left:
node.sprite.zRotation = CGFloat(M_PI_2)
case .Right:
node.sprite.zRotation = CGFloat(-M_PI_2)
case .Down:
node.sprite.zRotation = CGFloat(M_PI)
case .Up, .Unknown:
break
}
node.physicsBody?.dynamic = true
node.physicsBody?.restitution = 0.0 // bounciness
node.physicsBody?.categoryBitMask = PhysicsCategoryBitmask.ActionSceneObject
node.physicsBody?.collisionBitMask = 0
return (node, jointArray)
}