iOS2012. 6. 14. 17:54


출처 : http://www.raywenderlich.com/3997/introduction-to-augmented-reality-on-the-iphone

This is a post by iOS Tutorial Team member and Forum Moderator Nick Waynik, a web and iOS developer in Pittsburgh, Pennsylvania.

Create a simple augmented reality game where you can blast some aliens!

Create a simple augmented reality game where you can blast some aliens!

iPhone/iPod에서 AR game을 간단하게 만드는 방법을 소개한다.

이겜은 카메라, 자이로스코프 그리고 cocos2d framework를 사용한다.

여러가지 기술들을 탐험할것이고 약간의 수학과 변환기술들이 언급될건데 겁먹지마! 별로 어렵지 않거든.

iPhone4이상이 필요하지 왜냐구? 자이로스코프땜에.

그리고 Cocos2D에 대한 기초지식과 Cocos2D를 이미 설치했어야 해. 알간? cocos2D를 전혀 모른다면 여길 ->  other Cocos2D tutorials 가바

시작하자!

Getting Started

Xcode열고 New/New Project. 그리고 iOS/cocos2d/cocos2d template선택해!, 다음눌러. project명은 ARSpaceships입력하고 다음, .. 머 암튼 프로젝트 생성하라고.

Space Shooter game의 일부 리소스를 사용하게 될거야 그건 여기(download them)서 다운받을 수 있지.

파일을 다운받았으면 폰트, 사운드 그리고 Spritesheets 폴더를 Resources그룹에 집어넣어. 폴더째로 이동시켜서.. 먼말인지 알지? 시킨대로 했다면 아래 그림처럼 보일겨.


A default Xcode project with the project resources added

We will use some of these items later on.

Roll the Camera!

앱을 당장 실행하고 싶다고? 안보는게 낳아. 까만스크린에 "Hello World"만 보일거야. AppDelegate.h를 열어서 UIView를 추가해!

UIView *overlay;

AppDelegate.m를 열어. EAGLView *glView가 보이는데까지 스크롤해. 그리고 pixelFormat을 kEAGLColorFormatRGBA8로 바꺼. 이렇게..

EAGLView *glView = [EAGLView viewWithFrame:[window bounds] 
    pixelFormat:kEAGLColorFormatRGBA8 depthFormat:0];

이거 안바꾸면 카메라가 암것도 표시하지 않는다네. 이건 AR겜이기때문에 그러면 안되지.

[window addSubview: viewController.view]; 코드 아래 다음코드를 넣을거야.

 
// set the background color of the view
[CCDirector sharedDirector].openGLView.backgroundColor = [UIColor clearColor];
[CCDirector sharedDirector].openGLView.opaque = NO;
 
// set value for glClearColor
glClearColor(0.0, 0.0, 0.0, 0.0);
 
// prepare the overlay view and add it to the window
overlay = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
overlay.opaque = NO;
overlay.backgroundColor=[UIColor clearColor];
[window addSubview:overlay];

여기서 우린 openGLView의 배경색을 클리어하기 위해 셋팅하지. 불투명하지 않게. glClearColor를 셋팅해서 말야. 그리고 마침내 overlay로 명명된 UIView를 생성해서 추가하고 있어. 우린 이걸 카메라를 위해 사용할거야.

다음엔 방금 추가한 코드 아래에 다음코드를 추가해~

#define CAMERA_TRANSFORM  1.24299
 
UIImagePickerController *uip;
 
@try {
    uip = [[[UIImagePickerController alloc] init] autorelease];
    uip.sourceType = UIImagePickerControllerSourceTypeCamera;
    uip.showsCameraControls = NO;
    uip.toolbarHidden = YES;
    uip.navigationBarHidden = YES;
    uip.wantsFullScreenLayout = YES;
    uip.cameraViewTransform = CGAffineTransformScale(uip.cameraViewTransform, 
        CAMERA_TRANSFORM, CAMERA_TRANSFORM);
}
@catch (NSException * e) {
    [uip release];
    uip = nil;
}
@finally {
    if(uip) {
        [overlay addSubview:[uip view]];
        [overlay release];
    }
}
 
[window bringSubviewToFront:viewController.view];

첫번째로, 카메라를 스케일링하기 위한 상수를 정의해. 카메라는 4:3의 비율이고 아이폰은 3:4기 때문에 우리는 카메라 이미지를 스케일링해야 하지.

두번째로, UIImagePickerController를 생성, 속성 설정, 스케일링하고 나서 overlay뷰에 추가해.

마지막으로 viewController를 카메라뷰의 앞으로 보이도록 가져와야 해. Cocos2D display를 포함하고 있지.

여기서 앱을 실행해바. 카메라화면위에 Hello World라는 글씨가 뵐겨.

The beginnings of an augmented reality app with Cocos2D!

Shake, Rattle, and Roll…Well at Least Yaw!

이제 좀더 어려운걸 해보자.

먼저 CoreMotion framework을 추가해. 

Adding CoreMotion to Link Binary with Libraries step in Xcode 4

HelloWorldLayer.h를 열어서 아래 코드를 추가해 맨위에..

#include <CoreMotion/CoreMotion.h>
#import <CoreFoundation/CoreFoundation.h>

다음 변수들도 추가하구

CMMotionManager *motionManager;
CCLabelTTF *yawLabel;
CCLabelTTF *posIn360Label;

property도 정의하고.

@property (nonatomic, retain) CMMotionManager *motionManager;

이제 고기랑 감자를 프로젝트에 가져올 차례야. HelloWorldLayer.m파일을 열러. if((self=[super init])) 구문 내에다 "Hello World" 라벨을 넣는 코드를 제거하고 아래 코드를 넣어.

// add and position the labels
yawLabel = [CCLabelTTF labelWithString:@"Yaw: " fontName:@"Marker Felt" fontSize:12];
posIn360Label = [CCLabelTTF labelWithString:@"360Pos: " fontName:@"Marker Felt" fontSize:12];
yawLabel.position =  ccp(50, 240);
posIn360Label.position =  ccp(50, 300);
[self addChild: yawLabel];
[self addChild:posIn360Label];

폰트정보를 갖는 라벨을 추가했을 뿐이야. 라벨들은 왼쪽에 배치되지.

이제 motion manager를 설정해야 해. 자이로스코프를 시작할거거든.

self.motionManager = [[[CMMotionManager alloc] init] autorelease];
motionManager.deviceMotionUpdateInterval = 1.0/60.0;
if (motionManager.isDeviceMotionAvailable) {
       [motionManager startDeviceMotionUpdates];
}
 
[self scheduleUpdate];

여기서 우리는 motion manager를 할당하고 초기화했어. 업데이트 인터벌도 초당 6회로 했고. 이제 디바이스가 자이로스코프가 가능하다면 업데이트가 시작될거야. 

motion manager의 synthesize로 추가해야 해.

@synthesize motionManager;

업데이트를 스케쥴링하고 있기 때문에 아래와 같이 업데이트메소드를 추가해야 해.

-(void)update:(ccTime)delta {
    CMDeviceMotion *currentDeviceMotion = motionManager.deviceMotion;
    CMAttitude *currentAttitude = currentDeviceMotion.attitude;
 
    // 1: Convert the radians yaw value to degrees then round up/down
    float yaw = roundf((float)(CC_RADIANS_TO_DEGREES(currentAttitude.yaw)));
 
    // 2: Convert the degrees value to float and use Math function to round the value
    [yawLabel setString:[NSString stringWithFormat:@"Yaw: %.0f", yaw]];
 
    // 3: Convert the yaw value to a value in the range of 0 to 360
    int positionIn360 = yaw;
    if (positionIn360 < 0) {
        positionIn360 = 360 + positionIn360;
    }
 
    [posIn360Label setString:[NSString stringWithFormat:@"360Pos: %d", positionIn360]];
 
}

이제 앱을 실행해! Yaw와 positionIn360값의 변화를 볼수 있을거야.

How Did That Work?!

잘 동작하긴 하는데 대체 어케 동작하는건지 궁금할거야. 자 이제 위 코드를 섹션단위로 설명해주께.

Gyroscope app을 다운받아서 실행해바 그러면 아주 멋집 화면을 볼거야.

Free gyroscope app on iTunes App Store

여기서 눈여겨 볼 값은 Yaw값이다! 이 값은 오른쪽에서 왼쪽으로 이동한값이야. 앱에서는 이 값을 각도값으로 표시하지. CC_RADIANS_TO_DEGREES함수를 변환하기 위해 사용하는 예가 되지.

그래서 섹션1에서는 yaw값을 각도값으로 얻고, 각도를 degree로 변환하고, yaw변수로 대입하는 법에 대해 설명하고. 섹션2에서는 화면에 yaw값을 표시할거야. 앱을 실행해보면 각도 값의 범위가 0~180, -180~0인걸 알수 있지.

Gyroscope yaw values displayed on a number line

섹션3을 보면 positionIn360값은 또 머야? 할거야. 자. 이값은 그냥 트릭값인데 화면에 떠있는 물건을 표시하기 위해 사용하게 될거야.

Converting yaw values to 0-360 range


Lights, Camera, Action!

이제 우주선을 추가할차례야. Objective-C class를 하나 추가해 NSObject를 상속하고 EnemyShip.m이란 파일을 생성해.

Replace the contents of EnemyShip.h with:

#import "cocos2d.h"
 
@interface EnemyShip : CCSprite {
    int yawPosition;
    int timeToLive;
}
 
@property (readwrite) int yawPosition;
@property (readwrite) int timeToLive;
 
@end

Replace the contents of EnemyShip.m with:

#import "EnemyShip.h"
 
 
@implementation EnemyShip
 
@synthesize yawPosition, timeToLive;
 
-(id)init {
    self = [super init];
    if (self){ 
        yawPosition = 0;
        timeToLive = 0;
	}
    return self;
}
 
@end

HelloWorldLayer.h를 다시 열고 아래 코드를 추가해

#import "EnemyShip.h"

Inside the interface add:

NSMutableArray *enemySprites;
int enemyCount;
CCSpriteBatchNode *batchNode;

Finally below the interface, add the property for the enemyCount and the definition of methods:

 
@property (readwrite) int enemyCount;
 
-(EnemyShip *)addEnemyShip:(int)shipTag;
-(void)checkEnemyShipPosition:(EnemyShip *)enemyShip withYaw:(float)yawPosition;
-(void)updateEnemyShipPosition:(int)positionIn360 withEnemy:(EnemyShip *)enemyShip;
-(void)runStandardPositionCheck:(int)positionIn360 withDiff:(int)difference withEnemy:(EnemyShip *)enemyShip;

Jump over to the HelloWorldLayer.m file, and make the following modifications to the file:

// Place after the #import statement
#include <stdlib.h>
 
// Place after the other @synthesize statement
@synthesize enemyCount;
#define kXPositionMultiplier 15
#define kTimeToLive 100
 
// Add to the bottom of init
batchNode = [CCSpriteBatchNode batchNodeWithFile:@"Sprites.pvr.ccz"];
[self addChild:batchNode];   
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"Sprites.plist"];

여기서 우리가 튜토리얼 초반에 프로젝트에 추가했던 spritesheet를 로딩해. 다음 우주선을 생성하는 메서드를 추가할거야. 

-(EnemyShip *)addEnemyShip:(int)shipTag {
 
    EnemyShip *enemyShip = [EnemyShip spriteWithSpriteFrameName:@"enemy_spaceship.png"];
 
    // Set position of the space ship randomly
    int x = arc4random() % 360;
    enemyShip.yawPosition = x;   
 
    // Set the position of the space ship off the screen, but in the center of the y axis
    // we will update it in another method
    [enemyShip setPosition:ccp(5000, 160)];
 
    // Set time to live on the space ship
    enemyShip.timeToLive = kTimeToLive;
    enemyShip.visible = true;
 
    [batchNode addChild:enemyShip z:3 tag:shipTag];
 
    return enemyShip;
}

This method accepts an integer value for the tag and returns an EnemyShip CCSprite. The next line of code we are creating an EnemyShip sprite from the spritesheet. Next we are using the arc4random method to get a random integer from 0 to 360. Finally we set the position of the ship, set the timeToLive value to 100, adding the ship to the batch node, and returning the ship.

Below the addEnemyShip method add the following code for the checkEnemyShipPosition method:

-(void)checkEnemyShipPosition:(EnemyShip *)enemyShip withYaw:(float)yawPosition {
    // Convert the yaw value to a value in the range of 0 to 360
    int positionIn360 = yawPosition;
    if (positionIn360 < 0) {
        positionIn360 = 360 + positionIn360;
    }
 
    BOOL checkAlternateRange = false;
 
    // Determine the minimum position for enemy ship
    int rangeMin = positionIn360 - 23;
    if (rangeMin < 0) {
        rangeMin = 360 + rangeMin;
        checkAlternateRange = true;
    }
 
    // Determine the maximum position for the enemy ship
    int rangeMax = positionIn360 + 23;
    if (rangeMax > 360) {
        rangeMax = rangeMax - 360;
        checkAlternateRange = true;
    }    
 
    if (checkAlternateRange) {
        if ((enemyShip.yawPosition < rangeMax || enemyShip.yawPosition > rangeMin ) || (enemyShip.yawPosition > rangeMin || enemyShip.yawPosition < rangeMax)) {
            [self updateEnemyShipPosition:positionIn360 withEnemy:enemyShip];
        }        
    } else {
        if (enemyShip.yawPosition > rangeMin && enemyShip.yawPosition < rangeMax) {
            [self updateEnemyShipPosition:positionIn360 withEnemy:enemyShip];
        } 
    }
}

This method might seem a little bit confusing with the alternate, min, and max ranges. Don’t worry it is pretty simple. First we start out by checking the yaw position of the device (positionIn360) and placing it in the range from 0 to 360 (think full circle).

Gyroscope yaw position visualized on iPhone

Since we have two ends to our number line of 0 to 360, we will need to check to see if the device’s positionIn360 is on either end. We use 23 as an arbitrary number representing the number of degrees that will show on the half of the screen.

Visible degrees on iPhone

So we only need to worry about the ranges from 0 to 23 and 337 to 360 because the other end of the line will need to wrap around.

Lastly we update the position of the enemy space ship if it is in the 46-degree range of the screen. The (checkAlternateRange) if statement is used for determining when to update the position of the enemy spaceship.

If checkAlternateRange is true, then we check to see if the enemy spaceship’s position falls within the min and max range. All of the checks in the first part of this if statement may seem extreme, but if we walk through it using values it makes perfect sense. Let’s assume:

positionIn360 = 20
rangeMin = 357
rangeMax = 20
enemyShip.yawPosition = 359

Because we have to account for both ends of the number line, our min range is greater than the max range. Now we do all of the checks and find out that the enemy ship’s position is greater than rangeMin so we will display the ship on the screen.

The else in that if statement is more straightforward. It just checks to see if the enemy ship’s position is within the min and max range.

What a great segway into the update method! Add the following code below the checkEnemyShipPosition method.

-(void)updateEnemyShipPosition:(int)positionIn360 withEnemy:(EnemyShip *)enemyShip {
    int difference = 0;
    if (positionIn360 < 23) {
        // Run 1
        if (enemyShip.yawPosition > 337) {
            difference = (360 - enemyShip.yawPosition) + positionIn360;
            int xPosition = 240 + (difference * kXPositionMultiplier);
            [enemyShip setPosition:ccp(xPosition, enemyShip.position.y)];
        } else {
            // Run Standard Position Check
            [self runStandardPositionCheck:positionIn360 withDiff:difference withEnemy:enemyShip];
        }
    } else if(positionIn360 > 337) {
        // Run 2
        if (enemyShip.yawPosition < 23) {
            difference = enemyShip.yawPosition + (360 - positionIn360);
            int xPosition = 240 - (difference * kXPositionMultiplier);
            [enemyShip setPosition:ccp(xPosition, enemyShip.position.y)];
        } else {
            // Run Standard Position Check
            [self runStandardPositionCheck:positionIn360 withDiff:difference withEnemy:enemyShip];
        }
    } else {
        // Run Standard Position Check
        [self runStandardPositionCheck:positionIn360 withDiff:difference withEnemy:enemyShip];
    }
}

In this method we are testing to see if the device’s positionIn360 is in one of the three ranges. In the first test we look to see if the positionIn360 is less than 23, if so we want to check to see if there are any enemy ships on the other end of the line (greater than 337).

The second test we look to see if the positionIn360 is greater than 337. If so we want to do the exact opposite of what we just did (check if the enemy ship is less than 23).

The third test (final outer else) we look to we set the position for the enemy ship if it falls between 23 and 337. We are calling the method runStandardPositionCheck. Place the following code below the last method.

-(void)runStandardPositionCheck:(int)positionIn360 withDiff:(int)difference withEnemy:(EnemyShip *)enemyShip {
    if (enemyShip.yawPosition > positionIn360) {
        difference = enemyShip.yawPosition - positionIn360;
        int xPosition = 240 - (difference * kXPositionMultiplier);
        [enemyShip setPosition:ccp(xPosition, enemyShip.position.y)];
    } else {
        difference = positionIn360 - enemyShip.yawPosition;
        int xPosition = 240 + (difference * kXPositionMultiplier);
        [enemyShip setPosition:ccp(xPosition, enemyShip.position.y)];
    }
}

In this method we check to see if the enemyShip position is to the left or right of the device’s positionIn360. When the enemyShip position is less than the positionIn360, it appears on the left side of the screen. When the enemyShip position is greater than the positionIn360 it appears on the right.

Now you say wait a minute! You forgot the difference variable and describing what it does. Okay, here it goes.

If the enemy ship’s yaw position is in the screen’s range (from positionIn360 – 23 to positionIn360 + 23), then first we figure out which side of the screen it is on. If it is greater than the positionIn360 then it goes on the right side of the screen, else it goes on the left.

The difference variable is used to measure the degrees of difference between the device’s positionIn360 and the yaw position of the enemy ship. Once that is known, we multiply the difference by an arbitrary multiplier. This multiplier represents the amount of pixels for each degree. In this case we choose 15.

Based on which side of the screen we will add or subtract this calculated value from 240(screen width divided by 2). And that’s it for the updateEnemyShipPosition method.

Now that all of the required methods are in place we will move on to calling those methods.

At the bottom of the init method, add the following code to add five enemy space ships on the screen.

// Loop through 1 - 5 and add space ships
enemySprites = [[NSMutableArray alloc] init];
for(int i = 0; i < 5; ++i) {
    EnemyShip *enemyShip = [self addEnemyShip:i];
    [enemySprites addObject:enemyShip];
    enemyCount += 1;
}

Since we added the enemy space ships to the screen, we need to make sure their positions update. At the very end of the update method add the following code:

// Loop through array of Space Ships and check the position
for (EnemyShip *enemyShip in enemySprites) {
    [self checkEnemyShipPosition:enemyShip withYaw:yaw];
}

And before we forget, add the following to the bottom of your dealloc method to clean up the enemySpritesArray we created in init:

[enemySprites release];

Now for the moment of truth, go ahead and run your app! You will see 5 space ships at different locations when you rotate the device around.

A simple augmented reality game for the iPhone!

Gratuitous Lasers and Explosions!

So far our augmented reality game is coming along really well, except there’s one major problem: those darn spaceships are getting away scott free!

Obviously we can’t have that, so let’s add some awesome lasers and explosions.

Before we start, let’s get rid of the labels that are on the screen – those were just there for debugging purposes. So search through HelloWorldLayer.m and comment out all matches for yawLabel and posIn360Label. Once you’re done, compile and run and make sure everything still works ok.

Now for the fun part – let’s add some firepower to the game! First we will add a method to check if the player’s firing area hits a space ship. Inside the HelloWorldLayer.h file add the following line of code before @end.

- (BOOL) circle:(CGPoint) circlePoint withRadius:(float) radius collisionWithCircle:(CGPoint) circlePointTwo collisionCircleRadius:(float) radiusTwo;

Moving on to the HelloWorldLayer.m add the method above the dealloc.

- (BOOL) circle:(CGPoint) circlePoint withRadius:(float) radius collisionWithCircle:(CGPoint) circlePointTwo collisionCircleRadius:(float) radiusTwo {
	float xdif = circlePoint.x - circlePointTwo.x;
	float ydif = circlePoint.y - circlePointTwo.y;
 
	float distance = sqrt(xdif*xdif+ydif*ydif);
	if(distance <= radius+radiusTwo) return YES;
 
	return NO;
}

This method is used to check if the radii of two points overlap. The input parameters are for the position of the enemy spaceship and the center of the screen. The radii for both points are set to 50.

First we find the difference between the two points for both x and y. Next we calculate the distance. You may remember this calculation from your studies, it’s called the Pythagorean Theorem. You can read more about this here.

Next we will add a scope to the screen so we can see where our firepower be aimed at. Download theresources for this project, unzip the file, and drag scope.png into your project under the Resources folder. Make sure the “Copy items into destination group’s folder” is checked then click Finish.

Find the init method in HelloWorldLayer.m and add the following code to setup that sprite just before [self scheduleUpdate];

// Add the scope crosshairs
CCSprite *scope = [CCSprite spriteWithFile:@"scope.png"];
scope.position = ccp(240, 160);
[self addChild:scope z:15];
 
// Allow touches with the layer
[self registerWithTouchDispatcher];

If you run the app now, you will see the scope crosshairs in the center of the screen.

A scope added to the augmented reality iPhone game

Great, now let’s add some explosions when the player taps the screen. We will follow the same steps to add Explosion.plist as we did for scope.png. From the resources for the project that you downloaded earlier, drag Explosion.plist into the Resources folder in Xcode, make sure the “Copy items into destination group’s folder” is checked, and click Finish.

You may be wondering what this file is. I used an awesome program to create it, which you may have heard of. It is called Particle Designer, from the good folks of 71 Squared. I will not cover how to create these files, but it is as easy as selecting a type of particle system, making adjustments, and exporting it to a plist.

Now, right before the dealloc method add the following code.

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint location = CGPointMake(240,160);
 
    // 1
    for (EnemyShip *enemyShip in enemySprites) {
        if (enemyShip.timeToLive > 0) {
            // Check to see if yaw position is in range
            BOOL wasTouched = [self circle:location withRadius:50 collisionWithCircle:enemyShip.position collisionCircleRadius:50];
 
            if (wasTouched) {
                enemyShip.timeToLive = 0;
                enemyShip.visible = false;
                enemyCount -= 1;
            }
        }
    }
 
    // 2
    CCParticleSystemQuad *particle = [CCParticleSystemQuad particleWithFile:@"Explosion.plist"];
    particle.position = ccp(240,160);
    [self addChild:particle z:20];
    particle.autoRemoveOnFinish = YES;
 
    // 3
    if (enemyCount == 0) {
        // Show end game
        CGSize winSize = [CCDirector sharedDirector].winSize;
        CCLabelBMFont *label = [CCLabelBMFont labelWithString:@"You win!" fntFile:@"Arial.fnt"];
        label.scale = 2.0;
        label.position = ccp(winSize.width/2, winSize.height/2);
        [self addChild:label z:30];
    }
}

The first section of this code uses the collision detection method we added earlier to check if a space ship is inside of the scope. If one of the space ships was shot, then we will set some properties on the ship to hide it and reduce the enemyCount variable by one. The second section adds the particle system explosion in the center of the screen. The third and final section checks to see if the enemyCount variable equals zero, and if it does, it displays a label to inform the player that the game is over.

The game is a little bit boring at this point in time, so let’s add some very basic AI to change up the position of the space ships after a certain amount of time. At the bottom of the update method add the following code.

// Loop through array of Space Ships and if the timeToLive is zero
    // change the yawPosition of the sprite 
    for (EnemyShip *enemyShip in enemySprites) {
        enemyShip.timeToLive--;
        if (enemyShip.timeToLive == 0) {
            int x = arc4random() % 360;
            [enemyShip setPosition:ccp(5000, 160)];
            enemyShip.yawPosition = x;
            enemyShip.timeToLive = kTimeToLive;
        }
    }

This code will loop through the enemySprites array and update the timeToLive property. Then it will check to see if that property is equal to zero, if it is then it will assign the ship a different random yawPosition and reset the timeToLive. Go ahead and run the game. The game is now much harder to track those space ships down and shoot them!

Pump up the Volume!

Games without audio can seem very boring, so let’s spice things up!

At the top of HellowWorldLayer.m add the import statement for the Simple Audio Engine, which is included with Cocos2D.

#import "SimpleAudioEngine.h"

Scroll down the file and add the following code to the bottom of the init method just before the end of the if ((self=[super init])) statement.

[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"SpaceGame.caf" loop:YES];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"explosion_large.caf"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"laser_ship.caf"];

This will load the background music and preload the effects.

Now, continue scrolling down the file and locate the ccTouchesBegan method. At the top of this method add the following line of code.

[[SimpleAudioEngine sharedEngine] playEffect:@"laser_ship.caf"];

This will play a laser sound effect when the user touches the screen.

Stay inside of the ccTouchesBegan method. In the enemyShip in enemySprites for loop, add the following line inside the (wasTouched) if statement.

[[SimpleAudioEngine sharedEngine] playEffect:@"explosion_large.caf"];

This will play the explosion sound effect when a ship is hit!

Compile and run your code, and enjoy your new tunes!

Where To Go From Here?

Here is the sample project for the augmented reality game we made in the above tutorial.

If you want to learn more about making augmented reality games, here are some great resources to check out:

I hope you had as much fun reading the article as I did creating it! If you have any questions or suggestions for others learning about augmented reality, please join in the forum discussion below!


Posted by 삼스