SKCropNode issue - ios

Spent a whole day on this. I don't find this in the iOS docs or on SO.
I have a SKShapeNode* that is like a window in my app, and I add a background that is an SKSpriteNode, and the background has another 10 SKSpriteNode as its children. So the node tree is like this:
SKScene -> window -> background -> (child1, ..., child10)
The dimensions are such that the background matches the size of the window, and all the background's children fit inside the background.
I want to zoom when I click inside the window (have the background & 10 children all zoom together). I accomplish this by setting the background's xScale & yScale, and the children inherit this scaling. But I also don't want to spill outside the window's boundaries, so I made a SKCropNode, and added the background as its child. Now the background doesn't spill out:
SKScene -> window -> SKCropNode -> background -> (child1, ..., child10)
Problem is, the background's children spill out when zooming. This is counter-intuitive to me. I tried searching online and looking in docs, "does SKCropNode crop its children & all descendants"? Since the answer appears to be no, I thought to change all 10 children's parent from background to SKCropNode:
SKScene -> window -> SKCropNode -> (background, child1, ..., child10)
Now I scale the SKCropNode. This scales background and all children, but now it spills to outside the window again. (Later in the game, the number of children may increase from 10 to 300, and I don't want to do a for loop on 300 items. So I want to be able to set scale on just one parent.)
I finally decided to try something a bit "hacky". This I did not find anywhere online, so I'm wondering if I'm in "undefined behavior" territory.
SKScene -> window -> SKCropNode1 -> SKCropNode2 -> (background, child1, ..., child10)
I added another SKCropNode on top of my original SKCropNode. Now, I only scale SKCropNode2. This works. However, now I'm getting very strange behavior. My SKShapeNode buttons (completely outside the window) will disappear one by one, then come back, and cycle like this. Further, the "nodes: 10, 60.0 fps" in the lower right will disappear too and return in the cycle. By cycle I mean me clicking inside the window zooming. It seems I've hit a bug in SpriteKit? I set the zPosition of the buttons to 20, way higher than anything else (5 and below). I also set skview.ignoresSiblingOrder = false; Appreciate any help or advice on how to accomplish this!
Edit: In reply to the comments, I did not use a simulator. I tested this on my iPad Pro and iPhone 6+, both running iOS 9.2. Below is my code that compiles & reproduces the behavior. I also took out the zooming code, but it's still reproducible. Please try to tap on the spaceship (Apple's sample image) about 30 times, you will start to see it then.
MainScene.h
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
#interface MainScene : SKScene<NSStreamDelegate>
#property (strong, nonatomic) SKCropNode* skcrop;
#end
MainScene.m
#import "MainScene.h"
#implementation MainScene
- (void)didMoveToView: (SKView*)view { }
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if ((int)[touches count] != 1) return;
UITouch* touch = [touches anyObject];
const CGPoint location = [touch locationInNode:self];
{ // without the 6 lines below, the disappearing-sprites behavior is gone
SKShapeNode* newshape = [SKShapeNode shapeNodeWithRectOfSize:
CGSizeMake(10.0, 10.0) cornerRadius:1.0];
newshape.position = location;
newshape.zPosition = 5;
newshape.fillColor = [UIColor purpleColor];
[self.skcrop addChild:newshape];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { }
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { }
#end
GameViewController.m:
#import "GameViewController.h"
#import "MainScene.h"
#import <CoreFoundation/CoreFoundation.h>
#implementation GameViewController
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeLeft
| UIInterfaceOrientationMaskLandscapeRight;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Configure SKView
SKView* skview = (SKView*)self.view;
skview.showsFPS = true;
skview.showsNodeCount = true;
skview.ignoresSiblingOrder = false;
skview.multipleTouchEnabled = false;
// Get Screen Size
// IPad Pro prints: screen size 768 1024
// IPhone 6+ prints: screen size 375 667
const int screenWidth = floor(0.5+skview.bounds.size.width);
const int screenHeight = floor(0.5+skview.bounds.size.height);
NSLog(#"screen size %d %d", screenWidth, screenHeight);
const double width = (screenWidth < 375) ? 360 : 720;
// Configure SKScene
MainScene *skscene = [[MainScene alloc]
initWithSize:CGSizeMake(screenWidth, screenHeight)];
skscene.scaleMode = SKSceneScaleModeFill;
skscene.backgroundColor = [UIColor whiteColor];
[skview presentScene:skscene];
// Set up window's crop mask
const CGSize winSurface = CGSizeMake(width, width);
const CGPoint winPosition = CGPointMake(
CGRectGetMidX(skscene.frame), CGRectGetMidY(skscene.frame));
NSLog(#"pos %f %f", winPosition.x, winPosition.y);
SKSpriteNode* winMaskParent = [[SKSpriteNode alloc]
initWithColor:[UIColor redColor] size:winSurface];
[winMaskParent retain];
winMaskParent.position = winPosition;
SKCropNode* scnParent = [SKCropNode node];
scnParent.zPosition = 1;
scnParent.maskNode = winMaskParent;
[skscene addChild:scnParent];
SKSpriteNode* winMask = [[SKSpriteNode alloc]
initWithColor:[UIColor blueColor] size:winSurface];
[winMask retain];
winMask.position = winPosition;
SKCropNode* scn = [SKCropNode node];
scn.zPosition = 1;
scn.maskNode = winMask;
[scnParent addChild:scn];
// Add window sprite
SKSpriteNode* win =
[SKSpriteNode spriteNodeWithImageNamed:#"Spaceship.png"];
win.zPosition = 2;
win.position = winPosition;
[scn addChild:win];
for (int i = 0; i < 5; ++i) {
const double height = 30.0;
const double width = 50.0;
const double posY = screenHeight - (1+i)*100.0;
const double posX = screenWidth - width - 10.0;
SKShapeNode* button = [SKShapeNode shapeNodeWithRectOfSize:
CGSizeMake(width, height) cornerRadius:1.0];
button.position = CGPointMake(posX, posY);
button.zPosition = 15;
button.fillColor = [UIColor greenColor];
button.lineWidth = 1.0;
button.glowWidth = 0.0;
[skscene addChild:button];
}
skscene.skcrop = scn;
return;
}
#end
Edit 2: I removed the nested SKCropNode so that there is only 1 layer of SKCropNode. The button sprites disappear after a few clicks on the spaceship.

Related

Objective-C. How is your first SKScene initialised?

This method sets up the initial scene and is called as soon as the application opens:
#import "GameScene.h"
#import "WarScene.h"
#import "Math.h"
#implementation GameScene
{
SKNode *map;
float oldY;
float oldX;
BOOL buttonClicked;
int thisButton;
float oldMapPosition;
float midScreenX;
float midScreenY;
int separation;
float sendY;
BOOL interacting;
CGVector speed;
float oldPosition;
float newPosition;
BOOL isReleased;
int iterations;
float diff;
BOOL comeToStop;
BOOL actualStop;
BOOL clicked;
}
int numberOfLevels = 20;
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
map = [SKNode node];
separation = [UIScreen mainScreen].bounds.size.height;
if (UIDeviceOrientationIsLandscape((UIDeviceOrientation)[[UIApplication sharedApplication] statusBarOrientation]))
{
//landscape mode
midScreenX = ([[UIScreen mainScreen]bounds].size.width>[[UIScreen mainScreen]bounds].size.height?[[UIScreen mainScreen]bounds].size.width:[[UIScreen mainScreen]bounds].size.height)/2;
midScreenY = ([[UIScreen mainScreen]bounds].size.width<[[UIScreen mainScreen]bounds].size.height?[[UIScreen mainScreen]bounds].size.width:[[UIScreen mainScreen]bounds].size.height)/2;
}
else
{
//portrait mode
midScreenX = [[UIScreen mainScreen]bounds].size.width/2;
midScreenY = [[UIScreen mainScreen]bounds].size.height/2;
}
NSLog(#"Initial Width: %f Height: %f", midScreenX*2, midScreenY*2);
map.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: CGSizeMake([UIScreen mainScreen].bounds.size.width, separation*(numberOfLevels+1))];
map.physicsBody.affectedByGravity = NO;
map.physicsBody.allowsRotation = NO;
clicked = NO;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(handleTap:)];
tap.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tap];
self.backgroundColor = [SKColor blackColor];
for (int i = 0; i<numberOfLevels; i += 1) {
SKLabelNode *title;
{
title = [SKLabelNode labelNodeWithFontNamed:#"Cochin"];
title.text = [NSString stringWithFormat: #"Level %d", 1+i];
title.fontSize = 60;
title.position = CGPointMake(CGRectGetMidX(self.frame),
((i+1)*separation));
title.fontColor = [UIColor whiteColor];
title.name = [NSString stringWithFormat: #"Level %d", 1+i];
[map addChild:title];
}
}
[self addChild:map];
}
This works exactly as I intended it to, however, when I call this from another class:
-(void)continueMethod:(UIButton*)button{
NSLog(#"InitwithSize to GameScene Width: %f Height: %f", midScreenX*2, midScreenY*2);
GameScene *map = [[GameScene alloc] initWithSize: CGSizeMake(midScreenX*2 ,midScreenY*2)];
SKTransition *reveal = [SKTransition revealWithDirection:SKTransitionDirectionDown duration:1.0];
SKView * skView = (SKView *)self.view;
UIView *viewToRemove = [self.view viewWithTag:3];
[viewToRemove removeFromSuperview];
[skView presentScene:map transition:reveal];
}
The scene which should be set up doesn't appear as I intended it to, or indeed how it used to look the last time that it was initialised. The separation variable appears bigger, the text appears bigger and everything is wider. I've verified that the UIScreen that I have initialised is exactly the same throughout.
This led me to question how the initial scene of a SKSprite application comes to be and whether it is different to "initWithSize:" however, looking through all the code that comes in the game template I can't ever see my first scene get called. The closest that I can find to initWithSize: is the following from the GameViewController-
GameScene *scene = [GameScene unarchiveFromFile:#"GameScene"];
scene.scaleMode = SKSceneScaleModeAspectFill;
Firstly, is this what is initialising my initial scene? Secondly is it in anyway different to initWithSize: ? And finally if the answer to the previous tow questions is yes, should it be used instead of initWithsize: ?
Yes, this is the initialization of the initial scene! What you are seeing in the View Controller is a slightly different initialization. You are using the sks file, first of all, and initWithCoder: is being called when the view controller unarchives it. However, this isn't very different from initWithSize if you specify all of the same dimensions and properties.
That being said, the scene's scaleMode in your initialization and the view controller's scaleMode is different. As you can see, the view controller specifies:
scene.scaleMode = SKSceneScaleModeAspectFill;
The AspectFill scale mode according to Apple:
The scaling factor of each dimension is calculated and the smaller of the two is chosen. Each axis of the scene is scaled by the same scaling factor. This guarantees that the entire scene is visible but may require letterboxing in the view.
When you initialize your scene, on the other hand, you leave the default scaleMode, which happens to be SKSceneScaleModeFill. This maps each axis of the scene to the view, so you get a distorted scene. What you need to do is simply state:
map.scaleMode = SKSceneScaleModeAspectFill;
This will use the same scale mode as in the original scene and the distortion that you see now will be gone.
Hope this helps, let me know if you have questions.

Sprite Kit customFieldWithEvaluationBlock - block not called

I created a new SpriteKit iOS project and added this code to GameScene.m. The block to calculate the force field is never called, so node n1 never moves. Anyone know why? What am I missing?
#implementation GameScene
-(void)didMoveToView:(SKView *)view {
// Create a red circle in the middle of scene
SKShapeNode *n1 = [SKShapeNode shapeNodeWithCircleOfRadius:20];
n1.fillColor = [UIColor redColor];
n1.position = CGPointMake(self.size.width / 2, self.size.height / 2);
n1.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:20];
n1.physicsBody.affectedByGravity = NO;
n1.physicsBody.dynamic = YES;
[self addChild:n1];
// Try to add a custom force field to the scene
SKFieldNode *f1 = [SKFieldNode customFieldWithEvaluationBlock:^vector_float3(vector_float3 position, vector_float3 velocity, float mass, float charge, NSTimeInterval deltaTime) {
printf("block called\n");
vector_float3 res = { 1.0, 0.0, 0.0 };
return res;
}];
f1.enabled = YES;
[self addChild:f1];
}

Moving a camera in SpriteKit

//UPDATE
The updated code has been added that works as I expected. See didSimulatePhysics method in the updated code below. In my case, I only care about moving a character left or right on the x axis where 0 on the x axis is the absolute left and right on the x axis is a configurable value. The Apple adventure game really helped a lot too.
//ORIGINAL POST BELOW
I'm working with Apple SpriteKit and I'm struggling to implement a camera as I would like it to behave. What I've done in the code is load a sprite character, two buttons, and a red box that is off to the right outside of the view at the start. What I'd like to be able to do is move the character with the buttons, and once the player reaches the middle or end of the screen, the camera will then re-adjust to uncover what couldn't be seen in the view. So moving to the right should eventually show the red box that is off outside of the view initially once the player gets there. However, with the code I'm using below, I'm unable to get the camera to follow and adjust the coordinates to the main character at all. I've looked at Apple's advanced scene processing doc as well as a few other stack overflow posts but can't seem to get it right. If anyone could offer some advice it would be appreciated.
#define cameraEdge 150
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
/* Setup your scene here */
//320 568
self.backgroundColor = [SKColor whiteColor];
myWorld = [[SKNode alloc] init];
[self addChild:myWorld];
mainCharacter = [SKSpriteNode spriteNodeWithImageNamed:#"0"];
mainCharacter.physicsBody.dynamic = YES;
mainCharacter.name = #"player";
mainCharacter.position = CGPointMake(20, 20);
CGRect totalScreenSize = CGRectMake(0, 0, 800, 320);
SKSpriteNode *box = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(60, 60)];
SKSpriteNode *boxTwo = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(60, 60)];
SKSpriteNode *boxThree = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(60, 60)];
boxThree.position = CGPointMake(40, 50);
[myWorld addChild:boxThree];
boxTwo.position = CGPointMake(1100, 50);
box.position = CGPointMake(650, 50);
[myWorld addChild:box];
[myWorld addChild:boxTwo];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:totalScreenSize];
self.physicsWorld.gravity = CGVectorMake(0, -5);
mainCharacter.name = #"mainCharacter";
mainCharacter.physicsBody.linearDamping = 0;
mainCharacter.physicsBody.friction = 0;
mainCharacter.physicsBody.restitution = 0;
mainCharacter.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:mainCharacter.size];
[myWorld addChild:mainCharacter];
[self addChild:[self buildLeftButton]];
[self addChild:[self buildRightButton]];
}
return self;
}
- (void)didSimulatePhysics
{
SKSpriteNode *hero = mainCharacter;
if(hero)
{
CGPoint heroPosition = hero.position;
CGPoint worldPosition = myWorld.position;
NSLog(#"%f", heroPosition.x);
CGFloat xCoordinate = worldPosition.x + heroPosition.x;
if(xCoordinate < cameraEdge && heroPosition.x > 0)
{
worldPosition.x = worldPosition.x - xCoordinate + cameraEdge;
self.worldMovedForUpdate = YES;
}
else if(xCoordinate > (self.frame.size.width - cameraEdge) && heroPosition.x < 2000)
{
worldPosition.x = worldPosition.x + (self.frame.size.width - xCoordinate) - cameraEdge;
self.worldMovedForUpdate = YES;
}
myWorld.position = worldPosition;
}
}
-(SKSpriteNode *)buildLeftButton
{
SKSpriteNode *leftButton = [SKSpriteNode spriteNodeWithImageNamed:#"left"];
leftButton.position = CGPointMake(20, 20);
leftButton.name = #"leftButton";
leftButton.zPosition = 1.0;
return leftButton;
}
-(SKSpriteNode *)buildRightButton
{
SKSpriteNode *leftButton = [SKSpriteNode spriteNodeWithImageNamed:#"right"];
leftButton.position = CGPointMake(60, 20);
leftButton.name = #"rightButton";
leftButton.zPosition = 1.0;
return leftButton;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if([node.name isEqualToString:#"leftButton"])
{
[mainCharacter.physicsBody applyImpulse:CGVectorMake(-120, 0)];
}
else if([node.name isEqualToString:#"rightButton"])
{
[mainCharacter.physicsBody applyImpulse:CGVectorMake(120, 10)];
}
}
If you want the view to always be centered on your player's position, modify your code with these points in mind:
1) Create a SKNode and call it myWorld, worldNode or any other name like that.
2) Add the worldNode [self addChild:worldNode];
3) Add all other nodes to the worldNode, including your player.
4) In the didSimulatePhysics method, add this code:
worldNode.position = CGPointMake(-(player.position.x-(self.size.width/2)), -(player.position.y-(self.size.height/2)));
Your view will now always be centered on your player's position.
Update May 2015:
If you are using a map created with Tiled Map Editor, you can use the free SKAToolKit framework. Features include player camera auto follow, test player, test HUD and sprite buttons.

Make an elastic band type slingshot in spritekit

I'm working on a game where I have a line across the bottom of the screen that I use to launch things up into the air. It should behave like a rubber band or a slingshot. I have hacked together something that works, but it's kind of a bad solution and I'm hoping someone can suggest another way. My way basically involved redrawing a mutablepath by repeated calls to the draw method during the touchesMoved method. Again, I know this is a bad way of doing it, so sorry for the horrible code.
-(void)drawLine:(CGPoint)location
{
[_powerLine removeFromParent];
CGPoint pointTL = CGPointMake(19, 131);
CGPoint pointTR = CGPointMake(308, 131);
CGPoint pointBL = CGPointMake(location.x-10, location.y);
CGPoint pointBR = CGPointMake(location.x+10, location.y);
UIBezierPath *lineShape = [UIBezierPath bezierPath];
[lineShape moveToPoint:pointTL];
[lineShape addLineToPoint:pointBL];
[lineShape addLineToPoint:pointBR];
[lineShape addLineToPoint:pointTR];
_powerLine = [SKShapeNode node];
_powerLine.path = lineShape.CGPath;
_powerLine.lineWidth = 2.0;
_powerLine.strokeColor = [SKColor colorWithRed:0.0 green:0 blue:0 alpha:1];
[self addChild:_powerLine];
CGMutablePathRef powerLinePath = CGPathCreateMutable();
CGPathMoveToPoint(powerLinePath, nil, pointTL.x, pointTL.y);
CGPathAddLineToPoint(powerLinePath, nil, pointBL.x, pointBL.y);
CGPathAddLineToPoint(powerLinePath, nil, pointBR.x, pointBR.y);
CGPathAddLineToPoint(powerLinePath, nil, pointTR.x, pointTR.y);
_powerLine.physicsBody = [SKPhysicsBody bodyWithEdgeChainFromPath:powerLinePath];
_powerLine.physicsBody.categoryBitMask = WFPhysicsCategoryPowerline;
_lastBR = pointBR;
_lastBL = pointBL;
}
I'm hoping there is a better way to do this other than constantly redrawing it when the person pulls the line down to shot the object up in the air. I looked into spring joints but couldn't convince them to work. The other problem I had with spring joints was how to get the image to stretch to match where the line should be. This approach solves trying to stretch an image by simply eliminating the image. It would be nice to use springs so that I could avoid having to hand code the physics of this.
Anyone have thoughts on how to do this?
I'm not sure if you're concerned about how to draw a convincing elastic band onscreen, or how to emulate the physics of one. If it's the former I can't help you much, but if it's the latter you could try something like this! You should be able to copy and paste it into an existing sprite kit app to play around with it, just initialize it and call SKView's presentScene: with it.
(header file)
#import <SpriteKit/SpriteKit.h>
#interface SlingScene : SKScene
#end
(implementation file)
#import "SlingScene.h"
#interface SlingScene ()
#property (nonatomic, strong) SKAction *slingAction;
#end
#implementation SlingScene
- (instancetype)initWithSize:(CGSize)size {
self = [super initWithSize:size];
if (self) {
CGPoint center = CGPointMake(self.size.width/2.0, self.size.height/2.0);
self.slingAction = [SKAction sequence:
#[[SKAction waitForDuration:0.1],
[SKAction runBlock:
^{
[self.physicsWorld removeAllJoints];
}
]]];
// Create a square, which will be slung by the spring
SKSpriteNode *square =
[SKSpriteNode spriteNodeWithColor:[SKColor whiteColor]
size:CGSizeMake(60.0, 60.0)];
square.position = CGPointMake(center.x, center.y - 2*square.size.height);
square.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:square.size];
square.physicsBody.collisionBitMask = 0;
square.name = #"square";
// Create a post to anchor the square to
SKShapeNode *post = [SKShapeNode node];
post.path = CGPathCreateWithEllipseInRect(
CGRectMake(0.0, 0.0, 60.0, 60.0), NULL);
post.fillColor = [SKColor brownColor];
post.strokeColor = [SKColor brownColor];
post.position = CGPointMake(center.x-30.0, center.y-30.0);
post.physicsBody =
[SKPhysicsBody bodyWithCircleOfRadius:60.0 center:center];
// Give the post a near-infinite mass so the square won't tug at it
// and move it around
post.physicsBody.mass = 1000000;
post.physicsBody.affectedByGravity = NO;
// Set their collision bit masks to the same value to allow them to pass
// through each other
post.physicsBody.collisionBitMask = 0;
square.physicsBody.collisionBitMask = 0;
// Add them to the scene
[self addChild:post];
[self addChild:square];
// Connect them via a spring
SKPhysicsJointSpring *spring =
[SKPhysicsJointSpring jointWithBodyA:post.physicsBody
bodyB:square.physicsBody
anchorA:center
anchorB:square.position];
spring.damping = 0.4;
spring.frequency = 1.0;
[self.physicsWorld addJoint:spring];
// Lower gravity from the default {0.0, -9.8} to allow the
// square to be slung farther
self.physicsWorld.gravity = CGVectorMake(0.0, -4.0);
}
return self;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// Move the square to the touch position
SKSpriteNode *square = (SKSpriteNode *)[self childNodeWithName:#"square"];
CGPoint location = [[touches anyObject] locationInNode:self];
[square runAction:[SKAction moveTo:location duration:0.1]];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// Sling the square by
// 1. allowing the spring to accelerate it, and
// 2. removing the spring altogether
[self runAction:self.slingAction];
}
#end
Another method might be to compute the x and y positions relative to a specific point, and apply an impulse in the opposite direction. For example, if you find dx = -100.0 and dy = -100.0, you could use applyImpulse:CGVectorMake(-dx, -dy) to launch it up and right. Using the spring joint gives you some acceleration, however.

Not working right, start and end positon

I'm trying to graph some trigonometric functions on an SKScene.. I'm using an SKShapeNode for each point in the screen so when it reaches the left side I remove if from the parent.
The problem is that, for some reason it only draws on a portion of the screen as if it were contained by a smaller view.. The position on the screen is not matching the real screen... for example if I place it at 100 it is actually at a different place.. Plus the size of the area where it graphs is reduced...
There is some code at the bottom
I hope someone could help me! Thank you very much!
Anything else that might help ask and I'll re-edit the post.
Thank you!
Here is some code:
- (void) createTrigonometricFunction
{
[self calculateFunction];
CGMutablePathRef pathToDraw = CGPathCreateMutable();
CGPathMoveToPoint(pathToDraw, NULL, groundOriginLocation.x,groundOriginLocation.y + groundPointPrevious.y);
CGPathAddLineToPoint(pathToDraw, NULL, groundOriginLocation.x + 1,groundOriginLocation.y + groundPointCurrent.y);
SKShapeNode * currentLine = [SKShapeNode node];
currentLine.position = CGPointMake(groundOriginLocation.x,groundOriginLocation.y);
currentLine.path = pathToDraw;
CGPathRelease(pathToDraw);
[currentLine setStrokeColor:[UIColor whiteColor]];
currentLine.name = #"terrainLine";
currentLine.lineWidth = 1;
[currentScene addChild: currentLine];
groundPointPrevious = groundPointCurrent;
//NSLog(#"%f - %f",currentLine.position.x,currentLine.position.y);
}
- (void) calculateFunction
{
groundDominio += 1;
groundPointCurrent.x = groundOriginLocation.x;
groundPointCurrent.y = 2*(sin(degreesToRadian(groundDominio)*2)/5*degreesToRadian(180))*cos(degreesToRadian(150) + degreesToRadian(groundDominio)*5)*sin(degreesToRadian(groundPointCurrent.x));
groundPointCurrent.y = radianToDegrees(groundPointCurrent.y);
}
//The view controller:: (This is how I load it)
- (void)viewDidLoad
{
[super viewDidLoad];
// Configure the view.
SKView * skView = (SKView *)self.view;
//skView.showsFPS = YES;
skView.showsNodeCount = YES;
// Create and configure the scene.
SKScene * scene = [MainGame sceneWithSize: skView.bounds.size];
//scene.scaleMode = SKSceneScaleModeAspectFill;
NSLog(#"%f $$ %f",self.view.frame.size.height,self.view.frame.size.width);
// Present the scene.
[skView presentScene:scene];
}
Do you draw on the scene or on another node?
If you are drawing on another node, your drawing will be off since the default anchor point for node is 0.5, 0.5 (it is pinned to scene with its center) but the actual 0.0 position inside the node is not its center.

Resources