How to detect contact on different areas of a physicsbody
Asked Answered
S

2

3

I would like to achieve the classic 'headshot' effect in a sprite-kit game.

My ideas and attempts:

  1. Create separate 'body' and 'head' physicsBodies on the same sprite and pin them with a joint. Impossible :(

  2. 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.

  3. 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!

Shimmer answered 8/7, 2014 at 16:29 Comment(7)
1. should be possible, especially with iOS 8 where I believe you can now create multi-shaped bodies. Though even a joint with very rigid behavior should work. 2. would be the alternative and only requires the head body & sprite to be a child of the body sprite, and updating the head's position every frame so that it remains at the same offset to the body. Very simple and effective.Revanchism
@LearnCocost2D iOS 8 lets you create multi-shaped bodies using SKPhysicsBody.bodyWithBodies() but only the shapes are used. You can't set collisionBitMask for the separate bodies unfortunately. This question my help author too: #18993719Claresta
@LearnCocos2D Thank you for elaborating on how to successfully achieve method 2! This will let me keep the two sprites together without destroying the simplicity of sprite kits physics. (individually keeping track of enemies)Shimmer
@Claresta I found that question as well however my projectiles are removed on contact so I am only really interested contactBitMasks and which section was hit. (head or body)Shimmer
@Shimmer I'd be interested in seeing your implementation once you get it done. I need to do the same thing but haven't gotten to it yet.Claresta
@Claresta Absolutely! I should be able to bang that out this weekend in my free time.Shimmer
@Claresta Seems we already have a tested answer.Shimmer
G
1

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;
}
Gulick answered 8/7, 2014 at 17:46 Comment(4)
Will this move the head relative to the body if an action is performed on the body?Shimmer
Yeah, you just treat the enemy as a single entity, all of its child sprites will come along with it. For instance, in one of my projects I have a head and a cape in there, and the head and the cape each run their own actions on a loop, just to look nice, but the main enemy is the only sprite I actually position in the world.Gulick
@CHBuckingham Could you elaborate on your physicsBody configurations? I created a dog character with a body and a head, where head is the child of the main dog body. The head does not move relative to the main body. The two physicsBodies are treated independently... so the head simply falls to the ground.Claresta
You can't have the physics bodies be moved by physics. They would just be for contact checking, like a head shot. I suppose if you needed them to be moved by physics you could use a fixed joint.Gulick
C
1

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

    }

}

enter image description here

Claresta answered 11/7, 2014 at 16:38 Comment(1)
This is a great answer as well. I'm not in swift yet :/Shimmer

© 2022 - 2024 — McMap. All rights reserved.