【问题标题】:How to add client data to SKNode / SKSpriteNode?如何将客户端数据添加到 SKNode / SKSpriteNode?
【发布时间】:2014-03-07 09:12:16
【问题描述】:

我正在使用IOS SpriteKit 并想知道是否有某种方法可以将客户端数据添加到精灵节点?

例如,我想将特定行为附加到节点、附加属性、与其他节点的关系等。

我不愿意继承SKNode,因为这似乎会破坏节点只是“视图”的模型/视图/控制器模型。

目前,我保留了一个单独的控制器对象层次结构,但这感觉很笨重,而且在性能方面也不是很好。

最佳做法是什么?

【问题讨论】:

  • 我发现最好在自己的类中实现特定于节点的行为。但是,如果您只想将信息存储在节点中,控制器对象可以根据这些信息做出决策,则可以使用 userData 属性。

标签: ios model-view-controller sprite-kit skspritenode sknode


【解决方案1】:

在这方面,子类化不会改变任何东西。您仍然保留完整的功能,并且不会破坏任何内容。事实上,我认为如果您正在制作大型游戏,这几乎是不可避免的。

但如果你真的不想再使用 userData: SKNode -> userData

【讨论】:

    【解决方案2】:

    所有 SKNode 类都提供了一个 userData 属性,可用于此目的。

    您可以编写一个 Objective-C 类别,通过它您可以添加其他属性而无需子类化。下面是一个经过验证的模式。

    界面:

    #import "YourCustomObject.h"
    
    @interface SKNode (customObject)
    @property (nonatomic) YourCustomObject* yourCustomObject;
    @end
    

    实施:

    static NSString* YourCustomObjectUserDataKey = @"YourCustomObjectUserDataKey";
    
    @implementation SKNode (customObject)
    -(NSMutableDictionary*) internal_getOrCreateUserData
    {
        NSMutableDictionary* userData = self.userData;
        if (userData == nil)
        {
            userData = [NSMutableDictionary dictionary];
            self.userData = userData;
        }
    
        return userData;
    }
    
    -(void) setYourCustomObject:(YourCustomObject*)customObject
    {
        NSMutableDictionary* userData = [self internal_getOrCreateUserData];
        [userData setObject: customObject forKey:YourCustomObjectUserDataKey];
    }
    
    -(YourCustomObject*) yourCustomObject
    {
        NSMutableDictionary* userData = [self internal_getOrCreateUserData];
        return (YourCustomObject*)[userData objectForKey:YourCustomObjectUserDataKey];
    }
    @end
    

    YourCustomObject 替换为您的实际班级名称。

    类别当然可以扩展为托管多个属性,您不必为每个属性编写单独的类别。该类别也不必在 SKNode 上,如果您需要其他属性但只在 SKSpriteNode 上,您可以将此作为 SKSpriteNode 上的类别。

    您经常需要访问YourCustomObject 中的拥有节点。

    因此,最好提供一个将拥有节点作为输入的初始化程序和/或属性。我更喜欢只读属性和自定义初始化程序,因为通常您不希望所有者在对象的整个生命周期内更改。非常重要:此属性必须为 weak 才能不创建保留循环。

    @interface YourCustomObject
    @property (weak, readonly) SKNode* owningNode;
    +(instancetype) customObjectWithOwningNode:(SKNode*)owningNode;
    @end
    
    @implementation YourCustomObject
    +(instancetype) customObjectWithOwningNode:(SKNode*)owningNode
    {
        return [[self alloc] initWithOwningNode:owningNode];
    }
    -(id) initWithOwningNode:(SKNode*)owningNode
    {
        self = [super init];
        if (self) 
        {
            _owningNode = owningNode;
        }
        return self;
    }
    @end
    

    然后您可以在节点类中创建和分配您的自定义对象:

    YourCustomObject* customObject = [YourCustomObject customObjectWithOwningNode:self];
    self.yourCustomObject = customObject;
    

    【讨论】:

    • 谢谢 - 这很有帮助。我最终将子分类作为一种快速解决方案。我在阅读 SKNode 时错过了 userData!
    【解决方案3】:

    虽然这里的其他答案已经提到您可以将 userData 字典用于任意键值,但让我补充一点,您可以将 SKNodes 子类化,因为 SpriteKit 首先不是 MVC(或在至少不是 UIKit 的方式)。

    SKNodes 旨在适应常见的游戏架构(组件模式 和朋友),实际上可以是模型、视图或控制器。 SKNode 例如不是可显示的对象,但可以保存有关游戏实体/状态或其他子节点的信息。

    【讨论】:

      猜你喜欢
      • 2018-06-28
      • 2021-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多