Spritekit collision to platform while player is falling - ios

I am making a spritekit platformer game with the help of spritekit objective c. I am using spritekit's physics engine for that, every thing is going well except that I haven't found a way to implement a plaformer style collision of the player with the platform.
What I want is my player should collide with the platform while he is falling and not while jumping. Like in following image. Here the player is jumping so he must not collide with the platform
and as In this image the player is falling so he must stand on the platform.
I tried to remove collision of the platform with player in didBeginContact method, but that didn't help as my platform is not dynamic type. Adding and removing collision does work with player but not with platform.
Any help will be greatly appreciated.
Edit: Here it is, example of what will happen if I change player's collision bitmask on contact with two adjacent platforms.
player will fall as soon as it will react with another platform.
Edit: aramusss's second solution is good, But it does create one more problem for me. As I have enemies in my game standing on platforms, if I remove platform's physics body the enemies will fall standing on it.

You can save the platforms in an array, and then check the player Y position. If player.position.y - (player.size.height/2) < platform.position.y - (platform.size.height/2) you deactivate collisions for this platform (means player is below the platform and we don't want it to collide). You should use:
// You should set collision bit mask to avoid collisioning between player and platforms, but not between other objects:
player.physicsBody.collisionBitMask = 1;
player.physicsBody.categoryBitMask = playerCategory; // An int constant, for example 101
player.physicsBody.contactTestBitMask = platformCategory; //Another constant, for example 102
platform.physicsBody.collisionBitMask = 1;
platform.physicsBody.categoryBitMask = platformCategory;
platform.physicsBody.contactTestBitMask = playerCategory;
Setting the values like this will make both bodies not collide, and changing them will make them collide again.
EDIT
Another solution would be to use a NSTimer that will call a method each 0,5 seconds (for example) and this method will check if there is a platform near the player. If there is and it is behind the player, it will create a physicsBody the same size as the platform. If there is a body created that is no more near to the player, or the player is below this platform, this function will delete it.

Related

What's the relationship between physicsbody.dynamic and physicsbody.categorybitmask

Recently I have found that some sprite nodes can't test the collision with others. After some days trying and googling finally I made them works as usual. I have realized that there seems to be some relations between the dynamic and category bit mask. My guess is that:
player.dynamic = false
enemy.dynamic = true
player.category = player
enemy.collision = player
In the conditions above, enemy can't test the collision with player, but I wanna to know more details, any help will be appreciated.
update:
In my game, I want some of the sprites fixed in the scene, whose dynamic should be set to false, but can be collided by the players or enemies. For example the ground, a tree, or some buildings. What should I do to deal with these properties correctly ?
Like
tree.dynamic = false
enemy.collision = tree //can't works
tree.collision = enemy //should I do this? Is there another way to do this?
Non-dynamic bodies don't collide. From Apple's docs:
The dynamic property controls whether a volume-based body is affected
by gravity, friction, collisions with other objects, and forces or
impulses you directly apply to the object.

Sometimes sprite is pushed away when touches another sprite

I am making a game using cocos2d and SpriteBuilder. There is a hero sprite and coins, that should be collected by him. That's a horizontal scrolling game, so every time hero touches a coin, this coin changes it's x-coordinate 2000px to the right and new y-coordinate is generated at random. Using update method I move it to the visible area as a "new" coin. But when hero flyies by and doesn't collect it ,coin must change coordinates only when it's already off the screen, so I tried this solution:
-(void)update:(CCTime)delta{
_coin.position=ccp(_coin.position.x - delta * scrollSpeed, _coinY);
if (CGRectIntersectsRect(_hero.boundingBox,_coin.boundingBox)) {
_coinY=arc4random() % 801 + 100;
_coin.position=ccp(_coin.position.x + 2000.f,_coinY);
}
else if(_hero.position.x >= _coin.position.x + 150){
_coinY=arc4random() % 801 + 100;
_coin.position=ccp(_coin.position.x + 2000.f,_coinY);
}
It works,but after that I found a small bug(I am not sure, whether it's related to this code) : sometimes, when hero touches coin, hero is like pushed away to the left. I have no idea why.
How to fix it?
Is that way, that I am using for coin ,right?
I see 2 issues with your approach:
1. Hero bounces of the coin.
To fix this you need to make your coin a sensor. This way you will still be notified about collisions, but the hero will simply pass through the coin without actually hitting it.
I'm not sure if you can set this in SpriteBuilder, but probably you can enumerate all coins after loading the scene and set sensor property to YES:
coin.physicsBody.sensor = YES;
Things like this is one of the reasons I believe you first need to learn pure Cocos2D and only then use tools making your life easier such as SpriteBuilder. Which is a great tool, but in some cases you still need know what happens behind the scenes.
2. You're mixing physics with things like CGRectIntersectsRect
If you're using physics engine you need to detect collisions via collision delegate and not by checking CGRectIntersectsRect in update:.
It is hard to explain how to do this in a few sentences, so here is a nice tutorial that shows how to detect collisions in Cocos2D v3 and of course there is a chapter about this in my book.
By the way you shouldn't use update:at all when manipulating physics nodes, use fixedUpdate: instead.
I hope this will help you to solve your issue.

b2DistanceJointDef anchor point

I just started doing Box2d programming. I'm trying to create a platform game. When the player (dynamic body) jump and landed on the moving platform (kinematic body), I need to make the player stay and move together with the platform. So i try using distance joint to "stick" the player to the platform. However, I've set the anchor point-Y so that the player will stay above the platform but I don't want to set a fix X. What approach should i use?
eg:
A.When player jump from right to left, it will land on left.
B. When player jump from left to right, it will land on right.
So when the player jump from any position, the X will be based on the player except Y is fix. Thank you.
b2DistanceJointDef jointDef;
b2Vec2 playerAnchor = curPlayerBody->GetWorldPoint(b2Vec2( 1, -0.8));
jointDef.Initialize( curPlayerBody, curPlatformBody, playerAnchor, curPlatformBody->GetWorldCenter() );
jointDef.length = 0;
jointDef.dampingRatio = 0;
jointDef.frequencyHz = 0;
jointDef.collideConnected = false;
playerPlatformJoint = (b2DistanceJoint*)world->CreateJoint(&jointDef);
I am assuming that you don't want to fix X because you want the player to move along the X axis on the platform.
I don't think the distance joint is a good solution for this.
One way to do what you want could be to set the friction of the player and platform fixture to a level that makes them "stick" together when the platform is moving. You should also have a look at the Friction Joint which let's you set friction in a more dynamic way. You can learn more about friction and the friction joint in the Fixture and Joint chapters of the Box2D manual.
Another way to do what you want would be to synchronize the movement of your player and the platform. But that depends a bit on how you move the platform and the player. If you are doing it by impulse for example, you could apply the same impulse that you apply to the platform to your player additionally to whatever you already apply to the player. You'll have to take properties like mass into account though.
Also take care on how you move the platform. If you are manually setting the position of the platform instead of using impulses, velocity or forces it will cause problems with the mentioned solutions.
I managed to find the answer. The idea is using weld joint and manually move the player.
Referenced from here

How to make a specific object defy gravity? (SpriteKit / Objective-C)

I'm working on a piece of code, and I want there to be gravity in the view but I want specific projectiles to defy gravity and fly across the screen. I know to get rid of the gravity on the whole view its just:
self.physicsWorld.gravity = CGVectorMake(0, 0);
But as stated I want gravity on the scene.
So I'm wondering if there is a way to take the gravity off one specific item? (i.e. the SKSpriteNode _debris item in my case)
By setting the physicsBody to not be affected by gravity.
E.g.
myNoGravityObject.physicsBody.affectedByGravity = NO;
See the documentation of SKPhysicsBody.
If you don't want a node to interact with physics calculations at all, but still want it to have a physicsBody (i.e. to make it begin to interact with things later on, or to check for collisions with other nodes), you can set
node.physicsBody.dynamic = NO;
This will cause the node to ignore gravity, as well as collisions, impulses, and the like. If you are setting up the contact delegate, note that at least one node in any given contact must be dynamic for the contact delegate to be notified of the event.

How would I build pool-cues / simplified pinball-style plungers with SpriteKit?

I'm working on a game in which the user should be able to trigger 'rods' that come out from the edge of the screen to displace elements on screen (balls). These projectiles roughly resemble pool-cues. Or perhaps pinball plungers, except that they start from the 'loaded' position (mostly offscreen), and when triggered, they eject out, then quickly retreat.
I'm unclear how I should build these with Sprite Kit.
The game uses the PhysicsEngine, and the onscreen balls should be effected both by gravity AND they should be displaced when they collide with the rods. However the rods should neither be effected by gravity, not displaced when they collide with the balls -- they should simply retreat regardless of whether they've made contact with the balls.
I realize I can set the affectedByGravity property for the rods. However because they will still displace slightly when they collide with the balls. How can I 'fix' or 'peg' them in place? Do I need to use an SKPhysicsSlidingJoint? If so, has anyone encountered any examples online? Is there a simpler way to do this?
A related physics engine, Box2D distinguishes static, kinematic, and dynamic bodies.
Kinematic bodies can move and will collide with other objects, but they are themselves not affected by dynamic bodies or forces like gravity. Thus, consider setting rod.dynamic = NO; but animate it with actions. See also here in the reference for SKPhysicsBody.

Resources