2011-10-19 68 views
3

長時間讀卡器第一次張貼海報等等。Cocos2d,使用加速度計在x軸上使用加速度計在橫軸上移動時豎直向上

我的問題是這樣的,目前我正在使用加速度計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值錯誤的方式和數學是完全錯誤的。我希望用戶能夠從任何位置使用應用程序。任何幫助或指針在正確的方向將不勝感激。如果您需要了解其他內容,請詢問。我希望我能夠讓自己清楚。

Regards, James。

回答

0

有一個不幸的過於簡單的建議,所有校準加速度計需要減去偏移位置。這當然是錯誤的,因爲加速度計軸的取值範圍從-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; 

我希望這個代碼仍然有效,我從它複製舊項目。

+0

您好,謝謝您的回覆,我嘗試了您的建議,但x值的值仍然看起來不正確。在x軸上,正值直接上升,負值上幾乎沒有變化。 –

2

如果您可以負擔得起依賴包含陀螺儀的較新設備並安裝了iOS 4,我建議使用Core Motion接口而不是UIAccelerometer,因爲它將被棄用。它精確得多,並且在CMAttitude中有一個內置校準multiplyByInverseOfAttitude:

請看Simple iPhone motion detect以及指向文檔的鏈接以獲取有關Core Motion API入門的更多一般信息。

3

最好的答案考慮了所有三個軸,假設你想要它與「但是」用戶在校準點上保持一致。堅持以重力爲導向的x和y意味着你的價值觀將在某種程度上傾向於任何其他方向。

從亞歷克斯 - 奧卡福上Parade of Rain

- (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); 

} 

「。硬編碼我們的‘中性’的方向[沿y]默認[‘中立’位置]是具有對稍微傾斜設備的打印方向如果你需要嚴格的'自上而下'的方向,那麼一個(0,0,-1)向量將被放置在這裏。爲了創建一個新的'中立'位置,你可以對單個幀的UIAcceleration參數進行採樣,並將其設置爲成爲應用程序其餘部分(又稱校準)的新[ay]「。