2

I am trying to create a conveyor belt effect using SpriteKit like so

Screenshot

MY first reflex would be to create a conveyor belt image bigger than the screen and then move it repeatedly forever with actions. But this does not seem ok because it is dependent on the screen size.

Is there any better way to do this ?

Also obviously I want to put things (which would move independently) on the conveyor belt so the node is an SKNode with a the child sprite node that is moving.

Update : I would like the conveyor belt to move "visually"; so the lines move in a direction giving the impression of movement.

Tibor Udvari
  • 2,932
  • 3
  • 23
  • 39

2 Answers2

2

Apply physicsBody to all those sprites which you need to move on the conveyor belt and set the affectedByGravity property as NO.

In this example, I am assuming that the spriteNode representing your conveyor belt is called conveyor. Also, all the sprite nodes which need to be moved are have the string "moveable" as their name property.

Then, in your -update: method,

-(void)update:(CFTimeInterval)currentTime
{
    [self enumerateChildNodesWithName:@"moveable" usingBlock:^(SKNode *node, BOOL *stop{ 
        if ([node intersectsNode:conveyor])
        {
            [node.physicsBody applyForce:CGVectorMake(-1, 0)];
            //edit the vector to get the right force. This will be too fast.
        }
    }];
}

After this, just add the desired sprites on the correct positions and you will see them moving by themselves.

For the animation, it would be better to use an array of textures which you can loop on the sprite.

Alternatively, you can add and remove a series of small sprites with a sectional image and move them like you do the sprites which are travelling on the conveyor.

ZeMoon
  • 20,054
  • 5
  • 57
  • 98
  • Hey thank you for the feedback. I updated my question. The effect I am looking for is making the conveyor belt look like it's moving. Like so http://www.randomfeature.co.uk/files/gimgs/47_quartet01.gif . What would be a good way to get this effect ? – Tibor Udvari Jan 10 '14 at 09:50
  • It would probably be difficult to get the animation and objects in sync (so they appear to move with the same speed) when cycling through different textures. But this effect can easily be achieved with CoreAnimation (there are several ways to achieve this, search StackOverflow). The idea is to set `view width = screen width + texture width`, move with `x = -texture width` to `x = 0` and repeat. – DarkDust Jan 10 '14 at 10:17
  • @DarkDust if I am understanding correctly, the texture in this case must be larger than the screen in order for it to work correctly and the would thus require a large image (this is what I was thinking about) – Tibor Udvari Jan 10 '14 at 10:52
  • @akashg has a better solution with the idea of small repeating sectional images; an implementation would be great; Ideally I think we could apply a repeating texture only vertically and then offset it by a delta each frame; I am not sure if this is possible though – Tibor Udvari Jan 10 '14 at 10:52
  • @TiborUdvari: No, the texture should be as small as you can draw it to make it repeatable, then your view should draw it repeatedly. So the _view_ would be larger than the screen, the _texture_ not. – DarkDust Jan 10 '14 at 11:06
  • @DarkDust OK I think we are coming to the conclusion that that would be the best compromise to achieve this; now do we have any idea how to apply the repeatable horizontal texture to any sized Sprite ? If we have that piece of code I think we are ok to go. – Tibor Udvari Jan 10 '14 at 11:20
  • Isn't a sprite just an UIView? (Haven't worked with SpriteKit yet) If so, just [set the background color using `+[UIColor colorWithPatternImage:`](http://stackoverflow.com/questions/224503/repeating-background-image-in-native-iphone-app). – DarkDust Jan 10 '14 at 11:31
  • Sprite nodes are very different from UIViews and SpriteKit converts all images to textures before using them. Look at http://stackoverflow.com/questions/19490970/sprite-kit-and-colorwithpatternimage. I will try and put down a possible implementation within a couple of hours... – ZeMoon Jan 10 '14 at 11:51
0

@akashg has pointed out a solution for moving objects across the conveyor belt, I am giving my answer as how to make the conveyor belt look as if it is moving

One suggestion and my initial intuition was to place a larger rectangle than the screen on the scene and move this repeatedly. Upon reflecting I think this is not a nice solution because if we would want to place a conveyor belt on the middle, in a way we see both it ends this would not be possible without an extra clipping mask.

The ideal solution would be to tile the SKTexture on the SKSpriteNode and just offset this texture; but this does not seem to be possible with Sprite Kit (no tile mechanisms).

So basically what I'm doing is creating subtextures from a texture that is like so [tile][tile](2 times a repeatable tile) and I just show these subtextures one after the other to create an animation.

Here is the code :

- (SKSpriteNode *) newConveyor
{
    SKTexture *conveyorTexture = [SKTexture textureWithImageNamed:@"testTextureDouble"];
    SKTexture *halfConveyorTexture = [SKTexture textureWithRect:CGRectMake(0.5, 0.0, 0.5, 1.0) inTexture:conveyorTexture];

    SKSpriteNode *conveyor = [SKSpriteNode spriteNodeWithTexture:halfConveyorTexture size:CGSizeMake(conveyorTexture.size.width/2, conveyorTexture.size.height)];

    NSArray *textureArray = [self horizontalTextureArrayForTxture:conveyorTexture];
    SKAction *moveAction = [SKAction animateWithTextures:textureArray timePerFrame:0.01 resize:NO restore:YES];
    [conveyor runAction:[SKAction repeatActionForever:moveAction]];

    return conveyor;
}

- (NSArray *) horizontalTextureArrayForTxture : (SKTexture *) texture
{
    CGFloat deltaOnePixel = 1.0 / texture.size.width;
    int countSubtextures = texture.size.width / 2;

    NSMutableArray *textureArray = [[NSMutableArray alloc] initWithCapacity:countSubtextures];

    CGFloat offset = 0;
    for (int i = 0; i < countSubtextures; i++)
    {
        offset = i * deltaOnePixel;
        SKTexture *subTexture = [SKTexture textureWithRect:CGRectMake(offset, 0.0, 0.5, 1.0) inTexture:texture];
        [textureArray addObject:subTexture];
    }

    return [NSArray arrayWithArray:textureArray];
}

Now this is still not ideal because it is necessary to make an image with 2 tiles manually. We can also edit a SKTexture with a CIFilter transform that could potentially be used to create this texture with 2 tiles.

Apart from this I think this solution is better because it does not depend on the size of the screen and is memory efficient; but in order for it to be used on the whole screen I would have to create more SKSpriteNode objects that share the same moveAction that I have used, since tiling is not possible with Sprite Kit according to this source : How do you set a texture to tile in Sprite Kit.

I will try to update the code to make it possible to tile by using multiple SKSpriteNode objects.

Community
  • 1
  • 1
Tibor Udvari
  • 2,932
  • 3
  • 23
  • 39