Search code examples
iosobjective-ccocos2d-iphonecore-graphicssprite

Varying Vertical Position of Sprite During Movement


I have sprites in my iOS application that move across the screen horizontally, both left to right and right to left. For most of these sprites, a straight line or a well-defined arc is acceptable. I have some sprites, however, that I would like to have move a little more randomly, specifically varying the vertical position of the sprite as it moves.

In the following code, "y_variant_" is an ivar that specifies the degree of variance that I would like to apply. It is a smaller value for natural objects like birds or man-made objects like paper airplanes, which should only move a small amount up and down as they fly, but a larger value for natural objects like insects and bees, which have much greater variance.

This is the code that I am currently using (the "update:" method for the sprite):

//  track/vary the object as it moves along its path...
- ( void ) update: ( ccTime ) delta

{

    //  ask director for the window size...
    CGSize const size = [ [ CCDirector sharedDirector ] winSize ];

    //  get the current position of the projectile...
    CGPoint const ptRaw = [ self position ];

    //  create a variant of the vertical position for "intelligent" items...
    CGPoint const pt = ( y_variant_
                       ? ccp( ptRaw.x
                            , ptRaw.y + y_variant_ * (float)( rand( ) % 25 ) * 0.02f - fmodf( ptRaw.x, y_variant_ )
                            )
                       : ptRaw
                       );
    [ self setPosition: pt ];
        :
        :
        :
        //  if we're supposed to stop the projectile on impact (a "brick wall", etc.)...
        if ( fStopProjectile == ObjectImpactActionStop )

            {

            //  object impact, if this is a "smart" projectile (i.e., something with a brain)...
            if ( y_variant_ )

                {

                //  move the projectile around the object...
                CCAction * const move = [ CCMoveTo actionWithDuration: 0.25f
                                                             position: ccpAdd( [ self position ]
                                                                             , ccp( - CS_IMAGE_OBJECT_W
                                                                                  , CS_IMAGE_OBJECT_H
                                                                                  )
                                                                             )
                                        ];

                [ self runAction: move ];

                }  // end "smart" projectile

            }  //  end projectile impact
        :
        :
        :
    return;

}  //  end update

You'll notice that there's logic involving collision with solid objects: if a solid obstruction (wall, building, etc.) is encountered, the object backs up and moves vertically to avoid the obstacle.

The problem that I'm running into is that the viewed motion is very erratic for the larger values of "y_variant_", and I would like it to appear smoother....

Even if you don't have a solution, any comments as to what can be improved or investigated would be appreciated.

Thanks for your help.

p.s.: If you're feeling ambitious, one of the suggestions from a user was to have the bee very occasionally loop around backwards and then continue its path. Once I've fixed the current "bouncing" problem, I'll incorporate that, so please keep that in mind....


Solution

  • There's no simple answer to your question. But if you're using Cocos2d, I would look into using actions instead of manually positioning the sprites. So to reiterate, I recommend you look into using actions. But here's a simple example that might help if you stick with manual positioning:

    #define kAmountToMovePerFrameInY 10.0 / 60.0
    
    @property float posYCurrentlyMovingTo;
    @property SomeSpriteClass *theSpriteMoving;
    @property float someXPosition;
    @property float nextMoveAmount;
    
    
    -(void)doStuffDuringUpdate
    {
    
    
        if (_theSpriteMoving.position.y < labs(_posYCurrentlyMovingTo)) {
            //sprite is still moving to its position
    
            _theSpriteMoving.position = CGPointMake(_someXPosition, _theSpriteMoving.position.y + _nextMoveAmount);
    
        }else{
            float variationAmountInY = arc4random_uniform(200) - 100.0;
            _posYCurrentlyMovingTo = variationAmountInY;
            _nextMoveAmount = variationAmountInY * kAmountToMovePerFrameInY;
    
    
        }
    
    
    }