繁体   English   中英

Cocos2d,使用加速度计在景观虫中用x轴移动精灵直立时

[英]Cocos2d, moving a sprite using accelerometer in landscape bug with x axis when held upright

长时间读者第一次海报等。

我的问题是,目前我正在使用加速度计x和y值以及cocos2d在iPod touch(风景)的屏幕上移动精灵。 用户可以通过触摸屏幕来校准加速度计零点的位置,这只是抓取当前x和y值,准备在应用程序运行时从加速度计中减去。 这允许用户选择舒适的位置来握住iPod。

当iPod平放在桌面背面或握在手中并在校准时在x轴上略微向我倾斜时,这种工作正常,当在x上倾斜时,精灵将以相同的速度在屏幕上上下移动轴。

然而,对我来说,当校准出现奇怪的事情时,屏幕会倾斜(好吧我还没有想到的事情)。 如果我的屏幕在x轴上倾斜远离我,精灵以通常的速度或更快的速度向上移动屏幕,如果我在x轴上向我倾斜屏幕,精灵向下移动的速度要慢得多,有时甚至根本不会。

看着xi的加速度计值,我意识到,当iPod向我倾斜时,它接近0,倾斜或朝向我数小于或大于0.我觉得可能是因为这个但是我不确定如何进步,有没有人遇到过这个问题并设法找到解决方案?

这是我到目前为止的代码。

TestLayer.H

@interface TestSceneLayer : CCLayer {
CCSprite *redShip;
float movementX, movementY;
float xCallib, yCallib;
BOOL willMoveX, willMoveY;  
}

TestLayer.m

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

// Set up variables
CGSize winSize = [CCDirector sharedDirector].winSize;
UIAccelerationValue rollingX, rollingY, rollingZ;
float accelX, accelY, accelZ;
invertedControlls = NO;

// High pass filter for reducing jitter
rollingX = (acceleration.x * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor));    
rollingY = (-acceleration.y * kFilteringFactor) + (rollingY * (1.0 - kFilteringFactor));    

accelX = acceleration.x - rollingX;
accelY = acceleration.y - -rollingY;

// Calculate movement for x and y axis
float accelDiffX = accelX - kRestAccelX;
float accelFractionX = accelDiffX / kMaxDiff;
movementY = kShipMaxPointsPerSec * accelFractionX;

float accelDiffY = accelY - kRestAccelY;
float accelFractionY = accelDiffY / kMaxDiff;
movementX = kShipMaxPointsPerSec * accelFractionY;

// Thresh holds for x and y axis movement
willMoveX = YES;
willMoveY = YES;

if (((movementX < 70.0f) && (movementX > -70.0f))) willMoveX = NO;
else if (((movementY < 70.0f) && (movementY > -70.0f))) willMoveY = NO; 
}


- (void) applyAccelerometerToNode:(CCNode*)tempNode ForTime:(ccTime)dTime {
// temp node is the sprite being moved
CGSize screenSize = [[CCDirector sharedDirector]winSize];

float oldX = [tempNode position].x;
float oldY = [tempNode position].y;
float newX, newY;


if (willMoveY) { 
    newY = [tempNode position].y + (movementY * dTime);
} else newY = oldY;
if (willMoveX) { 
    newX = [tempNode position].x - (movementX * dTime);
} else newX = oldX;


// Constrain movement on screen to stop it shooting off like a little bastard
if ((newY > (screenSize.height - 40.0f)) || newY < 40.0f ) {
    newY = oldY;
}

if ((newX > (screenSize.width -40)) || newX < 40.0f ) {
    newX = oldX;
}

[tempNode setPosition:ccp(newX,newY)];
}

- (void) update:(ccTime)deltaTime {     
[self applyAccelerometerToNode:redShip ForTime:deltaTime];
}

- (id) init {
if (([super init])) {
    CCLOG(@"TestSceneLayer --> Layer init");

    CGSize screenSize = [[CCDirector sharedDirector]winSize];

    [self scheduleUpdate];
    self.isTouchEnabled = YES;
    self.isAccelerometerEnabled = YES;

// Grab the default Accelerometer values
    xCallib = [GameManager sharedGameManager].xCallib;
    yCallib = [GameManager sharedGameManager].yCallib;

// Setup and add children
    redShip = [CCSprite spriteWithFile:@"red_ship.png"];
    [redShip setPosition:ccp(50.0f, screenSize.height / 2)];
    [redShip setScaleX:screenSize.width/1024.0f];
    [redShip setScaleY:screenSize.height/768.0f];
    [self addChild:redShip];
}
return self;
}

Constants.h

#define kFilteringFactor 0.1
#define kShipMaxPointsPerSec (winSize.height*0.5)        
#define kRestAccelX (xCallib)
#define kMaxDiff 0.2
#define kRestAccelY (yCallib)
#define kMaxDiffY 0.1

我想也许我正在以错误的方式攻击xy值,数学就是错误的。 我希望用户能够从任何位置使用该应用程序。 任何帮助或指针在正确的方向将非常感激。 如果您需要了解其他信息,请询问。 我希望我能说清楚自己。

问候,詹姆斯。

最佳答案考虑了所有三个轴,假设您希望它相对于用户在校准点保持的“然而”。 坚持以重力为导向的x和y意味着你的价值观会在某种程度上偏向任何其他方向。

来自Alex Okafor 的Rain Parade

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
  // A much more concise version courtesy of Mikko Mononen http://digestingduck.blogspot.com/
  Vec2 accel2D(0,0);
  Vec3 ax(1, 0, 0);
  Vec3 ay(-.63f, 0,-.92f); // this is your "neutral" / calibrated position
  Vec3 az(Vec3::Cross(ay,ax).normalize());
  ax = Vec3::Cross(az,ay).normalize();
  accel2D.x = -Vec3::Dot(Vec3(acceleration.x, acceleration.y, acceleration.z), ax);
  accel2D.y = -Vec3::Dot(Vec3(acceleration.x, acceleration.y, acceleration.z), az);

}

“硬编码我们的'中性'方向[在yy]。默认情况下[”中性“位置]是让设备略微向你的脸倾斜的方向。如果你想要严格的”自上而下“方向,那么a(0, 0,-1)向量将放在此处。要创建一个新的“中性”位置,您可以为单个帧采样UIAcceleration参数,并将其设置为应用程序其余部分的新[ay](也称为校准)“ 。

如果您能够依赖包含陀螺仪并安装了iOS 4的新设备,我建议使用Core Motion接口而不是UIAccelerometer,因为它将被弃用。 它更准确,并且在CMAttitude multiplyByInverseOfAttitude中有一个内置校准:

查看简单iPhone动作检测和文档链接,以获取更多关于Core Motion API入门的一般信息。

有一个令人遗憾的过度简化的建议,即校准加速度计所需要的是减去偏移位置。 这当然是错误的,因为加速度计轴的值范围从-1到1。

如果沿轴的校准点为0.5,则得到1.5的范围,使您的设备沿负轴定向,沿正轴仅定向0.5。 这不可避免地使您的设备对正轴的运动更敏感,同时限制其最大速度。

您可以通过设置校准范围来解决此问题,您将使用该范围在减去校准点后将得到的加速度值除以:

calibrationValueRange = CGPointMake(1.0f - fabsf(calibrationPoint_.x), 
                                    1.0f - fabsf(calibrationPoint_.y));
accelerationPoint.x = (accelerationPoint.x - calibrationPoint_.x) /               
                                                   calibrationValueRange.x;
accelerationPoint.y = (accelerationPoint.y - calibrationPoint_.y) / 
                                                   calibrationValueRange.y;

我希望这段代码仍然有效,我从旧项目中复制了它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM