• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            兔子的技術博客

            兔子

               :: 首頁 :: 聯系 :: 聚合  :: 管理
              202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

            留言簿(10)

            最新評論

            閱讀排行榜

            評論排行榜

            免責申明(必讀!):本博客提供的所有教程的翻譯原稿均來自于互聯網,僅供學習交流之用,切勿進行商業傳播。同時,轉載時不要移除本申明。如產生任何糾紛,均與本博客所有人、發表該翻譯稿之人無任何關系。謝謝合作!

            原文鏈接地址:http://www.raywenderlich.com/3997/introduction-to-augmented-reality-on-the-iphone

            教程截圖:

            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 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成員變量。

            UIView *overlay;

              現在,打開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類的頭文件,如下所示:

            #import "EnemyShip.h"

              在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數組:

            [enemySprites release];

              現在,編譯并運行工程吧!當你旋轉設備的時候,你將會看到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"];

              當飛船被打中的時候,將會播放爆炸的音效!

              編譯并運行代碼,盡情玩吧!

            何去何從?

              這里有本教程的完整源代碼

              如果你想學習更多有關制作增強現實的游戲的話,下面有一些比較好的資源:

              我希望你在學習這個教程的時候會得到許多快樂!如果有什么建議或意見,請留言,謝謝!


            轉自:http://www.cnblogs.com/andyque/archive/2011/07/03/2096510.html
            posted on 2011-07-04 11:57 會飛的兔子 閱讀(2165) 評論(0)  編輯 收藏 引用 所屬分類: 蘋果相關
            久久久国产亚洲精品| 伊人色综合久久| 99久久精品午夜一区二区 | 久久99国产综合精品免费| 狠狠色丁香婷综合久久| 亚洲AV伊人久久青青草原| 77777亚洲午夜久久多喷| 亚洲欧洲精品成人久久奇米网 | 久久综合成人网| 精品人妻久久久久久888| 亚洲欧美日韩精品久久亚洲区 | 久久综合偷偷噜噜噜色| 免费观看久久精彩视频| 久久综合综合久久综合| 亚洲国产精品成人久久蜜臀 | 日韩精品久久无码中文字幕| 国产真实乱对白精彩久久| 久久综合噜噜激激的五月天| 欧美久久久久久| 日本亚洲色大成网站WWW久久| 高清免费久久午夜精品| 久久亚洲欧美国产精品| 久久久精品人妻一区二区三区蜜桃 | 国产精品99久久精品| 国产亚洲精品久久久久秋霞| 内射无码专区久久亚洲| 精品无码久久久久久久久久| 国产亚洲婷婷香蕉久久精品| 久久久一本精品99久久精品66| 无码人妻久久一区二区三区蜜桃| 久久久WWW成人免费毛片| 久久国产香蕉一区精品| 一本色道久久88加勒比—综合| 97久久久精品综合88久久| 久久精品欧美日韩精品| 久久精品亚洲一区二区三区浴池| 久久夜色精品国产网站| 精品久久久久久亚洲精品| 久久久久亚洲AV片无码下载蜜桃 | 狠狠精品干练久久久无码中文字幕| 精品国产VA久久久久久久冰|