I would like to achieve the classic 'headshot' effect in a sprite-kit game.
My ideas and attempts:
Create separate 'body' and 'head' physicsBodies on the same sprite and pin them with a joint. Impossible :(
Create a 'body' physics body on the "enemy" sprite and create another transparent sprite with a 'head' physicsBody that follows the body (sits on top). This approach requires me to keep track of what head is associated with what body. It will also decrease the games efficiency. I am curious if I could make a subclass of SKSpriteNode and create an "enemy" that has these two spritenodes and physicsBodies tied together.
Check the location of the projectile vs. the enemy to see if the projectile made contact in a certain Y range on the top of the sprite. I believe this will be inefficient as the projectiles are flying quite fast.
I would appreciate it if anyone has created this effect and can share their knowledge. Thank you!
I use this setup in a lot of places. It scales pretty well if you find yourself wanting to add more parts, or weapons, and it lets you visually hide any of those parts or weapons easily. The use of userData can come in handy if you have a lot going on and different enemies have different "things", or you're doing crazy stuff like parenting child sprites to different entities based on gameplay, etc.
-(SKSpriteNode*)makeAnEnemy
{
SKSpriteNode *mainEnemy;
SKSpriteNode *enemyHead;
//setup mainEnemy physics body
//setup enemyHead physics body
[mainEnemy addChild:enemyHead];
// depending on your plans, on hit you could use the following code later:
SKSpriteNode *theEnemyThatWasHit = (SKSpriteNode*)enemyHead.parent;
//or you can use userdata and set it all up here
[mainEnemy.userData setObject:enemyHead forKey:@"myHead"];
[enemyHead.userData setObject:mainEnemy forKey:@"myBody"];
return mainEnemy;
}
Using the pinned
attribute of a physicsBody makes it easy to create complex sprites with multiple contact zones. Pinning a Physics Body to the Node's Parent:
The default value is NO. If YES, then the node’s position is fixed
relative to its parent. The node’s position cannot be changed by
actions or physics forces. The node can freely rotate around its
position in response to collisions or other forces. If the parent node
has a physics body, then the two physics bodies are treated as if they
are connected with a pin joint.
Here is a basic Dog class, where the dog has a main body and a head. Note that I set allowsRotation = false
as well so the head cannot move around the body.
import SpriteKit
// for readability
let mainSize = CGSize(width: 300, height: 300)
let headSize = CGSize(width: 100, height: 100)
class Dog : SKSpriteNode {
let head = SKSpriteNode(color: SKColor.greenColor(), size: headSize)
init() {
super.init(texture: nil, color: SKColor.redColor(), size: mainSize)
head.position = CGPoint(x: mainSize.width - headSize.width, y: 0)
addChild(head)
}
// called after Dog has been added to the scene
func configurePhysicsBody() {
physicsBody = SKPhysicsBody(circleOfRadius: mainSize.width / 2)
physicsBody.dynamic = true
physicsBody.allowsRotation = false
// set contactBitmask for main body
head.physicsBody = SKPhysicsBody(circleOfRadius: headSize.width / 2)
head.physicsBody.dynamic = true
head.physicsBody.allowsRotation = false
// The head is pinned to the parent node, so position is fixed relative to parent
head.physicsBody.pinned = true
// set contactBitmask for head
}
}