I am making a game with sprites that move and obstacles to learn SpriteKit. I want the sprites that move to collide with the obstacles and bounce off of them but I want the obstacles to stay fixed. How do I do this? I have tried the following with no success:
Setting obstacle.physicsBody?.isDynamic = true. This made the sprites go through the obstacle.
Fixing the movement and rotation of the object with SKConstraint. When I do this they just go through each other.
Setting the mass of the body to be really high as follows obstacle.physicsBody?.mass = CGPoint.maxFiniteMagnitude but this freezes the game. When I set it really high it doesn't seem to do anything.
Setting obstacle?.physicsBody.velocity = CGVector(dx: 0, dy: 0) when the objects collide. I know that the contact.bodyA and contact.bodyB are passed by value and not reference so I loop through an array with the obstacles and set the velocity this way. The obstacles are still pushed by the other sprites.
Update:
- Setting obstacle.physicsBody?.collisionBitMask = PhysicsCategory.none so the sprite collides with the obstacle but not the other way around.
The object is setup as follows, with fish being the other sprite:
obstacle.position = location
obstacle.physicsBody = SKPhysicsBody(rectangleOf: obstacle.size)
obstacle.physicsBody?.isDynamic = true
obstacle.physicsBody?.categoryBitMask = PhysicsCategory.obstacle
obstacle.physicsBody?.contactTestBitMask = PhysicsCategory.fish
obstacle.physicsBody?.collisionBitMask = PhysicsCategory.fish
obstacle.physicsBody?.usesPreciseCollisionDetection = true
self.obstacles.append(obstacle)
super.addChild(obstacle)
Please let me know if there is something I am doing wrong / misunderstanding. Thanks.
Found the answer here. One of the objects needs to have .physicsBody?.isDynamic = true. In this case I set the obstacle to false so it is stationary.
Related
I am making a game in Swift using spritekit and I want 2 objects on screen, one that I move with the touchesMoved function (player) and the other to stay still in its position in the screen (cell).
I wanted to make the objects physicsbody's so that I could work out collisions between them, but now whenever the scene loads the objects fall straight away. And the object moved through touch falls as soon as the user stops touching the screen.
Here's all of the code relating to the object that should stay stationary in the scene and I am unsure what makes it fall.
//Defining the cell
let cell = SKSpriteNode(imageNamed: "cell.png")
override func didMove(to view: SKView){
self.physicsWorld.contactDelegate = self
cell.physicsBody?.categoryBitMask = cellCategory
cell.physicsBody?.contactTestBitMask = playerCategory
cell.physicsBody?.isDynamic = true
cell.physicsBody = SKPhysicsBody(rectangleOf: cell.frame.size)
//Adding the cell to the scene
cell.position = CGPoint(x:size.width * 0.9, y:size.height * 0.9)
cell.size = CGSize(width: 50, height: 50)
addChild(cell)
Any help in what makes the object fall and how I can stop it from happening would be greatly appreciated.
Gravity is by default on. You can either turn it off entirely by setting the gravity property of the scene's physicsWorld:
// somewhere in the scene's initialization, or in didMove if you like
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
See https://developer.apple.com/documentation/spritekit/skphysicsworld for info on that.
Or you can turn off whether individual objects are affected by gravity. E.g.,
let body = SKPhysicsBody(circleOfRadius: 10.0)
body.affectedByGravity = false
See https://developer.apple.com/documentation/spritekit/skphysicsbody, and in particular, https://developer.apple.com/documentation/spritekit/skphysicsbody/1519774-affectedbygravity
You have a different problem in that you're setting the properties of your cell's physics body before you're creating it. cell.physicsBody?... = will not assign anything until cell.physicsBody exists. So those assignments must be moved after you create cell.physicsBody = SKPhysicsBody(rectangleOf: ...)
Hi I am making a endless scrolling game where the character basically avoids obstacles as they come and he can jump over them. I got everything to work pretty well but I see that the character texture will bounce slightly after hitting the ground. I want the sprite to stop immediately after touching down. I tried setting the .restitution property to 0 but i still see it bouncing. Here is the setup code for my stickman character and the edge physics category in question
stickman.physicsBody?.dynamic = true
stickman.physicsBody?.allowsRotation = false
stickman.physicsBody?.usesPreciseCollisionDetection = true
stickman.physicsBody?.categoryBitMask = PhysicsCategory.Stickman
stickman.physicsBody?.collisionBitMask = PhysicsCategory.Edge
stickman.physicsBody?.contactTestBitMask = PhysicsCategory.Obstacle | PhysicsCategory.Edge
stickman.physicsBody?.restitution = 0
self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
physicsBody = SKPhysicsBody(edgeLoopFromRect: playableRect)
physicsWorld.contactDelegate = self
physicsBody?.categoryBitMask = PhysicsCategory.Edge
Where playable rect is just the screen boundary for universal deployment purposes.
Has anyone run into this problem. I couldn't quite find the same issue in other posts.
Set the restitution of the physics body your sprite is running into to 0 as well. Both physics bodies in a physics collision need to have a restitution of 0 to result in no bounciness.
I have a simple scene there is a floor, block, camera and light.
The floor is static
SCNNode* floor = [SCNNode node];
SCNPhysicsBody *staticBody = [SCNPhysicsBody staticBody];
floor.physicsBody = staticBody;
[[scene rootNode] addChildNode:floor];
The block is dynamic
SCNNode *block = [SCNNode node];
block.position = SCNVector3Make(-10, 45, -20)
block.geometry = [SCNBox boxWithWidth:5 height:5 length:5 chamferRadius:0];
block.physicsBody = [SCNPhysicsBody dynamicBody];
The block's starting position is above the floor, so when the app runs, the block falls to the floor as expected.
I have added motion manager that will move the floor down, simulating the floor being pulled out from under the block by translating negative changes in Y to the block and this is where the trouble begins.
if(userAcceleration.y < 0)
{
SCNVector3 vector = floor.position;
vector.y += userAcceleration.y*10.0;
floor.position = vector;
}
If the motion occurs before the block has come to rest, I can shake the device and can keep the block moving around as expected.
However, if the motion occurs after the block has come to a rest for a few seconds, the block will only rise (higher and higher with each motion) above the floor never to fall again.
Why does the gravity affect appear to stop?
Is there something that turns off gravity that I need to checking during the motion check? or is there something else I am missing?
It might sound silly, but have you set the playing property of your renderer to true?
If that doesn't work, my hack is to add an empty SCNNode and make it rotate forever with a SCNAction. It keeps the scene rendering/calculations going even if nothing is moving.
EDIT: I forgot about the allowResting property. It's probably what is causing your problem. Just turn it off for your object!
You can read more about it here: https://developer.apple.com/library/prerelease/ios/documentation/SceneKit/Reference/SCNPhysicsBody_Class/index.html#//apple_ref/occ/instp/SCNPhysicsBody/allowsResting
I'm making a platform and want to stop the character (a ball) from going through the ground.
Can I write an if statement similar to if (Ball.center.y == 463) Ball.center.y = 463;?
463 is the y position that the ground is in the game.
While that approach is certainly possible, typically you want to abstract away the details (such as the 463 y-position of the ground) so that your code is more robust. For example, if you changed the y-position of the ground, you would have to change the 463 value everywhere you use it!
But fundamentally, yes you would use an if statement somewhat like what you provided. One thing to note is that if the ground is at 463, your ball will be half-way through the ground (since you are looking at the y-position of the centre of the ball.
Moreso, you want a check that is not so absolute... what if the position of the ball somehow becomes lower than the ground? Say 462? What should the behavior be now?
Without getting into the physics and design of your program, you would at the very least want to change your statement to something like:
int ball_lower_bound = Ball.center.y - Ball.height/2;
int ground_bound = 463;
if (ball_lower_bound < ground_bound) {
ball_lower_bound = ground_bound;
}
Since you are using sprite kit you should use physics body to handle that.
This is in swift:
variables of your class:
let balCategory:UInt32 = 1 << 0
let groundCategory:UInt32 = 1 << 1
Then when you define your ball sprite:
ball.physicsBody.categoryBitMask = ballCategory
ball.physicsBody.collisionBitMask = groundCategory
ball.physicsBody.contactTestBitMask = groundCategory
Then when you define your ground sprite (hopefully you have a image for your ground, if not make a very thin transparent or have something just below the screens edge):
ground.physicsBody.categoryBitMask = groundCategory
ground.physicsBody.collisionBitMask = ballCategory
ground.physicsBody.contactTestBitMask = ballCategory
Hopefully you can translate it to objective C if you are using that.
I am using the following code to put a floor in my SpriteKit based game:
var floorNode = SKSpriteNode()
var floorBody = SKPhysicsBody(edgeFromPoint: CGPointMake(self.frame.minX, self.frame.minY), toPoint: CGPointMake(self.frame.maxX, self.frame.minY))
floorNode.physicsBody = floorBody
addChild(floorNode)
This places a floor at the bottom of the screen as expected. However as I add more things to the scene, one end of the floor eventually sinks down and everything in the scene that is resting on it slides off into the abyss.
I am at a complete loss here since Apple's documentation says that "an edge-based body does not have mass or volume, and is unaffected by forces or impulses in the system. Edge-based bodies are used to represent volume-less boundaries or hollow spaces in your physics simulation."
Anyone else seen this kind of behavior?
The easiest way to define floor for your scene, without adding any nodes to it:
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
where self is your SKScene.
If you don't want ceiling on the scene, define physicsBody as this:
[SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width,
self.frame.size.height*5)];