Skip to content

Instantly share code, notes, and snippets.

@tnydwrds
Last active August 29, 2015 14:18
Show Gist options
  • Save tnydwrds/8ea1198e33cba8bb5c61 to your computer and use it in GitHub Desktop.
Save tnydwrds/8ea1198e33cba8bb5c61 to your computer and use it in GitHub Desktop.
Line Example - Updates to someone's code demonstrating how to extend a line beyond touch location and for me to learn some trigonometry.
#import "GameScene.h"
@implementation GameScene {
SKShapeNode *line; // Declaration of the SKShapeNode "line".
// I thought storing a starting point was more convenient than calculating it in drawLine:.
CGPoint startingPoint;
CGFloat lineLength;
}
-(void)didMoveToView:(SKView *)view {
/* Setup your scene here */
self.backgroundColor = [SKColor blackColor];
// Inititalize the SKShapeNode "line".
line = [SKShapeNode node];
[self addChild:line];
[line setStrokeColor:[UIColor greenColor]];
// The startingPoint will still be the origin of your path, but it will be (0, 0) in the
// SKShapeNode's coordinate system as I thought that would make the math easier. Additionally
// the SKShapeNode is positioned in the world space rather than the node, again to help make the
// math easier.
startingPoint = CGPointZero;
line.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - (CGRectGetMidY(self.frame) * 0.5));
// I'm being lazy here and just storing the value of the largest screen dimension to use that
// as the line length to guarantee that the line goes to the edge.
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.height;
lineLength = (width > height) ? width : height;
}
-(void)drawLine:(CGPoint)endingPoint {
// I'm not a trigonometry expert, so there is probably a better way to do this, but after
// reading up to get a better understanding this seems to work.
// First we consider that the line from startingPoint to endingPoint (the touch location)
// is the hypotenuse of a right triangle...
// - with the adjacent leg length being the startingPoint.x to endingPoint.x
// - with the opposite leg length being the startingPoint.y to endingPoint.y
// Since we made startingPoint CGPointZero, this is easy and we don't have to do any math to
// calculate any offets or deltas.
CGFloat adjacentLegLength = endingPoint.x;
CGFloat oppositeLegLength = endingPoint.y;
// Now that we have the lengths we can find the alpha angle with arctangent.
CGFloat alphaAngle = atan2(oppositeLegLength, adjacentLegLength);
// With all this we now have enough information to essentially scale the hypotenuse to extend
// beyond our touch point. Again, not a trig expert so forgive inaccurate terminology here (^_^;)
// Cosine is the relationship of the adjacent leg to the alpha angle, so we can use that to
// figure out the actual x coordinate of the endpoint based on our hard-coded lineLength (our
// new hypotenuse length).
endingPoint.x = cos(alphaAngle) * lineLength;
// Sine is the relationship of the opposite leg to the alpha angle, so we use that to find y.
endingPoint.y = sin(alphaAngle) * lineLength;
// I guess if you're doing some type of reflection, you probably want to end up doing some math
// to find x or y at the bounds of the frame instead of what I've done here. Then you can use
// more trig to continue the line at the appropriate angle. Hopefully this gets you in the right
// direction?
CGMutablePathRef pathToDraw = CGPathCreateMutable();
// Now, this below is about 1/4 of the way up the screen.
CGPathMoveToPoint(pathToDraw, NULL, startingPoint.x, startingPoint.y); // Starting Point.
CGPathAddLineToPoint(pathToDraw, NULL, endingPoint.x, endingPoint.y); // Where to draw the line TO.
CGFloat dashedPattern[2];
dashedPattern[0] = 20.0; // The length of them.
dashedPattern[1] = 20.0; // The distance between them.
CGFloat dottedPattern[2];
dottedPattern[0] = 5.0; // The length of them.
dottedPattern[1] = 20.0; // The distance between them.
CGPathRef dashed = CGPathCreateCopyByDashingPath(pathToDraw, NULL, 0, dashedPattern, 2); // Reference, Transform, Phase, Lengths, Count.
CGPathRef dotted = CGPathCreateCopyByDashingPath(pathToDraw, NULL, 0, dottedPattern, 2); // Reference, Transform, Phase, Lengths, Count.
line.path = dashed; // Turn the SKShapeNode "line" into a dotted or dashed line, and not just empty.
CGPathRelease(dashed);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:line];
[self drawLine:location]; // Call the drawLine function to draw the line to the finger's location.
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:line];
[self drawLine:location]; // Keep calling the drawLine function, so it'll stay updated with where your finger is at.
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
line.path = nil; // Remove the SKShapeNode "line" from the screen when you release your touch.
}
-(void)update:(NSTimeInterval)currentTime {
/* Update function ... you know what it does ;) */
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment