Created
March 17, 2018 04:42
-
-
Save mohiji/f3f395a0bb0e6ad1c3495f1c448e3ef7 to your computer and use it in GitHub Desktop.
Components and delegates
This file contains hidden or 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 GameplayKit; | |
@import SpriteKit; | |
@class AnimatedSpriteComponent; | |
@protocol AnimatedSpriteComponentDelegate | |
- (void)animatedSpriteComponent:(AnimatedSpriteComponent *)component didUpdateToFrame:(SKTexture *)frame; | |
- (void)animatedSpriteComponent:(AnimatedSpriteComponent *)component didCompleteAnimation:(NSString *)animationName; | |
@end | |
@interface AnimatedSpriteComponent : GKComponent | |
@property (weak, nonatomic) id<AnimatedSpriteComponentDelegate> delegate; | |
@property (assign, nonatomic) int framesPerSecond; | |
@property (readonly, nonatomic) float secondsPerFrame; | |
@property (readonly, nonatomic) NSString *currentAnimation; | |
- (void)addAnimationNamed:(NSString *)name withFrames:(NSArray<SKTexture *> *)frames; | |
- (void)playAnimation:(NSString *)name looping:(BOOL)looping; | |
- (void)stopAnimation; | |
@end |
This file contains hidden or 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 "AnimatedSpriteComponent.h" | |
static const int kDefaultFramesPerSecond = 5; | |
@interface AnimatedSpriteComponent () { | |
int _currentFrame; | |
CFTimeInterval _timeThisFrame; | |
BOOL _looping; | |
BOOL _animating; | |
} | |
@property (strong, nonatomic) NSMutableDictionary<NSString *, NSArray<SKTexture *> *> *animations; | |
@property (copy, nonatomic) NSString *currentAnimation; | |
@end | |
@implementation AnimatedSpriteComponent | |
- (id)init { | |
self = [super init]; | |
if (self != nil) { | |
self.animations = [NSMutableDictionary dictionary]; | |
_framesPerSecond = kDefaultFramesPerSecond; | |
} | |
return self; | |
} | |
- (float)secondsPerFrame { | |
return 1.0f / _framesPerSecond; | |
} | |
- (void)addAnimationNamed:(NSString *)name withFrames:(NSArray<SKTexture *> *)frames{ | |
self.animations[name] = frames; | |
} | |
- (void)playAnimation:(NSString *)name looping:(BOOL)looping{ | |
NSArray *animation = self.animations[name]; | |
if (animation == nil) { | |
return; | |
} | |
self.currentAnimation = name; | |
_currentFrame = 0; | |
_timeThisFrame = 0.0; | |
_looping = looping; | |
_animating = YES; | |
[self.delegate animatedSpriteComponent:self didUpdateToFrame:animation[_currentFrame]]; | |
} | |
- (void)updateWithDeltaTime:(NSTimeInterval)seconds { | |
if (!_animating) { | |
return; | |
} | |
_timeThisFrame += seconds; | |
float secondsPerFrame = [self secondsPerFrame]; | |
if (_timeThisFrame >= secondsPerFrame) { | |
_currentFrame++; | |
_timeThisFrame -= secondsPerFrame; | |
NSArray *animation = self.animations[self.currentAnimation]; | |
if (_currentFrame >= [animation count]) { | |
_currentFrame = 0; | |
if (!_looping) { | |
[self stopAnimation]; | |
return; | |
} | |
} | |
[self.delegate animatedSpriteComponent:self didUpdateToFrame:animation[_currentFrame]]; | |
} | |
} | |
- (void)stopAnimation { | |
_animating = NO; | |
[self.delegate animatedSpriteComponent:self didCompleteAnimation:self.currentAnimation]; | |
} | |
@end |
This file contains hidden or 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 GameplayKit; | |
@class MovementComponent; | |
@protocol MovementComponentDelegate | |
- (CGPoint)currentPositionForMovementComponent:(MovementComponent *)component; | |
- (void)movementComponent:(MovementComponent *)component didMoveToPosition:(CGPoint)position; | |
- (void)movementComponent:(MovementComponent *)component didReachTarget:(CGPoint)target; | |
@end | |
@interface MovementComponent : GKComponent | |
@property (weak, nonatomic) id<MovementComponentDelegate> delegate; | |
@property (assign, nonatomic) CGFloat threshold; | |
@property (assign, nonatomic) CGFloat speed; | |
@property (readonly, nonatomic) CGPoint target; | |
@property (readonly, nonatomic) BOOL moving; | |
- (void)moveToPosition:(CGPoint)position; | |
@end |
This file contains hidden or 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 "MovementComponent.h" | |
#import "CGPointMath.h" | |
static const CGFloat kMovementComponentDefaultThreshold = 1.0f; | |
static const CGFloat kMovementComponentDefaultSpeed = 90.0f; | |
@interface MovementComponent () | |
@property (assign) CGPoint target; | |
@property (assign) BOOL moving; | |
@end | |
@implementation MovementComponent | |
- (id)init { | |
self = [super init]; | |
if (self != nil) { | |
self.threshold = kMovementComponentDefaultThreshold; | |
self.speed = kMovementComponentDefaultSpeed; | |
} | |
return self; | |
} | |
- (void)moveToPosition:(CGPoint)position { | |
_moving = YES; | |
_target = position; | |
} | |
- (void)updateWithDeltaTime:(NSTimeInterval)seconds { | |
if (!_moving || _delegate == nil) { | |
return; | |
} | |
CGPoint current = [_delegate currentPositionForMovementComponent:self]; | |
CGPoint dv = CGPointSubtract(_target, current); | |
if (CGPointMagnitude(dv) < _threshold) { | |
_moving = NO; | |
[_delegate movementComponent:self didReachTarget:_target]; | |
return; | |
} | |
dv = CGPointNormalized(dv); | |
CGPoint newPosition = CGPointAdd(current, CGPointScale(dv, seconds * _speed)); | |
[self.delegate movementComponent:self didMoveToPosition:newPosition]; | |
} | |
@end |
This file contains hidden or 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 GameplayKit; | |
@import SpriteKit; | |
#import "MovementComponent.h" | |
#import "AnimatedSpriteComponent.h" | |
@interface PlayerControllerComponent : GKComponent<MovementComponentDelegate, AnimatedSpriteComponentDelegate> | |
@property (strong, nonatomic) SKTexture *idleUpTexture; | |
@property (strong, nonatomic) SKTexture *idleDownTexture; | |
@property (strong, nonatomic) SKTexture *idleLeftTexture; | |
@property (strong, nonatomic) SKTexture *idleRightTexture; | |
- (void)moveToPosition:(CGPoint)position; | |
@end |
This file contains hidden or 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 "PlayerControllerComponent.h" | |
#import "SpriteComponent.h" | |
#import "CGPointMath.h" | |
@implementation PlayerControllerComponent | |
- (void)moveToPosition:(CGPoint)position { | |
MovementComponent *m = [self mover]; | |
if (m == nil) { | |
return; | |
} | |
m.delegate = self; | |
[m moveToPosition:position]; | |
CGPoint current = [self currentPosition]; | |
CGPoint dv = CGPointSubtract(position, current); | |
AnimatedSpriteComponent *animator = [self animator]; | |
animator.delegate = self; | |
if (fabs(dv.x) > fabs(dv.y)) { | |
if (dv.x < 0.0) { | |
[animator playAnimation:@"walk-left" looping:YES]; | |
} | |
else { | |
[animator playAnimation:@"walk-right" looping:YES]; | |
} | |
} | |
else { | |
if (dv.y < 0) { | |
[animator playAnimation:@"walk-down" looping:YES]; | |
} | |
else { | |
[animator playAnimation:@"walk-up" looping:YES]; | |
} | |
} | |
} | |
- (CGPoint)currentPositionForMovementComponent:(MovementComponent *)component { | |
return [self currentPosition]; | |
} | |
- (void)movementComponent:(MovementComponent *)component didMoveToPosition:(CGPoint)position { | |
[self spriteComponent].sprite.position = position; | |
} | |
- (void)movementComponent:(MovementComponent *)component didReachTarget:(CGPoint)target { | |
[self spriteComponent].sprite.position = target; | |
[[self animator] stopAnimation]; | |
} | |
- (void)animatedSpriteComponent:(AnimatedSpriteComponent *)component didCompleteAnimation:(NSString *)animationName { | |
if ([@"walk-up" isEqualToString:animationName]) { | |
[self spriteComponent].sprite.texture = self.idleUpTexture; | |
} | |
else if ([@"walk-down" isEqualToString:animationName]) { | |
[self spriteComponent].sprite.texture = self.idleDownTexture; | |
} | |
else if ([@"walk-left" isEqualToString:animationName]) { | |
[self spriteComponent].sprite.texture = self.idleLeftTexture; | |
} | |
else if ([@"walk-right" isEqualToString:animationName]) { | |
[self spriteComponent].sprite.texture = self.idleRightTexture; | |
} | |
} | |
- (void)animatedSpriteComponent:(AnimatedSpriteComponent *)component didUpdateToFrame:(SKTexture *)frame { | |
[self spriteComponent].sprite.texture = frame; | |
} | |
- (MovementComponent *)mover { | |
return (MovementComponent *)[self.entity componentForClass:[MovementComponent class]]; | |
} | |
- (SpriteComponent *)spriteComponent { | |
return (SpriteComponent *)[self.entity componentForClass:[SpriteComponent class]]; | |
} | |
- (AnimatedSpriteComponent *)animator { | |
return (AnimatedSpriteComponent *)[self.entity componentForClass:[AnimatedSpriteComponent class]]; | |
} | |
- (CGPoint)currentPosition { | |
SpriteComponent *s = [self spriteComponent]; | |
if (s == nil) { | |
return CGPointZero; | |
} | |
return s.sprite.position; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment