I am trying to mirror my SKSpriteNode using SKAction *mirrorDirection = [SKAction scaleXTo:-1 y:1 duration:0.0]; but every time I do, the sprite's physics body seems to get messed up and it drops off the screen. I have several objects (floors) beneath the sprite and it falls through all of them as if they are not there.
This only happens when I mirror the sprite. Anyone know how to fix this?
Update:
Reseting the physics body as one answer suggested unfortunately did not fix the problem. It appears that only the contact part of the physics body malfunctions. Gravity still has an effect as the little guy drops like a rock.
I also tried to reset by again self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.size.width, self.size.height)];
right after the self.xScale = -1; but this also did not fix the issue.
Add your mirror-able node as a child of some regular SKNode and set the physics body on this parent node instead of the negatively scaled node.
I don't know how to fix this but I would like to suggest one way you could create a mirrored sprite.
To achieve this set the x or y scale of your sprite node to -1. Then use the SKView method textureFromNode: to create a texture from this mirrored node.
You can then use this texture to create a new sprite node that is mirrored but doesn't require any negative scaling.
Don't use an SKAction, just set it directly to the SKSpriteNode's xScale property.
self.yourSprite.xScale = -1;
Roecrew is right about setting the xScale property directly. I would suggest you try this:
node.xScale = -1;
node.physicsBody = node.physicsBody;
You will need to 'reset' the physicsBody each time you change the xScale property.
The xScale issue with physicsBody is a bug in SpriteKit, but I was able to 'retain' the physicsBody using the second line.
I'm meeting the problem exactly like yours. I spent about 2 hours to figure it out.
Just init your physicsBody after you scaleX, i dont know why but i had correct this issue by doing this way.
walkRight = [SKAction sequence:#[resetDirection,[SKAction runBlock:^{
[self changePhysicsDirectionRight];
}],[SKAction repeatActionForever: walk]]];
walkLeft = [SKAction sequence:#[mirrorDirection,[SKAction runBlock:^{
[self changePhysicsDirectionLeft];
}],[SKAction repeatActionForever: walk]]];
walkRight and walkLeft is my action when changing direction, and resetDirection and mirrorDirection is exactly the action i used to scaleXTo:1 and scaleXTo:1
So after i scaleXTo i use a method call changePhysicsDirectionRight to re-init my physicBody like
- (void)changePhysicsDirectionRight{
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.size.width,self.size.height)];
self.physicsBody.categoryBitMask = guyCategory;
self.physicsBody.contactTestBitMask = 0;
self.physicsBody.collisionBitMask = 0;
}
Remember to re-assign all your category and everything like you init before.
I hope someone pro at spritekit can tell me the reason why ....
Related
I have two nodes one near another. And I want one node to be on top of another when I tap. I do so like this:
SKAction *moveUp= [SKAction moveByX:0 y:25 duration:0.1];
SKAction *moveDown= [SKAction moveByX:0 y:-25 duration:0.1];
SKAction *playerSequence = [SKAction sequence:#[moveUp,moveDown]];
[self.player runAction:[SKAction repeatAction:playerSequence count:1] withKey:#"attack"];
And instead I get that one node pushes the other (bots nodes created via editor and both body type is set to none).
I tried adding these to didMoveToView on both nodes:
node.physicsBody.dynamic = NO;
node.physicsBody.collisionBitMask = 0;
node.physicsBody.contactTestBitMask = 0;
node.physicsBody.affectedByGravity = NO;
I even tried setting velocity to 0 on Update. And still no effect.
Set your bit masks in
-(void)didBeginContact:(SKPhysicsContact *)contact
as shown in this post.
I think you have a timing issue if you set the bit masks in
didMoveToView
because only one of those will be run at a time and both physics bodies will need to mutually agree not contact each other.
You have to set the physics body to nil:
node.physicsBody = nil;
I'm very new to cocos2d development.
What I am trying to implement is some sprite nodes with physics bodies. As far as I understand, you're supposed to add them to the scene like this ("physics" here is the name of CCPhysicsNode declared earlier):
[physics addChild:node];
instead of
[self addChild:node];
The second one is pretty self-explanatory, I never had any trouble with it. But with the first the position of collision shapes does not match the position of the actual sprite (as seen in debug drawing, and by offset I mean greatly offset, like 2x the actual position). This is how I declare and add the node:
CCSprite *sprite = [CCSprite spriteWithImageNamed:#"sprite.png"];
sprite.position = position;
sprite.physicsBody = [CCPhysicsBody bodyWithRect:[sprite boundingBox] cornerRadius:0];
sprite.physicsBody.collisionType = #"SomeCollisionType";
sprite.name = #"Name";
[physics addChild:sprite];
What am I doing wrong? Please explain me how to make the positions match. TIA.
I have two nodes in my scene. The first node is a ball at the top of my view. The second node is a rectangle at the bottom of my view to stop the ball from dropping out of view. I am wanting this ball to have NO bounciness at all. I am wanting it to just completely stop when it hits the rectangle. I don't know what I am doing wrong. Any help would be greatly appreciated!
SKSpriteNode *rectangle = [SKSpriteNode spriteNodeWithColor:[UIColor whiteColor] size:CGSizeMake(self.frame.size.width, 50)];
bottom.position = CGPointMake(self.frame.size.width / 2, 0);
bottom.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(rectangle, bottom.size.height)];
bottom.physicsBody.dynamic = NO;
[self addChild:bottom];
SKSpriteNode *ball = [SKSpriteNode spriteNodeWithImageNamed:#"ball"];
ball.position = CGPointMake(node.position.x, node.position.y);
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius: 5];
ball.physicsBody.restitution = 0;
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 0, 0);
CGPathAddLineToPoint(path, NULL, [self randomX], [self randomY]);
SKAction *move = [SKAction followPath:path asOffset:YES orientToPath:NO duration:3.0];
[ball runAction:move];
[self addChild: ball];
Why is is still bouncing off the rectangle?
In my experience, you should in more cases than not be working with frameworks like they expects you to, hacks just end up with weird quirks like the one you encountered. In this case, as #LearnCocos2D said, you should probably be using [ball.physicsBody applyImpulse:(CGVEctor)] if you need the ball to move along a specific path but still maintain a dynamic physicsBody. If you then set the restitution to 0, it will not bounce. I promise.
Read up on vectors and vector maths if you need the ball to follow a specific path (it's knowledge that is good to have anyways when working with physics). I've found this to be a good resource for that. It's for openFrameworks, hence C++, but the concept remains the same.
And if you still really need to use a CGPath, then I think you should tell us a bit more specific about what you need to accomplish. There might be a better solution, or maybe we should file a bug to Apple. Sprite-Kit is still fairly young, I have myself encounter problems I believe to be bugs.
The documentation indicates that the value of the "restitution" property of SKPHysicsBody is "how much energy the physics body loses when it bounces off another object." (here). By setting the restitution to zero, you make the ball as bouncy as possible - it loses 0 energy. If you set the restitution to 1 - loses all energy - it should stop.
i have a method to create sprites with an initial position, final position, height, image of the sprite and a name property to the sprite (to access the sprite later)
The problem is when i need to debug, because i can't display, for example, a number (of a position in this case...)
In this case, i want to know what sprite is disapearing sooner than expected, so i want to set a new parameter in my method which would be an NSString number(1,2,3..)so i could localize what sprite is making troubles... but i cant display this number or i don't know how. The other debugging technique i thought to do were to put an if(x.position> 600)callAMethod with a label, but... the coordinates are CGPoint and not float. So i'm a bit lost... Do anybody know a technique to do this??
here is my method to create sprites:
-(void)crearMontanaconLaPosicionFinal:(CGFloat)xFinal inicial:(CGFloat)xInicial altura:(CGFloat)altura imagen:(NSString*)imagen nombre:(NSString*)nombre
{
CGPoint posicionFinal = CGPointMake(xFinal, altura);
SKSpriteNode *montaña = [SKSpriteNode spriteNodeWithImageNamed:imagen];
montaña.name = nombre;
SKAction* parallaxMoveAction3 = [SKAction sequence:#[[SKAction moveTo:posicionFinal duration:20],[SKAction customActionWithDuration:0 actionBlock:^(SKNode* montaña, CGFloat elapsedTime){
[montaña setPosition:CGPointMake(xInicial,altura)];
}]]];
montaña.position = CGPointMake(xInicial, altura);
SKAction *repetir=[SKAction repeatActionForever:parallaxMoveAction3];
[montaña runAction:repetir];
[self addChild:montaña];
}
I have a sprite with a given texture using:
joyStickRight = [SKSpriteNode spriteNodeWithImageNamed:#"joyStick.png"];
And I'd like to change it when the user touches and holds the sprite. When I detect the touch, I try changing the sprite texture by calling the same function with a different image:
joyStickRight = [SKSpriteNode spriteNodeWithImageNamed:#"joyStick_rollOver.png"];
But this does not seem to work. Nothing changes.
This for an iPad application. I am creating the on screen elements with SKSpriteNodes.
This is likely to be related to variable scope. I'm guessing you are trying to modify another instance of 'joyStickRight' SKSPriteNode. This second instance would not have been added to the scene and therefore not taking any effect.
The only way i found out to change textures ist to swap them via action like this:
SKTexture *texture1 = [SKTexture textureWithImageNamed:#"texture1"];
SKTexture *texture2 = [SKTexture textureWithImageNamed:#"texture2"];
SKAction *swapTextures = [SKAction repeatAction:[SKAction animateWithTextures:#[texture1,texture2] timePerFrame:0.1] count:3];
[node (in your case joyStickRight) runAction:swapTextures];
I still hope this is not the only solution, and also wonder why it does not work when i run it once!!!