Wednesday, November 4, 2015

My Experiments with SpriteKit: Part Two - Movement!


At the end of Part One, we had a cute little kitten, or some other image, displayed right in the middle of our scene.

Your GameScene.m implementation should look like this:
#import "GameScene.h"

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    CGFloat midX = CGRectGetMidX(self.frame);
    CGFloat midY = CGRectGetMidY(self.frame);
    CGPoint center = CGPointMake( midX, midY);
    SKSpriteNode* sprite = [SKSpriteNode spriteNodeWithImageNamed:@"cat"];
    sprite.position = center;
    [self addChild:sprite];
}

-(void)update:(CFTimeInterval)currentTime {  
}
@end
You might have a different image name.

The grey background is a bit dull, so lets brighten it up a bit with sky blue, RGB=(135, 206, 235). SKGameScene has a backgroundColor property of type NSColor. We can set that property in didMoveToView:
-(void)didMoveToView:(SKView *)view {
    self.backgroundColor = [NSColor colorWithRed:(135.0/255.0)
                                           green:(206.0/255.0)
                                            blue:(235.0/255.0)
                                           alpha:1.0];
    CGFloat midX = CGRectGetMidX(self.frame);
    CGFloat midY = CGRectGetMidY(self.frame);
    ...
The colorWithRed:green:blue:alpha: takes CGFloat values in the range of 0 to 1.0 as parameters, so we need to scale the RGB values.

This puts a nice blue background behind our kitty:


Let's move our kitty around a bit now. Recall that our kitty sprite has a position property of type CGPoint, so we can change that variable to move it.

The update: method of our GameScene is called once per frame. Based on the debug info in the lower left of the scene, we are getting about 60 frames per second. The parameter being passed to update is the current system time, a NSTimeInterval type. As a simple experiment we can use that time value to move our sprite around the centre of scene.

First, we need a way to access our sprite from the update: method. One way is to make use of the childNodeWithName: method of SKNode. Since SKGameScene is-a SKNode, and we have added our sprite as a child of our GameScene, we can get our sprite. All we need to do is set the name property of our sprite in the didMoveToView: method:
-(void)didMoveToView:(SKView *)view {
    self.backgroundColor = [NSColor colorWithRed:(135.0/255.0)
                                           green:(206.0/255.0)
                                            blue:(235.0/255.0)
                                           alpha:1.0];
    CGFloat midX = CGRectGetMidX(self.frame);
    CGFloat midY = CGRectGetMidY(self.frame);
    CGPoint center = CGPointMake( midX, midY);
    SKSpriteNode* sprite = [SKSpriteNode spriteNodeWithImageNamed:@"cat"];
    sprite.name = @"cat";
    sprite.position = center;
    [self addChild:sprite];
}
In the update: method we can access our sprite, and make it move:
-(void)update:(CFTimeInterval)currentTime {
    SKSpriteNode* sprite = (SKSpriteNode*)[self childNodeWithName:@"cat"];
    CGFloat midX = CGRectGetMidX(self.frame);
    CGFloat midY = CGRectGetMidY(self.frame);
    sprite.position = CGPointMake(midX + 200 * cos(currentTime), midY + 200 * sin(currentTime));
}
There's a bit of code duplication, so lets refactor things a bit by adding a CGPoint property for the centre of the scene in an interface extension:
#import "GameScene.h"

@interface GameScene ()
@property CGPoint center;
@end

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    self.backgroundColor = [NSColor colorWithRed:(135.0/255.0)
                                           green:(206.0/255.0)
                                            blue:(235.0/255.0)
                                           alpha:1.0];
    _center = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    SKSpriteNode* sprite = [SKSpriteNode spriteNodeWithImageNamed:@"cat"];
    sprite.name = @"cat";
    sprite.position = self.center;
    [self addChild:sprite];
}

-(void)update:(CFTimeInterval)currentTime {
    SKSpriteNode* sprite = (SKSpriteNode*)[self childNodeWithName:@"cat"];
    sprite.position = CGPointMake(self.center.x + 200 * cos(currentTime),
                                  self.center.y + 200 * sin(currentTime));
}
@end
And finally, lets make our kitty sprite a property as well, then we can remove the call to childNodeWithName:, which may make things a bit quicker:
#import "GameScene.h"

@interface GameScene ()
@property CGPoint center;
@property SKSpriteNode* kitty;
@end

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    self.backgroundColor = [NSColor colorWithRed:(135.0/255.0)
                                           green:(206.0/255.0)
                                            blue:(235.0/255.0)
                                           alpha:1.0];
    _center = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
    _kitty = [SKSpriteNode spriteNodeWithImageNamed:@"cat"];
    self.kitty.name = @"cat";
    self.kitty.position = self.center;
    [self addChild:self.kitty];
}

-(void)update:(CFTimeInterval)currentTime {
    self.kitty.position = CGPointMake(self.center.x + 200 * cos(currentTime),
                                  self.center.y + 200 * sin(currentTime));
}
@end
There, now we have a kitty, or whatever, sprite moving around the centre of a game scene!

Next time, lets look at generating textures for our sprites, then we can add a border and a background to our scene.

No comments: