溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

瘋狂ios講義之瘋狂打飛機(jī)(2)

發(fā)布時(shí)間:2020-07-15 21:46:43 來(lái)源:網(wǎng)絡(luò) 閱讀:501 作者:fkJava李剛 欄目:移動(dòng)開(kāi)發(fā)

4玩家飛機(jī)飛行效果

下面添加游戲背景圖片和玩家操控的飛機(jī)。打開(kāi)HelloWorldLayer.m文件,首先定義4個(gè)變量,實(shí)現(xiàn)代碼如下。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/HelloWorldLayer.m

// 精靈表單tag
    static NSInteger kTagBatchNode = 1;
    // 玩家飛機(jī)變量
    CCSprite* planeSprite;
    // 屏幕寬度、高度的變量
    NSInteger screenWidth , screenHeight;

然后在init方法中添加背景圖片,實(shí)現(xiàn)代碼如下(程序清單同上)。

-(id) init
{
    if( (self=[super init]) ) {
        // ①本例使用精靈表單來(lái)優(yōu)化游戲性能,
        // CCSpriteBatchNode中的所有CCSprite只會(huì)被渲染1次,因此可以提高游戲的FPS
        batchNode = [CCSpriteBatchNode batchNodeWithFile:@"airfightSheet.png"];
        batchNode.position = CGPointZero;
        [self addChild:batchNode z:0 tag:kTagBatchNode];
        // 獲取屏幕寬度和高度
        CGSize winSize = [[CCDirector sharedDirector] winSize];
        screenWidth = winSize.width;
        screenHeight = winSize.height;
        // ②添加背景圖片
        CCSprite* bgSprite = [CCSprite spriteWithSpriteFrameName:@"bg1.png"];
        bgSprite.position = ccp(screenWidth/2,screenHeight/2);
        [batchNode addChild:bgSprite];
    }
    return self;
}

以上代碼①創(chuàng)建了一個(gè)CCSpriteBatchNode使用精靈表單加載精靈,優(yōu)化游戲性能。接下來(lái)獲取屏幕寬度和高度。代碼②初始化了一個(gè)背景圖片精靈,添加到CCSpriteBatchNode當(dāng)中。

最后在onEnter方法中添加玩家飛機(jī),實(shí)現(xiàn)代碼如下(程序清單同上)。

// 節(jié)點(diǎn)調(diào)用init方法以后將會(huì)調(diào)用此方法
-(void) onEnter{
    [super onEnter];
    // ③添加玩家飛機(jī)精靈
    planeSprite = [CCSprite spriteWithSpriteFrameName:@"plane0.png"];
    planeSprite.position = ccp(screenWidth/2, planeSprite.contentSize.height/2+5);
    [batchNode addChild:planeSprite];
}

代碼③初始化了一個(gè)玩家飛機(jī)精靈,通過(guò)屏幕的寬度和高度設(shè)置相對(duì)坐標(biāo),添加到CCSpriteBatchNode當(dāng)中。

瘋狂ios講義之瘋狂打飛機(jī)(2)


再次編譯并運(yùn)行游戲,資源加載完畢后將顯示背景圖片和玩家飛機(jī)。模擬器顯示效果如圖13.61所示。

瘋狂ios講義之瘋狂打飛機(jī)(2)


現(xiàn)在,玩家飛機(jī)精靈已經(jīng)顯示在屏幕當(dāng)中了,但是這只是一個(gè)靜態(tài)效果,我們可以使用動(dòng)畫技術(shù),讓玩家飛機(jī)精靈實(shí)現(xiàn)飛行動(dòng)畫效果,這樣可以使得游戲效果更加逼真。

打開(kāi)HelloWorldLayer.m文件,在私有分類中添加一個(gè)新的輔助方法,因?yàn)橹蠛芏嗟胤蕉夹枰@取動(dòng)畫幀,所以將獲取動(dòng)畫幀的代碼封裝起來(lái),從而達(dá)到代碼重用的效果。示例代碼如下:

-(CCAnimation*) getAnimationByName:(NSString*)animName delay:(float) delay animNum:(int) num;

該方法的作用是根據(jù)動(dòng)畫幀的名字和動(dòng)畫幀的數(shù)量,以及動(dòng)畫幀與幀之間的間隔時(shí)間創(chuàng)建一個(gè)CCAnimation動(dòng)畫。使用該方法要注意如下兩點(diǎn)。

q動(dòng)畫幀的命名必須帶序號(hào),比如xxx1.pngxxx2.png等。

q動(dòng)畫幀的命名必須連續(xù),而且必須從0開(kāi)始命名。

接下來(lái)是該方法的具體實(shí)現(xiàn),實(shí)現(xiàn)代碼如下(程序清單同上)。

-(CCAnimation*)getAnimationByName:(NSString *)animName delay:(float)delay animNum: (int)num{
    NSMutableArray *animeFrames = [NSMutableArray arrayWithCapacity:num];
    for (int i=0; i< num; i++) {
        // 獲取動(dòng)畫圖片名稱
        NSString *frameName = [NSString stringWithFormat:@"%@%d.png",animName,i];
        // 根據(jù)圖片名稱獲取動(dòng)畫幀
        CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache]
            spriteFrameByName:frameName];
        [animeFrames addObject:frame];
    }
    return [CCAnimation animationWithSpriteFrames:animeFrames delay:delay];
}

回到onEnter方法中,在③添加玩家飛機(jī)精靈部分代碼之后添加動(dòng)畫效果,實(shí)現(xiàn)代碼如下(程序清單同上)。

// ④玩家飛機(jī)動(dòng)畫(尾部噴火)
CCAnimation* planeFlyAnimation = [self getAnimationByName:@"plane" delay:0.08 animNum:2];
// 重復(fù)動(dòng)作
id planeFlyAction = [CCRepeatForever actionWithAction:
    [CCAnimate actionWithAnimation:planeFlyAnimation]];
// 執(zhí)行動(dòng)作,達(dá)到飛機(jī)尾部噴火效果
[planeSprite runAction:planeFlyAction];

這段代碼調(diào)用輔助方法getAnimationByName: delay: animNum:創(chuàng)建了玩家飛機(jī)飛行動(dòng)畫,然后使用CCRepeatForeverCCAnimation創(chuàng)建了一個(gè)重復(fù)飛行動(dòng)作,最后調(diào)用planeSpriterunAction方法播放動(dòng)畫效果。再次編譯并運(yùn)行游戲,屏幕上玩家飛機(jī)的尾部會(huì)產(chǎn)生不斷的噴火效果,給玩家的感覺(jué)就是飛機(jī)在不斷地向前飛行。

5玩家飛機(jī)Touch實(shí)現(xiàn)

現(xiàn)在,我們要完成控制玩家飛機(jī)的移動(dòng)了。找到onEnter方法,在④玩家飛機(jī)動(dòng)畫部分代碼后添加touch事件,實(shí)現(xiàn)代碼如下(程序清單同上)。

// ⑤這是一種新的方式來(lái)激活層的touch事件
[[[CCDirector sharedDirector] touchDispatcher]
    addTargetedDelegate:self priority:0 swallowsTouches:YES];

這是一種新的方式來(lái)激活層的touch事件,老的方式是設(shè)置層的isTouchEnabled屬性為“YES”。cocos2dCCLayer默認(rèn)是采用addTargetedDelegate: priority: swallowsTouches:這種方式進(jìn)行touch事件處理的。每次touch事件發(fā)生時(shí),先調(diào)用ccTouchBegan: withEvent:方法,該方法對(duì)每個(gè)UITouch進(jìn)行響應(yīng)并返回一個(gè)BOOL值,若為“YES”,則表明用戶觸摸事件已經(jīng)被處理,后續(xù)的ccTouchMoved: withEvent:、ccTouchEnabled: withEvent:ccTouchCancelled: withEvent:會(huì)接著響應(yīng),其他事件則不會(huì)再去進(jìn)行監(jiān)聽(tīng)。ccTouchBegan: withEvent:方法返回的值如果為假,則會(huì)繼續(xù)交給其他注冊(cè)過(guò)的類型進(jìn)行處理。

接下來(lái)是ccTouchBegan: withEvent:方法和 ccTouchMoved: withEvent:方法的處理,實(shí)現(xiàn)代碼如下(程序清單同上)。

-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
    return YES;
}
- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event {
    // 把touch坐標(biāo)轉(zhuǎn)換成局部node坐標(biāo)
    CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
    // 把舊坐標(biāo)也轉(zhuǎn)換成局部node坐標(biāo)
    CGPoint oldTouchLocation = [touch previousLocationInView:touch.view];
    oldTouchLocation = [[CCDirector sharedDirector] convertToGL:oldTouchLocation];
    oldTouchLocation = [self convertToNodeSpace:oldTouchLocation];
    // ccpSub計(jì)算兩點(diǎn)的差異,即計(jì)算touch偏移量,把當(dāng)前的點(diǎn)坐標(biāo)減去上一個(gè)點(diǎn)坐標(biāo)
    CGPoint translation = ccpSub(touchLocation, oldTouchLocation);
    // ccpAdd讓兩個(gè)坐標(biāo)相加
    CGPoint newPos = ccpAdd(planeSprite.position, translation);
    // 給玩家飛機(jī)精靈設(shè)置新的坐標(biāo)位置
    planeSprite.position = newPos;
}

再次編譯并運(yùn)行游戲,在模擬器中使用鼠標(biāo)選擇玩家飛機(jī),然后移動(dòng)鼠標(biāo),玩家飛機(jī)會(huì)隨著鼠標(biāo)軌跡移動(dòng)。模擬器顯示效果如圖13.62所示。

瘋狂ios講義之瘋狂打飛機(jī)(2)


6背景滾動(dòng)效果

現(xiàn)在,玩家飛機(jī)已經(jīng)開(kāi)始飛行,但是背景圖片一直都沒(méi)有變化,我們將為游戲添加連續(xù)滾動(dòng)的背景,制作出更加逼真的飛行效果。步驟如下。

打開(kāi)HelloWorldLayer.m文件,添加一個(gè)變量:

CCParallaxNode* backgroundNode;

我們定義了一個(gè)CCParallaxNode(視差視圖)變量,用來(lái)完成背景滾動(dòng)效果。當(dāng)移動(dòng)時(shí),會(huì)看到離我們?cè)浇奈矬w移動(dòng)得越快,越遠(yuǎn)的物體,比如遠(yuǎn)處的山會(huì)移動(dòng)得很慢,而最遠(yuǎn)處的物體,比如太陽(yáng)幾乎不動(dòng),這種現(xiàn)象叫視差,而在游戲中模仿視差,可以讓玩家感覺(jué)到游戲中的角色的確是在移動(dòng)。CCParallaxNode可以很容易地建立一個(gè)視差層,你可以控制每一層的視差率、位置和層級(jí)的高低;而CCFollow可以讓你的層鏡頭跟隨目標(biāo),所以,這里我們會(huì)使用CCParallaxNodeCCFollow給游戲添加連續(xù)滾動(dòng)的背景效果。

找到init方法,注釋掉之前②添加背景圖片的代碼;再找到onEnter方法,添加兩個(gè)背景圖片用于拼接,實(shí)現(xiàn)代碼如下(程序清單同上)。

// ②添加連續(xù)滾動(dòng)的背景
//初始化CCParallaxNode添加到當(dāng)前層中
backgroundNode = [CCParallaxNode node];
[self addChild:backgroundNode z:-1];
// ratio指在CCParallaxNode移動(dòng)時(shí),添加進(jìn)去的背景圖片精靈的移動(dòng)速度和CCParallaxNode的比率
CGPoint ratio = ccp(1.0,1.0);
// 屏幕高度480是iPhone Retina(3.5-inch),568是iPhone Retina(4-inch)
NSString *bgName;
if (screenHeight == 480) {
    bgName = @"bg1.png"; // 640*960
}else{
    bgName = @"bg2.png"; // 640*1136
}
// 第1張背景圖
CCSprite *bgSprite1 = [CCSprite spriteWithFile:bgName];
// setAliasTexParameters用于解決拼接的地圖在連接滾動(dòng)時(shí)容易形成黑色縫隙的問(wèn)題
[[bgSprite1 texture] setAliasTexParameters];
bgSprite1.anchorPoint = ccp(0,0);
[backgroundNode addChild:bgSprite1 z:1 parallaxRatio:ratio positionOffset:ccp(0,0)];
// 第2張背景圖
CCSprite *bgSprite2 = [CCSprite spriteWithFile:bgName];
[[bgSprite2 texture] setAliasTexParameters];
bgSprite2.anchorPoint = ccp(0,0);
// positionOffset時(shí)在第2張背景圖與第1個(gè)背景圖拼接處減去1個(gè)像素,可以消除地圖拼接的縫隙
[backgroundNode addChild:bgSprite2 z:1 parallaxRatio:ratio positionOffset:ccp(0, winSize.height - 1)];
// 添加開(kāi)始連續(xù)滾動(dòng)背景的代碼
const int MAX_WIDTH = 320;
const int MAX_HEIGHT = 480 * 100;
CCSprite *hiddenPlaneSprite = [CCSprite spriteWithSpriteFrameName:@"plane0.png"];
hiddenPlaneSprite.visible = NO;
hiddenPlaneSprite.position = ccp(winSize.width / 2, winSize.height / 2);
[batchNode addChild:hiddenPlaneSprite z:-4 tag:1024];
id move = [CCMoveBy actionWithDuration:300.0f position:ccp(0,MAX_HEIGHT)];
[hiddenPlaneSprite runAction:move];
// 讓背景開(kāi)始滾動(dòng),背景跟隨隱形飛機(jī)移動(dòng)
[backgroundNode runAction:[CCFollow actionWithTarget:hiddenPlaneSprite
    worldBoundary:CGRectMake(0, 0, MAX_WIDTH, MAX_HEIGHT)]];

上面代碼首先初始化了一個(gè)CCParallaxNode,并把它添加到當(dāng)前層中。初始化兩個(gè)背景圖片精靈,設(shè)置錨點(diǎn)為(0,0),并把兩個(gè)背景圖片精靈都添加到CCParallaxNode當(dāng)中。CCParallaxNoderatio屬性表示在CCParallaxNode移動(dòng)時(shí),添加進(jìn)去的背景圖片精靈的移動(dòng)速度和CCParallaxNode的比率。假設(shè)CCParallaxNode是以每秒10像素移動(dòng)的,如果設(shè)置的ratio(1,1),那么bgSprite1bgSprite2X軸方向的速度也是每秒10像素,Y軸方向的速度也是每秒10像素。如果需要飛行速度加快,則可以將ratio設(shè)置為(1,2),讀者可以自行設(shè)置來(lái)測(cè)試背景圖片移動(dòng)的速度。在兩個(gè)背景圖片精靈上面都調(diào)用了setAliasTexParameters方法,用于解決拼接的地圖在連接滾動(dòng)時(shí)容易形成黑色縫隙的問(wèn)題。同時(shí),在設(shè)置positionOffset時(shí),在第2張背景圖與第1張背景圖拼接處減去1個(gè)像素,可以消除地圖拼接的縫隙。

接下來(lái)是添加連續(xù)滾動(dòng)背景的代碼。這里創(chuàng)建了一個(gè)隱形的飛機(jī)精靈,因?yàn)橄胍獙?shí)現(xiàn)背景的連續(xù)滾動(dòng),需要背景能夠跟隨一個(gè)不斷向上前進(jìn)的CCNode才會(huì)產(chǎn)生連續(xù)向下滾動(dòng)的效果。讓隱形的飛機(jī)精靈執(zhí)行一個(gè)moveBy動(dòng)作,在一定的時(shí)間范圍內(nèi)運(yùn)行一定的距離,而backgroundNode則執(zhí)行一個(gè)CCFollow跟隨動(dòng)作,跟隨隱形飛機(jī)移動(dòng),從而達(dá)到背景滾動(dòng)的效果。

這里還需要一個(gè)算法來(lái)計(jì)算backgroundNode的坐標(biāo)位置。讀者可以在配套光盤的Resource目錄下找到兩個(gè)預(yù)先制作好的CCParallaxNode的擴(kuò)展類:CCParallaxNode-Extras.hCCParallaxNode-Extras.m,將這兩個(gè)文件添加到項(xiàng)目的“AirfightGame”組中。

瘋狂ios講義之瘋狂打飛機(jī)(2)


打開(kāi)HelloWorldLayer.m文件,在私有分類中添加一個(gè)更新背景圖片滾動(dòng)的方法,示例代碼如下:

-(void) updateBackground:(ccTime)delay;

下面是該方法的具體實(shí)現(xiàn),實(shí)現(xiàn)代碼如下(程序清單同上)。

-(void) updateBackground:(ccTime)delay{
    CCSprite *sprite;
    int index = 0;
    CCARRAY_FOREACH([backgroundNode children],sprite){
    CGPoint pt = [backgroundNode convertToWorldSpace:sprite.position];
        if (pt.y <= -sprite.contentSize.height) {
            // sprite.contentSize.height表示精靈的高度,即背景圖片的高度
            [backgroundNode incrementOffset:ccp(0, (sprite.contentSize.height - 1) *
2.0f) forChild:sprite];
        }
        index++;
    }
}

updateBackground的作用是循環(huán)遍歷backgroundNode中的背景圖片精靈,即時(shí)修改背景圖片精靈的坐標(biāo)位置。

找到onEnter方法,在最后添加游戲的主循環(huán)代碼,實(shí)現(xiàn)代碼如下。

// ⑥游戲主循環(huán),每幀都調(diào)用的更新方法
// 這樣以默認(rèn)cocos2d的刷新頻率1/60.0s調(diào)用(void)update:(ccTime)delta一次
 [self scheduleUpdate];

這個(gè)方法是游戲的主循環(huán)。任何游戲都包括一個(gè)游戲主循環(huán),用來(lái)更新游戲的狀態(tài)、玩家和敵人的數(shù)量、碰撞處理的邏輯等。

定義一個(gè)update方法,調(diào)用更新背景圖片滾動(dòng)的方法,實(shí)現(xiàn)代碼如下(程序清單同上)。

-(void) update:(ccTime)delta{
    [self updateBackground:delta];
}

再次編譯并運(yùn)行游戲,可以看到一個(gè)連續(xù)滾動(dòng)的游戲背景效果。

 ————本文節(jié)選自《瘋狂ios講義(下)》   瘋狂ios講義之瘋狂打飛機(jī)(2)


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI