How to locate CCParticleFire, so that it will be always at the same position as a moving sprite? - ios

I have a sprite and a particle fire. Sprite is moving, so I want fire be at the same place as sprite all the time.
That's what I tried. _abcdis the name of sprite.
CCParticleFire *emitter;
emitter = [CCParticleSystem particleWithFile:#"suchfire.particle"];
emitter.position=ccp(_abcd.position.x,_abcd.position.y);
[self addChild: emitter z:10];
When I run the game, fire is located in the lower left corner. Any ideas?

Your sprite is moving after its position is assigned to the emitter. Remember that the position you're assigning to your emitter is not going to update with the movement of the sprite.
So the best way forward is to update the emitter's position as the position for the sprite updates. This can be done in your update method.
Or better yet apply whatever movement you're apply to your sprite, be it by the game or the user, to your emitter.

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.

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

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?

didBeginContact not called on fast moving sprite

I have a game where a user is dragging around my main sprite. The main sprite collides with other sprites just fine except when the user drags the main sprite very quickly. Sometimes when the main sprite is moving quickly, the physics bodies just pass right through each other and the two sprites suddenly overlap. I have a breakpoint set that logs the hit count at didBeginContact, and it is not hit.
Is there a limit to how fast a sprite can move and still be covered by didBeginContact? Am I allowing the user to move the sprite faster than the game cycle can handle the collisions?
Again, when the sprite is moving at slow speeds, the physics are working perfectly.
Remember, these things are all calculated frame by frame. You're probably moving the sprite so fast that its ending up on the other side of the screen in too few frames to count as a collision. If someone is spastically moving their finger around it might not catch it. You could put some kind of speed limit on the sprite or something.
try to set physic body with usesPreciseCollisionDetection = YES

Does SpriteKit apply physics if I modify the position and rotation of a SKSpriteNode directly without an SKAction?

For example if I want to do my own custom animation and move an SKSpriteNode every frame programmatically by x += 10, will Sprite Kit still apply physics correctly or must I always use SKAction?
Manually moving a node with a physics body is possible regardless of how or when you do it. But in any case it's not recommended since it can adversely affect the physics simulation. The node (view) could be out of sync with the position of the body for 1 frame, and you might move the body into a collision which the physics engine will forcibly resolve, causing jumps, jitter, exploding velocities or skipping collisions.
When you use physics, stick to moving the physics body through force, impulse or changing the body velocity directly.
No, you don't have to use SKAction to move SKSpriteNode. This approach works fine for me:
- (void)update:(CFTimeInterval)currentTime {
myNode.position = CGPointMake(myNode.position.x + 0.1,myNode.position.y);
}
All physics work as expected

How to implement mouse joint in Sprite Kit?

I have working implementation of drag and drop feature written in Cocos2d + Box2d for iOS. I need to port it to Sprite Kit. The logic is pretty basic:
when user touching the screen, find sprite under the finger
create mouse joint between found sprite and the scene's physics body, set joint's target to position of touch
when touches moved, update joint's target to new position
when touches ended, remove the joint
Everything is working quite well. I like the way physics is simulated when touches ends - the dragged shape has velocity dependent on dragging speed and direction, so when I left my finger from the screen while moving the sprite, it will continue moving in the same direction, but now affected by gravity and damping.
Unfortunately, I'm not able to reproduce the same effect using Sprite Kit. There is no such joint like mouse joint, but I have tried using other joint types. I almost succeeded with SKPhysicsJointFixed - I'm creating new sprite and joint between it and dragged sprite, when touches moving I'm moving the newly created sprite. Unfortunately it doesn't work like mouse joint in Cocos2d + Box2d - while dragging the sprite, its velocity always equals zero. So, every time I left my finger from the screen, the dragged sprite stops immediately and start falling affected by gravity. No matter how fast I move the finger when dragging, after releasing dragged shape, it behaves exactly the same way.
My question is how to implement mouse joint in Sprite Kit, or how to implement drag and drop feature that works like described above?
Update:
This is a box2d mouse joint example that could give you more clear view on what I am trying to implement using Sprite Kit:
http://blog.allanbishop.com/wp-content/uploads/2010/09/Box2DJointTutorial1.swf
I'm pretty new to iOS development so I guess this might not be the best way, but this is how I solved it and it seems to work pretty smooth actually.
I'm using a UIPanGestureRecognizer to handle the touch event. I set this one up in my didMoveToView: with this code:
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
An UIPanGestureRecognizer is passed to handlePan: and I check with recognizer.state == UIGestureRecognizerStateEnded if the touched stopped. This is where I want to "release" the object and "let it fly away". For doing so I needed to calculate a few things, first of all I get the velocity of the finger/touch with this code:
CGPoint velocity = [recognizer velocityInView:recognizer.view];
(I use the same method (handlePan:) with other statements for getting the right object when touch starts, and letting the object be under the finger all the time by setting the position of the object to the location of the touch when moving)
Now I know the velocity, but I still don't know how much force I need to apply to the object. You should be able to calculate the force by this formula: Force = mass * acceleration. We know the mass (object.physicsBody.mass) and we know the velocity. To get the acceleration we need the time as well because acceleration = velocity / time.
In my update: method that is called every time a new frame is to be rendered I calculate the difference between the last time a frame was about to be rendered by doing something like this:
self.delta = currentTime - self.lastTime;
self.lastTime = currentTime;
I now can calculate which force that is needed to get the object moving in the velocity I'm "dragging it in". To do this I do the following:
[self.currentNode.physicsBody applyForce:CGVectorMake(velocity.x/self.delta * self.currentNode.physicsBody.mass, -velocity.y/self.delta * self.currentNode.physicsBody.mass)];
I take velocity divided with the difference in time since last frame (self.delta) to get the acceleration, and then multiply it with the mass of the object to get the force needed to keep (or actually getting) the object moving in the same direction and in the same velocity as it was moved by my finger.
This is working for me at the moment and I hope it helps other people too, and please tell me if I got something wrong or if there is a better solution. So far I have not found any "native solution".
If the only issue is velocity, then that is simple to fix.
Subtract the current touch position from the previous touch position to get the velocity between the last and current touch. Use applyForce: to apply this velocity to the body.
In order to prevent the body from moving on its own while dragging, read out the new velocity from the body after calling applyForce: and keep it in an ivar and set the body's velocity to zero.
When the touch ends, set the body's velocity to the one you keep as an ivar.
If this doesn't work, try using applyImpulse: and/or setting the velocity before calling any of the two methods, ie:
sprite.physicsBody.velocity = bodyVelocity;
[sprite.physicsBody applyForce:touchVelocity];
bodyVelocity = sprite.physicsBody.velocity;
sprite.physicsBody.velocity = CGVectorMake(0, 0);
That way you can keep the body's velocity without losing control over it while dragging.

Resources