0

I'm getting int SpriteKit. And would like to know how to create motion effect on SKNode object.

For UIView I use following method :

+(void)registerEffectForView:(UIView *)aView
                   depth:(CGFloat)depth
{
UIInterpolatingMotionEffect *effectX;
UIInterpolatingMotionEffect *effectY;
effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x"
                                                          type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y"
                                                          type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];


effectX.maximumRelativeValue = @(depth);
effectX.minimumRelativeValue = @(-depth);
effectY.maximumRelativeValue = @(depth);
effectY.minimumRelativeValue = @(-depth);

[aView addMotionEffect:effectX];
[aView addMotionEffect:effectY];
}

I haven't found anything similar for SKNode. So my question is is it possible? And if not then how can I implement it.

haawa
  • 3,078
  • 1
  • 26
  • 35

2 Answers2

0

UIInterpolatingMotionEffect just maps the device tilt to properties of the view it's applied to -- it's all about what keyPaths you set it up with, and what the setters for those key paths do.

The example you posted maps horizontal tilt to the x coordinate of the view's center property. When the device is tilted horizontally, UIKit automatically calls setCenter: on the view (or sets view.center =, if you prefer your syntax that way), passing a point whose X coordinate is offset proportionally to the amount of horizontal tilt.

You can just as well define custom properties on a custom UIView subclass. Since you're working with Sprite Kit, you can subclass SKView to add properties.

For example... say you have a cloud sprite in your scene that you want to move as the user tilts the device. Name it as a property in your SKScene subclass:

@interface MyScene : SKScene
@property SKSpriteNode *cloud;
@end

And add properties and accessors in your SKView subclass that move it:

@implementation MyView // (excerpt)

- (CGFloat)cloudX {
    return ((MyScene *)self.scene).cloud.position.x;
}
- (void)setCloudX:(CGFloat)x {
    SKSpriteNode *cloud = ((MyScene *)self.scene).cloud;
    cloud.position = CGPointMake(x, cloud.position.y);
}

@end

Now, you can create a UIInterpolatingMotionEffect whose keyPath is cloudX, and it should* automagically move the sprite in your scene.

(* totally untested code)

rickster
  • 124,678
  • 26
  • 272
  • 326
  • The problem here is that SKView should be used only for displaying some SKScenes, not instead of SKNodes. Using your approach i will have to handle two Scenes instead of one. Which is forbidden, because you should always present 1 SKScene at a time. – haawa Feb 05 '14 at 10:11
  • This is just a sketch of a general architecture you could use -- the point is that `UIInterpolatingMotionEffect` maps to whatever properties you choose on a view, so what it does is a matter of what properties you implement and how. `MyScene` in this example is whatever scene you wish to present in your view. There's no saying that the motion-affected node has to be the only node in it, so if you want the scene to contain other nodes, it can. Or you can set up the property accessors on your `SKView` subclass to work with a node that changes as you present different scenes in the view. – rickster Feb 05 '14 at 23:46
0

UIInterpolatingMotionEffect works in deep level and you can't use an arbitrary keyPath like "cloudX". Even after adding motionEffects, the actual value of centre property won't change. So the answer is, you can't add a motion effect other than UIView. Using arbitrary property other than particular property such as 'center' or 'frame' is not possible either.

user5865651
  • 1,478
  • 1
  • 9
  • 11