iPhoneのサンプルプログラム その5

SATCHを用いたナビアプリ(2)

シナリオファイル(圧縮)

disp0.lua(SATCHのスクリプト)
local componentInterface = getComponentInterface()
local scene = getCurrentScene()
local tRoll = Text2D(scene:getObjectByName("txtRoll"))

--Data for compass
local boussole = Entity(scene:getObjectByName("Boussole"))
local fleche = Entity(scene:getObjectByName("Fleche"))
boussole:setVisible(true)
fleche:setVisible(true)

local isCommand = nil
local command = nil

repeat

	if componentInterface then
		isCommand, command = componentInterface:pullCommand()
		if isCommand then
			if command["CommandName"]=="sendGyro" then
				tRoll:setText("Roll:"..command["arg0"])
				fleche:setOrientationEuler(0,command["arg1"],0,boussole)
			end
		end
	end

until coroutine.yield()

AppDelegate.h
#import <Foundation/Foundation.h>
#import <CoreMotion/CoreMotion.h>
#import "satchARViewer.h"

#define NAVI_DIRECT_FORWARD     1
#define NAVI_DIRECT_RIGHT       2
#define NAVI_DIRECT_LEFT        3

@interface AppDelegate : UIResponder  {
    UIWindow *window;
    UIView *mRender;
    SatchARViewer *mPlayer;
    
    CMMotionManager *motionManager;
    CMAttitude *referenceAttitude;
    BOOL isCaptured;

    NSArray *path;
    int curDirect;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UIView *mRender;
@property (retain, nonatomic) IBOutlet UILabel *labMsg;

- (IBAction)pushCornerButton:(id)sender;

- (void)start;
- (void)stop;

@end

AppDelegeta.mm
#import "AppDelegate.h"

@implementation AppDelegate

@synthesize window;
@synthesize mRender;
@synthesize labMsg;

- (void)dealloc
{
    [self stop];

    if (mPlayer) {
        [mPlayer terminate];
        [mPlayer release];
        mPlayer = nil;
    }

    [path release];
    [motionManager release];
    [mRender release];
    [window release];
    [labMsg release];
    [super dealloc];
}

- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    path = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:NAVI_DIRECT_FORWARD],
            [NSNumber numberWithInt:NAVI_DIRECT_RIGHT],
            [NSNumber numberWithInt:NAVI_DIRECT_LEFT],
            nil];
    counter = 0;
    
    [SatchARViewer setDialogMessageLoading:@"ローディング..."];
    [SatchARViewer
        setToastMessageNoNetworkConnection:@"ネットワークに接続されていません。"];
    [SatchARViewer setToastMessageNetworkError:@"通信中にエラーが発生しました。"];
    [SatchARViewer setToastMessageLicenceError:@"認証に失敗しました。"];

    mPlayer = [[[SatchARViewer alloc] init] initialize:mRender];
    [self.window makeKeyAndVisible];
    [self start];

    [self stepNext];
    motionManager = [[CMMotionManager alloc] init];
    motionManager.deviceMotionUpdateInterval = 1.0f/4.0f; // ジャイロのサンプリング間隔[s]    
    isCaptured = NO;
    referenceAttitude = nil;
    [self startGyro];

    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    if (mPlayer != nil) {
        [mPlayer applicationWillResignActive];
    }
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    if (mPlayer != nil) {
        [mPlayer applicationDidEnterBackground];
    }
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    if (mPlayer != nil) {
        [mPlayer applicationWillEnterForeground];
    }
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    if (mPlayer != nil) {
        [mPlayer applicationDidBecomeActive];
    }
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    if (mPlayer != nil) {
        [mPlayer applicationWillTerminate];
    }
}

- (void)callback:(NSNumber*)num
{
    switch ([num intValue]) {
        case LOAD_SCENARIO_STATUS_COMPLETE:
            [mPlayer playScenario];
            break;
    }
}

- (void)stepNext
{
    if (counter < [path count]) {
        NSNumber *num = (NSNumber *)[path objectAtIndex:counter];
        curDirect = [num intValue];
        
        switch (curDirect) {
            case NAVI_DIRECT_FORWARD:
                labMsg.text = @"まっすぐ進んでください!";
                break;
                
            case NAVI_DIRECT_RIGHT:
                labMsg.text = @"右に進んでください!";
                break;
                
            case NAVI_DIRECT_LEFT:
                labMsg.text = @"左に進んでください!";
                break;            
        }
        
        counter++;
    }
}

- (IBAction)pushCornerButton:(id)sender 
{
    [self stepNext];
}

- (void)start
{
    if (mPlayer) {
        [mPlayer loadScenario:@"Gyro1_iphone/Gyro1.dpd"
                 callback:@selector(callback:)
                      obj:self];
    }
}

- (void)stop
{
    if (mPlayer && ![mPlayer isScenarioPaused]) {
        [mPlayer pauseScenario];
}
}

- (void)startGyro
{
    // デバイスのハードウェアチェック
    if (!motionManager.deviceMotionAvailable)
    {
        NSLog(@"DeviceMotion is not available.");
        return;
    }

    isCaptured = NO;

    // モーションデータ更新時のハンドラを作成
    void (^handler)(CMDeviceMotion *, NSError *) = ^(CMDeviceMotion *motion, NSError *error)
    {
        if (isCaptured == NO) {
            referenceAttitude = [motion.attitude retain];
            isCaptured = YES;
        }
        else {
            // ジャイロデータの記録
            [self recordGyroData:motion];
        }
    };

    // モーションデータの測定を開始
    NSOperationQueue *queue = [NSOperationQueue currentQueue];
    [motionManager startDeviceMotionUpdatesToQueue:queue withHandler:handler];
}

- (NSNumber *)calcDirection:(float)roll mode:(int)num
{
    float _direct = 0.0;
    switch (num) {
        case NAVI_DIRECT_FORWARD:
            _direct = roll;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;

        case NAVI_DIRECT_RIGHT:
            _direct = roll + 90.0;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;

        case NAVI_DIRECT_LEFT:
            _direct = roll - 90.0;
            if (_direct <= 0) {
                _direct = -_direct;
            }
            else {
                _direct = 360.0 - _direct;
            }
            break;
    }
    
    NSNumber *direct = [[NSNumber alloc] initWithFloat:_direct];
    return direct;
}

- (void)recordGyroData:(CMDeviceMotion *)motion
{
    if (!mPlayer) {
        return;
    }

    CMAttitude *currentAttitude = motion.attitude;

    if (referenceAttitude != nil) {
        [currentAttitude multiplyByInverseOfAttitude: referenceAttitude];
    }

    // 角度を度数に変換
    float rollDegree = 180 * currentAttitude.roll / M_PI;
    NSNumber *direct = [self calcDirection:rollDegree mode:curDirect];
    
    NSString *_roll = [NSString stringWithFormat:@"%.4f", rollDegree];
    NSString *_roll2 = [NSString stringWithFormat:@"%.4f", [direct floatValue]];

    NSArray *para = [NSArray arrayWithObjects:_roll, _roll2, nil];
    NSLog(@"roll=%f, roll2=%f", rollDegree, [direct floatValue]);

    [direct release];
    [mPlayer enqueueCommand:@"sendGyro" args:para];
}

@end