Sprite's Boundingbox in SpriteKit - sprite-kit

We used below code to get sprite's collision area in cocos2d.
CGRect heroRect = [heroBird boundingBox];
if(CGRectContainsPoint(heroRect, bullet.position))
How to get boundingBox in sprite-kit?

Use the following line to get the bounding box:
CGRect heroRect = [heroBird calculateAccumulatedFrame]
see also Apple Docu

SKSpriteNode *heroBird;
heroBird = [SKSpriteNode spriteNodeWithImageNamed:#"heroBird.png"];
//heroBird rect can be set to whatever you like, shapes,rects,circles
heroBird.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:heroBird.size];
// set heroBird collision, category and contact bitmasks
// detect using didBeginContact method
CGRect heroRect = heroBird.frame;

Related

SKNode nodeAtPoint: / containsPoint: not the same behaviour for SKSpriteNode and SKShapeNode

The nodeAtPoint: gives not the same result if using SKShapeNode and SKSpriteNode. If i am correct nodeAtPoint: will use containsPoint: to check which nodes are at the given point.
The docu states that containsPoint: will use its bounding box.
I set up a simple scene, where in situation 1 the circle is parent of the purple node and in situation 2 the green node is parent of the purple node.
I clicked in both cases in an area where the bounding box of the parent should be.
The result is differs. If i use a SKSpriteNode the nodeAtPoint: will give me the parent. If i use SKShapeNode it returns the SKScene.
(The cross marks where i pressed with the mouse.)
The code:
First setup:
-(void)didMoveToView:(SKView *)view {
self.name = #"Scene";
SKShapeNode* circle = [SKShapeNode node];
circle.path = CGPathCreateWithEllipseInRect(CGRectMake(0, 0, 50, 50), nil);
circle.position = CGPointMake(20, 20);
circle.fillColor = [SKColor redColor];
circle.name = #"circle";
SKSpriteNode* pnode = [SKSpriteNode node];
pnode.size = CGSizeMake(50, 50);
pnode.position = CGPointMake(50, 50);
pnode.color = [SKColor purpleColor];
pnode.name = #"pnode";
[self addChild: circle];
[circle addChild: pnode];
}
Second setup:
-(void)didMoveToView:(SKView *)view {
self.name = #"Scene";
SKSpriteNode* gnode = [SKSpriteNode node];
gnode.size = CGSizeMake(50, 50);
gnode.position = CGPointMake(30, 30);
gnode.color = [SKColor greenColor];
gnode.name = #"gnode";
SKSpriteNode* pnode = [SKSpriteNode node];
pnode.size = CGSizeMake(50, 50);
pnode.position = CGPointMake(30, 30);
pnode.color = [SKColor purpleColor];
pnode.name = #"pnode";
[self addChild: gnode];
[gnode addChild: pnode];
}
Call on mouse click:
-(void)mouseDown:(NSEvent *)theEvent {
CGPoint location = [theEvent locationInNode:self];
NSLog(#"%#", [self nodeAtPoint: location].name);
}
Did i miss something? Is it a bug in SpriteKit? Is it meant to work that way?
The short answers: yes, no, yes
The long answer...
The documentation for nodeAtPoint says that it
returns the deepest descendant that intersects a point
and in the Discussion section
a point is considered to be in a node if it lies inside the rectangle returned by the calculateAccumulatedFrame method
The first statement applies to SKSpriteNode and SKShapeNode nodes, while the second only applies to SKSpriteNode nodes. For SKShapeNodes, Sprite Kit ignores the node's bounding box and uses the path property to determine if a point intersects the node with CGPathContainsPoint. As shown in the figures below, shapes are selected on a per-pixel basis, where white dots represent the click points.
Figure 1. Bounding Boxes for Shape (blue) and Shape + Square (brown)
Figure 2. Results of nodeAtPoint
calculateAccumulatedFrame returns a bounding box (BB) that is relative to its parent as shown in the figure below (brown box is the square's BB). Consequently, if you don't adjust the CGPoint for containsPoint appropriately, the results will not be what you expected. To convert a point from scene coordinates to the parent's coordinates (or vice versa), use convertPoint:fromNode or convertPoint:toNode. Lastly, containsPoint uses a shape's path instead of its bounding box just like nodeAtPoint.

Is there a way to make a soft body with Spritekit using SKSpriteNode and PhysicsBody parameters?

I have the following sprite that falls to the bottom of the screen:
// The View
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.contactDelegate = self;
// The Sprite
SKSpriteNode *cube = [[SKSpriteNode alloc] initWithImageNamed:#"cube"];
[cube setPosition:CGPointMake(160,250);
[self addChild:cube];
// The Physics
cube.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:cube.frame.size];
cube.physicsBody.dynamic = YES;
cube.physicsBody.affectedByGravity = YES;
cube.physicsBody.mass = 0.02;
Is there a way to make it so its sides are bulging when it hits the bottom border of the screen? Something that would be Jelly like or a soft body that still maintains its shape to some extent but bulges out under its own weight? I hope this makes sense....
Visit the site https://gist.github.com/kazukitanaka0611/4b9d4ac9dff0cd317b6c it have explanation and source code for soft bodies (jelly) in sprite kit
quick and easy way without math:
1 use flash to tween your box warping.
2 export the tweened frames as a sprite sheet (texture atlas)
3 animate the texture atlas on contact with an edge physics body in your scene.
your box will fall and on contact animate the separate images to give the impression its warping/bulging sides.
i used this method and it works - in other words it gives the desired effect, which in my view is what is important - your gamers don't care how you did it, as long as it looks great.

Rotate CGRect property of a CCSprite ?

I have a sublclass of a CCSprite that rotates throughout the game and there is a shield that has to rotate around the sprite according to the sprite's rotation. So if the sprite's rotation is 75 degrees there should be a CGRect located at 75 degrees. The dimensions of the CGRect are subordinate as it almost resembles a square.
What I did is:
I subclassed CCSprite and added a property called shieldArea.
Upon initialization I set this rect to be
self.shieldArea = CGRectMake(self.position.x-30, self.position.y, 8, 10);
Then I rotate the sprite itself, however, the rect stays at its initial position.
I hoped that the CGrect would be affected by the rotation, but I kind of expected it not to affect it, of course, why should it ? So, my question is, how do I rotate a CGRect at all ? Or do I have to add a new CGRect all the time ?
Side notes: I do not want to use Box2d or anything the like. I handle collision detection myself.
Have you tried CGAffineTransform?
Something like this:
float centerX = myOldRect.origin.x + (myOldRect.size.width / 2.0);
float centerY = myOldRect.origin.y + (myOldRect.size.height / 2.0);
CGAffineTransform rotation = CGAffineTransformMakeRotation(someAngleInRadians);
CGAffineTransform moveAnchor = CGAffineTransformMakeTranslation(centerX, centerY);
CGAffineTransform centeredRotation = CGAffineTransformConcat(moveAnchor, rotation);
CGRect rotatedRect = CGRectApplyAffineTransform(myOldRect, centeredRotation);
Note, this is NOT tested. Use at your own risk :p

Cocos2D - filling a sprite

UIImageViews have a property called contentMode that you can use as
imageView.contentMode = UIViewContentModeScaleAspectFit;
and it will fill the entire view with your image without distorting, even if it has to bleed the image to do that.
Is there any similar stuff on Cocos2D? Sorry about the question, but I am new to Cocos2d.
I am creating the sprite like this:
CCTexture2D *textBack = [[CCTexture2D alloc] initWithImage:image];
CCSprite *sprite = [CCSprite spriteWithTexture:textBack];
thanks.
The equivalent method to performing a UIViewContentModeScaleAspectFit would be the .scale property. When a CCNode (or any of the sub nodes such as CCSprite etc.) is first created, the scale property is 1. Keep increasing it to scale the sprite up proportionally.
sprite.scale = 2.0f; // Scales the sprite proportionally at a factor of 2
As for it fitting to a specific size, you would have to write a routine:
Pass in desired rect and CCSprite bounding box rect.
Scale the box rect to aspect fit the desired rect.
Return the scaling factor
The result can then be applied to the CCSprite.scale property.
You can certainly scale the sprite to do that...
sprite.scale = ?
sprite.scaleX = ?
sprite.scaleY = ?
but I don't believe there is a function to automatically fill the entire screen. If you don't get a definitive reply here I would suggest posting on the Cocos2D forums (http://www.cocos2d-iphone.org/forum/).

How to get UIView's Position in DrawRect method

I have 4 views and i am drawing circles inside these views.The user is able to move these views.How can i get the position of each view?
If your views are instance variables in your class you can use view.frame or view.center but your question is quite low on details so I'm just shooting in the dark.
CGPoint origin = view.origin;
CGPoint center = view.center;
CGRect frame = view.frame;
All these things can be used to get what you want.