SKEmitterNode targetNode path following is inverted - ios

I created an SKEmitterNoder (standard Fire.sks template) & added it to an SKSpriteNode called ball. The thing is, I followed a tutorial of iOS Games by Tutorials & the way they taught me to create Tiled maps, is essentially flip them upon init so that (0, 0) would be in bottom left corner of the screen & NOT top left. I think this is affecting my SKEmitterNode targetNode property because as the ball is moving in the scene, the fire emitter node goes in the exact opposite direction. Could someone tell me what to do to change this? I can't change the world parameters, so I need something that would alter the SKEmitterNode trajectory so that it actually follows the ball node properly. Here's my current code:
NPCBall *ball = [[NPCBall alloc] initWithBallType:BallTypeRed andName:#"Ball Red"];
ball.position = CGPointMake(x + w/2, y + h/2);
ball.zPosition = -104.0;
[_entityNode addChild:ball];
//Create a random Vector.dx & dy for the NPC. This will apply a random impulse to kick start NPC non-stop movement.
[ball.physicsBody applyImpulse:CGVectorMake([self randomVectorGeneration].dx, [self randomVectorGeneration].dy)];
//Create a particle for the ball (fire).
SKEmitterNode *emitFire = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"Particle_Fire" ofType:#"sks"]];
emitFire.position = CGPointMake(ball.position.x, ball.position.y);
emitFire.targetNode = ball;
[_entityNode addChild:emitFire];
P.S. _entityNode, to which both the ball & SKEmitterNode fire are added, is an SKNode. Which in turn is a child of an SKNode called _worldNode. _worldNode is a child of self (which is an SKScene). This _worldNode is the one flipped to have (0, 0) coordinates begin at the bottom left.

A buddy of my'n has found a solution to this. I'm posting it here in case someone also has an inverted Tiled map where the (0, 0) coordinates are in the bottom left corner of the scene.
//Create a ball sprite.
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(20, 20)];
ball.position = CGPointMake(_worldNode.frame.size.width/2, _worldNode.frame.size.height/2);
[_entityNode addChild:ball]; //<--_entityNode is also an SKNode. It's a child of _worldNode.
ball.zPosition = -104.0;
//Create a random Vector.dx & dy for the NPC. This will apply a random impulse to kick start NPC non-stop movement.
[ball.physicsBody applyImpulse:CGVectorMake([self randomVectorGeneration].dx, [self randomVectorGeneration].dy)];
//Create a particle effect for the ball.
SKEmitterNode *emitFire = [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:#"Particle_Fire" ofType:#"sks"]];
emitFire.name = #"Fire Emitter";
emitFire.targetNode = _worldNode; //<-- This is the demon. Make the emitter follow this SKNode since it moves when the ball moves. Everything in my game is a child of _worldNode.
[ball addChild:emitFire]; //Add the emitter to the ball.

Related

SpriteNode from class not rotating correctly in Scene

I have a Class with a SpriteNode that rotates very wide, when rotated within the main Scene(as if the anchor point is in the middle of the screen and the Sprite is rotating around it). I want it to rotate around the anchor point of itself in the main Scene(anchor point on the Sprite).
So in the Class i have something like the following
- (void)createChainWithPos:(CGPoint)pos {
SKTexture *myTex...
SKTexture *myTex2...
SKSpriteNode *chainFront = [SKSpriteNode spriteWithTexture:myTex];
chainFront.position = pos;
chainFront.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:mytex.size];
[self addChild:chainFront];
[_chainParts addObject:chainFront];
SKSpriteNode *chainSide = [SKSpriteNode spriteWithTexture:myTex2];
chainSide.position = CGPointMake(chainFront.position.x, chainFront.position.y - chainSide.size.height + 6);
chainSide.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:myTex2.size;
[self addChild:chainSide];
[_chainParts addObject:chainSide];
}
I have an loop creating the chain parts in the main file but couldn't get it rotate so stripped it down in an new project. There is actually 4 chain parts but i only did two. The other two are just mirrors of the ones above with their positions mirroring the chainSide.(to position them in a chain like fashion)
and in the Scene
self.chain1 = [chain node];
[self.chain1 createChainWithPos:CGPointMake(self.size.width/2, self.size.height/2);
self.chain1.zRotation = 3.14/4;
[self addChild:self.chain1];
I have a NSMutableArray in the chain class header that i use to hold the chains.
the physics joints
for (int i = 1; i < self.chain1.chainParts.count; i++ {
SKSpriteNode *nodeA = [[self.chain1 chainParts]objectAtindex:i-1];
SKSpriteNode *nodeB = [[self.chain1 chainParts]objectAtindex:i];
SKPhysicsJointPin *pin = [SKPhysicsJointPin jointWithBodyA:nodeA.physicsBody
bodyB:nodeB.physicsBody
anchor:CGPointMake(CGRectGetMidX(nodeA.frame), CGRectGetMinY(nodeA.Frame))];
}
I found that if i set the position of the chain in the middle in the Class, it rotates correctly in the Scene. However, the physics joints just start moving randomly across the screen and isn't correct to the anchor points set. (the physics joints are set in the Scene)
I don't know if i have to convert the coordinates or play with random anchor point positions , but if someone could shed some light if would be greatly appreciated.
You do not want to use the nodes frame, you want to use the nodes size, the frame mid is the screen coordinate + the fitted node size / 2, you want the middle of your sprite only, also for pi / 4 use M_PI_4

How to let SKSpriteNode don't rotation texture

I want to create a metal ball on the screen, I had the material and run animation done. But When the ball was rolling that I hope the texture shouldn't roating. Because that made rolling ball not look like metal ball...
There is anyways or not? I could make SKSpriteNode don't rotate the ball.
SKSpriteNode *node = [self spriteNodeWithImageNamed:#"ball.png"];
node.name = #"ball";
node.size = CGSizeMake(sideSize, sideSize);
node.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius: sideSize/2];
node.physicsBody.restitution = 0.2;
node.physicsBody.friction = 0.01;
node.physicsBody.angularDamping = 0.5;
node.physicsBody.categoryBitMask = GMCategoryBall;
node.position = CGPointMake(wood.position.x,wood..position.y +wood..size.height);
node.physicsBody.contactTestBitMask =.....
node.physicsBody.collisionBitMask =.....
Here are some suggestions:
Add another SKSpriteNode without a physicsBody that is just there for looks. Have it always centered on your ball.
Add another SKSpriteNode as a sub-node of your ball, and set its rotation to the opposite of your ball's rotation.
Add another SKSpriteNode, set its physicsBody to a bit mask value that won't interact with anything else in the scene (0 is a good choice) and set a joint that keeps it locked to the ball. Turn off rotation for that Sprite.

Sprite Kit - Make SKPhysicsBody with restitution only on sides

I am trying to create a complex SKPhysicsBody that does not bounce on the top, but does allow bouncing on the sides and bottom. Currently I am creating two nodes. One that has the image of the Sprite and a no restitution PhysicsBody on the top.
My second node matches the first node, but is clear with the same size as the first node It just has a PhysicsBody on the front and bottom and has a restitution. to allow my main character to bounce off the bottom and front.
Here is the code for my current setup:
//This is the top part.
- (void)nodePhysicsBodySetup:(SKSpriteNode *)node
{
CGPoint topStart = CGPointMake(0, node.size.height);
CGPoint topEnd = CGPointMake(node.size.width, node.size.height);
SKPhysicsBody *topEdge = [SKPhysicsBody bodyWithEdgeFromPoint:topStart toPoint:topEnd];
node.physicsBody = topEdge;
//[SKPhysicsBody bodyWithBodies:#[topEdge, frontEdge, bottomEdge]]
//node.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node.frame.size];
node.physicsBody.dynamic = NO;
node.physicsBody.restitution = 0.0;
node.physicsBody.affectedByGravity = NO;
node.physicsBody.categoryBitMask = groundCategory;
node.physicsBody.collisionBitMask = mainHeroCategory;
node.physicsBody.contactTestBitMask = mainHeroCategory;
}
//This is the bottom physicsbody that matches up with the image of the main node.
- (void)bottomNodePhysicsBodySetup:(SKSpriteNode *)node
{
CGPoint topStart = CGPointMake(0, node.size.height);
CGPoint frontEnd = CGPointMake(0,0);
CGPoint bottomEnd = CGPointMake(node.size.width,0);
SKPhysicsBody *frontEdge = [SKPhysicsBody bodyWithEdgeFromPoint:topStart toPoint:frontEnd];
SKPhysicsBody *bottomEdge = [SKPhysicsBody bodyWithEdgeFromPoint:frontEnd toPoint:bottomEnd];
bottomNode.physicsBody = [SKPhysicsBody bodyWithBodies:#[frontEdge, bottomEdge]];
bottomNode.physicsBody.dynamic = NO;
bottomNode.physicsBody.affectedByGravity = NO;
bottomNode.physicsBody.restitution = 0.5;
bottomNode.physicsBody.categoryBitMask = otherCategory;
bottomNode.physicsBody.collisionBitMask = mainHeroCategory;
bottomNode.physicsBody.contactTestBitMask = mainHeroCategory;
}
Picture as screenshots are under NDA:
Currently, the Green PhysicsBody is attached to the node, and the red PhysicsBody is attached to a transparent second node with the same position as the first node.
This does not really work. My main character (mainHeroCategory) gets stuck sometimes on the node corner where the PhysicsBody with restitution and the one without meet. What is a better way to do this?
I would try to do this using only one physics body and look at the contact delegate methods to determine where the contact occurred and what the normal vector is (that information is in the SKPhysicsContact object passed in the delegate method).
Once I got that information I would apply an impulse to the mainHeroCategory object, or not, depending on where the contact occurred.
I suggest you join the physics bodies with an SKPhysicsJointFixed or by constraining the bodies with an SKConstraint or two. SpriteKit only uses the shape when merging two or more bodies with bodyWithBodies. From the docs...
The properties on the children, such as mass or friction, are ignored.
Only the shapes of the child bodies are used.
The restitution property is ignored.

Set permanent SKSpritenode image orientation

Hi I have a bunch of round SKSpriteNodes with a circle physical body. Now when these balls roll down a path I want some of these SKSpritenodes image to stay upright even when rolling. So think of an arrow pointing upwards. When the ball starts rolling the arrow spins in circles. But for some balls Id like the arrow to remain pointing up even when the ball rolls. Whats the best way of doing this?
Edit
So an answer was given but from testing it turns out it is not the correct one. Not allowing the ball to rotate affects the way it rolls down the path. So I guess what I want is rotation to be on but the image to always appear to the user like its not rotating. Thanks.
This looks like a job for SupermSKConstraint. Constraints are evaluated and applied after the physics simulation runs on each frame, so you can use them for tasks like making a node point a certain direction regardless of what physics does to it. For this, you'd want a zRotation constraint.
But there's a bit more to it than that. If you set a zero-rotation constraint on the ball:
// Swift
let constraint = SKConstraint.zRotation(SKRange(constantValue: 0))
ball.constraints = [constraint]
You'll find that SpriteKit resets the physics body's transform every frame due to the constraint, so it only sort-of behaves like it's rolling. Probably not what you want. (To get a better idea what's going on here, try adding a zero-rotation constraint to a rectangular physics body in a world without gravity, applying an angular impulse to it, and watching it try to spin in a view with showsPhysics turned on. You'll see the sprite and its physics body get out of sync and shake a bit -- probably due to accumulated rounding errors as the physics engine and the constraint engine fight it out.)
Instead, you can do a bit of what's in 0x141E's answer, but use constraints to make it less code (and run more efficiently):
Give the ball node a circular physics body. (And possibly no texture, if the only art you want for the ball is a non-rotating sprite.)
Add the arrow node as a child of the ball node. (It doesn't need its own physics body.)
Put a zero-rotation constraint on the arrow.
Wait, that doesn't work -- I told the arrow to not rotate, but it's still spinning?! Remember that child nodes are positioned (and rotated and scaled) relative to their parent node. So the arrow isn't spinning relative to the ball, but the ball is spinning. Don't worry, you can still solve this with a constraint:
Tell the constraint to operate relative to the node containing the ball (probably the scene).
Now the constraint will keep the arrow in place while allowing the ball to rotate however the physics simulation wants it to.
Here's some test code to illustrate:
// Step 1: A rectangular spinner so we can see the rotation
// more easily than with a ball
let spinner = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 300, height: 20))
spinner.position.x = scene.frame.midX
spinner.position.y = scene.frame.midY
spinner.physicsBody = SKPhysicsBody(rectangleOfSize: spinner.size)
scene.addChild(spinner)
spinner.physicsBody?.applyAngularImpulse(0.1) // wheeeeee
// Step 2: Make the arrow a child of the spinner
let arrow = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 20, height: 50))
spinner.addChild(arrow)
// Step 3: Constrain the arrow's rotation...
let constraint = SKConstraint.zRotation(SKRange(constantValue: 0))
arrow.constraints = [constraint]
// Step 4: ...relative to the scene, instead of to its parent
constraint.referenceNode = scene
Here are two methods to create a ball with a physics body and an arrow:
Add an arrow as a child of a ball
Add both the ball and the arrow directly to the scene
Here's what will happen when you add the above to the SpriteKit simulation:
The arrow will rotate when the ball rotates
Both the arrow and the ball will move/rotate independently
If you want the arrow to rotate with the ball, choose Option 1. If you want the arrow to remain fixed, choose Option 2. If you choose Option 2, you will need to adjust the rotation of the arrow to ensure that it points upward. Here's an example of how to do that.
-(void)didMoveToView:(SKView *)view {
self.scaleMode = SKSceneScaleModeResizeFill;
/* Create an edge around the scene */
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:view.frame];
// Show outline of all physics bodies
self.view.showsPhysics = YES;
CGFloat radius = 16;
SKNode *balls = [SKNode node];
balls.name = #"balls";
[self addChild:balls];
// Create 5 balls with stationary arrows
for (int i = 0;i<5;i++) {
// Create a shape node with a circular physics body. If you are targeting iOS 8,
// you have other options to create circular node. You can also create an SKSpriteNode
// with a texture
SKShapeNode *ball = [SKShapeNode node];
// Create a CGPath that is centered
ball.path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-radius,-radius,radius*2,radius*2)].CGPath;
ball.fillColor = [SKColor whiteColor];
ball.position = CGPointMake(100, 100+i*radius*2);
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:radius];
[balls addChild:ball];
// Create an arrow node
CGSize size = CGSizeMake(2, radius*2);
SKSpriteNode *arrow = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:size];
arrow.name = #"arrow";
arrow.position = CGPointZero;
[ball addChild:arrow];
// Apply angular impulse to the ball so it spins when it hits the floor
[ball.physicsBody applyAngularImpulse:-1];
}
}
- (void) didSimulatePhysics
{
SKNode *balls = [self childNodeWithName:#"balls"];
for (SKNode *ball in balls.children) {
SKNode *arrow = [ball childNodeWithName:#"arrow"];
arrow.zRotation = -ball.zRotation;
}
}
sprite.physicsBody.allowsRotation = NO;
The allowRotation property should control exactly what you are asking.

Sprite Kit - Do not allow node to move out of screen

I am creating a game where I do not want the player to be able to move out of the screen. The node follows the players moving touch. The code I have "under construction" so the player can't move out on the top or right side, but I do not want the player to be able to move out on any of the sides.
- (void)movementPlayer {
SKAction * actionMoveX = [SKAction moveToX:MIN(location2.x - playerPositionX, self.size.width - (_player.size.width/2)) duration:0];
SKAction * actionMoveY = [SKAction moveToY:MIN(location2.y - playerPositionY, self.size.height - (_player.size.height/2)) duration:0];
[_player runAction:[SKAction sequence:#[actionMoveX, actionMoveY]]];
}
You should create a physics world and add a border rectangle around the screen. This border must have a physics body that is set to collide with the physics body collision category given to your player node. If the player node starts inside the border, the player cannot leave the screen and no additional coding is required (besides properly setting up collision categories for each physics body)
RayWenderlich.com has easy to understand game tutorials that show how to handle collisions following the sprite kit manual.
In your SKScene:
self.physicsBody=[SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.gravity=CGVectorMake=(0,0);
_player.physicsBody=[SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(10,10)];//example; use bodyWithPolygonFromPath:yourCGPath if player has more complex form, or bodyWithCircleOfRadius:radius if its shape is circle
_player.physicsBody.velocity=CGVectorMake(10,10); //or more then 10,10
Good luck!
just add the bottom code to your method that is called it should stop all physical bodies from leaving the screen!! veryuseful!
SKPhysicsBody* gameborderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
// 2 Set physicsBody of scene to borderBody
self.physicsBody = gameborderBody;
// 3 Set the friction of that physicsBody to 0
self.physicsBody.friction = 1.0f;

Resources