SpriteKit-Components 1.0.2

SpriteKit-Components 1.0.2

测试已测试
语言语言 Obj-CObjective C
许可证 MIT
发布最后发布2014年12月

未声明的 维护。



  • 作者
  • buddingmonkey

适用于 iOS 7+ SpriteKit 框架的组件模型。向您的节点添加执行特定行为的组件。使用基于组件的模型的好处包括

  • 允许您编写可重复使用的在任意节点上应用的可重用行为,并能跨项目重复使用
  • 为每个 SKComponentNode 和行为添加一个更新方法,该方法会调用 delta time
  • 为每个 SKComponentNode 添加 onEnter 和 onExit 方法,类似于 Cocos2d 的模型,这允许您在节点添加到和从场景中移除时执行组装和拆卸
  • 简化了基本触摸交互,以自动支持选择、轻触、拖动、放置和长按

项目设置

  1. 从一个 SpriteKit 游戏 project 开始
  2. 将 SpriteKit-Components.xcodeproj 拖放到您的 project 工作区
  3. 将 SpriteKit-Components 添加到您的目标依赖项
  4. 将 libSpriteKit-Components.a 添加到您的 Link Binary With Libraries 构建阶段
  5. 将 SKComponents.h 添加到您的项目,并在 prefix.pch header 中包含它,如果您再也不想包含它

组件模型使用

您的基场景必须继承自 SKComponentScene。SKComponentScene 是组件模型的主机,确保所有 SKComponentNodes 都被找到并注册。

您的场景图应基于 SKComponentNodes,它们应将您的图形/渲染节点作为其子节点。SKComponentNodes 可以在场景的任何位置添加。

使用 [node addComponent:[MyComponent new]]; 将行为添加到您的 SKComponentNodes

SKComponent 协议

您的组件必须实现以下协议。所有方法都是可选的,但是 enabled 属性是必需的。

@protocol SKComponent <NSObject>

@property (nonatomic, readwrite) BOOL enabled;

@optional
@property (nonatomic, weak) SKNode *node;

@optional
// triggered when the component is added to a component node
- (void)awake;

// when the node is added to the scene
- (void)onEnter;

// when the node is removed from the scene
- (void)onExit;

// called every frame. dt = time since last frame
- (void)update:(CFTimeInterval)dt;

// SpriteKit - forwarded from SKScene
- (void)onSceneSizeChanged:(CGSize)oldSize;

// SpriteKit - forwarded from SKScene
- (void)didEvaluateActions;

#pragma mark -- Physics Handlers --

// SpriteKit - forwarded from SKScene
- (void)didSimulatePhysics;

// SpriteKit - forwarded from SKScene when this node is one of the nodes in contact
- (void)didBeginContact:(SKPhysicsContact *)contact;
- (void)didEndContact:(SKPhysicsContact *)contact;


#pragma mark -- Touch Handlers --
// all touch handlers are only triggered if the tough down is inside the node content area

// called once a touch moves beyond the SKComponentNode dragThreshold (defaults to 4 units)
- (void)dragStart:(SKCTouchState*)touchState;

// called every time a touch moves after dragging has started
- (void)dragMoved:(SKCTouchState*)touchState;

// called on touch up after dragging has started
- (void)dragDropped:(SKCTouchState*)touchState;

// called if the touch is canceled after dragging has started
- (void)dragCancelled:(SKCTouchState*)touchState;
- 

// called on Touch Up if UITouch tap count >= 1 and touch is not classified as dragging or a long touch
- (void)onTap:(SKCTouchState*)touchState;

// called if touch is held for SKComponentNode longPressTime (defaults to 1 second)
// AND touch has not moved beyond dragThreshold
- (void)onLongPress:(SKCTouchState*)touchState;

// equivalent to iOS Touch Up Inside. Typically used for menu items rather than tap
- (void)onSelect:(SKCTouchState*)touchState;


// standard touchesBegan event, called prior to touchState based events
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

// standard touchesMoved event, called prior to touchState based events
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

// standard touchesEnded event, called prior to touchState based events
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

// standard touchesCancelled event, called prior to touchState based events
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;


@end

示例组件 - 将 Alpha 应用到所有子节点

SKComponentNodes 自动将其 alpha 值应用到其直接子节点,但假设您想将此 alpha 值应用到您的节点子节点的子节点,依此类推。

SKCDeepAlpha.h

@interface SKCDeepAlpha : NSObject<SKComponent> {
    float previousAlpha;
}
@end

SKCDeepAlpha.m

#import "SKCDeepAlpha.h"

@implementation SKCDeepAlpha
@synthesize node,enabled;

- (void)onEnter {
    recursivelyApplyAlpha(node, node.alpha);
}

- (void)didEvaluateActions {
    if (previousAlpha != node.alpha) {
        recursivelyApplyAlpha(node, node.alpha);
        previousAlpha = node.alpha;
    }
}

void recursivelyApplyAlpha(SKNode* node, float alpha) {
    for (SKNode *child in node.children) {
        child.alpha = alpha;
        if (child.children.count > 0)
            recursivelyApplyAlpha(child, alpha);
    }
}
@end

当您将此组件添加到场景中的节点时,onEnter 和 didEvaluateActions 将自动被调用。将此组件添加到您的 SKComponentNodes 之一,并且每次您更改组件节点上的 alpha,它都会设置每个后代的 alpha。

要使用此组件,只需像这样将其添加到任何 SKComponentNode:

SKNode* node = [SKComponentNode node];
[node addComponent:[SKCDeepAlpha new]];
// add sprites or shapes as children of your node, then add it to the scene
[scene addChild:node];

示例组件 - 添加触摸交互

首先,不要忘记在你的SKComponentNode上启用用户交互功能,使用代码node.userInteractionEnabled = YES;。在组件的唤醒(awake)方法中做这个操作是个好方法。

每个应用都有按钮。让我们创建一个组件,它可以响应触摸内部的手势。

@implementation SKCSelectTest
@synthesize node, enabled;

- (void)awake {
    node.userInteractionEnabled = YES;
}

- (void)onSelect:(SKCTouchState*)touchState {
    // do something
}
@end

哎呀,这太简单了。让我们创建一个组件,可以让你在屏幕上拖动节点。

@implementation SKCDraggable
@synthesize node, enabled;
@synthesize startPosition;

- (void)awake {
    node.userInteractionEnabled = YES;
}

- (void)dragStart:(SKCTouchState*)touchState {
    // we could do something here to clue the user in on the fact that we started dragging
    startPosition = node.position;
}

- (void)dragMoved:(SKCTouchState*)touchState {
    // check out the skHelper.m for a couple shorthand functions/methods for vector` math
    node.position = skpAdd(node.position, touchState.touchLocation);
}

- (void)dragDropped:(SKCTouchState*)touchState {
    // we could show the user we dropped successfully here
}

- (void)dragCancelled:(SKCTouchState*)touchState {
    node.position = startPosition;
}
@end

命名和访问组件

假设你给节点添加了一些组件,现在你需要更改其中某个组件的属性。你可以保留对每个组件的引用,但这会很烦人。相反,你只需请求组件节点即可。

// Disable the component of type MyComponent (callbacks will immediately stop)
[node getComponent:[MyComponent class]].enabled = NO;

// or better yet, get the component casted to the proper type
SKGetComponent(node, MyComponent).customProperty = 42;

通常情况下,节点上的每个组件类型不同,但如果你想添加两个相同类型的组件,你需要命名它们,而不是依靠类名。

[node addComponent:[SpeedDoubler new] withName:@"2xSpeed"];
[node addComponent:[SpeedDoubler new] withName:@"4xSpeed"];
[node getComponentWithName:@"4xSpeed"].enabled = NO;

SKComponentNodes也可以是一个组件

如果你是SKComponentNode的子类,并且想使用组件回调而不创建额外的组件,只需实现SKComponent协议。现在你的节点也获得所有组件回调。请确保调用[super onEnter/onExit/update:],这样组件节点就可以执行它背后的魔法。

测试

查看我们CI在https://travis-ci.org/xr1337/SpriteKit-Components

许可证

此软件受MIT许可证(MIT)许可。有关详细信息,请参阅LICENSE文件。