Last active
August 29, 2015 14:18
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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