开发者

iPhone, cocos2d and accelerometer

I'm reading 'Learn iPhone and iPad Cocos2D Game Development' and in chapter 4, there's a simple sample using accelerometer. It works well if I use x-axis only as the book but with y-axis, sprite's movement is not smooth if it on the edge of the screen.

+ (id)scene
{
    CCScene*    scene   = [CCScene node];
    CCLayer*    layer   = [GameScene node];
    [scene addChild:layer];
    return scene;
}

- (id)init
{
    if ((self = [super init]))
    {
        CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);

        self.isAccelerometerEnabled = YES;

        player  = [CCSprite spriteWithFile:@"alien.png"];
        [self addChild:player z:0 tag:1];

        CGSize  screenSize  = [[CCDirector sharedDirector] winSize];
        float   imageHeight = [player texture].contentSize.height;
        player.position = CGPointMake(screenSize.width / 2, imageHeight / 2);

        [self scheduleUpdate];
    }

    return self;
}

- (void)dealloc
{
    CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);

    [super dealloc];
}

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{   
    float   deceleration    = 0.4f;
    float   sensitivity     = 6.0f;
    float   maxVelocity     = 100;

开发者_开发问答    playerVelocity.x    = playerVelocity.x * deceleration + acceleration.x * sensitivity;
    playerVelocity.y    = playerVelocity.y * deceleration + acceleration.y * sensitivity;

    if (playerVelocity.x > maxVelocity)
    {
        playerVelocity.x    = maxVelocity;
    }
    else if (playerVelocity.x < -maxVelocity)
    {
        playerVelocity.x    = -maxVelocity;
    }

    if (playerVelocity.y > maxVelocity)
    {
        playerVelocity.y    = maxVelocity;
    }
    else if (playerVelocity.y < -maxVelocity)
    {
        playerVelocity.y    = -maxVelocity;
    } 
}

- (void)update:(ccTime)delta
{
    CGPoint pos = player.position;
    pos.x   += playerVelocity.x;
    pos.y   += playerVelocity.y;

    CGSize  screenSize  = [[CCDirector sharedDirector] winSize];
    float   imageWidthHalved    = [player texture].contentSize.width * 0.5f;
    float   leftBorderLimit     = imageWidthHalved;
    float   rightBorderLimit    = screenSize.width - imageWidthHalved;

    if (pos.x < leftBorderLimit)
    {
        pos.x   = leftBorderLimit;
        playerVelocity  = CGPointZero;
    }
    else if (pos.x > rightBorderLimit)
    {
        pos.x   = rightBorderLimit;
        playerVelocity  = CGPointZero;
    }

    float   imageHeightHalved   = [player texture].contentSize.height * 0.5f;
    float   topBorderLimit      = screenSize.height - imageHeightHalved;
    float   bottomBorderLimit   = imageHeightHalved;

    if (pos.y < bottomBorderLimit)
    {
        pos.y   = bottomBorderLimit;
        playerVelocity  = CGPointZero;
    }
    else if (pos.y > topBorderLimit)
    {
        pos.y   = topBorderLimit;
        playerVelocity  = CGPointZero;
    }

    player.position = pos;
}

What's the problem?


If you want you can try what I did in my game:

#define SIGN(x) ((x < 0.0f) ? -1.0f : 1.0f)


- (void)accelerometer:(UIAccelerometer*)accelerometer didAccelerate:(UIAcceleration*)acceleration {

    float kFilteringFactor = 0.01;

    accels[0] = acceleration.x * kFilteringFactor + accels[0] * (1.0f - kFilteringFactor);
    accels[1] = acceleration.y * kFilteringFactor + accels[1] * (1.0f - kFilteringFactor);
    accels[2] = acceleration.z * kFilteringFactor + accels[2] * (1.0f - kFilteringFactor);

    float xx;
    float yy;

    // extract the acceleration components 
    xx = -[acceleration x]; 
    yy = [acceleration y];  

    // Has the direction changed? 
    float accelDirX = SIGN(xvelocity) * -1.0f;
    float newDirX = SIGN(xx);
    float accelDirY = SIGN(yvelocity) * -1.0f; 
    float newDirY = SIGN(yy);

    // Accelerate. To increase viscosity, lower the values below 1.0f 
    if (accelDirX == newDirX)
        xaccel = (abs(xaccel) + 0.99f) * SIGN(xaccel); 
    if (accelDirY == newDirY)
        yaccel = (abs(yaccel) + 0.99f) * SIGN(yaccel);

    // Apply acceleration changes to the current velocity
    xvelocity = -xaccel * xx; 
    yvelocity = -yaccel * yy;

    [sprite moveByAccelerometerX:yvelocity Y:xvelocity];        
}


First of all, thanks for reading my book! :)

You can find an improved filtering method (ease exponential) that I'm using in this article, it also contains basic info on how the accelerometer works.

You can learn more about accelerometer input from the Tilt to Live developers and their approach, comes with a sample project.


I have bought the book and I found that the edge of screen collision detection doesn't work properly unless you have the same size sprite as in the example. Either make your sprite the same size or make the sprite wrap around the screen instead of stopping, which is what I did.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜