刚性轻质环在水下移动(设备的运动)。我无法想象任何其他逻辑或代码来完成逼真的模拟水下运动。我真的想要了解如何通过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