通过Spritekit实现轻量级刚体的现实水下运动

时间:2014-08-26 12:08:30

标签: ios cocos2d-iphone sprite-kit game-physics skphysicsbody

刚性轻质环在水下移动(设备的运动)。我无法想象任何其他逻辑或代码来完成逼真的模拟水下运动。我真的想要了解如何通过spritekit实现这一目标,或者我应该研究Underwater Rigid Body Dynamics并选择OpenGL。 我是spritekit的新手,欢迎提出任何帮助和建议,并提前致谢!

#define kScale 0.6
const float MaxPlayerAccel = 300.0f;
const float MaxPlayerSpeed = 100.0f;
const float BorderCollisionDamping = 0.1f;

static inline CGFloat sigmoid(CGFloat x, CGFloat offset, CGFloat scale)
{
    return 1 / (1 + exp(-(x-offset)/scale));
}
-(void)update:(CFTimeInterval)currentTime {
    if (_lastUpdateTime) {
    _deltaTime = currentTime - _lastUpdateTime;
} else {
    _deltaTime = 0;
}
_lastUpdateTime = currentTime;  
[self updatePlayerAccelerationFromMotionManager];
[self updatePlayer:_deltaTime];
[self enumerateChildNodesWithName: @"player" usingBlock:^(SKNode *node, BOOL *stop) {
    // Calculate depth of object
    CGFloat dy = _waterLine - node.position.y;
    if (node.position.y > _waterLine) {
        // If above water...
        node.physicsBody.linearDamping = 0.1;
    }
    else {
        // If under water, increase viscosity
        node.physicsBody.linearDamping = 5.0;
    }
    if (dy > 0) {
        dy = kScale * sigmoid(dy, 2, 10);
        [node.physicsBody applyImpulse:CGVectorMake(0,dy)];
    }
  }];
}
- (void)updatePlayerAccelerationFromMotionManager
{
    const double FilteringFactor = 0.75;

    CMAcceleration acceleration = _motionManager.accelerometerData.acceleration;
    _accelerometerX = acceleration.x * FilteringFactor + _accelerometerX * (1.0 - FilteringFactor);
    _accelerometerY = acceleration.y * FilteringFactor + _accelerometerY * (1.0 - FilteringFactor);

    if (_accelerometerY > 0.05)
    {
        _playerAccelX = -MaxPlayerAccel;
    }
    else if (_accelerometerY < -0.05)
    {
        _playerAccelX = MaxPlayerAccel;
    }
    if (_accelerometerX < -0.05)
    {
        _playerAccelY = -MaxPlayerAccel;
    }
    else if (_accelerometerX > 0.05)
    {
        _playerAccelY = MaxPlayerAccel;
    }
}

- (void)updatePlayer:(NSTimeInterval)dt
{
    _playerSpeedX += _playerAccelX * dt;
    _playerSpeedY += _playerAccelY * dt;

    _playerSpeedX = fmaxf(fminf(_playerSpeedX, MaxPlayerSpeed), -MaxPlayerSpeed);
    _playerSpeedY = fmaxf(fminf(_playerSpeedY, MaxPlayerSpeed), -MaxPlayerSpeed);

        float newX = ring.position.x + _playerSpeedX*dt;
        float newY = ring.position.y + _playerSpeedY*dt;

        BOOL collidedWithVerticalBorder = NO;
        BOOL collidedWithHorizontalBorder = NO;

        if (newX < 0.0f)
        {
            newX = 0.0f;
            collidedWithVerticalBorder = YES;
        }
        else if (newX > _winSize.width)
        {
            newX = _winSize.width;
            collidedWithVerticalBorder = YES;
        }

        if (newY < 0.0f)
        {
            newY = 0.0f;
            collidedWithHorizontalBorder = YES;
        }
        else if (newY > _winSize.height)
        {
            newY = _winSize.height;
            collidedWithHorizontalBorder = YES;
        }

        if (collidedWithVerticalBorder)
        {
            _playerAccelX = -_playerAccelX * BorderCollisionDamping;
            _playerSpeedX = -_playerSpeedX * BorderCollisionDamping;
            _playerAccelY = _playerAccelY * BorderCollisionDamping;
            _playerSpeedY = _playerSpeedY * BorderCollisionDamping;
        }

        if (collidedWithHorizontalBorder)
        {
            _playerAccelX = _playerAccelX * BorderCollisionDamping;
            _playerSpeedX = _playerSpeedX * BorderCollisionDamping;
            _playerAccelY = -_playerAccelY * BorderCollisionDamping;
            _playerSpeedY = -_playerSpeedY * BorderCollisionDamping;
        }


        ring.position = CGPointMake(newX, newY);

        float speed = sqrtf(_playerSpeedX*_playerSpeedX + _playerSpeedY*_playerSpeedY);
        if (speed > 40.0f)
        {
            float angle = atan2f(_playerSpeedY, _playerSpeedX);

            // Did the angle flip from +Pi to -Pi, or -Pi to +Pi?
            if (_lastAngle < -3.0f && angle > 3.0f)
            {
                _playerAngle += M_PI * 2.0f;
            }
            else if (_lastAngle > 3.0f && angle < -3.0f)
            {
                _playerAngle -= M_PI * 2.0f;
            }
            _lastAngle = angle;
            const float RotationBlendFactor = 0.2f;
            _playerAngle = angle * RotationBlendFactor + _playerAngle * (1.0f - RotationBlendFactor);
           }

        ring.zRotation = _playerAngle - SK_DEGREES_TO_RADIANS(90.0f);
       ring.zRotation += -SK_DEGREES_TO_RADIANS(_playerSpin);

        if (_playerSpin > 0.0f)
        {
            _playerSpin -= 2.0f * 360.0f * dt;
            if (_playerSpin < 0.0f)
            {
                _playerSpin = 0.0f;
            }
        }
    }

@end

0 个答案:

没有答案