applying masks to SKEmitterNodes - ios

May be some one can give me a hand… I’m trying to add a couple of SKEmitterNodes in their own SKCropNodes.
My code:
// left emitter node
NSString *path = [[NSBundle mainBundle] pathForResource:#"LeftParticle" ofType:#"sks"];
SKEmitterNode *lEmitterNode = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
// left crop node
SKSpriteNode *lMask = [SKSpriteNode spriteNodeWithColor:[UIColor blackColor] size:CGSizeMake(self.size.width/2, self.size.height)];
[lMask setAnchorPoint:CGPointZero];
SKCropNode *lCropNode = [SKCropNode node];
lCropNode.maskNode = lMask;
// move the left emitter under the mask
lEmitterNode.position = CGPointMake(CGRectGetMinX(lMask.frame) + lMask.size.width / 2, self.size.height);
[lCropNode addChild:lEmitterNode];
[self addChild:lCropNode];
// right emitter node
path = [[NSBundle mainBundle] pathForResource:#"RightParticle" ofType:#"sks"];
SKEmitterNode *rEmitterNode = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
// right crop node
SKSpriteNode *rMask = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(self.size.width/2, self.size.height)];
[rMask setAnchorPoint:CGPointZero];
rMask.position = CGPointMake(rMask.size.width, 0);
SKCropNode *rCropNode = [SKCropNode node];
rCropNode.maskNode = rMask;
// move the right emitter under the mask
rEmitterNode.position = CGPointMake(CGRectGetMinX(rMask.frame) + rMask.size.width / 2, self.size.height);
[rCropNode addChild:rEmitterNode];
[self addChild:rCropNode];
And this is the result:
As you can see, my red particles render under the left mask... Why?
I’ve tried to reduce the size of mask with:
lMask.xScale = lMask.yScale = 0.9;
rMask.xScale = rMask.yScale = 0.9;
And this is the result:
I presume it’s a problem with render buffer, or may be it’s something about zPosition, or a bug, or may be I’m really lost.
Thnx

Related

different reaction to collision on node using sprite kit

I have rectangle shape paddle node, my question is - is it possible to "cut" node in half so when, for example ball, hit right side of node ball will go back with bigger angle, that it came, and same thing on other side. Im bad with words so, here are image of what I want to do :
For paddle node i use this code:
paddle = [[SKSpriteNode alloc] initWithImageNamed: #"board.png"];
paddle.name = paddleCategoryName;
paddle.position = CGPointMake(self.frame.origin.x + 50, CGRectGetMidY(self.frame));
[self addChild:paddle];
paddle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:paddle.frame.size];
paddle.physicsBody.restitution = 0.1f;
paddle.physicsBody.friction = 0.4f;
paddle.physicsBody.dynamic = NO;
and for ball :
ball = [SKSpriteNode spriteNodeWithImageNamed: #"ball.png"];
[self addChild:ball];
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.size.width];
ball.physicsBody.friction = 0.0f;
ball.physicsBody.restitution = 1.0f;
ball.physicsBody.linearDamping = 0.0f;
ball.physicsBody.allowsRotation = NO;

How can I apply physics to a SKShapeNode in Sprite Kit?

In the following example, there are three things on the screen:
ball (a SKShapeNode)
spriteContainer (a SKSpriteNode that contains ball2, a SKShapeNode)
box (a SKSpriteNode)
Why does ball fall out of view? Does a SKShapeNode need to be inside a SKSpriteNode to have physics properly applied to it?
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKColor * warmRed = [SKColor colorWithRed:0.99 green:0.41 blue:0.25 alpha:1.0];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.backgroundColor = warmRed;
//falls out of view
SKShapeNode * ball = [[SKShapeNode alloc] init];
CGMutablePathRef ballPath = CGPathCreateMutable();
CGPathAddArc(ballPath, NULL, size.width-40, self.size.height/2, 20, 0, M_PI*2, YES);
ball.path = ballPath;
ball.lineWidth = 2;
ball.fillColor = warmRed;
ball.strokeColor = [SKColor whiteColor];
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:20];
[self addChild:ball];
//lands on bottom of screen
SKShapeNode * ball2 = [[SKShapeNode alloc] init];
CGMutablePathRef ball2Path = CGPathCreateMutable();
CGPathAddArc(ball2Path, NULL, 0, 0, 20, 0, M_PI*2, YES);
ball2.path = ball2Path;
ball2.lineWidth = 2;
ball2.fillColor = warmRed;
ball2.strokeColor = [SKColor whiteColor];
CGSize spriteContainerSize = CGSizeMake(40,40);
CGPoint spriteContainerPosition = CGPointMake(size.width/2, size.height/2);
SKSpriteNode * spriteContainer = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:spriteContainerSize];
spriteContainer.position = spriteContainerPosition;
spriteContainer.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spriteContainerSize];
[spriteContainer addChild:ball2];
[self addChild:spriteContainer];
//lands on bottom of screen
CGSize boxSize = CGSizeMake(40,40);
CGPoint boxPosition = CGPointMake(boxSize.width, size.height/2);
SKSpriteNode * box = [SKSpriteNode spriteNodeWithColor:[SKColor blackColor] size:boxSize];
box.position = boxPosition;
box.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:boxSize];
[self addChild:box];
}
return self;
}
Screenshot:
https://dl.dropboxusercontent.com/u/164157126/example.jpg
Note that you don't set a position for the node which falls off the screen, but set a position for the other two nodes you create.
The default position of a node is 0,0. Your ball will appear at the bottom left of the scene, and since it is over the edge body you defined, will fall off immediately.
Set the ball's position appropriately so that it does not intersect the edge of the screen, and the ball will not fall off.

Spritekit scene anchorpoint affecting child node positioning

I have created my SKScene subclass which sets the anchorpoint and then adds one SKSpriteNode for the world, the world has multiple SKSpriteNodes for the obstacles, player etc. I am also centering on the
The problem I am having is that as I have set the anchorpoint of the scene to (0.5, 0.5), the position of any child node that I add to the world starts at the center of the world. How do I fix the postion of the nodes so that position = (0,0) will be at the bottom left of the world node and any child nodes added to it, instead of the center?
#implementation LevelScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
NSLog(#"width:%f height:%f", self.view.bounds.size.width, self.view.bounds.size.height);
// set the physics body
self.physicsWorld.gravity = CGVectorMake(0,-5);
self.physicsWorld.contactDelegate = self;
self.anchorPoint = CGPointMake(0.5, 0.5);
NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"LevelScene" ofType:#"plist"]];
NSString *backgroundImage = [plistDict objectForKey:#"background"];
// add a node that holds the background
background = [SKSpriteNode spriteNodeWithTexture:[SKTexture textureWithImageNamed:backgroundImage] size:CGSizeMake(1024, 768)];
background.position = CGPointMake(0, 0);
[self addChild:background];
world = [SKSpriteNode spriteNodeWithColor:[SKColor brownColor] size:CGSizeMake(1024, 768)];
world.position = CGPointMake(0, 0); // this should be bottom-left
world.size = CGSizeMake(1024, 768);
world.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:world.frame];
world.physicsBody.categoryBitMask = worldCategory;
[self addChild:world];
// load in the game tiles (these are non-dynamic tiles the player can use)
[self loadInTiles];
// add in game object to the world skspritenode - this just creates a subclass of skspritenode and sets position to 0,0
[self addGameObject:CGPointMake(0, 0)];
...
}
// ...setup functions, input handling, etc
-(void)didSimulatePhysics {
// setup the player to move depending on their direction
[player updatePosition];
[self centreOnNode:player];
}
-(void)centreOnNode: (SKSpriteNode *)node {
CGPoint cameraPositionInScene = [node.scene convertPoint:node.position fromNode:node.parent];
CGFloat x = node.parent.position.x - cameraPositionInScene.x;
CGFloat y = node.parent.position.y - cameraPositionInScene.y;
NSLog(#"camera x:%f y:%f", x, y);
NSLog(#"world frame origin x:%f y:%f", world.frame.origin.x, world.frame.origin.y);
node.parent.position = CGPointMake(x, y);
}
If you want to set the world sprite's origin to the bottom left side, just set it's anchor point.
world.anchorPoint = CGPointMake(0,0);
With this, the world sprite's coordinate system will be just like that of the scene's default.
Make sure to remove the line:
self.anchorPoint = CGPointMake(0.5, 0.5);
Replace this row:
world.position = CGPointMake(0, 0);
by this:
world.position = CGPointMake(-CGRectGetMidX(self.frame), -CGRectGetMidY(self.frame));
(0,0) is the center of the scene, since you set anchor point of the SKScene to (0.5,0.5)

Sprite Kit pin joints appear to have an incorrect anchor

I'm testing out pin joints with Sprite Kit, and I'm finding something unusual happening.
My desired setup is this: one wide, flat box, and two circles; the circles are connected via SKPhysicsPinJoints to the box, so they can act as wheels.
Here's my code. I've tried to make it as concise as possible:
- (SKNode*) createWheelWithRadius:(float)wheelRadius {
CGRect wheelRect = CGRectMake(-wheelRadius, -wheelRadius, wheelRadius*2, wheelRadius*2);
SKShapeNode* wheelNode = [[SKShapeNode alloc] init];
wheelNode.path = [UIBezierPath bezierPathWithOvalInRect:wheelRect].CGPath;
wheelNode.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:wheelRadius];
return wheelNode;
}
- (void) createCar {
// Create the car
SKSpriteNode* carNode = [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(150, 50)];
carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];
carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild:carNode];
// Create the left wheel
SKNode* leftWheelNode = [self createWheelWithRadius:30];
leftWheelNode.position = CGPointMake(carNode.position.x-80, carNode.position.y);
[self addChild:leftWheelNode];
// Create the right wheel
SKNode* rightWheelNode = [self createWheelWithRadius:30];
rightWheelNode.position = CGPointMake(carNode.position.x+80, carNode.position.y);
[self addChild:rightWheelNode];
// Attach the wheels to the body
CGPoint leftWheelPosition = leftWheelNode.position;
CGPoint rightWheelPosition = rightWheelNode.position;
SKPhysicsJointPin* leftPinJoint = [SKPhysicsJointPin jointWithBodyA:carNode.physicsBody bodyB:leftWheelNode.physicsBody anchor:leftWheelPosition];
SKPhysicsJointPin* rightPinJoint = [SKPhysicsJointPin jointWithBodyA:carNode.physicsBody bodyB:rightWheelNode.physicsBody anchor:rightWheelPosition];
[self.physicsWorld addJoint:leftPinJoint];
[self.physicsWorld addJoint:rightPinJoint];
}
What I'm expecting is that the pin joints are anchored at their centre points; however, when I test this, the anchors for the joints appear to be far off.
Am I missing something really obvious?
I also had this issue and the cause is setting the physics body before setting the sprites position.
carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];
carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
Change the above to
carNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
carNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carNode.size];
It should work. Thanks Smick.
SpriteKit: How to create Basic Physics Joints
Try this code, I used yours and got weird issues, so started from scratch.
- (SKShapeNode*) makeWheel
{
SKShapeNode *wheel = [[SKShapeNode alloc] init];
CGMutablePathRef myPath = CGPathCreateMutable();
CGPathAddArc(myPath, NULL, 0,0, 16, 0, M_PI*2, YES);
wheel.path = myPath;
return wheel;
}
- (void) createCar
{
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:CGRectMake(0, 0, self.size.width, self.size.height)];
// 1. car body
SKSpriteNode *carBody = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(120, 8)];
carBody.position = CGPointMake(200, 200);
carBody.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:carBody.size];
[self addChild:carBody];
// 2. wheels
SKShapeNode *leftWheel = [self makeWheel];
leftWheel.position = CGPointMake(carBody.position.x - carBody.size.width / 2, carBody.position.y);
leftWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
[self addChild:leftWheel];
SKShapeNode *rightWheel = [self makeWheel];
rightWheel.position = CGPointMake(carBody.position.x + carBody.size.width / 2, carBody.position.y);
rightWheel.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
[self addChild:rightWheel];
// 3. Join wheels to car
[self.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:carBody.physicsBody bodyB:leftWheel.physicsBody anchor:leftWheel.position]];
[self.physicsWorld addJoint:[SKPhysicsJointPin jointWithBodyA:carBody.physicsBody bodyB:rightWheel.physicsBody anchor:rightWheel.position]];
// 4. drive car
[carBody.physicsBody applyForce:CGVectorMake(10, 0)];
}

How do you scale SKSpirteNode without anti aliasing

I am trying to scale an SKSpriteNode object without smoothing/anti-aliasing (I'm using pixel-art so it looks better pixelated).
Is there a property I need to set to do this? This is the code I am using to render the sprite:
SKTextureAtlas *atlas = [SKTextureAtlas atlasNamed:#"objects"];
SKTexture *f1 = [atlas textureNamed:#"hero_1.png"];
SKSpriteNode *hero = [SKSpriteNode spriteNodeWithTexture:f1];
[self addChild: hero];
hero.scale = 6.0f;
The image is scaled correctly but blurry/smoothed out. This is hero_1.png .
Try,
SKTexture *texture = [SKTexture textureWithImageNamed:#"Fak4o"];
texture.filteringMode = SKTextureFilteringNearest;
SKSpriteNode *newHero = [SKSpriteNode spriteNodeWithTexture:texture];
newHero.position = CGPointMake(200, 200);
[newHero setScale:50];
[self addChild:newHero];
SKTextureFilteringNearest
Each pixel is drawn using the nearest point in the texture. This mode
is faster, but the results are often pixelated.
Swift:
sprite.texture!.filteringMode = .Nearest
Just a note, if you create a SKSpriteNode instead of SKTexture, you can set the SKTextureFilteringNearest like in the following example:
SKSpriteNode *asteroid = [SKSpriteNode spriteNodeWithImageNamed:#"o1"];
asteroid.size = CGSizeMake(36, 24);
asteroid.position = CGPointMake(startX, startY);
asteroid.name = #"obstacle";
// >>>
asteroid.texture.filteringMode = SKTextureFilteringNearest;
// <<<
[self addChild:asteroid];
try this:
hero.xscale = 6.0f;
hero.yscale = 6.0f;

Resources