免責申明(必讀!):本博客提供的所有教程的翻譯原稿均來自于互聯網,僅供學習交流之用,切勿進行商業傳播。同時,轉載時不要移除本申明。如產生任何糾紛,均與本博客所有人、發表該翻譯稿之人無任何關系。謝謝合作!
原文鏈接地址:http://www.raywenderlich.com/3997/introduction-to-augmented-reality-on-the-iphone
教程截圖:

Create a simple augmented reality game where you can blast some aliens!
在這篇教程中,你將學習到如何為你的iphone和ipod touch制作一個簡單的增強現實游戲。
在這個游戲中,你將使用到攝像頭,陀螺儀和cocos2d框架。聽起來很振奮人心吧?
在寫作這篇教程的時候,探索上面提到的一些技術的過程真的是非常有趣。這里有一些數學和轉換,不過不要擔心---沒有什么事情是很難的!
學習這篇教程的時候,你需要一個iPhone4,因為這個教程使用陀螺儀來移動游戲世界視圖。
你也需要一些基本的cocos2d方面的知識,當然要安裝好cocos2d。如果你對于cocos2d完全陌生的話,你可以先看看本博客上的其它cocos2d教程。
你準備好爆頭一些虛擬外星人了嗎?跟我來吧!
Getting Started
打開Xcode,然后從File菜單中選擇New\New Project。然后選擇 iOS\cocos2d\cocos2d template,接著點擊Next。把工程命名為ARSpaceShips,并點擊Next,同時選擇一個文件夾位置來保存本項目,最后點Create。
我們將重用Space Shooter游戲的一些資源文件,所以,先下載它們并解壓縮。
下載完后,把Fonts,Sounds和Spritesheet文件夾拖到Resources分組下面。同時確保 Copy items into destination group’s folder被復選中,并且ARSpaceships target也要被選中。然后點擊Finish。這時,你的工程看起來應該如下圖所示:

我們將在后面使用到這些資源。
玩一玩攝像頭!
如果你現在運行項目,那簡單太無聊了,就是一個黑屏的HelloWorld,這玩意兒誰沒看過!讓我們往里面添加一些非常好玩的內容吧。選擇AppDelegate.h,然后在interface里面添加一個UIView成員變量。
現在,打開AppDelegate.m文件,找到EAGLView *glView所在的代碼行,把像素格式改成kEAGLColorFormatRGBA8。改完后如下圖所示:
EAGLView *glView = [EAGLView viewWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGBA8 depthFormat:0];
如果你不改變像素格式的話,那么攝像頭里拍攝出來的圖像就顯示不出來。因為我們現在正在做一個增強現實的游戲,所以必須這樣做!
在 [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。這個視圖后面用來顯示camera里的內容。
接下來,在你剛剛添加的代碼后面增加以下代碼行:
#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,而iphone屏幕的比例是3:4,所以,我們需要縮放一下攝像頭,使之與屏幕匹配。
其次,我們創建了一個UIImagePickerController,設置了它的一些屬性,具體效果就是沒有控件并且縮放了的攝像頭。然后,我們把它添加到了overlay視圖中。
最后,我們需要把 viewController.view顯示到前面來(因為它包含了cocos2d的顯示內容)。這樣子攝像頭拍攝的內容也就會顯示到前臺來了。
現在,運行一下應用程序。現在,你將看到攝像頭里面捕捉的畫面是你的Hello World的背景了。

Shake, Rattle, and Roll…Well at Least Yaw!
因為我們現在的程序已經可以把現實捕捉并顯示出來了,接下來,我們將集中精力來解決本教程中比較難的部分。
首先,我們需要把CoreMotion framework添加到項目中去。點擊project文件,然后選擇ARSpaceships target,再選擇Build Phases標簽頁,展開 Link Binary With Libraries.。

點擊上圖中的+號,選擇 CoreMotion.framework,然后點擊Add按鈕。現在,我們就可以在項目中使用陀螺儀啦。
打開HelloWorldLayer.h,然后導入一些頭文件:
#include <CoreMotion/CoreMotion.h>
#import <CoreFoundation/CoreFoundation.h>
然后在interface里面添加一些成員變量:
CMMotionManager *motionManager;
CCLabelTTF *yawLabel;
CCLabelTTF *posIn360Label;
同時添加屬性聲明語句:
@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對象。同時,我們還設置了更新間隔為每秒60次。如果設置支持陀螺儀的話,那么就啟動更新。最后,我們觸發一個update定時器。
不要忘了在.m文件中添加synthesize語句,如下所示:
@synthesize motionManager;
因為我們觸發了update定時器,所以我們需要添加一個update方法。同時,在init方法的下面增加下面一個方法:
-(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的對應標簽值在改變。
那玩意兒究竟如何工作?
盡管可以跑起來了,但是你可能會問,它究竟是如何工作的呢?讓我們花幾分鐘時間來一步步解釋上面的代碼是如何工作的。
首先,下載iTunes app store上面的免費程序 Gyrosocope app。安裝并運行它,當你移動iphone的時候,就可以看到每個值究竟是怎么變化的。

我們關心的值是Yaw。這個值代表往左或往右移動。在Gyroscope程序中,它的單位是度,然而 motion manager獲取的值卻是弧度。這就是為什么我們需要使用內置的函數CC_RADIANS_TO_DEGREES來把弧度轉換成角度的原因啦。
因此,在第一部分中,我們得到了yaw的弧度值,并且把它轉換成角度,最后賦值給yaw變量。第二部分,我們只是把yaw的值顯示到屏幕上去。如果你運行工程,你會看到yaw值的變化范圍是從0~180,然后又從-180回到0.

現在看看第三部分,你可能會奇怪positionIn360的值倒底是什么啊?好吧,這里只是一個手段,目的是使得放置飛碟的過程變得容易。
這里的邏輯其實非常簡單。如果yaw值是正的,那么我們什么也不做。如果是負的,那么就減去360.(加上一個負值和減去一個正值是一樣的)。最后一行代碼只是在屏幕上顯示那個值。

如果你還沒完全理解,沒關系,運行一下程序,看看具體值是怎么變化的吧。
燈光,攝像機,Action!
現在,我們為陀螺儀的使用奠定基礎了,讓我們往里面添加一些太空飛船吧!我們將創建一個新的文件。首先,左鍵點ARSpaceships工程文件,然后選擇New File。接著選 iOS\Cocoa Touch\Objective-C class,然后點擊Next。確保NSObject被選中基類,然后點Next。把文件命名為EnemyShip.m,最后點Save。
把 EnemyShip.h里的內容換成下面的代碼:
#import "cocos2d.h"
@interface EnemyShip : CCSprite {
int yawPosition;
int timeToLive;
}
@property (readwrite) int yawPosition;
@property (readwrite) int timeToLive;
@end
同時修改EnemyShip.m:
#import "EnemyShip.h"
@implementation EnemyShip
@synthesize yawPosition, timeToLive;
-(id)init {
self = [super init];
if (self){
yawPosition = 0;
timeToLive = 0;
}
return self;
}
@end
現在,回到HelloWorldLayer.h。在頂部導入EnemyShip類的頭文件,如下所示:
在interface里面聲明以下成員變量:
NSMutableArray *enemySprites;
int enemyCount;
CCSpriteBatchNode *batchNode;
最后,在interface聲明下面,添加enemyCount屬性,同時定義一些方法,具體如下圖所示:
@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;
打開 HelloWorldLayer.m文件,同時作以下修改:
// 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,它的資源文件在一開始的時候,我們就把它拖到項目中來了。
接下來,我們將添加一個新的方法來創建新的敵人太空飛船。在dealloc方法的上面添加下列方法:
-(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;
}
這個方法接收一個整數值作為tag,并且返回一個EnemyShip CCSprite。下面一行代碼,我們從精靈表單中創建一個EnemyShip精靈。接著,我們使用arc4random方法來得到一個0~360的隨機數。最后,我們設置了飛船的位置,并把timeToLive的值設置為100,把飛船添加到batchNode里面,最后返回飛船精靈對象。
在addEnemyShip下面,我們添加一個checkEnemyShipPosition方法:
-(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];
}
}
}
這個方法看起來似乎有點讓人摸不著頭腦,一會最大值,一會兒最小值,一會候選值。不過,不要擔心,其實非常簡單。首先,我們檢查設置的yaw坐標址(positionIn360),然后把此值限制在0~360之間。

因為,我們有兩端范圍都是0~360,所以需要檢查一下設置的positionIn360具體屬于哪一端。我們使用一個任意數23來代表將在屏幕一半處顯示的度數。

因為,我們只需要關心變化范圍是0~23和337~360的空間了。因為,另一端的線將會包過來。(這里相像成3維空間的一個圓)
最后,如果敵人飛船在屏幕46度的范圍之內的話,那么就要更新敵人飛船。checkAlternateRange判斷語句只是用來決定什么時候來更新敵人飛船。
如果checkAlternateRange為真的話,那么我們就檢查敵船的位置是否落在min和max的范圍之內。
positionIn360 = 20
rangeMin = 357
rangeMax = 20
enemyShip.yawPosition = 359
因為我們要考慮線段的兩端,我們的min范圍比max范圍要大一些。現在,我們做一個判斷,看敵船的位置是不是大于rangeMin,如果是,則顯示在屏幕上。
if語句中的else就更加明了了。他檢查敵船的位置是不是大于min且小于max。
多么復雜的一個update方法啊!我們在checkEnemyShipPosition方法下面添加以下代碼:
-(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];
}
}
在這個方法中,我們測試,看是否設備的positionIn360是不是在討論的3個范圍內。在第一個測試中,我們檢測positionIn360是不理小于23,如果是,我們就看看是不是有一些敵船在線的另一端(大于337)。
第二部分測試,看是否positionIn360大于337.如果是的話,就再檢測它是否小于23.
第二部分測試,看敵船是否在23和337之間。如果是,則調用runStandardPositionCheck方法。這個方法的定義如下所示:
-(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)];
}
}
在這個方法中,我們檢查看是否enemyShip是否在設備的positionIn360的左邊還是右邊。當enemyShip的位置小于positionIn360時,它將出現在屏幕的左邊。當enemyShip的位置大于positionIn360,那么它將出現在屏幕的右邊。
現在,你會說,請等一下!你忘了描述這些變量的作用了!好吧,接下來就解釋一下。
如果敵船的yaw坐標值在屏幕的范圍之內(從 positionIn360 – 23到 positionIn360 + 23),然后,首先我們計算它位于屏幕的哪一邊。如果大于positionIn360,那么就在屏幕的右邊,否則就在屏幕的左邊。
difference變量的作用是保存設備的positionIn360和敵船的 yaw位置的角度差值。一旦計算出來后,我們就把這個差值乘以一個任意的倍數。這個倍數代表每一度的像素個數。這個里,我們選擇15.
基于它位于于當前屏幕的位置,我們將把這個計算出來的值增加240或者減去240。
現在,所有需要的方法已經全部準備就緒啦。
在init方法的底部,添加下面的代碼,在屏幕中增加5個飛船:
// 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;
}
因為,我們添加了敵船到屏幕中了,我們確保它們的位置被更新。在udpate方法的底部添加下面方法:
// Loop through array of Space Ships and check the position
for (EnemyShip *enemyShip in enemySprites) {
[self checkEnemyShipPosition:enemyShip withYaw:yaw];
}
在我們忘記之前,在dealloc里面添加清理代碼來清理我們之前創建的enemySpritesArray數組:
現在,編譯并運行工程吧!當你旋轉設備的時候,你將會看到5個飛船在不同的地方。

免費的激光和爆炸
目前為止,這個現實增加的游戲完成的差不多了。不過,還有一個很嚴重的問題:這里飛船打中后沒什么感覺。
很明顯,我們并不想這樣,所以,讓我們添加一些很酷的激光和爆炸效果吧。
在開始之前,讓我們移除屏幕上的label--他們只是作為調試時用的。因此,找開 HelloWorldLayer.m中關于labels的代碼,并把它們注釋掉。完成之后,編譯并運行,保證沒有錯誤。
現在,看看有趣的部分---讓我們往游戲中添加一些火力吧!首先,我們將添加一個方法用來判斷玩家的開火區域是否擊中了飛船。在HelloWorldLayer.h文件中,在@end之前聲明下列方法:
- (BOOL) circle:(CGPoint) circlePoint withRadius:(float) radius collisionWithCircle:(CGPoint) circlePointTwo collisionCircleRadius:(float) radiusTwo;
打開HelloWorldLayer.m,然后在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;
}
這個方法用來檢測是否兩個點的半徑有交集。輸入的參數是敵方飛船位置和屏幕的中心點位置。兩個點的半徑都設置為50.
首先,我們計算兩個點X和Y值的差。接下來計算兩點的距離。這個在高中就學過的,叫勾股定理。你可以從這里得到更多的信息。
接下來,我們往屏幕中添加一個區域,用作火力瞄準器。下載這些資源文件,解壓縮,然后把scope.png拖到Resouces文件夾下去。確保“Copy items into destination group’s folder”被復選中,然后點Finish。
打開HelloWorldLayer.m的init方法,然后在 [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];
如果你現在運行程序,你將看到一個瞄準器出現在屏幕的中間。

非常好,現在讓我們添加一些爆炸效果,在玩家點擊屏幕的時候就觸發。我們將按照添加scope.png的方法一樣,來添加Explision.plist。先找到之前下載的本項目資源文件。把Explosion.plist拖到資源文件夾中,確保“Copy items into destination group’s folder”被復選上,然后點擊Finish。
你可能會奇怪這個文件到底是什么?我使用一個很酷的軟件制作的,你可能之前也聽說過了,叫做 Particle Designer,它是由71 Squared的工程師所開發的。我不會在這里講解如何使用此軟件來制作這樣的粒子效果文件,但是,實際上這個過程是非常簡單的。選擇一種粒子效果,然后調節一些參數,最后導出plist文件就可以了。
現在,在dealloc方法之前,添加下列代碼:
-(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];
}
}
這段代碼的第一部分用來做碰撞檢測,用來測試是否飛船在瞄準器范圍之內。如果其中一個飛船被擊中了,我們就飛船的屬性來隱藏它,同時把enemyCount計數減1.第二部分代碼,往屏幕中心添加了一個爆炸粒子系統。第二部分代碼,也是最后一部分代碼,它用來檢查enemyCount是否為0,如果是的話,就顯示一個label,告知玩家游戲結束了。
這個游戲如果就這樣的話,有點無聊。所以,讓我們往游戲中添加一些基本的AI吧。其實也很簡單的,就是隨著時間的推移,我們會改變一下飛船的位置。所以,在update方法底部添加下列代碼:
// 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;
}
}
這段代碼將會遍歷所有的enemySprites,然后更新timeToLive屬性。然后,檢查這個timeToLive屬性是否等于0,如果是的話,那么就給飛船的yawPositon設置一個隨機值,同時重置timeToLive屬性。編譯并運行工程吧,現在你想要打中飛船的話就有一些難度了,開火!
Pump up the Volume!
游戲如果沒有聲音的話,那就太沒意思了!所以,讓我們添加一些音樂吧!
在HellowWorldLayer.m文件頂部包含Simple Audio Engine所需的頭文件,具體如下所示:
#import "SimpleAudioEngine.h"
然后在init方法的最后添加下列代碼,記得添加在 if ((self=[super init]))語句內部:
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"SpaceGame.caf" loop:YES];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"explosion_large.caf"];
[[SimpleAudioEngine sharedEngine] preloadEffect:@"laser_ship.caf"];
這里會加載背景音樂,同時預加載音效。
現在,找到ccTouchesBegan,然后在這個方法的開頭添加下列代碼:
[[SimpleAudioEngine sharedEngine] playEffect:@"laser_ship.caf"];
這里會在你點擊屏幕的時候播放一個發射激光的音效。
還是在ccTouchesBegan方法里面,打開遍歷enemySprites那個循環,然后在 (wasTouched)的if判斷句內添加下列代碼:
[[SimpleAudioEngine sharedEngine] playEffect:@"explosion_large.caf"];
當飛船被打中的時候,將會播放爆炸的音效!
編譯并運行代碼,盡情玩吧!
何去何從?
這里有本教程的完整源代碼。
如果你想學習更多有關制作增強現實的游戲的話,下面有一些比較好的資源:
我希望你在學習這個教程的時候會得到許多快樂!如果有什么建議或意見,請留言,謝謝!