Friday, November 6, 2015

My Experiments with SpriteKit: Part Three - Textures!

Let's create an interesting sprite from the ground up. We'll do everything!

Start with the code we've written already. Remove the sprite code that we've written, even remove the image from the Assets.xcassets folder. Your GameScene should look like this:
#import "GameScene.h"

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

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    self.backgroundColor = [NSColor blackColor];
    _height = CGRectGetHeight(self.frame);
    _center = CGPointMake(CGRectGetMidX(self.frame),
                          CGRectGetMidY(self.frame));
}

-(void)update:(CFTimeInterval)currentTime {
    
}

@end
I've also set the background colour of the scene to black. Build and run this and you'll get an application with a black window.

What does our scene need? It needs a border...

Let's make a nice gold (RED=255, GREEN=215, BLUE=0) border. It should hug the scene frame, have rounded inside corners and be 15 points thick.

SKSpriteKit has a couple of methods we can use to create our sprite: spriteNodeWithImageNamed: and spriteNodeWithTexture:. The first one is great if we already have a named image, for example we may already have an image that we have placed in our Assets.xcassets folder. And the second one is great if we have a Texture of type SKTexture.

Texture objects manage graphics resources that can be applied to our sprites when they are being rendered. Let's use spriteNodeWithTexture: method to create a sprite that we can use as a border to our scene. Sometimes it's necessary to work backwards towards our goal, let's try that.

-(void)didMoveToView:(SKView *)view {
    self.backgroundColor = [NSColor blackColor];
    _height = CGRectGetHeight(self.frame);
    _center = CGPointMake(CGRectGetMidX(self.frame),
                          CGRectGetMidY(self.frame));
    
    SKSpriteNode* border;
    border = [SKSpriteNode spriteNodeWithTexture:<#(nullable SKTexture *)#>];
    border.position = self.center;
    [self addChild:border];
}
So we need a SKTexture. Let's add one of those:
SKSpriteNode* border;
SKTexture* texture = [SKTexture textureWithImage:<#(nonnull NSImage *)#>];
border = [SKSpriteNode spriteNodeWithTexture:texture];
border.position = self.center;
[self addChild:border];
Right, now we need an NSImage:
SKSpriteNode* border;
NSImage* image;
image = [[NSImage alloc] initWithSize:self.frame.size];
// ???
SKTexture* texture = [SKTexture textureWithImage:image];
border = [SKSpriteNode spriteNodeWithTexture:texture];
border.position = self.center;
[self addChild:border];
OK, we're back to a build-able and run-able project. But it's still a black window. We have a sprite, having a texture that contains a image that has the same size as the window. Maybe... Let's find out by drawing the border.

In order to draw in the image we need to obtain a graphics context for the image, this turns out to be pretty easy with the NSImage method lockFocus.  When we're done drawing our image, we'll call unlockFocus.
NSImage* image;
image = [[NSImage alloc] initWithSize:self.frame.size];
[image lockFocus];
// ???
[image unlockFocus];
We just need to figure out how to draw the border. It's easy: use NSBezierPath to describe the outline of our border and then fill it in.
[image lockFocus];
NSBezierPath* path = [NSBezierPath bezierPathWithRect:self.frame];
[path appendBezierPathWithRoundedRect:CGRectInset(self.frame, 15, 15)
                              xRadius:25
                              yRadius:25];
// ???
[image unlockFocus];
That defines the path we want to fill: a large rect that is the size of view, and a smaller rounded rect with the same centre 15 points inside of the large rect. Now, we need to apply the path, with the gold colour to the image.
[image lockFocus];
NSBezierPath* path = [NSBezierPath bezierPathWithRect:self.frame];
[path appendBezierPathWithRoundedRect:CGRectInset(self.frame, 15, 15)
                              xRadius:25
                              yRadius:25];
[[NSColor colorWithRed:(255.0/255.0)
                 green:(215.0/255.0)
                  blue:(0.0/255.0)
                 alpha:1.0] set];
path.windingRule = NSEvenOddWindingRule;
[path fill];
[image unlockFocus];
the set method, called on an NSColor, sets the drawing fill and stroke colour to that of the receiver. The windingRule applies to the fill method that we use to actually draw the path and fill it with the gold colour. I chose the NSEvenOddWindingRule simply because it caused the fill to work correctly, inside the two rectangles as opposed to filling both rectangles (actually, there's a good reason to use NSEvenOddWindingRule, I explain why in another post).

Finally, call the fill method on our path. Here's the application:


A very nice border. Let's add one more sprite to set us up for the next blog post in this series. But first, a bit of refactoring. The didMoveToView: method is getting a bit ungainly:
-(void)didMoveToView:(SKView *)view {
    self.backgroundColor = [NSColor blackColor];
    _height = CGRectGetHeight(self.frame);
    _center = CGPointMake(CGRectGetMidX(self.frame),
                          CGRectGetMidY(self.frame));
    
    SKSpriteNode* border;
    NSImage* image;
    image = [[NSImage alloc] initWithSize:self.frame.size];
    [image lockFocus];
    NSBezierPath* path = [NSBezierPath bezierPathWithRect:self.frame];
    [path appendBezierPathWithRoundedRect:CGRectInset(self.frame, 15, 15)
                                  xRadius:25
                                  yRadius:25];
    [[NSColor colorWithRed:(255.0/255.0)
                     green:(215.0/255.0)
                      blue:(0.0/255.0)
                     alpha:1.0] set];
    path.windingRule = NSEvenOddWindingRule;
    [path fill];
    [image unlockFocus];
    
    SKTexture* texture = [SKTexture textureWithImage:image];
    border = [SKSpriteNode spriteNodeWithTexture:texture];
    border.position = self.center;
    [self addChild:border];
}
So we should pull the border creation code out into it's own method.
-(void)addBorderofThickness:(CGFloat)t andCornerRadius:(CGFloat)cr {
    SKSpriteNode* border;
    NSImage* image;
    image = [[NSImage alloc] initWithSize:self.frame.size];
    [image lockFocus];
    NSBezierPath* path = [NSBezierPath bezierPathWithRect:self.frame];
    [path appendBezierPathWithRoundedRect:CGRectInset(self.frame, t, t)
                                  xRadius:cr
                                  yRadius:cr];
    [[NSColor colorWithRed:(255.0/255.0)
                     green:(215.0/255.0)
                      blue:(0.0/255.0)
                     alpha:1.0] set];
    path.windingRule = NSEvenOddWindingRule;
    [path fill];
    [image unlockFocus];
    
    SKTexture* texture = [SKTexture textureWithImage:image];
    border = [SKSpriteNode spriteNodeWithTexture:texture];
    border.position = self.center;
    [self addChild:border];
}
Now we can create the border in didMoveToView with just one line.

On to the new sprite! I want a retro game style spaceship... Here's the drawing code:
NSImage* image;
image = [[NSImage alloc] initWithSize:CGSizeMake(30, 30)];
[image lockFocus];
NSBezierPath* path = [NSBezierPath bezierPath];
path.lineWidth = 2.5;
[path moveToPoint:CGPointMake(0, 0)];
[path lineToPoint:CGPointMake(15, 30)];
[path lineToPoint:CGPointMake(30, 0)];
[path lineToPoint:CGPointMake(15, 10)];
[path closePath];
[[NSColor colorWithRed:(255.0/255.0)
                 green:(215.0/255.0)
                  blue:(0.0/255.0)
                 alpha:1.0] set];
[path stroke];
[image unlockFocus];
 Go ahead and make the sprite, you'll get something like:



In part four we'll let the user rotate the space ship and move it around.

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.

Tuesday, November 3, 2015

My Experiments with SpriteKit: Part One - Sprites!


Yay! Sprites! I remember, vaguely, creating sprites on my C64 back in the '80's. Long before *you* were born! Back then we had peek and poke and do some sort of nerd wizard pickery-pokery magic to make a blocky image that could be moved on our 320x200 pixel screen...

And we were happy! And then we walked to school, in the snow, uphill...

Ok, lets see what we can do on OS X.

The goal of this experiment is to create a scene that contains a sprite that we have created all by ourselves!!!

For this experiment lets open Xcode (Version 7.1) and create a new project.

     File->New->Project

which opens the template dialog where you can select Application from the OS X section, and then the Game template. And press Next.

For Product Name I chose SimpleSprite, Objective-C  for Language and SpriteKit for Game Technology. No Unit or UI tests. Press Next and Create on the following Dialog and you have a runnable project! Run it and you get a game scene with the text Hello, World!,  mouse clicking on the scene gets you a spinning jet plane sprite..

Let's delete the template code we don't need, so we can learn how to create sprites. Open GameScene.m and delete everything except empty didMoveToView and update methods:
#import "GameScene.h"

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
}

-(void)update:(CFTimeInterval)currentTime {
}

@end
 
Go ahead and run, you will see an application with an empty scene save for the debug info at the bottom right. We'll leave the debug info for now.

Sprites, in sprite kit, are represented by the SKSpriteNode class which is a SKNode class. SKNodes are the building blocks of the sprite kit api. The GameScene class  is a SKScene. SKScene is the root of the SKNodes that provide the content for the scene we are creating. So... SKScene holds a tree of SKNodes, and we will be instantiating and adding SKNodes.

We're going to add our sprite in the didMoveToView method which, according to the Xcode Quick Help, is Called immediately after a scene is presented by a view. Here's the code
-(void)didMoveToView:(SKView *)view {
    CGFloat midX = CGRectGetMidX(self.frame);
    CGFloat midY = CGRectGetMidY(self.frame);
    CGPoint center = CGPointMake( midX, midY);
    SKSpriteNode* sprite = [SKSpriteNode spriteNodeWithColor:[NSColor redColor]
                                                        size:CGSizeMake(20.0, 20.0)];
    sprite.position = center;
    [self addChild:sprite];
}
we expect this to place a red square right in the middle of the application screen:


Great! We can add a sprite to the scene! Look at what we did. First we identified the centre of the scene using the CGRectGetMid functions to get the x and y coordinates of the centre of the screen from the CGRect self.frame. We could have also used (self.frame.size.width/2.0).

Then, we instantiated a SKSpriteNode using the factory class method spriteWithColor:size:. We could have also used the initWithColor:size: method, as long as we called alloc.

Sprites are initialized with a position of CGPointZero, so we need to set the position to the centre of the view. Note that the anchor point of our sprite is the centre of the sprite, more about this in a later post.

The final step is to add our sprite to the scene using the addChild method.

Let's do something more interesting than a red square. Find a nice image that would make a good sprite and drag it into the Assets.xcassets folder in your Project.



I found a nice cat photo that I cropped and gave a transparent background. Now we can rewrite our didMoveToView method:

-(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];
}
which gives us:



All it needs is a nice background! Perhaps in part two..

Tuesday, August 12, 2014

Yet Another "Ten Questions for Every Atheist".. and More Answers...

Oh no, not again:

           http://todaychristian.net/10-questions-every-atheist/

You'd think that the author of this would do a few minutes of searching the internet (Google is your friend) before re-asking these questions.


1. How Did You Become an Atheist?

When I was in grade 7 (I think, may have been earlier), the Gideons gave our school Gideon bibles.

This was great! I'll read the bible to become a better christian... from cover to cover!

I didn't even get through Genesis before I started to realize what nonsense the book was. I didn't know it then, but I had become an atheist. Still, I slogged through.

Since then, I've read many bibles, even wrote bible software for a time. I've remained an atheist.

This is why I am an advocate for the distribution of bibles in schools. Someone might actually read the things.

Oh, as an aside, I'm cool with bibles in hotel rooms as well. I always take the time to sign them: "From Jesus, I wrote this for you, hope you like it!".  In red, of course.


2. What happens when we die?

The same thing that happened before we were alive. Don't worry about it! We were fine for billions of years before we were alive, death can't be that bad(thanks, Samuel Clemens).


3. What if you’re wrong? And there is a Heaven? And there is a HELL!

Pascal's Wager... sigh... Please, please, before posing arguments, please, read the counter arguments first!

What happens if you're wrong, and Odin is supremely pissed that you were worshipping some minor hill god that couldn't deal with iron chariots(Judges 1:19)?

Pascal's wager presupposes that I could fool an omnipotent god by pretending to believe in it. I can't choose to believe things for which no evidence exists. In fact, I work very hard to rid myself of beliefs for which no evidence exists. Wouldn't an omniscient being realize that I was lying?

It also presupposes the existence of an afterlife, for which no evidence exists.

And Pascal's Wager is based on the threat of hell... How impressed would a god be that I only "believed" in him to avoid hell? Not any god worth worshipping.

How can I even *choose* to believe something? Especially without evidence?

For an fantastic dissection of Pascal's Wager watch Matt Dillahunty: https://www.youtube.com/watch?v=YBCDGohZT70


4. Without God, where do you get your morality from?

The same place you do. And that's not the bible! How moral is it
  • to keep slaves(Leviticus 25:44-46)? 
  • to test people by asking them to sacrifice children(Genesis 22)? 
  • to test people by destroying their lives(Job)? 
  • to be intolerant of people that don't agree with your religion(Luke 19:27)?

so, I really hope you don't get your morals from the bible, and I hope you don't rely on threats from a god to be a good person... But, if you do need threats to be good to your fellow humans, please don't give up your religion!


5 a. If there is no God, can we do what we want?

I pretty much do the things that I want to do. I go sailing, write software, discuss religion, travel...

Why would a god want to stop me from doing those things?


5 b. Are we free to murder and rape?

I don't want to murder or rape. And the god of the bible has done, ordered or condoned those actions on many occasions... Read your bible!


5 c. While good deeds are unrewarded?

I don't require rewards for the good that I do. I don't require threats to not harm people. It says a lot about people that need to be rewarded for just being reasonable human beings.


6. If there is no god, how does your life have any meaning?

I don't require the existence of a god to make meaning for my life.


7. Where did the universe come from?

I don't know, neither do you.. well, if you do please present your evidence, get it peer reviewed and accept your Nobel prize.

Now the "Big Bang model" talks about what happened shortly after the universe began... There's good evidence for the Big Bang model - it correctly predicted many phenomena that have since been observed:

  • the abundance of light elements
  • the cosmic microwave background
  • large scale structure
  • Hubble's Law.
all of these phenomena, and many more, were predicted before they were observed. This demonstrates the validity of the theory. What's even better, is that as cosmologists learn more about the universe, they'll update the theory and make it better.


8 a. What about miracles?

What about them? I've seen no evidence of any miracle.


8 b. What all the people who claim to have a connection with Jesus?

There are lots of people that claim to have a connection with aliens or ancient gods. Just because someone claims something, doesn't mean I need to believe it without evidence.


8 c. What about those who claim to have seen saints or angels?

 Again, anecdotal claims are not evidence. There are lots of people who claim to have seen flying saucers, and aliens.. Do I need to believe their claims? There are many people who have claimed to have seen Djinn and leprechauns... Do I need to believe them?


9. What’s your view of Dawkins, Hitchens and Harris?

I like them. I agree with some of what they say, and disagree with other things they say.

Dawkins explains himself very well, and has taught me a great deal about nature.

Hitchens was a fantastic journalist and had a great sense of humour. His writing makes me want to learn much more about the subjects he writes about.

Harris is a wonderful science and philosophy popularizer. I enjoy his discussions on faith and applications of science to problems of morality.


10.   If there is no God, then why does every society have a religion?

Your premise is incorrect, the Piraha people of Brazil had no religion.

Even if everyone had a religion, that still isn't evidence that a god exists.

In fact, it's a wonderful counter argument! Why are there so many different religions! Even within Christianity there are at least 41000 different denominations(according to the Pew Forum)!  If there were one god, why are there so many religions, let alone denominations within religions...