Draw rectangle in spritekit - ios

I'm trying to draw an empty rectangle with a SKShapeNode but does appear on the screen. If i set a color to the fill property the rectangle appears. What could be the issue?
//MyScene.h
#import <SpriteKit/SpriteKit.h>
#interface MyScene : SKScene
#end
//MyScene.m
#import "MyScene.h"
#implementation MyScene
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
SKShapeNode *shapeNode = [SKShapeNode shapeNodeWithRectOfSize:CGSizeMake(self.frame.size.width/2, self.frame.size.height/2)];
shapeNode.strokeColor = [SKColor redColor];
shapeNode.lineWidth = 3;
[self addChild:shapeNode];
}
return self;
}
#end

Related

How to detect touch on non-transparent parts of overlay image drawn by MKOverlayRenderer

I draw an image on my map as overlay like so (RW example code):
It has a transparent part in the middle (that should let touches through) and non-transparent sides that should catch touches (kind of like a donut :)).
Overlay.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#class PVPark;
#interface PVParkMapOverlay : NSObject <MKOverlay>
- (instancetype)initWithPark:(PVPark *)park;
#end
Overlay.m
#import "PVParkMapOverlay.h"
#import "PVPark.h"
#implementation PVParkMapOverlay
#synthesize coordinate;
#synthesize boundingMapRect;
- (instancetype)initWithPark:(PVPark *)park {
self = [super init];
if (self) {
boundingMapRect = park.overlayBoundingMapRect;
coordinate = park.midCoordinate;
}
return self;
}
#end
OverlayView.h
#import <MapKit/MapKit.h>
#interface PVParkMapOverlayView : MKOverlayRenderer
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage;
#end
OverlayView.m
#import "PVParkMapOverlayView.h"
#interface PVParkMapOverlayView ()
#property (nonatomic, strong) UIImage *overlayImage;
#end
#implementation PVParkMapOverlayView
- (instancetype)initWithOverlay:(id<MKOverlay>)overlay overlayImage:(UIImage *)overlayImage {
self = [super initWithOverlay:overlay];
if (self) {
_overlayImage = overlayImage;
}
return self;
}
- (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context {
CGImageRef imageReference = self.overlayImage.CGImage;
MKMapRect theMapRect = self.overlay.boundingMapRect;
CGRect theRect = [self rectForMapRect:theMapRect];
CGContextScaleCTM(context, 1.0, -1.0);
CGContextTranslateCTM(context, 0.0, -theRect.size.height);
CGContextDrawImage(context, theRect, imageReference);
}
#end
I add it to the map like so:
MainViewController
- (void) viewDidLoad
{
[super viewDidLoad];
[self addOverlay];
}
- (void)addOverlay {
PVParkMapOverlay *overlay = [[PVParkMapOverlay alloc] initWithPark:self.park];
[self.mapView addOverlay:overlay];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
if ([overlay isKindOfClass:PVParkMapOverlay.class]) {
UIImage *magicMountainImage = [UIImage imageNamed:#"overlay_park"];
PVParkMapOverlayView *overlayView = [[PVParkMapOverlayView alloc] initWithOverlay:overlay overlayImage:magicMountainImage];
return overlayView;
}
return nil;
}
How can I detect a touch on the non-transparent part of the overlayed image? I've tried using some examples using MKPolyLines but to no avail. Should I create an invisible (to the user) polyline using the cutout's location data and check for that? Seems like there should be a way to catch the overlay more efficiently, no?

No known class method for selector 'generatorWithWorld:'

I'm trying to create a platform game on xcode and this my first ever project and I've came across this error and it says "No known class method for selector 'generatorWithWorld:'" and i'm also getting the error "No visible #interface for 'HSWorldGenerator' declares the selector 'populate'"
This is the code for MyScene.h:
//
// MyScene.h
// The Adventure of Colin The Sloth
//
// Copyright (c) 2014 SunnersCorp. All rights reserved.
//
**#import <SpriteKit/SpriteKit.h>
#import "HSWorldGenerator.h"**
#interface MyScene : SKScene
#end
MyScence.m:
//
// MyScene.m
// The Adventure of Colin The Sloth
//
// Created by Harpreet Sunner on 24/07/2014.
// Copyright (c) 2014 SunnersCorp. All rights reserved.
//
#import "MyScene.h"
#import "HSSloth.h"
#interface MyScene()
#property BOOL isStarted;
#property BOOL isGameOver;
#end
#implementation MyScene
{
HSSloth *Sloth;
SKNode *world;
HSWorldGenerator *generator;
}
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
/* Setup your scene here */
self.anchorPoint = CGPointMake (0.5, 0.5);
self.backgroundColor = [SKColor colorWithRed:0.15 green:0.15 blue:0.3 alpha:1.0];
world = [SKNode node];
[self addChild:world];
generator = [HSWorldGenerator generatorWithWorld:world]; **THIS IS WHERE I GET THE FIRST ERROR**
[self addChild:generator];
[generator populate]; **THIS IS WHERE I GET THE SECOND ERROR**
Sloth = [HSSloth Sloth];
[world addChild:Sloth];
}
return self;
}
- (void)start
{
self.isStarted = YES;
[Sloth start];
}
-(void)clear
{
NSLog(#"clear method called");
}
- (void)gameOver
{
NSLog(#"gameOver method called");
}
- (void)didSimulatePhysics
{
[self centerOrNode:Sloth];
}
- (void)centerOrNode:(SKNode *)node
{
CGPoint postionInScene = [self convertPoint:node.position fromNode:node.parent];
world.position = CGPointMake(world.position.x - postionInScene.x, world.position.y);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (!self.isStarted)
[self start];
else if (self.isGameOver)
[self clear];
else
[Sloth jump];
}
-(void)update:(CFTimeInterval)currentTime {
/* Called before each frame is rendered */
}
#end
HSWorldGenerator.h:
//
// HSWorldGenerator.h
// The Adventure of Colin The Sloth
//
// Created by Harpreet Sunner on 24/07/2014.
// Copyright (c) 2014 SunnersCorp. All rights reserved.
//
#import <SpriteKit/SpriteKit.h>
#interface HSWorldGenerator : SKNode
+ (id)generatorWithWorld:(SKNode *)world;
- (void)populate;
- (void)generate;
#end
HSWorldGenerator.m:
//
// HSWorldGenerator.m
// The Adventure of Colin The Sloth
//
// Created by Harpreet Sunner on 24/07/2014.
// Copyright (c) 2014 SunnersCorp. All rights reserved.
//
#import "HSWorldGenerator.h"
#interface HSWorldGenerator ()
#property double currentGroundX;
#property double currentObstacleX;
#property SKNode *world;
#end
#implementation HSWorldGenerator
+ (id)generatorWithWorld:(SKNode *)world
{
HSWorldGenerator *generator = [HSWorldGenerator node];
generator.currentGroundX = 0;
generator.currentObstacleX = 400;
generator.world = world;
return generator;
}
- (void)populate
{
for (int i = 0; 1 <3; i++)
[self generate];
}
- (void)generate
{
SKSpriteNode *ground = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(self.scene.frame.size.width, 100)];
ground.position = CGPointMake(self.currentGroundX, -self.scene.frame.size.height/2 + ground.frame.size.height/2);
ground.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ground.size];
ground.physicsBody.dynamic = NO;
[self.world addChild:ground];
self.currentGroundX += ground.frame.size.width;
SKSpriteNode *obstacle = [SKSpriteNode spriteNodeWithColor:[UIColor redColor] size:CGSizeMake(40, 70)];
obstacle.position = CGPointMake(self.currentObstacleX, ground.position.y + ground.frame.size.height/2 + obstacle.frame.size.height/2);
obstacle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:obstacle.size];
obstacle.physicsBody.dynamic = NO;
[self.world addChild:obstacle];
self.currentObstacleX += 250;
}
#end
Could anyone please tell me what ive done wrong and how I can fix this please, I will appreciate it so much.
Thank You!
Check where you #import HSWorldGenerator.h into your MyScene.h file.
The error is telling you that it doesn't know where to find the class method.
Looks like where you try to import the header in MyScene.h you have extra '**'s that might be commenting out that line.

ios 7 SKScene size vs visible area?

Apple's documentation has me a bit confused.
According to the documentation page : https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Nodes/Nodes.html the relationship between the visible area of the scene in points and the size of the scene should be the same according to the sentence :
"The size of the scene specifies the size of the visible portion of
the scene in points".
I created a custom scene that gets its size from the size of the device's screen (in my case I've been testing this for the iPad in portrait mode so the size should be 768 wide by 1024 high).
The following line which is being called in the scene's createContent method
NSLog(#"self.size : %f %f", self.size.width, self.size.height);
Returns
2014-07-15 14:53:28.844 SpriteWalkthrough[15888:90b] self.size : 768.000000 1024.000000
as expected.
However when I try to draw a SKSpriteNode at the position(self.size.width/2,self.size.height/2) the node is drawn in the upper right hand corner of the screen, not in the middle.
Why is this happening?
For other people who may be making similar mistakes drawing SpriteNodes to a scene, take a look at my source code for the scene, and in particular pay attention to the //self.sCar.car.position = self.sCar.position;line.
FoolAroundScene.h
#import <SpriteKit/SpriteKit.h>
#interface FoolAroundScene : SKScene
#end
FoolAroundScene.m
#import "FoolAroundScene.h"
#import "ScrollingBackground.h"
#import "SpriteCar.h"
#define BACKGROUND_NAME #"clouds.jpg"
#interface FoolAroundScene ()
#property BOOL contentCreated;
#property (strong, nonatomic) ScrollingBackground * sbg;
#property (strong, nonatomic) SpriteCar * sCar;
#end
#implementation FoolAroundScene
-(void) didMoveToView:(SKView *)view
{
if (!self.contentCreated) {
[self createContent];
self.contentCreated = !self.contentCreated;
}
}
-(void)createContent
{
self.sbg = [[ScrollingBackground alloc] initWithBackgroundImage:BACKGROUND_NAME size:self.size speed:2.0];
self.sCar = [[SpriteCar alloc] init];
[self addChild:self.sbg];
[self addChild:self.sCar];
self.sCar.position = CGPointMake(self.size.width/2, self.size.height/2);
//self.sCar.car.position = self.sCar.position;
SKSpriteNode * spriteCar = [self.sCar makeCarSprite];
spriteCar.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
NSLog(#"anchor point : %f %f", self.anchorPoint.x, self.anchorPoint.y);
NSLog(#"self.size : %f %f", self.size.width, self.size.height);
NSLog(#"self.scalemode : %d", self.scaleMode);
}
-(void) update:(NSTimeInterval)currentTime
{
[self.sbg update:currentTime];
}
#end
Even though I had set the sCar's position property to the middle of the scene, by setting its child node (the sCar's car property) position to the same value, the child's position will not be the same as its parent's. This is because the child's position is relative to its parent's.
Explained another way : the parent's position in the context of the scene was (384,512) and the child's position in the context of its parent was (384,512). However this means that the child's position in the context of the scene was actually (768,1024), which is why the car was being drawn in the upper right hand corner of the screen.
Also, in case anyone wants the implementation for the sprite car, here it is. A crappily drawn car that can be used to get a grip on how the Sprite Kit works.
SpriteCar.h
#import <SpriteKit/SpriteKit.h>
#interface SpriteCar : SKNode
-(id)init;
-(SKSpriteNode *)makeCarSprite;
#end
SpriteCar.m
#import "SpriteCar.h"
#interface SpriteCar ()
#property (nonatomic, strong) SKSpriteNode * car;
#end
#implementation SpriteCar
-(id) init
{
self = [super init];
if (self) {
self.car = [self makeCarSprite];
[self addChild:self.car];
}
return self;
}
-(SKSpriteNode *) makeCarSprite
{
SKSpriteNode * carBody1 = [[SKSpriteNode alloc] initWithColor:[SKColor redColor] size:CGSizeMake(64.0, 24.0)];
SKSpriteNode * carBody2 = [[SKSpriteNode alloc] initWithColor:[SKColor redColor] size:CGSizeMake(32.0, 32.0)];
SKSpriteNode * wheel1 = [[SKSpriteNode alloc] initWithColor:[SKColor blackColor] size:CGSizeMake(8.0, 8.0)];
SKSpriteNode * wheel2 = [wheel1 copy];
SKSpriteNode * light = [[SKSpriteNode alloc] initWithColor:[SKColor yellowColor] size:CGSizeMake(6.0, 6.0)];
carBody2.position = carBody1.position;
wheel1.position = CGPointMake(30.0, -30);
wheel2.position = CGPointMake(-30.0, -30.0);
light.position = CGPointMake(32.0, 11.0);
[carBody1 addChild:carBody2];
[carBody1 addChild:wheel1];
[carBody1 addChild:wheel2];
[carBody1 addChild:light];
SKAction * hover = [SKAction sequence:#[[SKAction moveByX:0.0 y:5.0 duration:0.1],
[SKAction waitForDuration:0.05],
[SKAction moveByX:0.0 y:-5.0 duration:0.1],
[SKAction waitForDuration:0.05]]];
[carBody1 runAction:[SKAction repeatActionForever:hover]];
return carBody1;
}
#end

Forward declaration in SpriteKit

I have an issue with forward declaration in SKScene I have to show a label node's value from game scene to game over scene , for example , but the value it returns as null , here is my code :
GameOver Scene :
#import "MyScene.h"
#class MyScene;
#interface GameOver : SKScene {
MyScene *mainScene;
}
#implementation GameOver
- (void)didMoveToView:(SKView *)view {
scores = [[SKLabelNode alloc]initWithFontNamed:#"Pixel LCD7"];
scores.fontSize = 30;
scores.fontColor = [SKColor darkGrayColor];
//displaying score :
scores.text = [NSString
stringWithFormat:#"Score:%#",mainScene.scoreLabel.text];
scores.name = #"score";
scores.position = CGPointMake(CGRectGetMidX(self.frame), 230);
[self addChild:scores];
}
MyScene
#import "MyScene.h"
#class GameOver;
#interface MyScene : SKScene {
SKLabelNode *scoreLabel;
}
#property (nonatomic) SKLabelNode *scoreLabel;
It doesn't work because you initialise the label in wrong method.
Remove didMoveToView: method if you use it just to initialise and set up the label and move the code to initWithSize: method:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
// Your init code here
scores = [[SKLabelNode alloc]initWithFontNamed:#"Pixel LCD7"];
scores.fontSize = 30;
scores.fontColor = [SKColor darkGrayColor];
//displaying score :
scores.text = [NSString stringWithFormat:#"Score:%#",mainScene.scoreLabel.text];
scores.name = #"score";
scores.position = CGPointMake(CGRectGetMidX(self.frame), 230);
self addChild:scores];
}
return self;
}
You should add property to your GameOver Scene to accept your score or override initWithSize: to for example initWithSize:score: and you should update your score label when you initialise game over scene.

Adding a Layer to a Scene does not work

I have been trying to get a layer into my scene. My scene is called "Survival". My layer is called "SSpriteLayer". The scene initializes, but the layer doesn't.
SURVIVAL.H:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "SSpriteLayer.h"
#interface Survival : CCLayer {}
#end
SURVIVAL.M:
#implementation Survival
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
Survival *layer = [Survival node];
SSpriteLayer *spriteLayer = [SSpriteLayer node];
// add layer as a child to scene
[scene addChild: layer];
[scene addChild: spriteLayer];
// return the scene
return scene;
}
-(id) init
{
if( (self=[super init]))
NSLog(#"SCENE HAS INIT");
return self;
}
#end
SSPRITELAYER.H:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface SSpriteLayer : CCLayer {
}
#end
SSPRITELAYER.M:
#import "SSpriteLayer.h"
#implementation SSpriteLayer
-(id) init
{
if( (self=[super init]))
NSLog(#"SPRITELAYER HAS INIT");
return self;
}
#end
What I do not understand is why my layer isn't initizializing, and why I am not getting the message "SPRITELAYER HAS INIT" in the debug area.
// add layer as a child to scene
[self addChild: layer];
[self addChild: SpriteLayer];
Change it And Try
Make sure, that you call
[Survival scene];
not
[Survival node];
and post code with calling your scene here

Resources