I have a player. He has to jump over some blocks.
However, it seems like the SKPhysicsBody(rectangleOfSize: ... ) isn't aligned properly. When the character hits the upper half of the block it just passes through and he can't pass below it because it collides with an invisible SKPhysicsBody.
Depending on how I put the anchor point it sometimes even happens that the physics body is to the left or right of it's SKSpriteNode.
My code for the blocks:
self.smallBlock.anchorPoint = CGPointMake(0.5, 0.5)
self.smallBlock.position = CGPointMake(CGRectGetMaxX(self.frame) + self.smallBlock.size.width, CGRectGetMinY(self.frame) + self.runningBar.size.height * 2)
self.smallBlock.physicsBody = SKPhysicsBody(rectangleOfSize: self.smallBlock.size)
self.smallBlock.physicsBody?.dynamic = false
self.smallBlock.physicsBody?.categoryBitMask = colliderType.Block.rawValue
self.smallBlock.physicsBody?.contactTestBitMask = colliderType.Character.rawValue
self.smallBlock.physicsBody?.collisionBitMask = colliderType.Character.rawValue
self.smallBlock.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(self.smallBlock)
self.character.anchorPoint = CGPointMake(0, 0.25)
self.character.position = CGPointMake(CGRectGetMinX(self.frame) - self.character.size.width, CGRectGetMinY(self.frame) + self.character.size.height)
self.initPosX = CGRectGetMinX(self.frame) + (self.character.size.width * 1.25)
Code for the character
self.character.anchorPoint = CGPointMake(0, 0.25)
self.character.position = CGPointMake(CGRectGetMinX(self.frame) - self.character.size.width, CGRectGetMinY(self.frame) + self.character.size.height)
self.initPosX = CGRectGetMinX(self.frame) + (self.character.size.width * 1.25)
self.character.physicsBody = SKPhysicsBody(rectangleOfSize: self.character.size)
self.character.physicsBody?.affectedByGravity = true
self.character.physicsBody?.categoryBitMask = colliderType.Character.rawValue
self.character.physicsBody?.contactTestBitMask = colliderType.Block.rawValue
self.character.physicsBody?.collisionBitMask = colliderType.Block.rawValue
self.character.physicsBody?.usesPreciseCollisionDetection = true
self.character.physicsBody?.affectedByGravity = true
self.character.physicsBody?.allowsRotation = false
self.addChild(self.character)
Solution:
I've added skView.showsPhysics = true to my View Controller. When you run the app in the simulator it will outline every object like shown here.
It turns out setting custom anchor points messes up the rectangleOfSize-positions.
Related
I want CAEmitterCell emits in a specific angle. I use emitterCell.emissionLongitude = -CGFloat.pi to specify the orientation angle is -pi(which is left), but it emits to right as well.
func setUpEmitterCell() {
emitterCell.contents = UIImage(named: "spark_small")?.cgImage
emitterCell.velocity = 50.0
emitterCell.velocityRange = 500.0
let zeroDegreesInRadians = degreesToRadians(0.0)
emitterCell.spin = degreesToRadians(130.0)
emitterCell.spinRange = zeroDegreesInRadians
emitterCell.emissionRange = degreesToRadians(10.0)
emitterCell.emissionLongitude = -CGFloat.pi
emitterCell.lifetime = 1.0
emitterCell.birthRate = 1000.0
emitterCell.xAcceleration = 0.0
emitterCell.yAcceleration = 0.0
}
This is the problem:
emitterCell.velocity = 50.0
// but then:
emitterCell.velocityRange = 500.0
You are allowing the velocity to range so widely from its original value of 50 that it can be negative. When it is, the cells are emitted in the opposite direction (that is what negative velocity means).
I am working on a game with a variety of collisions. I have created an Enumeration as follows:
enum CollisionCategories: UInt32 {
case localPlayer = 1
case ball = 2
case remotePlayer = 4
case scene = 8
case goal = 16
}
I then created some category variables:
let localPlayerCategory: UInt32 = CollisionCategories.localPlayer.rawValue
let ballCategory: UInt32 = CollisionCategories.ball.rawValue
let remotePlayerCategory: UInt32 = CollisionCategories.remotePlayer.rawValue
let sceneCategory: UInt32 = CollisionCategories.scene.rawValue
let goalCategory: UInt32 = CollisionCategories.goal.rawValue
Here is where I print the info
func didBeginContact(contact: SKPhysicsContact) {
print("Body A: " + String(contact.bodyA.categoryBitMask))
print("Body B: " + String (contact.bodyB.categoryBitMask) + "\n")
}
However, when the goal and ball collide it returns the following:
Body A: 4294967295
Body B: 2
Body B is correctly the ball category; however, Body A is clearly off. Here is how I create the goal node:
let goal2 = self.newGoal()
goal2.zRotation = CGFloat(M_PI)
goal2.position = CGPoint(x: (gameFrame!.frame.width / 2), y: 0)
let bottom2 = SKPhysicsBody(edgeFromPoint: CGPoint(x: -(goal2.frame.width), y:-(goal2.frame.height / 2)), toPoint: CGPoint(x: 0, y:-(goal2.frame.height / 2)))
bottom2.categoryBitMask = sceneCategory
let top2 = SKPhysicsBody(edgeFromPoint: CGPoint(x: -(goal2.frame.width), y:(goal2.frame.height / 2)), toPoint: CGPoint(x: 0, y:(goal2.frame.height / 2)))
top2.categoryBitMask = sceneCategory
let back2 = SKPhysicsBody(edgeFromPoint: CGPoint(x: -(goal2.frame.width), y:(goal2.frame.height / 2)), toPoint: CGPoint(x: -(goal2.frame.width), y:-(goal2.frame.height / 2)))
back2.categoryBitMask = goalCategory
goal2.physicsBody = SKPhysicsBody(bodies: [bottom2,top2,back2])
//goal2.physicsBody!.categoryBitMask = goalCategory
goal2.physicsBody!.usesPreciseCollisionDetection = true
goal2.physicsBody!.affectedByGravity = false
goal2.physicsBody!.dynamic = false
As you can see in the line I commented out above, I have also tried setting the entire physics body to be the goal, rather than just the section to see if that was causing the issue. It was not.
Here is how I create the ball's physics properties:
ball.physicsBody!.collisionBitMask = localPlayerCategory | sceneCategory | goalCategory
ball.physicsBody!.categoryBitMask = ballCategory
ball.physicsBody!.contactTestBitMask = goalCategory
So, can anyone can explain why they think bodyA's categoryBitMask is returning the max UInt32? Please note that EVERY collision except for the ball hitting the goal works just fine.
Also, quick side question: Does anyone know how bodyA and bodyB are selected? Why which is which? Thanks!
According to https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/#//apple_ref/occ/clm/SKPhysicsBody/bodyWithBodies: The properties of the bodies used are ignored. Only their shapes are used to construct the new physics body. This means that individual sections cannot have their own categoryBitMask. I will have to use a separate node to get the result I want.
I am creating a space shooter game, and I want to make one of my nodes only be dynamic when it interacts with ones specific node, as opposed to all nodes. Essentially, I only want the node to act as dynamic when it interacts with one specified node. How can I do this?
Thanks.
I know the question is a but confusing, but if anyone has any ideas it would be extremely helpful!!
let Bullet = SKSpriteNode(imageNamed: "BulletGalaga.png")
Bullet.zPosition = -5
Bullet.position = CGPoint(x: ship.position.x, y: ship.position.y)
Bullet.zRotation = ship.zRotation
//let action = SKAction.moveTo(CGPointMake(400 * cos(Bullet.zRotation),(400 * -sin(Bullet.zRotation))), duration: 0.8)
let action = SKAction.move(
to: CGPoint(
x: 1200 * -cos(Bullet.zRotation - 1.57079633) + Bullet.position.x,
y: 1200 * -sin(Bullet.zRotation - 1.57079633) + Bullet.position.y
),
duration: 2.4)
//let action = SKAction.moveToY(self.size.height + 30, duration: 0.8)
//let action = SKAction.moveTo(self.ship.size.height, duration: 0.8)
let actionDone = SKAction.removeFromParent()
Bullet.run(SKAction.sequence([action, actionDone]), withKey: "bulletAction")
Bullet.physicsBody = SKPhysicsBody(rectangleOf: Bullet.size)
Bullet.physicsBody?.affectedByGravity = false
Bullet.physicsBody?.isDynamic = false
self.addChild(Bullet)
I added this:
ship.physicsBody?.categoryBitMask = shipCategoryBitMask
Bullet.physicsBody?.categoryBitMask = bulletCategoryBitMask
enemy.physicsBody?.categoryBitMask = enemyCategoryBitMask
enemyBullet.physicsBody?.categoryBitMask = enemyBulletCategoryBitMask
ship.physicsBody?.collisionBitMask = enemyBulletCategoryBitMask
Bullet.physicsBody?.collisionBitMask = enemyCategoryBitMask
enemyBullet.physicsBody?.collisionBitMask = shipCategoryBitMask
enemy.physicsBody?.collisionBitMask = bulletCategoryBitMask
Once you've set a SpriteNode's physics body, you can use the collisionBitMask to specify which other SpriteNodes it will collide with. You'll need to first set each node's physics body's categoryBitMask.
let node1CategoryBitMask = 0x1 << 0
let node2CategoryBitMask = 0x1 << 1
let node3CategoryBitMask = 0x1 << 2
node1.physicsBody.categoryBitMask = node1CategoryBitMask
node2.physicsBody.categoryBitMask = node2CategoryBitMask
node3.physicsBody.categoryBitMask = node3CategoryBitMask
At this point, three of the sprites have their categoryBitMask set. This is what identifies the physics body. Now to set the collisionBitMasks.
node1.collisionBitMask = node2CategoryBitMask
node2.collisionBitMask = node1CategoryBitMask | node3CategoryBitMask
This tells node1 to by collide with node2, but not node3. Node2 will collide with node1 and node3.
Hope this helps.
I'm trying to create a simple car with SKSpriteNode. Physics and everything works great, except for one tiny thing: when my car lands on the ground from a greater distance the body of the car is pushed down and then goes back to its place.
See image:
I want to get the left image, but I get the one on the right.
When it lands on the ground I don't want the body to go into the wheels, I want it to be in a fixed place relative to the wheels or vice-versa.
So here is how I do it:
This is in the car class:
carWheelJoint1 = SKPhysicsJointPin.jointWithBodyA(self.physicsBody!, bodyB: leftWheel.physicsBody!, anchor: leftWheel.position)
carWheelJoint2 = SKPhysicsJointPin.jointWithBodyA(self.physicsBody!, bodyB: rightWheel.physicsBody!, anchor: rightWheel.position)
And this is in the GameScene class:
//Add vehicle
vehicle = DevCar(color: UIColor.blueColor(), size: CGSize(width: 250, height: 50), cameraThreshold: cameraThreshold)
vehicle.position = (CGPoint(x: 0, y: cameraThreshold))
addChild(vehicle)
self.physicsWorld.addJoint(vehicle.carWheelJoint1)
self.physicsWorld.addJoint(vehicle.carWheelJoint2)
I tried using SKPhysicsJointFixed but that did not work either.
Any ideas?
EDIT: this is how the physicsBody is defined:
Here is the car body in the car class.
The car class is an SKSpriteNode and is the body of the car itself, the wheels are its children.
let baseBody = SKPhysicsBody(rectangleOfSize: size)
baseBody.mass = CGFloat(1)
baseBody.dynamic = true
baseBody.affectedByGravity = true
baseBody.friction = 0.2
baseBody.allowsRotation = false
baseBody.density = CGFloat(10)
self.physicsBody = baseBody
And here is the wheel body in the same class:
leftWheel = SKShapeNode(circleOfRadius: wheelSize)
leftWheel.position = CGPoint(x: size.width / -2 + wheelSize, y: size.height / -2 - wheelSize)
rightWheel = SKShapeNode(circleOfRadius: wheelSize)
rightWheel.position = CGPoint(x: size.width / 2 - wheelSize, y: size.height / -2 - wheelSize)
leftWheel.physicsBody = SKPhysicsBody(circleOfRadius: wheelSize)
leftWheel.physicsBody!.mass = CGFloat(0.2)
leftWheel.physicsBody!.dynamic = true
leftWheel.physicsBody!.affectedByGravity = true
leftWheel.physicsBody!.friction = 0.3
rightWheel.physicsBody = SKPhysicsBody(circleOfRadius: wheelSize)
rightWheel.physicsBody!.mass = CGFloat(0.2)
rightWheel.physicsBody!.dynamic = true
rightWheel.physicsBody!.affectedByGravity = true
rightWheel.physicsBody!.friction = 0.3
addChild(leftWheel)
addChild(rightWheel)
EDIT2: Added video
https://www.youtube.com/watch?v=TTwa-t4u4pI
The goal is to rotate a physics body around a point using angular velocity, not zRotation. Because of this, it seems necessary to add a second physics body (the one controlling the rotations), but changing the angular velocity on this parent doesn't move the child. In other words, the parent rotates, but the child remains in place.
How can you rotate both the parent and child?
parent = SKNode()
sprite = SKSpriteNode(color: SKColor.whiteColor(), size: spriteSize)
sprite.position = CGPoint(x: 0, y: 50)
parent.addChild(sprite)
parent.physicsBody = SKPhysicsBody(rectangleOfSize: parentSize)
parent.physicsBody?.affectedByGravity = false
parent.physicsBody?.friction = 0
parent.physicsBody?.linearDamping = 0
parent.physicsBody?.angularDamping = 0
parent.physicsBody?.collisionBitMask = 0
sprite.physicsBody = SKPhysicsBody(rectangleOfSize: spriteSize)
sprite.physicsBody?.affectedByGravity = false
sprite.physicsBody?.friction = 0
sprite.physicsBody?.linearDamping = 0
sprite.physicsBody?.angularDamping = 0
sprite.physicsBody?.categoryBitMask = bitMask
sprite.physicsBody?.collisionBitMask = 0
parent.physicsBody?.angularVelocity = 2.0
You can try to create joint between parent and child before setting angular velocity
let fixedJoint = SKPhysicsJointFixed()
fixedJoint.bodyA = parent.physicsBody
fixedJoint.bodyB = sprite.physicsBody
self.physicsWorld.addJoint(fixedJoint)