How to set category mask in sprite kit? - ios

let dart = SKSpriteNode(imageNamed: "Dart")
dart.physicsBody?.isDynamic = true
dart.physicsBody?.categoryBitMask = 3
dart.physicsBody?.collisionBitMask = 2
when I print the darts category masks it returns nil. I have set other sprites category masks through the scene editor and they work fine. Thanks for any help.

You haven't actually made a physics body.
dart.physicsBody = SKPhysicsBody(...)
dart.physicsBody?.isDynamic = true
// etc.
The ... depends on the type of physics body you want (circle, rectangle, polygon, etc.) See examples here:
https://developer.apple.com/documentation/spritekit/sknode/getting_started_with_physics_bodies

Related

Setting lighting in ARKit framework

Ok, I'm new to SceneKit and ARKit here and I just want to set any models I add to my scene to have a certain, bright lighting. I have tried all different configurations of the automatically update lighting settings with ARSceneView, however the only thing that really creates a discernible difference is autoenablesDefaultLighting:
func setup() {
antialiasingMode = .multisampling4X
//autoenablesDefaultLighting = true
preferredFramesPerSecond = 60
contentScaleFactor = 1.3
if let camera = pointOfView?.camera {
camera.wantsHDR = true
camera.wantsExposureAdaptation = true
camera.exposureOffset = -1
camera.minimumExposure = -1
camera.maximumExposure = 3
}
}
Regardless of the lighting obtained from the camera (as I know ArKit is able to do), I just want to set 1 lighting setting always. I want my scene contents to be lit like this:
Is this possible? What would I set sceneView.scene.lightingEnvironment equal to in order to achieve this effect?
According to the docs, you should be able to create a SCNNode in a position and then add a SCNLight to it:
https://developer.apple.com/documentation/scenekit/scnnode
https://developer.apple.com/documentation/scenekit/scnlight

Box2D: How to use b2ChainShape for a tile based map with squares

Im fighting here with the so called ghost collisions on a simple tile based map with a circle as player character.
When applying an impulse to the circle it first starts bouncing correctly, then sooner or later it bounces wrong (wrong angle).
Looking up on the internet i read about an issue in Box2D (i use iOS Swift with Box2d port for Swift).
Using b2ChainShape does not help, but it looks i misunderstood it. I also need to use the "prevVertex" and "nextVertex" properties to set up the ghost vertices.
But im confused. I have a simple map made up of boxes (simple square), all placed next to each other forming a closed room. Inside of it my circle i apply an impulse seeing the issue.
Now WHERE to place those ghost vertices for each square/box i placed on the view in order to solve this issue? Do i need to place ANY vertex close to the last and first vertice of chainShape or does it need to be one of the vertices of the next box to the current one? I dont understand. Box2D's manual does not explain where these ghost vertices coordinates are coming from.
Below you can see an image describing the problem.
Some code showing the physics parts for the walls and the circle:
First the wall part:
let bodyDef = b2BodyDef()
bodyDef.position = self.ptm_vec(node.position+self.offset)
let w = self.ptm(Constants.Config.wallsize)
let square = b2ChainShape()
var chains = [b2Vec2]()
chains.append(b2Vec2(-w/2,-w/2))
chains.append(b2Vec2(-w/2,w/2))
chains.append(b2Vec2(w/2,w/2))
chains.append(b2Vec2(w/2,-w/2))
square.createLoop(vertices: chains)
let fixtureDef = b2FixtureDef()
fixtureDef.shape = square
fixtureDef.filter.categoryBits = Constants.Config.PhysicsCategory.Wall
fixtureDef.filter.maskBits = Constants.Config.PhysicsCategory.Player
let wallBody = self.world.createBody(bodyDef)
wallBody.createFixture(fixtureDef)
The circle part:
let bodyDef = b2BodyDef()
bodyDef.type = b2BodyType.dynamicBody
bodyDef.position = self.ptm_vec(node.position+self.offset)
let circle = b2CircleShape()
circle.radius = self.ptm(Constants.Config.playersize)
let fixtureDef = b2FixtureDef()
fixtureDef.shape = circle
fixtureDef.density = 0.3
fixtureDef.friction = 0
fixtureDef.restitution = 1.0
fixtureDef.filter.categoryBits = Constants.Config.PhysicsCategory.Player
fixtureDef.filter.maskBits = Constants.Config.PhysicsCategory.Wall
let ballBody = self.world.createBody(bodyDef)
ballBody.linearDamping = 0
ballBody.angularDamping = 0
ballBody.createFixture(fixtureDef)
Not sure that I know of a simple solution in the case that each tile can potentially have different physics.
If your walls are all horizontal and/or vertical, you could write a class to take a row of boxes, create a single edge or rectangle body, and then on collision calculate which box (a simple a < x < b test) should interact with the colliding object, and apply the physics appropriately, manually calling the OnCollision method that you would otherwise specify as the callback for each individual box.
Alternatively, to avoid the trouble of manually testing intersection with different boxes, you could still merge all common straight edge boxes into one edge body for accurate reflections. However, you would still retain the bodies for the individual boxes. Extend the boxes so that they overlap the edge.
Now here's the trick: all box collision handlers return false, but they toggle flags on the colliding object (turning flags on OnCollision, and off OnSeparation). The OnCollision method for the edge body then processes the collision based on which flags are set.
Just make sure that the colliding body always passes through a box before it can touch an edge. That should be straightforward.

Making physics bodies responsive to fields but not to other physics bodies

In my game I have a body that flies across the screen, and is supposed to be affected by a radial gravity field that I have created. To do this, I needed to turn the
body.dynamic = true
But this results in the body colliding with other objects (with physics bodies) that are on the screen, when I just want it to be affected by the field and not by these objects. If I turn the
body.dynamic = false
then it doesn't get affected by the field.
What should I do to make the body stay on its path?
EDIT This is my code for the main body that flies across the screen, after a node has already been created
body.physicsBody = SKPhysicsBody(rectangleOfSize: rectangle)
body.physicsBody?.dynamic = true
body.physicsBody?.categoryBitMask = PhysicsCategory.body
body.physicsBody?.contactTestBitMask = PhysicsCategory.otherBody
body.physicsBody?.affectedByGravity = false
body.physicsBody?.fieldBitMask = PhysicsCategory.shield
body.physicsBody?.allowsRotation = false
The image shows the 2 possible ways I want the body to avoid colliding with the object. Either it can pass through it, or it can pass around it and return to the earlier path. How do I do that?
You should set
body.physicsBody?.collisionBitMask = 0
collisionBitMask - A mask that defines which categories of physics bodies can collide with this physics body. IF the value is not set your PhysicsBody collides with every other PhysicsBodies, If value is set to 0 your PhysicsBody do not collide with other PhysicsBodies
I you set collisionBitMask = 0 your body node will go through all other nodes, if you whant it to collide you need to set node physicsBody?.collisionBitMask (for example if you whant your node to collide only with ball and wall physicsBody?.collisionBitMask = kCategoryWall | kCategoryBall)
I hope it was helpfull

Swift edgeLoopForRect physics body not getting categoryBitMask correctly

I have a body with edgeLoopForRect and I'm giving it a categoryBitMask but when I'm debugging the object's categoryBitMask is different than what I assigned it...
self.physicsBody?.categoryBitMask = 1
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
when I'm debugging its showing up as 453453 not ``
You cannot assign physics bodies to self. you have to create a node first and then assign a category bit mask to its physics body.
IE:
let edge = SKNode()
edge.phisicsbody = SKPhisicsbody(edgeloopfromrect: frame)
edge.physicsbody!.restitution = 0
edge.physicsbody!.friction = 0
edge.physicsbody!.angularDamping = 1
edge.physicsbody!.dynamic = false
edge.physicsbody!.categotyBitMask = 2
edge.physicsbody!.collisionBitMask = 1 //The category bit mask of the object you want it to collide with I used 1 as example
addChild(edge)
Remember to follow the same procedure for the node that you want to collide with the edge and make the collision bit mask 2 if you follow this example.
Hope this helps mate.

sprite kit collisions: ignore transparency?

I am building a game with Xcode's spritekit. Its a platform game and right now it functions well with flat ground pieces. I was wondering if it was possible to ignore transparency in the png for collisions. That is to say, If i have a ground piece with a curved floor and transparency filling the troughs, can i make the player walk the curves instead of a square bounding box covering the whole thing? The only example i can find is in the Gamemaker GML language, you can do "precise" collisions such that blank space in the images do not count as part of the sprite. I can supply code if necessary but this seems like more of a conceptual question. Thanks in advance
Hey there's a easy solution for this provided in the Apple Documentation.
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
sprite.physicsBody = [SKPhysicsBody bodyWithTexture:sprite.texture size:sprite.texture.size];
This creates a physics body around the physical paths of the texture.
Simulating Physics - SpriteKit Programming Guide
It's all in how you instantiate the physicsBody of the node in question.
node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node.size];
is probably the easiest and most common way of making a physicsBody, but will also create the issue you've identified above, because, for all collision purposes, the node is a rectangle.
take a look at the documentation for SKPhysicsBody to see the other options available to you. PolygonFromPath and BodyWithBodies are probably the best suited for what you're doing.
SKPhysicsBody is the right move, just wanted to note that it does make sense to have a separate (simplified) mask-image for SKPhysicsBody to improve your performance, simplified from color and geometry standpoint, and here's the code:
let birdMask: UInt32 = 0x1 << 0
let pipeMask: UInt32 = 0x1 << 1
//...
pipeImage = SKSpriteNode(imageNamed: "realImage")
//... size and position
let maskTexture = SKSpriteNode(imageNamed: mask)
maskTexture.size = pipeImage!.size // size of texture w/ real imageNamed
pipeImage!.physicsBody?.usesPreciseCollisionDetection = true
pipeImage!.physicsBody = SKPhysicsBody(texture: maskTexture.texture!, size: size)
pipeImage!.physicsBody?.affectedByGravity = false // disable falling down...
pipeImage!.physicsBody?.allowsRotation = false
pipeImage!.physicsBody?.isDynamic = true
pipeImage!.physicsBody?.friction = 0
pipeImage!.physicsBody?.categoryBitMask = pipeMask
pipeImage!.physicsBody?.collisionBitMask = birdMask | pipeMask
pipeImage!.physicsBody?.contactTestBitMask = birdMask | pipeMask
and more detailed example/guide.

Resources