Contact with multiple physics bodies - swift

In my current app, I need to have multiple collisions with different nodes. I am pretty unfamiliar with the physics-world pertaining to Xcode. Within my ColliderType struct, contact with all nodes seem to work, except anything past the value type of 3. I am pretty confused with this stuff already, any help? Let me know if I should provide more code.
struct ColliderType {
static let player: UInt32 = 1
static let enemy: UInt32 = 2
static let coin: UInt32 = 3
static let arrow: UInt32 = 4
}

The problem was solved. I was missing some of the required contactTestBitMasks, and collisionBitMasks. To recap, the problem was that contact between the arrow and the enemy were not working. I thought this was something to do with my ColliderType Struct, however it was a simple error of not including the following when making my arrow:
arrow.physicsBody?.contactTestBitMask = ColliderType.enemy
arrow.physicsBody?.collisionBitMask = ColliderType.enemy

Related

Swift // Sprite Kit: Category Bit Mask Limitations

There's something that's always puzzled me about category bit masks, and I'm reaching a point where I'm going to need a greater understanding of them. I understand how they work on a fundamental level. Say I was making a dungeon crawler basic hack and slash capabilities. I might use a collection of categories like these:
enum PhysicsCategory{
static let none: UInt32 = 0
static let playerCategory: UInt32 = 0b1
static let enemyCategory: UInt32 = 0b10
static let weaponCategory: UInt32 = 0b100
static let collectibleCategory: UInt32 = 0b1000
static let enemyProjectileCategory: UInt32 = 0b10000
}
This would probably suffice, I could test if I'm attacking the enemy, they're attacking me, etc. That said, if I wanted to make a dungeon crawler with different enemy classes, different weapon types, and different enemy weaknesses and strengths, I feel like I'd run out of categories really fast:
enum PhysicsCategory{
static let none: UInt32 = 0
static let playerCategory: UInt32 = 0b1
static let toxicWeaponCategory: UInt32 = 0b10
static let iceWeaponCategory: UInt32 = 0b100
static let explosiveWeaponCategory: UInt32 = 0b1000
static let bluntWeaponCategory: UInt32 = 0b10000
static let toxicEnemyCategory: UInt32 = 0b100000
static let iceEnemyCategory: UInt32 = 0b1000000
static let explosiveEnemyCategory: UInt32 = 0b10000000
}
I run out of options for enemies and haven't even gotten to things like collectibles, environmental objects, or bosses whose weaknesses and/or strengths make entirely new combinations. How are these things typically accounted for? What I'm trying to make demands more than what you see above and the books / guides I've read only explain this on a very basic level.
categoryBitmasks are used mostly for contact and collision detection and to establish what has made contact with what at a high level i.e. player with collectible, enemy with weapon etc. I'd be tempted to subclass these nodes (enemies, collectibles, bosses) and make the 'effect' (toxic, ice, explosive) a property within the node so that after making contact with something, you can call the appropriate routine from didBegin() based upon the enemy 'effectType'.
All contacts go through didBegin() anyway, and you're going to have to test the toxic/ice/explosive category anyway to work out how to handle the contact, so changing this logic to test a property within the node contacted won't actually add much (if any) code to your program.
Edit: You could code your didBegin() like this:
func didBegin(_ contact: SKPhysicsContact) {
print("didBeginContact entered for \(String(describing: contact.bodyA.node!.name)) and \(String(describing: contact.bodyB.node!.name))")
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case playerCategory | enemyCategory:
print("Playerand enemy have contacted.")
let playerNode = contact.bodyA.categoryBitMask == playerCategory ? contact.bodyA.node : contact.bodyB.node
let enemyNode = contact.bodyA.categoryBitMask == enemyCategory ? contact.bodyA.node : contact.bodyB.node
let enemyType = enemyNode.contactType // toxic, ice, explosive
processCollision(between: playerNode and: enemyNode ofType: enemyType)
default:
print("Some other contact occurred")
}
Although you'd be more likely to extract the enemey's type in processCollision()
If you're not familiar with Swift's argument labels for parameters, the definition of processCollision could be:
func: processCollision(between node: SKSpriteNode, and node2: SkSpriteNode ofType type: string)
which allows you to refer to node1 and node2 in the function, but the calling syntax is more readable. Also type would probably be a enum of the available enemy types.
Edit
A few links to some SK guides you may (or may not) find useful:
My step-by-step guide for collisions and contacts:
https://stackoverflow.com/a/51041474/1430420
And a guide to collision and contactTest bit masks:
https://stackoverflow.com/a/40596890/1430420
Manipulating bit masks to turn individual collision and contacts off and on.
https://stackoverflow.com/a/46495864/1430420
Small sample project with contacts, collision and touches
https://stackoverflow.com/a/43605825/1430420

Calling getsectiondata from Swift

This question and answer describe how to read data from a Mach-O section with Objective-C on modern OS X/macOS versions: Crash reading bytes from getsectbyname
The described answer works. I'm trying to implement the same thing with Swift. I can't make it work.
I have the following in "Other linker flags": -Wl,-sectcreate,__LOCALIZATIONS,__base,en.lproj/Localizable.strings,-segprot,__LOCALIZATIONS,r,r.
This Swift code gets me the a pointer to the embedded data, until I try to run the code outside Xcode and ASLR breaks it:
var size: UInt = 0
let _localizationSection = getsectdata(
"__LOCALIZATIONS",
"__base",
&size)
To get around the ASLR problem, according to the above question and answer, and based on my own testing, I should be using getsectiondata instead. It works great in Objective-C, but I'm having no luck in Swift. The following is the only thing I've managed to get past the compiler, but it returns nil:
var size: UInt = 0
var header = _mh_execute_header
let localizationSection = getsectiondata(
&header,
"__LOCALIZATIONS",
"__base",
&size)
Is taking a copy of _mh_execute_header the problem and is there any way to avoid it? I need an UnsafePointer<mach_header_64>, but using &_mh_execute_header as the first parameter to getsectiondata causes a compilation error.
I'm using Swift 3.0, and running my code on macOS 10.12.
The difference between the linked-to Objective-C code
void *ptr = getsectiondata(&_mh_execute_header, ...);
and your Swift translation
var header = _mh_execute_header
let localizationSection = getsectiondata(&header, ...)
is that the latter passes the address of a copy of the global
_mh_execute_header variable to the function, and apparently that
is not accepted. If you modify the Objective-C code to
struct mach_header_64 header = _mh_execute_header;
void *ptr = getsectiondata(&header, ...);
then it fails as well (and actually crashed in my test).
Now the problem is that _mh_execute_header is exposed to Swift
as a constant:
public let _mh_execute_header: mach_header_64
and one cannot take the address of a constant in Swift. One possible
workaround is to define
#import <mach-o/ldsyms.h>
static const struct mach_header_64 *mhExecHeaderPtr = &_mh_execute_header;
in the bridging header file, and then use it as
let localizationSection = getsectiondata(mhExecHeaderPtr, ...)
in Swift.
Another option is to lookup the symbol via dlopen/dlsym
import MachO
if let handle = dlopen(nil, RTLD_LAZY) {
defer { dlclose(handle) }
if let ptr = dlsym(handle, MH_EXECUTE_SYM) {
let mhExecHeaderPtr = ptr.assumingMemoryBound(to: mach_header_64.self)
var size: UInt = 0
let localizationSection = getsectiondata(
mhExecHeaderPtr,
"__LOCALIZATIONS",
"__base",
&size)
// ...
}
}

Swift Uint32 Recognizing All Even Numbers as the Same

I am using SpriteKit in Swift and have the following situation:
I construct a struct in the superclass level that has a list of UInt32s to represent the various bitmasks that I need to establish types of physics bodies. (This is stupid because struct properties cannot be overridden in the subclass. Considering removing.)
In the subclass I create a physics body that has collision, contact, and category bitmasks of UInt32(4), referenced by a static constant from the superclass struct.
These bodies fall through the ground that is created in the superclass with bitmasks of UInt(2) from the struct property.
When I change the static constant from UInt(4) to an unsigned int 32 of any odd number between 0 - 32, the bodies do not fall through the ground. Using any even number makes the bodies fall through the ground.
Superclass.swift
struct physicsBitMasks {
static let one = UInt32(1) //for player
static let two = UInt32(2) //for ground
static let three = UInt32(3) //for you don't need to know
static let four = UInt32(4) //for enemy
...
ground.physicsBody?.categoryBitMask = physicsBitMasks.one
ground.physicsBody?.contactTestBitMask = physicsBitMasks.one
ground.physicsBody?.collisionBitMask = physicsBitMasks.two
}
Subclass.swift
Subclass: Superclass {
//create enemy
thing.physicsBody?.categoryBitMask = physicsBitMasks.four
thing.physicsBody?.contactTestBitMask = physicsBitMasks.four
thing.physicsBody?.collisionBitMask = physicsBitMasks.four
}
Enemy falls through ground
REDEFINE
Superclass.swift
struct physicsBitMasks {
static let one = UInt32(1) //for player
static let two = UInt32(2) //for ground
static let three = UInt32(3) //for you don't need to know
static let four = UInt32(5) // or 7, 9, ...31 for enemy
}
Enemy does not fall through ground.
What is going on?
Wouldn't playerMask, groundMask, mysteryMask, and enemyMask be better names than one, two, three, and four?
Also, because they are bit mask components, you need each to have a single unique bit set. But 3, for example, contains the bits of 1 and 2. Let's define them this way:
struct BodyMask {
static let Player = UInt32(1)
static let Ground = UInt32(2)
static let EmbarrassingSecret = UInt32(4)
static let Enemy = UInt32(8)
}
Now you need to set the various masks on your bodies. You should set each's body's categoryBitMask to the mask for its type:
ground.physicsBody?.categoryBitMask = BodyMask.Ground
player.physicsBody?.categoryBitMask = BodyMask.Player
enemies.forEach { $0.physicsBody?.categoryBitMask = BodyMask.Enemy }
twilightNovel.physicsBody?.categoryBitMask = BodyMask.EmbarrassingSecret
You need to set each body's collisionBitMask based on what other bodies you want it to bounce off of. That is, do you want an enemy to bounce off the ground? Then the enemy's collisionBitMask must include the BodyMask.Ground bit. Do you want the ground to bounce off of an enemy? Or bounce off of anything else? Probably not. Note that this is asymmetric! The enemy can bounce of the ground without the ground bouncing. That is, Newton's third law (for every action there is an equal and opposite reaction) doesn't have to apply.
If you want a body to bounce off of multiple other body types, you can bitwise-or the masks together. Let's assume you want enemies to bounce off of the ground and each other.
ground.physicsBody?.collisionBitMask = 0
player.physicsBody?.collisionBitMask = BodyMask.Ground
enemies.forEach { $0.physicsBody?.collisionBitMask = BodyMask.Ground | BodyMask.Enemy }
twilightNovel.physicsBody?.collisionBitMask = BodyMask.Ground
Finally, if you want to be notified when two bodies collide (regardless of whether they bounce), you can use contactTestBitMask. You probably want to know when the player touches an enemy, or when the player does something embarrassing, even though you don't necessarily want the player to bounce off of enemies or trashy novels.
ground.physicsBody?.contactTestBitMask = 0
player.physicsBody?.contactTestBitMask = BodyMask.Enemy | BodyMask.EmbarrassingSecret
enemies.forEach { $0.physicsBody?.contactTestBitMask = 0 }
twilightNovel.physicsBody?.contactTestBitMask = 0

Game Scene cannot be constructed because it has not accessible initializers

Xcode is dropping an error and I dont know how to solve it. Maybe someone can give me a hand or a good hint?
Here is my code that is working within my Game Scene:
var currentLevel: Int = 1
var platforms: PlatformsNode!
var platformNode1: PlatformNode!
var platformNode2: PlatformNode!
var platformNode3: PlatformNode!
var platformArray = [SKNode]()
let passenger = SKSpriteNode(imageNamed: "passenger")
var passengerNumber:Int = 1
var startPlatform = [3, 3, 2, 1, 2]
var destinationPlatform = [1, 1, 3, 2, 1]
// Level selection
class func level(levelNum: Int) -> GameScene? {
let scene = GameScene(fileNamed: "Level\(levelNum)")! // <- compiler error
scene.currentLevel = levelNum
scene.scaleMode = .AspectFill
return scene
}
As soon as I want to replace
let passenger = SKSpriteNode(imageNamed: "passenger")
with let passenger: PassengerNode! the compiler drops an compiler error "Game Scene cannot be constructed because it has not accessible initializers".
And this error just shows up, when I change the way I want to declare let passenger.
The reason I want to change it, is that I want to replace it with a class, so that the passenger
a. can have a different type with a different texture (this can may be solved differently)
b. can be removed from the parent and later be added again - with hopefully no error.
You got any ideas? I am really stuck somehow :-?
declaring passenger with only its type and no initial value requires that you add an init() to your class because the compiler does not know what initial value to give it when the object is created.
You can either create an init() and set a value to passenger or delare it as
let passenger: PassengerNode! = nil
(this assumes that your code does not reference the variable before making sure to put something in it or checks for nil/optional before using it).

Swift Sprite kit Collision Bitmask

I was wondering if anyone would be able to offer me some help with using 3 nodes, I understand if I just have 2 nodes E.g. body A and body B but I'm struggling with adding a third body, I hoped it was as simple as body C but that wasn't the case.
This is the related code below:
struct CollisionCategoryBitmask {
static let Player: UInt32 = 0x00
static let Enemy1: UInt32 = 0x01
static let Enemy2: UInt32 = 0x02
}
func didBeginContact(contact: SKPhysicsContact) {
var updateHud = false
_ = (contact.bodyA.node != player) ? contact.bodyA.node : contact.bodyB.node
updateHud = slowDown(player)
}
This function below is intended to slow the player down when contacting Enemy1
func slowDown (player: SKNode) -> Bool {
player.physicsBody?.velocity = CGVector(dx: 0, dy: -50.0)
return true
}
and this below is intended to get the game to end when contacting Enemy2
func endGame (player: SKNode) -> Bool {
endOfGame()
return true
}
At the moment both functions work, but only one at a time, so when the player contacts either Enemy 1 or 2. I can currently either get the player to slow down or get the game to end by just changing the
updateHud = slowDown(player) line. So how can I adjust the code to have the two different outcomes happen when the player touches either Enemy 1 or 2.
Thanks
You are not understanding how didBeginContact works. Basically what is happening is when any 2 nodes make a contact, the first thing that the system will do is make sure that the category and contact bit masks line up to make a valid contact. If it does, then didBeginContact gets called. now inside this function, you have the 2 arbitrary nodes that made contact, called bodyA, and bodyB. What you need to do first, is figure out what bodyA and bodyB are. So the first thing you do, is check the categoryBitMask.
if(contact.bodyA.categoryBitMask == HERO) then contact.bodyA is a hero
Now that we know what categories these nodes refer to, we can then check what the node actually is. To do this, you can either check the name of the node
if(contact.bodyA.node.name == "Hero") then bodyA is the hero
Or compare the node itself
if(contact.bodyA.node == heroNode) then bodyA is the hero
Now do the same for bodyB.
You have established at this point what your nodes are, you can proceed with the outcome results that you need based on this information.
If Hero hits both enemy nodes at the same time, then you need to handle this as well. What is going to happen is 2 calls to didBeginContact will happen, you need to find a way to remember this, and do your contact code in either the didEvaluateActions, or didSimulatePhysicsMethod. I do not remember which of these follows didBeginContact, so you will have to test it out on your own.