SpriteKit框架(动态文字)

  SpriteKit框架的工程项目和添加内容到视图中。
  那么下面的内容主要介绍的是怎样切换场景
Step I.使用动作让场景内的内容动起来

态的文字视图很友好,但是如果文字视图可以动起来的话,它会使整个程序变得更加有趣。
我们在SpriteKit框架中,通常是通过执行动作(action)来移动场景内的元素。

1、创建action对象来描述你想要完成的动画,然后告诉一个元素来运行它。
2、当渲染场景的时候,动作会被执行,在多个帧上发生变化知道完成为止。
 
我们要完成一个任务,当用户触摸场景内容的时候,文字会放大缩小发生变化。
当用户再次触摸场景内容的时候,文字会停止动作。 
 
详细代码
HelloScene.m
 
- (instancetype)initWithSize:(CGSize)size
{
self = [superinitWithSize:size];
if (self) {
SKLabelNode *labelNode = [SKLabelNodelabelNodeWithFontNamed:@"Avenir"];
        labelNode.fontSize = 13.0f;
        labelNode.text = @"Hello Lanou!";
        labelNode.position = CGPointMake(size.width / 2.0f, size.height / 2.0f);
        [selfaddChild:labelNode];
        labelNode.name = @"hello";
    }
returnself;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
SKNode *helloNode = [selfchildNodeWithName:@"hello"];
 
//如果程序内的helloNode标签有动作的话,就移除动作
if (helloNode.hasActions) {
        [helloNode removeAllActions];
return;
    }
//添加动作
if(helloNode != nil)
    {
SKAction *scaleAction_1 = [SKActionscaleTo:2.0fduration:0.25f];
SKAction *scaleAction_2 = [SKActionscaleTo:1.0fduration:0.25f];
SKAction *scaleSequence = [SKActionsequence:@[scaleAction_1,scaleAction_2]];
SKAction *scaleRepeat = [SKActionrepeatActionForever:scaleSequence];
        [helloNode runAction:scaleRepeat];
    }
}
 
HelloScene.m
们来详细看一下SKAction这个类,到底都包含方法
 
@interface SKAction (SKActions)
 
+ (SKAction *)moveByX:(CGFloat)deltaX y:(CGFloat)deltaY duration:(NSTimeInterval)sec;
+ (SKAction *)moveBY:(CGVector)delta duration:(NSTimeInterval)sec;
+ (SKAction *)moveTo:(CGPoint)location duration:(NSTimeInterval)sec;
+ (SKAction *)moveToX:(CGFloat)x duration:(NSTimeInterval)sec;
+ (SKAction *)moveToY:(CGFloat)y duration:(NSTimeInterval)sec;
 
+ (SKAction *)rotateByAngle:(CGFloat)radians duration:(NSTimeInterval)sec;
+ (SKAction *)rotateToAngle:(CGFloat)radians duration:(NSTimeInterval)sec;
+ (SKAction *)rotateToAngle:(CGFloat)radians duration:(NSTimeInterval)sec shortestUnitArc:(BOOL)shortestUnitArc;
 
+ (SKAction *)resizeByWidth:(CGFloat)width height:(CGFloat)height duration:(NSTimeInterval)duration;
+ (SKAction *)resizeToWidth:(CGFloat)width height:(CGFloat)height duration:(NSTimeInterval)duration;
 
+ (SKAction *)resizeToWidth:(CGFloat)width duration:(NSTimeInterval)duration;
+ (SKAction *)resizeToHeight:(CGFloat)height duration:(NSTimeInterval)duration;
 
+ (SKAction *)scaleBy:(CGFloat)scale duration:(NSTimeInterval)sec;
+ (SKAction *)scaleXBy:(CGFloat)xScale y:(CGFloat)yScale duration:(NSTimeInterval)sec;
+ (SKAction *)scaleTo:(CGFloat)scale duration:(NSTimeInterval)sec;
+ (SKAction *)scaleXTo:(CGFloat)xScale y:(CGFloat)yScale duration:(NSTimeInterval)sec;
+ (SKAction *)scaleXTo:(CGFloat)scale duration:(NSTimeInterval)sec;
+ (SKAction *)scaleYTo:(CGFloat)scale duration:(NSTimeInterval)sec;
 
+ (SKAction *)sequence:(NSArray *)actions;
 
+ (SKAction *)group:(NSArray *)actions;
 
+ (SKAction *)repeatAction:(SKAction *)action count:(NSUInteger)count;
+ (SKAction*)repeatActionForever:(SKAction *)action;
 
+ (SKAction *)fadeInWithDuration:(NSTimeInterval)sec;
 (SKAction *)fadeInWithDuration:(NSTimeInterval)sec;
+ (SKAction*)fadeOutWithDuration:(NSTimeInterval)sec;
+ (SKAction *)fadeAlphaBy:(CGFloat)factor duration:(NSTimeInterval)sec;
+ (SKAction *)fadeAlphaTo:(CGFloat)alpha duration:(NSTimeInterval)sec;
 
+ (SKAction *)setTexture:(SKTexture *)texture;
+ (SKAction*)animateWithTextures:(NSArray *)textures timePerFrame:(NSTimeInterval)sec;
+ (SKAction*)animateWithTextures:(NSArray *)textures timePerFrame:(NSTimeInterval)sec resize:(BOOL)resize
             restore:  (BOOL)restore;

/*name must be the name or path of a file of a platform supported audio file format. Use a LinearPCM format audio file with 8 or 16 bits per channel for best performance */

+ (SKAction*)playSoundFileNamed:(NSString*)soundFile waitForCompletion:(BOOL)wait;
 
+ (SKAction*)colorizeWithColor:(SKColor *)color colorBlendFactor:(CGFloat)colorBlendFactor duration:(NSTimeInterval)sec;
+ (SKAction*)colorizeWithColorBlendFactor:(CGFloat)colorBlendFactor duration:(NSTimeInterval)sec;
 
+ (SKAction *)followPath:(CGPathRef)path duration:(NSTimeInterval)sec;
+ (SKAction *)followPath:(CGPathRef)path asOffset:(BOOL)offset orientToPath:(BOOL)orient duration:(NSTimeInterval)sec;
 
+ (SKAction *)speedBy:(CGFloat)speed duration:(NSTimeInterval)sec;
+ (SKAction *)speedTo:(CGFloat)speed duration:(NSTimeInterval)sec;
 
+ (SKAction*)waitForDuration:(NSTimeInterval)sec;
+ (SKAction*)waitForDuration:(NSTimeInterval)sec withRange:(NSTimeInterval)durationRange;
 
+ (SKAction*)removeFromParent;
 
+ (SKAction*)performSelector:(SEL)selector onTarget:(id)target;
 
+ (SKAction *)runBlock:(dispatch_block_t)block;
+ (SKAction *)runBlock:(dispatch_block_t)block queue:(dispatch_queue_t)queue;
 
+ (SKAction *)runAction:(SKAction *)action onChildWithName:(NSString*)name;
 
+ (SKAction*)customActionWithDuration:(NSTimeInterval)seconds actionBlock:(void (^)(SKNode *node, CGFloat elapsedTime))block;
 
@end
 


SKActions这个类目中,我们能够看到大量的动作,例如scaleBy:duration:和scaleTo:duration:,这两个到底有什么区别.
其中scaleBy:duration:这个方法返回的SKAction对象能够返回一个reversedAction对象,这两个对象是成完全相反的方向的。而scaleTo:duration:这个方法同样也会返回一个reversedAction对象,但是返回的这个对象却是没有动作内容的。
所以上述的touchesBegan:withEvent:方法中if结构可以用以下实现代替。
//添加动作
if(helloNode != nil)
    {
SKAction *scaleAction = [SKActionscaleBy:2.0fduration:0.25f];
SKAction *scaleSequence = [SKActionsequence:@[scaleAction,scaleAction.reversedAction]];
SKAction *scaleRepeat = [SKActionrepeatActionForever:scaleSequence];
        [helloNode runAction:scaleRepeat];
    }

  • 场景间的切换
SpriteKit框架在实现场景切换时非常容易。场景在切换过渡的过程中,你可以保留他们,也可以清除他们。
接下来,我们要完成的任务是,当用户触摸HelloScene场景后,切换到下一个场景,并且清除HelloScene场景。
     1、创建新的场景名称GameScene。
     2、在HelloScene导入GameScene的头文件。
     3、创建新的场景管理单例对象。
     4、创建一个按钮元素类。
    
  • 详细代码
GameScene.m
 
#import "SKSceneManager.h"
@interfaceGameScene()
@propertyBOOL contentCreated;
@end
@implementation GameScene
@synthesize contentCreated = _contentCreated;
- (instancetype)initWithSize:(CGSize)size
{
self = [superinitWithSize:size];
if (self) {

    }
returnself;
}
- (void)didMoveToView:(SKView *)view
{
    [superdidMoveToView:view];
if (!self.contentCreated) {
        [selfcreateSceneContents];
self.contentCreated = YES;
    }
}
- (void)createSceneContents
{
self.backgroundColor = [SKColorblackColor];
self.scaleMode = SKSceneScaleModeAspectFit;
//按钮的摆放位置
CGPoint position = CGPointZero;
#ifdef __IPHONE_7_0
    position.x = 60;
    position.y = 568 - 60;
#else
    position.x = 60;
    position.y = 480 - 60;
#endif
SKButton *button = [SKButtonbuttonWithSize:CGSizeMake(60, 30) andTitle:@"Back"];
    button.target = self;
    button.selector = @selector(didClickButton);
    button.position = position;
    [selfaddChild:button];
 }
 
- (void)didClickButton
{
SKScene *scene = [[SKSceneManagerinstance] sceneForKey:@"HelloScene"withSize:self.size];
    [self.viewpresentScene:scene transition:[SKTransitiondoorsCloseVerticalWithDuration:1.0f]];
}

@end
在游戏场景中添加了自定义按钮SKButton的实例对象以及该对象的回调方法didClickButton。
接下来,我们看一下SKButton按钮类的封装和SKSceneManager场景管理类的封装。
SKButton.h
 
@interface SKButton : SKShapeNode
//回调对象
@property (nonatomic ,assign) id target;
//回调方法
@property (nonatomic ,assign) SEL selector;
//便利构造器
+ (SKButton *)buttonWithSize:(CGSize)size andTitle:(NSString *)title;

@end

SKButton.m

@implementation SKButton
@synthesize target = _target;
@synthesize selector = _selector;

+ (SKButton *)buttonWithSize:(CGSize)size andTitle:(NSString *)title
{
CGRect rect = CGRectMake(0, 0, size.width, size.height);
SKButton *result = [[SKButtonalloc] init];
//创建路径
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRoundedRect(path, NULL, rect, 5.0f, 5.0f);
//设置路径及相关属性
    result.path = path;
    result.lineWidth = 0.5f;
    result.strokeColor = [SKColoryellowColor];
    result.userInteractionEnabled = YES;
    result.antialiased = YES;
//释放路径
CFRelease(path);
//创建文本标签
SKLabelNode *label = [[SKLabelNodealloc] initWithFontNamed:@"Avenir"];
    [label setName:@"label"];
    [label setFontSize:22];
    [label setText:title];
    [label setFontColor:[SKColoryellowColor]];
    [label setPosition:CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect) - CGRectGetMidY(label.frame))];
    [result addChild:label];
 
return result;
}
 
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//接收到用户触摸后,将SEL对象发送给id对象
    [self.targetperformSelector:self.selectorwithObject:nil];
}

@end

SKSceneManager.h

#import <SpriteKit/SpriteKit.h>
 
@interface SKSceneManager : NSObject
 
+ (SKSceneManager *)instance;
 
//key是场景类的类名
//size是场景获得的场景对象的尺寸大小
- (SKScene *)sceneForKey:(NSString *)key withSize:(CGSize) size;
//移除对应场景类类名的场景
- (void)removeSceneForKey:(NSString *)key;
 
@end
 
 SKSceneManager.m

@interfaceSKSceneManager()
@property (nonatomic ,readonly) NSMutableDictionary *sceneInfo;
@end

@implementation SKSceneManager
@synthesize sceneInfo = _sceneInfo;
staticSKSceneManager *s_SKSceneManager = nil;
+ (SKSceneManager *)instance
{
staticdispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (s_SKSceneManager == nil) {
s_SKSceneManager = [[SKSceneManageralloc] init];
        }
    });
returns_SKSceneManager;
}

- (id)init
{
self = [superinit];
if (self) {
_sceneInfo = [[NSMutableDictionaryalloc] init];
    }
returnself;
}
- (SKScene *)sceneForKey:(NSString *)key withSize:(CGSize) size
{
SKScene *scene = [self.sceneInfoobjectForKey:key];
if (scene == nil)
    {
        scene = [[NSClassFromString(key) alloc] initWithSize:size];
        [self.sceneInfosetObject:scene forKey:key];
    }
    scene.size = size;
 
return sc ene;
}
- (void)removeSceneForKey:(NSString *)key
{
    [self.sceneInforemoveObjectForKey:key];
}

@end
接下来需要修改一下HelloScene场景中的点击方法。
 
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
SKNode *helloNode = [selfchildNodeWithName:@"hello"];
//如果程序内的helloNode标签有动作的话,就移除动作
if (helloNode.hasActions) {
        [helloNode removeAllActions];
return;
    }
//添加动作
if(helloNode != nil)
    {
SKAction *scaleAction = [SKActionscaleBy:2.0fduration:0.25f];
SKAction *scaleSequence = [SKActionsequence:@[scaleAction,scaleAction.reversedAction]];
SKAction *scaleRepeat = [SKActionrepeatActionForever:scaleSequence];
        [helloNode runAction:scaleRepeat];
    }
__blockHelloScene *b_self = self;
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
    {
//获取游戏场景
SKScene  *scene = [[SKSceneManagerinstance] sceneForKey:@"GameScene"withSize:self.size];
//创建场景切换对象
SKTransition  *doors= [SKTransitiondoorsOpenVerticalWithDuration:1.0f];
//开始切换场景
        [b_self.viewpresentScene:scene transition:doors];
    });
 }
 
注意到我们这里使用了GCD提供的延时机制!!
接下来我们需要看一下SKTransition场景切换对象的内容。
         
         上边的枚举定义了切换动画的4个方向。
 
typedefNS_ENUM(NSInteger, SKTransitionDirection) {
    SKTransitionDirectionUp,
    SKTransitionDirectionDown,
    SKTransitionDirectionRight,
    SKTransitionDirectionLeft
} NS_ENUM_AVAILABLE(10_9, 7_0);


SK_EXPORT@interface SKTransition : NSObject
 
+ (SKTransition*)crossFadeWithDuration:(NSTimeInterval)sec;
 
+ (SKTransition*)fadeWithDuration:(NSTimeInterval)sec;
 
+ (SKTransition *)fadeWithColor:(SKColor *)color duration:(NSTimeInterval)sec;
 
+ (SKTransition*)flipHorizontalWithDuration:(NSTimeInterval)sec;
+ (SKTransition*)flipVerticalWithDuration:(NSTimeInterval)sec;
 
+ (SKTransition*)revealWithDirection:(SKTransitionDirection)direction duration:(NSTimeInterval)sec;
+ (SKTransition*)moveInWithDirection:(SKTransitionDirection)direction duration:(NSTimeInterval)sec;
+ (SKTransition*)pushWithDirection:(SKTransitionDirection)direction duration:(NSTimeInterval)sec;
 
+ (SKTransition*)doorsOpenHorizontalWithDuration:(NSTimeInterval)sec;
+ (SKTransition*)doorsOpenVerticalWithDuration:(NSTimeInterval)sec;
+ (SKTransition*)doorsCloseHorizontalWithDuration:(NSTimeInterval)sec;
+ (SKTransition*)doorsCloseVerticalWithDuration:(NSTimeInterval)sec;
 
+ (SKTransition*)doorwayWithDuration:(NSTimeInterval)sec;
 
/* Create a transition with a CIFilter. The filter must be a transition filter which requires only two images (inputImage, inputTargetImage) and generates a single image (outputImage). SpriteKit sets the inputImage, inputTargetImage, and inputTime properties when rendering, all others must be setup beforehand. */
 
+ (SKTransition*)transitionWithCIFilter:(CIFilter*)filter duration:(NSTimeInterval)sec;
 
/**
 Pause the incoming Scene during the transition, defaults to YES.
 */
@property (SK_NONATOMIC_IOSONLY) BOOL pausesIncomingScene;
 
/**
 Pause the outgoing Scene during the transition, defaults to YES.
 */
@property (SK_NONATOMIC_IOSONLY) BOOL pausesOutgoingScene;
 
@end

在SKTransition这个封装类的API中,我们能够看到系统封装了大量的切换效果,例如淡入淡出、水滴效果、移除、推进、开门关门,甚至我们可以使用CoreImage框架中的CIFilter过滤器完成场景转换。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值