Skip to main content
replaced http://stackoverflow.com/ with https://stackoverflow.com/
Source Link

Recently, I asked the questionquestion which asked if there was a way to create a method in a new class which automatically ran itself every frame. I was answered that it would be a good idea to use CADisplayLink. However, I soon realised I could not, as it is exclusive to iOS — and I had forgotten to specify that I wanted this class to be usable in both platforms. This was quite a surprise, and I had to dig deep into the system’s .h files to be sure this was true.

Recently, I asked the question which asked if there was a way to create a method in a new class which automatically ran itself every frame. I was answered that it would be a good idea to use CADisplayLink. However, I soon realised I could not, as it is exclusive to iOS — and I had forgotten to specify that I wanted this class to be usable in both platforms. This was quite a surprise, and I had to dig deep into the system’s .h files to be sure this was true.

Recently, I asked the question which asked if there was a way to create a method in a new class which automatically ran itself every frame. I was answered that it would be a good idea to use CADisplayLink. However, I soon realised I could not, as it is exclusive to iOS — and I had forgotten to specify that I wanted this class to be usable in both platforms. This was quite a surprise, and I had to dig deep into the system’s .h files to be sure this was true.

Shortened title
Link
Phrancis
  • 20.4k
  • 6
  • 68
  • 154

Several questions about my new solution to creating Creating a class which has a method running every frame

Source Link
Shuri2060
  • 227
  • 1
  • 6

Several questions about my new solution to creating a class which has a method running every frame

I’m working in Objective-C, SKSpriteKit and am trying to create a class which will work in both OS X and iOS for flexibility.

Recently, I asked the question which asked if there was a way to create a method in a new class which automatically ran itself every frame. I was answered that it would be a good idea to use CADisplayLink. However, I soon realised I could not, as it is exclusive to iOS — and I had forgotten to specify that I wanted this class to be usable in both platforms. This was quite a surprise, and I had to dig deep into the system’s .h files to be sure this was true.

I also forgot to mention that I was using SKSpriteKit and that my class was a subclass of SKSpriteNode in the question. So I then tried to add the method which needed to be ran every frame using SKActions and performSelector:. However, the end result was undesirable, as I observed 2 identical nodes of this class (called PhysicsObject) move across the screen at different speeds. Using SKActions and runBlock: was even worse, as the runBlock: action can’t be copied when the node is copied.

As a result, I managed to invent my own solution which was to created a new category: SKNode (updateExtension). The SKNode(updateExtension).h file (which is quite short) is pasted below.

The extension works by adding 2 new methods to all SKNodes, and hence all subclasses of SKNode:

- (void)update:(NSTimeInterval)currentTime;
- (void)updater:(NSTimeInterval)currentTime;

The update: method works by calling the node’s own updater: method, and then calling all of its children’s update: methods. The updater: method of any particular node is then filled with custom code of the user’s choice (if left blank, it will do nothing). The update: method then cannot be touched.

The idea behind this was that the topmost node of the node tree would then be able to call all of its descendantsupdater: methods which would only take one line of code. Or even better, no lines of code, since the SKScene, which is the topmost node of the tree, already has its update: method called every frame — which was why I had given my method the same name.

Or so I had hoped. Omitting the update: method from where I would usually put it in the @implementation GameScene doesn’t seem to have worked, as my version of update: isn’t called at all. I am forced to copy and paste my own version of the update: method from the category into the @implementation GameScene for this all to work…

  1. Why does this happen? Surely the SKScene should call its update: method every frame even if I had omitted it from the @implementation since it already has been implemented by my category?

  2. In addition to this issue, I was wondering about the efficiency of my method. Given a reasonably large tree of nodes (around 1000 nodes?), even if the majority of the nodes’ updater: methods were empty, would the program be slowed to less than 60 frames per second as it would have to dig to the bottom of the node tree each frame? I have only been working with OS X so far — would the efficiency be much worse with iOS?

  3. I now want to add 2 boolean properties to the SKNode category: selfPaused and childrenPaused. I would add 2 if statements inside the update: method for this (selfPaused around the call to the node’s own updater: method and childrenPaused around the children enumeration block). However, it turned out that I could not add properties to class categories, and to do so required access to the @implementation file using class extensions. Is there any way around this problem that anyone could think of?

The advantage of this would be that a node could pause all of its descendants’ update: methods with one line of code saving time for the user.

The SKNode(updateExtension).h file:

#import <SpriteKit/SKNode.h>
#import <SpriteKit/SpriteKitBase.h>

@interface SKNode (updateExtension)

- (void)update:(NSTimeInterval)currentTime;
- (void)updater:(NSTimeInterval)currentTime;

@end
@implementation SKNode (updateExtension)

- (void)update:(NSTimeInterval)currentTime {
    
    [self updater:currentTime];
    
    [self.children enumerateObjectsUsingBlock:^(SKNode *child, NSUInteger idx, BOOL * _Nonnull stop) {
        [child update:currentTime];
    }
     ];
}
- (void)updater:(NSTimeInterval)currentTime {
}
@end // SKNode (updateExtension)