3

I'm trying to add a hitbox to the bottom of my player to only detect platforms. After a lot of trial and error I figured out to have an additional physicsbody attached as a child in a fixed position to another physicsbody I need to use an SKPhysicsJoint. I did this and it seems to have an unforeseen consequence. when I add the hitbox to the player in this way, it alters the players collision / contact bit masks slightly.

In my game you tap the screen to jump and it works seamlessly with no lag like so:

Player jumping

But when I add this hitbox with the joint I have to hold the screen with my finger and eventually the player jumps, but most of the time the input is ignored. Almost as if there's some sort of severe lag when reading the input.In this gif I'm tapping the screen constantly trying to make my player jump and a lot of the inputs are being ignored or blocked:

Player hitbox not behaving


This function setups up the player in my gamescene.swift and adds the hitbox to the player via a fixed SKPhysicsJoint to the scene:

func playerSetup(){
    //setups player
    addChild(player)
    player.addChild(playerPlatformHitbox)
    let myCGPoint = player.position // sets joint position

    let myJoint = SKPhysicsJointFixed.joint(withBodyA: playerPlatformHitbox.physicsBody!, bodyB: player.physicsBody!, anchor: myCGPoint)

    scene?.physicsWorld.add(myJoint)
}

And this is the hitbox class I made to only detect platforms for the player. you'll see it should ignore everything expect platforms from the bit masks. For some reason it's not allowing the player to accept contact with it's bit masks even though this hitbox and player arent touching:

import Foundation
import SpriteKit

class PlayerPlatformHitbox: SKSpriteNode{

init() {

    super.init(texture: nil, color: SKColor.blue, size: CGSize(width: playerTexture.size().width, height: 10))


  physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.size.width, height: self.size.height))

    position = CGPoint(x:0, y: (-playerTexture.size().height * 0.6))
    physicsBody?.categoryBitMask = CollisionTypes.jumpHitBox.rawValue
    physicsBody?.contactTestBitMask = CollisionTypes.platform.rawValue
    physicsBody?.collisionBitMask =  CollisionTypes.platform.rawValue
    physicsBody?.restitution = 0.0
    physicsBody?.friction = 0.0
    zPosition = 20
    physicsBody?.linearDamping = 0.0
    physicsBody?.angularDamping = 0.0

}
required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)}

}

And this is my player class

class Player: SKSpriteNode {

init() {

    super.init(texture: nil, color: SKColor.clear, size: playerTexture.size())

    //starts accelerameter
    motionManager = CMMotionManager()
    motionManager.startAccelerometerUpdates()
    physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: playerTexture.size().width,
                                                    height: playerTexture.size().height))

    physicsBody?.categoryBitMask = CollisionTypes.player.rawValue
    physicsBody?.contactTestBitMask =     CollisionTypes.memoryModule.rawValue | CollisionTypes.spikes.rawValue | CollisionTypes.finish.rawValue | CollisionTypes.enemy.rawValue | CollisionTypes.ground.rawValue

    physicsBody?.collisionBitMask = CollisionTypes.ground.rawValue | CollisionTypes.sceneEdge.rawValue
    physicsBody?.affectedByGravity = true
    physicsBody?.restitution = 0.0
    physicsBody?.friction = 0.3
    physicsBody?.isDynamic = true
    //physicsBody?.friction = 0.0
    physicsBody?.allowsRotation = false
    setScale(0.65)
    zPosition = 1
    physicsBody?.linearDamping = 0.0
    physicsBody?.angularDamping = 0.0

    animateWalk()

}

The goal of all this is to use the hitbox to detect platforms instead of the player in this function I have in my update method:

  //jump through platform check
    if let body = player.physicsBody {
        let dy = body.velocity.dy

            if dy > 0{
                // Prevent collisions if the hero is jumping
                body.collisionBitMask &= ~CollisionTypes.platform.rawValue
                body.contactTestBitMask &= ~CollisionTypes.platform.rawValue
                        }
                        else {
                // Allow collisions if the hero is falling
                body.collisionBitMask |= CollisionTypes.platform.rawValue
                body.contactTestBitMask |= CollisionTypes.platform.rawValue
                        }
                    }

and the only reason I need to do this is because when the player is falling, if he falls and hits the side of the platform he will stop and slide down it because collisions are back on and the players physicsbody is a square.

If i can use the platform detection hitbox to detect the platforms instead of the players bulky hitbox it will get rid of this issue.

Thanks for any and all advice.

EDIT: this is the childs behavior with a physics body and no joint:

Odd behavior

genericguy25
  • 602
  • 3
  • 16
  • If your guy needs 2 physicsBodies, I would just add a childnode with the 2nd body. Joints seem to be overkill for what you need – Knight0fDragon Dec 23 '17 at 03:30
  • btw, Contact happens before collision, so if I am reading this correctly, you do not even need to have the physicsbody, just check the contact point to determine whether to activate or deactivate the platform checking on your collision mask – Knight0fDragon Dec 23 '17 at 03:33
  • @Knight0fDragon Thanks, adding a child node without a physics body works fine and behaves how i would expect. But with no physics body I cant detect collisions. as soon as I add a physics body to the child with out the joint the childs position changes drastically once the player starts moving around. It seems like a bug almost but the joint was the only way to prevent wild movement while maintain a physics body. – genericguy25 Dec 23 '17 at 14:53
  • I think I am going to right a tutorial on this, so many people struggle with this – Knight0fDragon Dec 23 '17 at 15:06
  • That would be much appreciated. I added an Edit to the OP showing the strange child behavior when it has a physics body but no joint. I move the player by changing its x velocity. maybe that has something to do with it? – genericguy25 Dec 23 '17 at 15:22

1 Answers1

4

I found the solution.

It seems there's some bugs with fixed joints and the answer was to use a "pin" joint instead. This StackO question goes into detail about a rotation bug with fixed joints. On a whim I decided to change my fixed joint to a pin and now the child behaves as you would expect, positionally speaking anyway.

So it appears fixed joints have a few bugs that need to be worked out.

genericguy25
  • 602
  • 3
  • 16