Drawing line with SpriteKit and detecting collision - ios

I have managed to draw a line with array of my random CGPoints.
-(void)drawLine
{
SKShapeNode *mainLine = [SKShapeNode node];
CGMutablePathRef pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, 0, 0);
for(int i;i<pointsInMyView.count;i++)
{
CGPoint myPoint = [pointsInMyView[i] CGPointValue];
CGPathAddLineToPoint(pathToDraw, NULL, myPoint.x, myPoint.y);
mainLine.path = pathToDraw;
}
[mainLine setLineWidth:40];
[mainLine setStrokeColor:[SKColor whiteColor]];
mainLine.name = #"mainLine";
[self addChild:mainLine];
}
As you can see I am drawing a SKShapeNode. My goal is to check collision of my SKSpriteNode with my line. But of course, this shape node makes a frame that contains all points of my line, and in this case my ShapeNode is all over my view. My SpriteNode detects collision with this ShapeNode all the time.
I should draw multiple different ShapeNodes I guess, so every node would have its own frame. But if i do it this way, my line is not connected.
Is there some solution to draw this node by node and still get nice line.

Unfortunately nodes in SpriteKit cannot be concave (http://mathworld.wolfram.com/ConcavePolygon.html), with lines that cross over each other.
You will have to create separate nodes for each lines between adjacent points and then possibly join them together. you could do this either by:
Create the 1st segment and then add subsequent segments as children
of that 1st segment.
Create a non-visible node for the whole line and add wll the line
segments as children of that node.
Create physicsbodies for each segment and join them with
SKPhysicsJointFixed.

Related

Search for node inside circle (SKShapeNode) with lowest y-coordinate

I want to search for nodes inside a circle - the circle is a SKShapeNode. The return node (SKSpriteNode) should be the nodes found inside the circle, with the lowest y-value.
For people who are interested, this is the code I use for the search:
SKSpriteNode *currentNode = [SKSpriteNode spriteNodeWithColor:[UIColor clearColor] size:CGSizeMake(0, 0)];
[currentNode setPosition:CGPointMake(0, 99999)];
SKShapeNode *circle = [SKShapeNode shapeNodeWithCircleOfRadius:100];
// adding circle and other nodes to scene
[self enumerateChildNodesWithName://* usingBlock:^(SKSpriteNode *foundNode, BOOL * _Nonnull stop) {
if ([circle containsPoint:currentNode.position]) {
if (currentNode.position.y > foundNode.position.y) {
currentNode = foundNode;
}
}];
// currentNode = node inside circle with lowest y
I don't like this solution, looks like it takes too much effort to find just the one node. I also tried using nodesAtPoint/nodeAtPoint but that does not work in my project - 'big' child nodes.
I am curious: is there an easier way to search for a node with specifics like this?
Checking the Y coordinate is going to be much faster than [circle containsPoint] so you might want to change the order of your condition to first compare the y coordinate of candidate nodes and only check circle containsPoint for nodes that have a y coordinate between the lowest point of your circle (-100) and the currentNode's Y coordinate.
something like :
if ( foundNode.position.y > -100
&& foundNode.position.y < currentNode.position.y )
{
if ([circle containsPoint:foundNode.position])
{ currentNode = foundNode }
}
note: i'm assuming enemy.position was actually meant to be foundNode.position.

Can I set anchor point of SKPhysicsJoint outside node?

Let's say I have two circles respectively at (0,0) and (0,1).
I have a SKPhysicsJoint between them and it is working good, now I want to separate them with a distance of 2 on runtime, meaning while physics are working in-game. How can I achieve this?
I've tried setting anchor points to (0,0) and (0,2) but something is bugged, although I see the joint it doesn't have any affect.
I want the circles smoothly push each other, as if the length of the spring has increased.
Everything works if I make a circle 'teleport' to a distance of 2 and then anchor the spring to it, but making a physics object teleport cause other bugs as you can guess.
Before adding the joint I 'teleported' the second object to the desired position, then added the joint and then 'teleported' back to the original position.
Here is the code piece:
SKSpriteNode* node1 = [_bodies objectAtIndex:loop];
SKSpriteNode* node2 = [_bodies objectAtIndex:loop-1];
CGPoint prev1 = node1.position;
CGPoint prev2 = node2.position;
node1.position = [((NSValue*)[positions objectAtIndex:loop]) CGPointValue];
node2.position = [((NSValue*)[positions objectAtIndex:loop-1]) CGPointValue];
[self AttachPoint:node1 secondPoint:node2 pos1:node1.position pos2:node2.posiiton] ;
node1.position = prev1;
node2.position = prev2;
it is working as it is, but I'm not sure how efficient this is. I wish SKPhysicsJointSpring had a 'length' parameter that can be changed over time.

Smooth motion of a SKSpriteNode on a random path

I am making a small SpriteKit game. I want the "enemies" in this game to move on random paths around the player (which is static).
If I just select a random point on the screen and animate a motion to there and then repeat (e.g.: every 2 seconds), this will give a very jagged feel to the motion.
How do I make this random motion to be very smooth (e.g.: if the enemy decides to turn around it will be on a smooth U turn path not a jagged sharp angle).
PS: The enemies must avoid both the player and each other.
You can create an SKAction with a CGPathRef that the node should follow.
Here is an example how to make a node make circles:
SKSpriteNode *myNode = ...
CGPathRef circlePath = CGPathCreateWithEllipseInRect(CGRectMake(0,
0,
400,
400), NULL);
SKAction *followTrack = [SKAction followPath:circle
asOffset:NO
orientToPath:YES
duration:1.0];
SKAction *forever = [SKAction repeatActionForever:followTrack];
[myNode runAction:forever];
You can also create a random UIBezierPath to define more sophisticated paths and make your objects follow them.
For example:
UIBezierPath *randomPath = [UIBezierPath bezierPath];
[randomPath moveToPoint:RandomPoint(bounds)];
[randomPath addCurveToPoint:RandomPoint(YourBounds)
controlPoint1:RandomPoint(YourBounds)
controlPoint2:RandomPoint(YourBounds)];
CGPoint RandomPoint(CGRect bounds)
{
return CGPointMake(CGRectGetMinX(bounds) + arc4random() % (int)CGRectGetWidth(bounds),
CGRectGetMinY(bounds) + arc4random() % (int)CGRectGetHeight(bounds));
}
You make a node follow the path using an SKAction and when the action completes (node is at the end of the path), you calculate a new path.
This should point you to the right direction.
If you want to generate random path, I highly suggest you to use "CGPathAddCurveToPoint", it is simple to understand and easy to use
Go to title 2. Add & Move Enemies
http://code.tutsplus.com/tutorials/build-an-airplane-game-with-sprite-kit-enemies-emitters--mobile-19916
It is coded by Jorge Costa and Orlando Pereira

Error attempting to create polygon with CGPathAddEllipseInRect

I am trying to create an ellipses. I used bodyWithEdgeLoopFromPath and it worked but there seems to be something wrong with it because sometimes other objects get caught in the middle of it.
But I want the ellipses to be solid, So I tried bodyWithPolygonFromPath (I want it static)
horizontalOval = [[SKShapeNode alloc] init];
theRect = CGRectMake(0, 0, self.frame.size.width/6 , 15);
CGMutablePathRef ovalPath = CGPathCreateMutable();
CGPathAddEllipseInRect(ovalPath, NULL, theRect);
horizontalOval.path = ovalPath;
horizontalOval.fillColor = [UIColor blueColor];
horizontalOval.physicsBody.dynamic = NO;
horizontalOval.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:ovalPath];
But got the error
SKPhysicsBody: Error attempting to create polygon with 17 vertices, maximum is 12
How do I create complex paths and make them solid?
Also when I pud it in position self.frame.size.width/2 and self.frame.size.height/2 It doesn't stay center, it goes a little to the right.
I had to theRect = CGRectMake(-40, 0........) to make it center but why is that?
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: _paddleRect];
But has 13 vertices. Trying to use PaintCode.
You can think of an edge body as one that has no volume, just the edges, a body with 'negative space' - that's why your objects got caught in the middle of it. As the Sprite Kit Programming Guide says:
The main difference between a edge and a volume is that an edge permits movement inside its own boundaries, while a volume is considered a solid object.
Since you want your oval to be a solid object, you do need a volume-based body. For these bodies, you have three options to create their shape: a circle (bodyWithCircleOfRadius:), a rectangle (bodyWithRectangleOfSize:), or a polygon (bodyWithPolygonFromPath:).
For an oval shape, you probably have to draw a polygon - however, the Sprite Kit physics engine will only accept those with a maximum of 12 vertices (that's why you were getting an error when drawing an actual ellipse). Your best bet is drawing a polygon using a helper tool, such as this one: http://dazchong.com/spritekit/ - just drag and drop your sprite and draw the path. Remember that the polygon must be convex (no angles over 180 degrees inside it) and that it can have a maximum of 12 vertices.
Also check out this answer for a similar issue: Ellipse SKPhysicsBody

SKAction followPath, creating the path

I am using a simple A* Pathfinding algorithm to create a path between two points (the green and red circles below), each square is an SKSpriteNode (with a CGPoint [x,y] position). I want to animate another SKSpriteNode along a smooth path that passes through each point.
My thinking was that I could use the SKAction -followPath:duration: to do this but I am having trouble working out how to create/specify the CGPath. Any help would be much appreciated.
You can create a simple CGPath like this
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 0, 0);
CGPathAddLineToPoint(path, NULL, 100, 0);
CGPathAddLineToPoint(path, NULL, 100, 100);
Depending on what you want to achieve you can add different elements to your path like arcs, curves, rects...
You can find more about it here.

Resources