iphone - Cocos2d,在直立时使用 x 轴的景观错误中的加速度计移动 Sprite

标签 iphone objective-c ios cocos2d-iphone accelerometer

长期读者第一次海报等。

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

当 iPod 平放在 table 上或手持并在校准时在 x 轴上稍微向我倾斜时,这工作正常,倾斜时 Sprite 将以相同的速度在屏幕上上下移动在 x 轴上。

然而,当校准时屏幕越靠近我倾斜,一些奇怪的事情发生了(无论如何我没想到的事情)。如果我在 x 轴上远离我的屏幕倾斜,则 Sprite 以通常的速度或更快的速度在屏幕上移动,如果我在 x 轴上将屏幕向我倾斜,则 Sprite 在屏幕上向下移动的速度要慢得多,有时甚至根本不移动。

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

这是我目前的代码。

测试层.H

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

测试层.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;
}

常量.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

我在想,也许我以错误的方式攻击 x y 值,而且数学完全错误。我希望用户能够从任何位置使用该应用程序。任何正确方向的帮助或指示将不胜感激。如果您需要了解其他任何信息,请询问。我希望我能说清楚。

问候, 詹姆斯。

最佳答案

最佳答案考虑了所有三个轴,假设您希望它与用户在校准点“无论如何”保持一致。坚持以重力为导向的 x 和 y 意味着您的值将在某种程度上偏离任何其他方向。

来自 Alex Okafor 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);

}

“[在 ay] 中对我们的‘中立’方向进行硬编码。默认情况下,[‘中立’位置] 是让设备稍微向你的脸倾斜的方向。如果你想要严格的‘自上而下’方向,那么(0,0,-1) vector would be put here. To create a new 'neutral' position you can sample the UIAAcceleration parameter for a single frame and set it to be new [ay] for the remainder of the app (aka校准)”。

关于iphone - Cocos2d,在直立时使用 x 轴的景观错误中的加速度计移动 Sprite ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7826375/

相关文章:

ios - 即使数据库 FMDB Swift 中有数据,结果集也返回 nil

objective-c - NSImage 标准图稿和图标 NSImageNameStatusAvailable

ios - 在容器 View 中交换 subview

objective-c - 如何在 View 顶部添加模糊 View ?

ios - 在 iOS 中控制背光强度

iphone - iOS Simulator v5.1 窗口缺少设备框架和主页按钮

ios - iOS 6和7中的UISearchbar自定义

ios - 在选项卡栏 Controller 中隐藏当前 View Controller 的选项卡

ios - iCloud 和 NSFileWrapper : Showing as 2 different files in Settings

iphone - 如何为 CAShapeLayer 路径和 fillColor 设置动画