SpriteKit physics: How to make a player sprite follow the (sloped) ground - ios

I am creating a tilemap platform game in SpriteKit. I assigned collision paths to the physics body of all ground tiles and made them non-dynamic. To the player I assigned two collision polygons: a circle on the bottom and a rectangle on the top.
The player sprite has a fixed position on screen, while the level is scrolling from right to left. Now, as long as the player sprite is on flat ground, the collisions work perfectly and the player is walking on the ground. However, I also have some sloped terrain tiles that I want the player to follow (e.g. walking uphill). But when the player reaches a sloped tile, he simply bounces off of it, being unable to "climb" it.
Similarly, when I drop the player from above on a sloped tile, he slides down the "hill", instead of remaining in position.
I have both restitution and friction set to 0.
So how can I make the player sprite follow the ground regardless of its shape and how can I make the player stay on a sloped tile instead of sliding down?
I tried using SKConstraints with positionX set to a constant value. At first it seemed to work, but then the player got stuck in the middle of a sloped tile and eventually fell through it.
I also tried different shapes of collision polygons on the player (e.g. a rectangle instead of a circle at the bottom) but that changed nothing.
Any help is appreciated!

This has more to do with your game logic instead of your map properties. You need to have several "states" for your player. For example, if your player is idle you can set the CGVector to 0,0. This will stop the player from moving in any direction.
To give you some examples on movement. Let's say you want to make your object move right:
// move node's physics body to the right while leaving vertical movement as is
// 160 is just an example
myNode.physicsBody.velocity = CGVectorMake(160, self.physicsBody.velocity.dy);
// do not allow right movement to exceed 160
if(myNode.physicsBody.velocity.dx > 160)
myNode.physicsBody.velocity = CGVectorMake(160, self.physicsBody.velocity.dy);
To move left you inverse the dx value:
myNode.physicsBody.velocity = CGVectorMake(-160, self.physicsBody.velocity.dy);
if(myNode.physicsBody.velocity.dx < -160)
myNode.physicsBody.velocity = CGVectorMake(-160, self.physicsBody.velocity.dy);
Allow myNode to be affected by gravity and it should remain in contact with the ground as it moves down a slope.

It's a tilemap platform game...
Then gravity isn't important, put gravity to a very low value and then change all your impulses for the jumps and such in relation to the change in gravity...
OR,
Possibly, if the game isn't randomly generated you can set up a uibezierpath, and turn the path off if he stops moving up the hill.
But then if he stopped mid-hill or was starting from the top, he would still slide down...
And increasing friction (not setting it to 0) may help. Try friction at 1?

Related

How to make SKEmitter particles stay relative to the background when I move my SKEmitterNode around the screen?

I feel like this should be a very simple question, but I looked around and it seems to just be working for everybody automatically. But for some reason, when I move the particle emitter around the screen, the particles move with it, and there is no trail behind the emitter node of particles.
I am making a SpriteKit game of a character running around on the bottom of the screen, and he has a boost ability which releases small bubble particles behind him when he boosts because he is underwater. But the particles aren't staying relative to the screen, they are relative to the player and move with him.
Here's some code to add the boost bubbles:
func addBoostBubbles(){
boostBubbles = SKEmitterNode(fileNamed: "bubbleBoost")!
boostBubbles.particlePositionRange = CGVector(dx: player.frame.size.width, dy: player.frame.size.height)
boostBubbles.position = player.position
boostBubbles.zPosition = 0
self.addChild(boostBubbles)
}
I call this func to create the emitter node and set it to the player's position.
then to move the position of the bubbles in the didSimulatePhysics func I have this:
boostBubbles.position.x += xAcceleration
I see the bubbles on the screen and the emitter node is moving to the right places, but I want them relative to the background so the bubbles just slowly float up behind the player.
Any help would be greatly appreciated!!!!
Set the targetNode property of your emitter to be the background node. In addBoostBubbles, try adding the line:
boostBubbles.targetNode = <background node name>
https://developer.apple.com/documentation/spritekit/skemitternode
targetNode - The target node that renders the emitter’s particles.
This causes the particles to render as though they are children of the background.
If you don't have a background node then you'll need to add one.

PhysicsBody stays after translation and rotation

I have a node with a cube attached which represents for example a door. The physicsbody type is .static. If i animate the node up, rotate it and animate it down to the orignial position of the physicsbody stays in the upper position.
In the debug mode the color of the phyisicsbody is first grey (i asume grey = .static), after the translation up, the physicsbody stays at the bottom. As soon as I rotate the node in the upper position, the physicsbody becomes green and moves up to the nodes position. After I translate the node down to the original position, the physicsbody stays in the upper position. Why is this behaviour? Is this because the type is .static?
I know if I set the physicsbody type to .kinematic (shown red in debug) mode it works as expected. The physicsbody adapts the translations and rotations. But with .static type I can place more objects before the fps drops than with .dynamic.
From the documentation for SCNPhysicsBodyTypeStatic we learn that it is
A physics body that is unaffected by forces or collisions and cannot move
However you can use resetTransform to explicitly tell the engine that the node has moved and that the physics body needs to be updated:
If you change the position or orientation of a node with an attached
static or dynamic physics body, call this method afterward to ensure
that the physics simulation incorporates the change. You need not call
this method for kinematic bodies.
Note that dynamic and physics bodies
are designed to be moved only by the physics simulation or not at all.
You may use this method to move them regardless of this restriction,
but at a cost to performance.

How to reduce the impact of gravity on a single SKSpriteNode

I am building an endless runner game where platforms appear at random intervals and then scroll right to left across the screen.
I have a sprite that jumps up vertically using
- (void)makeCharacterJump {
[self.spriteCaveman.physicsBody applyImpulse:CGVectorMake(0.0f, 80.0f)];
}
The problem is that the effect of gravity on the sprite means that it falls quite quickly and cant make the gap between the platforms.
What I would like to do is slightly slow down the effect of gravity on the falling sprite so it creates the impression of slightly floating down.
Any ideas?
If the character is the only node affected by gravity then you can change the scene’s gravity with:
self.physicsWorld.gravity = CGVectorMake(0, desiredGravity);
If it is not then you’ll have to play with the character’s physics body properties: friction, linearDamping or angularDamping values.
Hope that helps.

Scrolling combined with physics moves my sprite out of the screen

I'm implementing a side scrolling game with SpriteKit:
As long as my sprite stays in the middle of the screen, I'm moving the sprite
When the sprite reaches the left or the right part of the screen, I'm moving the level instead of my sprite:
This works quite well, unless my sprite collides with another object. In that case the level (triggered by my code) and the sprite (triggered by the physics engine) are moved and the sprite moves outside the screen:
I tried to stop the impulse which is applied from the physics engine. This hasn't worked.
Any idea how to handle this?
Thanks
Stefan
I suppose by "moving the level" you mean moving the background view.
Why don't you just have an area in which your sprite moves that is the same size as your background? You can scroll to keep the sprite visible without disturbing the logic of physics and other manipulation of the movement.

Collision with two objects

I have many bricks (physics body) on screen (different- different x and y direction) and one ball comes from up direction(y = 0). In this movement, if a ball collides with a brick (from top part) then it is getting some velocity.
Up to here everything works fine, but I want that when ball collides with a brick (from bottom part ) then the ball should behave like an "un-physics" body. Meaning that when it collides from the top part of brick that time, the ball must be a physics body and when it collides with the bottom part in that movement ball must behave like an "un-physics" body.
Is it possible?
Just detect the direction the ball is coming (you can use the vertical speed of the ball for example), and if the ball is going upward you set
bar.isSensor = true
on the object, and then you put it back to false after the ball is not colliding with it anymore or is going down.

Resources