Skip to content

Instantly share code, notes, and snippets.

@hollance
Created January 28, 2014 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hollance/8671187 to your computer and use it in GitHub Desktop.
Save hollance/8671187 to your computer and use it in GitHub Desktop.
Motion streak code using SKShapeNode that didn't make it into the book iOS Games by Tutorials (raywenderlich.com).
#import <SpriteKit/SpriteKit.h>
@interface MotionStreak : SKShapeNode
- (void)addPosition:(CGPoint)position;
- (void)updateStreak;
@end
#import "MotionStreak.h"
#import "SKTUtils.h"
static const int MaxPoints = 20;
static const CGFloat Thickness = 8.0f;
@implementation MotionStreak
{
UIBezierPath *_path;
CGPoint _points[MaxPoints];
CGFloat _angles[MaxPoints];
CGPoint _previousPoint;
int _count;
int _index;
}
- (instancetype)init
{
if ((self = [super init]))
{
_path = [UIBezierPath bezierPath];
self.lineWidth = 0.0f;
self.fillColor = SKColorWithRGBA(255, 255, 255, 64);
self.antialiased = NO;
// NOTE: This is necessary because of an issue with Sprite Kit.
// If the ShapeNode does not cover the entire playing area when it
// is created, then it gets hidden in the areas it doesn't cover,
// even if you add those later. I consider this a bug.
[_path moveToPoint:CGPointZero];
[_path addLineToPoint:CGPointMake(1000.0f, 1000.0f)];
[_path closePath];
self.path = _path.CGPath;
}
return self;
}
- (void)addPosition:(CGPoint)position
{
// Ignore the new point if it is too close to the prevous point.
if (CGPointDistance(_previousPoint, position) < 2.0f)
return;
_points[_index] = position;
if (_count < MaxPoints)
_count++;
CGFloat angle = CGPointToAngle(CGPointSubtract(position, _previousPoint));
_angles[_index] = angle + M_PI_2;
_previousPoint = position;
_index++;
if (_index == MaxPoints)
_index = 0;
}
- (void)updateStreak
{
[_path removeAllPoints];
if (_count > 1)
{
int i = _index % _count;
CGPoint point = _points[i];
CGFloat taper = 1.0f / _count;
CGFloat s = sinf(_angles[i]) * taper * Thickness;
CGFloat c = cosf(_angles[i]) * taper * Thickness;
[_path moveToPoint:CGPointMake(point.x + c, point.y + s)];
[_path addLineToPoint:CGPointMake(point.x - c, point.y - s)];
for (int t = 1; t < _count; ++t)
{
int i = (_index + t) % _count;
point = _points[i];
taper = (t + 1) / (float)_count;
s = sinf(_angles[i]) * taper * Thickness;
c = cosf(_angles[i]) * taper * Thickness;
[_path addLineToPoint:CGPointMake(point.x - c, point.y - s)];
}
for (int t = _count - 1; t >= 1; --t)
{
int i = (_index + t) % _count;
point = _points[i];
taper = (t + 1) / (float)_count;
s = sinf(_angles[i]) * taper * Thickness;
c = cosf(_angles[i]) * taper * Thickness;
[_path addLineToPoint:CGPointMake(point.x + c, point.y + s)];
}
[_path closePath];
self.path = _path.CGPath;
}
}
@end
You can find SKTUtils.h at http://github.com/raywenderlich/SKTUtils
@ianwaters
Copy link

Yeap, this is brilliant. It only took 2 mins to set-up and implement. Many thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment