1

Here is my question:

  • How can I convert an SKSpriteNodearray into an array of GKObstacles so that an agent can appropriately avoid these obstacles by using the goalToAvoidObstacles:(nonnull NSArray<GKObstacle *> *) maxPredictionTime:(NSTimeInterval)/?

It seems that the way in which I am creating the GKObstacle array is not allowing the GKGoal to identify these as obstacles correctly, no matter what weight I give to the goal.

I have currently several SKNodes that are added to an SKScene chapterScene. Each of these nodes are added to an array that I am storing called obstaclesArray. I have set up a test in the following way that works quite well:

WORKING OBSTACLES

- (void)didMoveToView:(nonnull SKView *)view {
    [super didMoveToView:view];

    // Add three obstacles in a triangle formation around the center of the scene.
    NSArray<GKObstacle *> *obstacles = @[
                                         [self addObstacleAtPoint:CGPointMake(CGRectGetMidX(self.frame),
                                                                              CGRectGetMidY(self.frame) + 150)],
                                         [self addObstacleAtPoint:CGPointMake(CGRectGetMidX(self.frame) - 200,
                                                                              CGRectGetMidY(self.frame) - 150)],
                                         [self addObstacleAtPoint:CGPointMake(CGRectGetMidX(self.frame) + 200,
                                                                              CGRectGetMidY(self.frame) - 150)],
                                         ];

    // The player agent follows the tracking agent.
    self.player = [[OPlayer alloc] initWithScene:self
                                                radius:50
                                              position:CGPointMake(CGRectGetMidX(self.frame),
                                                                   CGRectGetMidY(self.frame))];
    self.player.agent.behavior = [[GKBehavior alloc] init];
    [self.agentSystem addComponent:self.player.agent];

    // Create the seek goal, but add it to the behavior only in -setSeeking:.
    self.seekGoal = [GKGoal goalToSeekAgent:self.character];

    // Add an avoid-obstacles goal with a high weight to keep the agent from overlapping the obstacles.
    [self.player.agent.behavior setWeight:100 forGoal:[GKGoal goalToAvoidObstacles:obstacles maxPredictionTime:1]];

}

- (GKObstacle *)addObstacleAtPoint:(CGPoint)point {
    SKShapeNode *circleShape = [SKShapeNode shapeNodeWithCircleOfRadius:50];
    circleShape.lineWidth = 2.5;
    circleShape.fillColor = [SKColor grayColor];
    circleShape.strokeColor = [SKColor redColor];
    circleShape.zPosition = 1;
    circleShape.position = point;
    [self addChild:circleShape];

    GKCircleObstacle *obstacle = [GKCircleObstacle obstacleWithRadius:50];
    obstacle.position = (vector_float2){point.x, point.y};

    return obstacle;
}

While this works just fine, the issue I am having is that I can not get the behavior to identify the SKNode bodies array that I have as obstacles. I can only get these manually created GKCircleObstacle items to register as valid obstacles that the agent avoids. The reason this is an issue is because I am relying on many obstacles that are not in fact simple circles, but polygon structures some complex, some more straightforward. Nevertheless, I was attempting the following but my agent did not seem to avoid any of the obstacles that are of SKNode this way:

NOT WORKING OBSTACLES

NSArray *obstacles = [SKNode obstaclesFromNodePhysicsBodies:obstaclesArray];

/*
 The other code seen above
 */

// Add an avoid-obstacles goal with a high weight to keep the agent from overlapping the obstacles.
[self.player.agent.behavior setWeight:100 forGoal:[GKGoal goalToAvoidObstacles:obstacles maxPredictionTime:1]];

Unfortunately, this does not seem to work as no matter how high I set the weight to, the agent never responds to avoiding the obstacles. Here is a log of the array I am passing to it:

2016-07-24 22:32:24.907 <GAME>[1516:475581] obstacles: (
    "<GKPolygonObstacle: 0x14d20d70>",
    "<GKPolygonObstacle: 0x14d20e10>",
    "<GKPolygonObstacle: 0x14d20ba0>",
    "<GKPolygonObstacle: 0x14d20bb0>",
    "<GKPolygonObstacle: 0x14d20bc0>",
    "<GKPolygonObstacle: 0x14d20a60>",
    "<GKPolygonObstacle: 0x14d208b0>",
    "<GKPolygonObstacle: 0x14d207d0>",
    "<GKPolygonObstacle: 0x14d20a70>"
)

Each of which have all been clearly and appropriately initialized and added to the scene. Each of these elements are in fact responsive with the SpriteKit didBeginContact:(SKPhysicsContact *)contact method, so it seems that the nodes are properly handing the boundaries that they should be having.

If someone knows what I am doing wrong or a better way to turn each of these 'obstacle nodes' into GKObstacle's I would be much appreciative. Thanks in advance!

UPDATE: Here is a node with a physics body that I am testing:

        SKSpriteNode *innerMap1 = [SKSpriteNode spriteNodeWithImageNamed:@"test"];
        innerMap1.physicsBody = [SKPhysicsBody bodyWithTexture:[SKTexture textureWithImageNamed:@"test"] size:CGSizeMake(innerMap1.frame.size.width*0.92, innerMap1.frame.size.height*0.92)];
        innerMap1.position = CGPointMake(-220, -140);
        innerMap1.physicsBody.dynamic = NO;

        [chapterSKSpriteNodes addObject:innerMap1];

Here is what the body looks like with skView.showsPhysics = YES;:

enter image description here

So I know that the physics body is what I need it to be. When I attempt to create the GKObstacle from this body however, it does not seem to register as an obstacle when being assigned in the avoidObstacles goal.

Will Von Ullrich
  • 2,129
  • 2
  • 15
  • 42
  • Physics bodies are not free, you need to create them for your nodes. I am not seeing this anywhere in the code provided – Knight0fDragon Jul 25 '16 at 15:25
  • Sorry - have TONS of nodes with PB so i didn't provide the code for me making them. I will give one example in an update to my question – Will Von Ullrich Jul 25 '16 at 15:26
  • Maybe you have am issue with the order of events? do you check prior to `obstaclesFromNodePhysicsBodies` to see if tall the nodes in the array have bodies? – Knight0fDragon Jul 25 '16 at 15:27
  • I am not checking this no, but I am trying to just for now use the object shown in the image above as an obstacle and it does not seem to be taking..So from what I am seeing and from how I have set it up, I am assuming it does have a body that can be used – Will Von Ullrich Jul 25 '16 at 15:44
  • 1
    well don't assume, it takes a minute to verify if physics body exists, write a for loop and check to make sure they exist. – Knight0fDragon Jul 25 '16 at 15:49
  • from what I am seeing they do exist. Not sure if this is what I need to do but i simply did `for (SKNode *node in obstaclesArray) { if (node.physicsBody) { NSLog(@"exists"); }}` and i got "exists" for all of them – Will Von Ullrich Jul 25 '16 at 15:52
  • any thoughts as to how to get these physics bodies to work with the GKGoal? – Will Von Ullrich Jul 25 '16 at 16:10
  • no idea, I do not use game kit, I can only go off what what seemed on in your question – Knight0fDragon Jul 25 '16 at 16:11
  • I'm experiencing the same thing, did you ever get this solved? – Chris Aug 16 '18 at 12:58
  • Not entirely - seems that as GameKit is still a baby I guess things like this are expected. Hopefully they get ironed out soon.. – Will Von Ullrich Aug 16 '18 at 13:15

1 Answers1

0

This sounds like a bug. You should check the return array from obstaclesFromNodePhysicsBodies and make sure you are actually getting back the obstacles you expect. I suspect you are not.

You can check the relevant vertices on your obstacles as such:

https://developer.apple.com/library/ios/documentation/GameplayKit/Reference/GKPolygonObstacle_Class/index.html#//apple_ref/occ/cl/GKPolygonObstacle

Make sure they are what you expect.

Whirlwind
  • 91
  • 1