日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

ios游戏开发 Sprite Kit教程:初学者 3

發(fā)布時(shí)間:2023/12/10 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ios游戏开发 Sprite Kit教程:初学者 3 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

注:本文譯自Sprite Kit Tutorial for Beginners

目錄

  • Sprite Kit的優(yōu)點(diǎn)和缺點(diǎn)
  • Sprite Kit vs Cocos2D-iPhone vs Cocos2D-X vs Unity
  • Hello, Sprite Kit!
  • 橫屏顯示
  • 移動(dòng)怪獸
  • 發(fā)射炮彈
  • 碰撞檢測(cè)和物理特性: 概述
  • 碰撞檢測(cè)和物理特性: 實(shí)現(xiàn)
  • 收尾
  • 何去何從?

碰撞檢測(cè)和物理特性: 概述

至此我們已經(jīng)可以讓炮彈任意的發(fā)射了——現(xiàn)在我們要讓忍者利用炮彈來(lái)消滅這些怪物。下面就添加一些代碼來(lái)給炮彈與怪物相交做檢測(cè)。

Sprite Kit內(nèi)置了一個(gè)物理引擎,這非常的棒!該物理引擎不僅可以模擬現(xiàn)實(shí)運(yùn)動(dòng),還能進(jìn)行碰撞檢測(cè)。

下面我們就在游戲中使用Sprite Kit的物理引擎來(lái)檢測(cè)炮彈與怪物的碰撞。首先,我們來(lái)看看需要做些神馬事情:

  • 物理世界的配置。物理世界是一個(gè)模擬的空間,用來(lái)進(jìn)行物理計(jì)算。默認(rèn)情況下,在場(chǎng)景(scene)中已經(jīng)創(chuàng)建好了一個(gè),我們可以對(duì)其做一些屬性配置,例如重力感應(yīng)。
  • 為精靈(sprite)創(chuàng)建對(duì)應(yīng)的物體(physics bodies)。在Sprite Kit中,為了碰撞檢測(cè),我們可以為每個(gè)精靈創(chuàng)建一個(gè)相應(yīng)的形狀,并設(shè)置一些屬性,這就稱為物體(physics body)。注意:圖文的形狀不一定跟精靈的外形一模一樣。一般情況,這個(gè)形狀都是簡(jiǎn)單的、大概的(而不用精確到像素級(jí)別)——畢竟這已經(jīng)足以夠大多數(shù)游戲使用了。
  • 將精靈分類。在物體(physics body)上可以設(shè)置的一個(gè)屬性是category,該屬性是一個(gè)位掩碼(bitmask)。通過(guò)該屬性可以將精靈分類。在本文的游戲中,有兩個(gè)類別——一類是炮彈,另一類則是怪物。設(shè)置之后,當(dāng)兩種物體相互碰撞時(shí),就可以很容易的通過(guò)類別對(duì)精靈做出相應(yīng)的處理。
  • 設(shè)置一個(gè)contact(觸點(diǎn)) delegate。還記得上面提到的物理世界嗎?我們可以在物理世界上設(shè)置一個(gè)contact delegate,通過(guò)該delegate,當(dāng)兩個(gè)物體碰撞時(shí),可以收到通知。收到通知后,我們可以通過(guò)代碼檢查物體的類別,如果是怪物和炮彈,那么就做出相應(yīng)的動(dòng)作!

上面大致介紹了一下游戲策略,下面就來(lái)看看如何實(shí)現(xiàn)!

碰撞檢測(cè)和物理特性: 實(shí)現(xiàn)

首先在MyScene.m文件頂部添加如下兩個(gè)常量:

1 2 static const uint32_t projectileCategory = 0x1 << 0; static const uint32_t monsterCategory = 0x1 << 1;

上面設(shè)置了兩個(gè)類別,記住需要用位(bit)的方式表達(dá)——一個(gè)用于炮彈,另一個(gè)則是怪物。

注意:看到上面的語(yǔ)法你可能感到奇怪。在Sprite Kit中category是一個(gè)32位整數(shù),當(dāng)做一個(gè)位掩碼(bitmask)。這種表達(dá)方法比較奇特:在一個(gè)32位整數(shù)中的每一位表示一種類別(因此最多也就只能有32類)。在這里,第一位表示炮彈,下一位表示怪獸。

接著,在initWithSize中,將下面的代碼添加到位置:添加player到場(chǎng)景涉及代碼的后面。

1 2 self.physicsWorld.gravity = CGVectorMake(0,0); self.physicsWorld.contactDelegate = self;

上面的代碼將物理世界的重力感應(yīng)設(shè)置為0,并將場(chǎng)景設(shè)置位物理世界的代理(當(dāng)有兩個(gè)物體碰撞時(shí),會(huì)受到通知)。

在addMonster方法中,將如下代碼添加創(chuàng)建怪獸相關(guān)代碼后面:

1 2 3 4 5 monster.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:monster.size]; // 1 monster.physicsBody.dynamic = YES; // 2 monster.physicsBody.categoryBitMask = monsterCategory; // 3 monster.physicsBody.contactTestBitMask = projectileCategory; // 4 monster.physicsBody.collisionBitMask = 0; // 5

來(lái)看看上面代碼意思:

  • 為怪獸創(chuàng)建一個(gè)對(duì)應(yīng)的物體。此處,物體被定義為一個(gè)與怪獸相同尺寸的矩形(這樣與怪獸形狀比較接近)。
  • 將怪獸設(shè)置位dynamic。這意味著物理引擎將不再控制這個(gè)怪獸的運(yùn)動(dòng)——我們自己已經(jīng)寫好相關(guān)運(yùn)動(dòng)的代碼了。
  • 將categoryBitMask設(shè)置為之前定義好的monsterCategory。
  • contactTestBitMask表示與什么類型對(duì)象碰撞時(shí),應(yīng)該通知contact代理。在這里選擇炮彈類型。
  • collisionBitMask表示物理引擎需要處理的碰撞事件。在此處我們不希望炮彈和怪物被相互彈開——所以再次將其設(shè)置為0。
  • 接著在touchesEnded:withEvent:方法中設(shè)置炮彈位置的代碼后面添加如下代碼。

    1 2 3 4 5 6 projectile.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:projectile.size.width/2]; projectile.physicsBody.dynamic = YES; projectile.physicsBody.categoryBitMask = projectileCategory; projectile.physicsBody.contactTestBitMask = monsterCategory; projectile.physicsBody.collisionBitMask = 0; projectile.physicsBody.usesPreciseCollisionDetection = YES;

    在上面的代碼中跟之前的類似,只不過(guò)有些不同,我們來(lái)看看: 1. 為了更好的效果,炮彈的形狀是圓形的。 2.?usesPreciseCollisionDetection屬性設(shè)置為YES。這對(duì)于快速移動(dòng)的物體非常重要(例如炮彈),如果不這樣設(shè)置的話,有可能快速移動(dòng)的兩個(gè)物體會(huì)直接相互穿過(guò)去,而不會(huì)檢測(cè)到碰撞的發(fā)生。

    接著,添加如下方法,當(dāng)炮彈與怪物發(fā)生碰撞時(shí),會(huì)被調(diào)用。注意這個(gè)方法是不會(huì)被自動(dòng)調(diào)用,稍后會(huì)看到我們?nèi)绾握{(diào)用它。

    1 2 3 4 5 - (void)projectile:(SKSpriteNode *)projectile didCollideWithMonster:(SKSpriteNode *)monster { NSLog(@"Hit"); [projectile removeFromParent]; [monster removeFromParent]; }

    當(dāng)怪物和炮彈發(fā)生碰撞,上面的代碼會(huì)將他們從場(chǎng)景中移除。很簡(jiǎn)單吧!

    下面該實(shí)現(xiàn)contact delegate方法了。將如下方法添加到文件中:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 - (void)didBeginContact:(SKPhysicsContact *)contact { // 1 SKPhysicsBody *firstBody, *secondBody; if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) { firstBody = contact.bodyA; secondBody = contact.bodyB; } else { firstBody = contact.bodyB; secondBody = contact.bodyA; } // 2 if ((firstBody.categoryBitMask & projectileCategory) != 0 && (secondBody.categoryBitMask & monsterCategory) != 0) { [self projectile:(SKSpriteNode *) firstBody.node didCollideWithMonster:(SKSpriteNode *) secondBody.node]; } }

    還記得之前給物理世界設(shè)置的contactDelegate嗎?當(dāng)兩個(gè)物體發(fā)生碰撞之后,就會(huì)調(diào)用上面的方法。

    在上面的方法中,可以分為兩部分來(lái)理解:

  • 該方法會(huì)傳遞給你發(fā)生碰撞的兩個(gè)物體,但是并不一定符合特定的順序(如炮彈在前,或者炮彈在后)。所以這里的代碼是通過(guò)物體的category bit mask來(lái)對(duì)其進(jìn)行排序,以便后續(xù)做出正確的判斷。注意,這里的代碼來(lái)自蘋果提供的Adventure示例。
  • 最后,檢測(cè)一下這兩個(gè)碰撞的物體是否就是炮彈和怪物,如果是的話就調(diào)用之前的方法。
  • 最后一步,為了編譯器沒有警告,確保private interface 中添加一下SKPhysicsContactDelegate:

    1 @interface MyScene () <SKPhysicsContactDelegate>

    現(xiàn)在編譯并運(yùn)行程序,可以發(fā)現(xiàn),當(dāng)炮彈與怪物接觸時(shí),他們就會(huì)消失!

    收尾

    現(xiàn)在,本文的游戲快完成了。接下來(lái)我們就來(lái)為游戲添加音效和音樂(lè),以及一些簡(jiǎn)單的游戲邏輯吧。

    蘋果提供的Sprite Kit里面并沒有音頻引擎(Cocos2D中是有的),不過(guò)我們可以通過(guò)action來(lái)播放音效,并且可以使用AVFoundation播放后臺(tái)音樂(lè)。

    在工程中我已經(jīng)準(zhǔn)備好了一些音效和很酷的后臺(tái)音樂(lè),在本文開頭已經(jīng)將resources添加到工程中了,現(xiàn)在只需要播放它們即可!

    首先在ViewController.m文件頂部添加如下import:

    1 @import AVFoundation;

    上面的語(yǔ)法是iOS 7中新的modules功能 —— 只需要使用新的關(guān)鍵字@import,就可以框架的頭文件和庫(kù)文件添加到工程中,這功能非常方便。要了解更多相關(guān)內(nèi)容,請(qǐng)看到iOS 7 by Tutorials中的第十章內(nèi)容中的:What’s New with Objective-C and Foundation。

    接著添加一個(gè)新的屬性和private interface:

    1 2 3 @interface ViewController () @property (nonatomic) AVAudioPlayer * backgroundMusicPlayer; @end

    接著將下面的代碼添加到viewWillLayoutSubviews方法中(在[super viewWillLayoutSubviews]后面):

    1 2 3 4 5 6 NSError *error; NSURL * backgroundMusicURL = [[NSBundle mainBundle] URLForResource:@"background-music-aac" withExtension:@"caf"]; self.backgroundMusicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:backgroundMusicURL error:&error]; self.backgroundMusicPlayer.numberOfLoops = -1; [self.backgroundMusicPlayer prepareToPlay]; [self.backgroundMusicPlayer play];

    上面的代碼會(huì)開始無(wú)限循環(huán)的播放后臺(tái)音樂(lè)。

    下面我們來(lái)看看如何處理音效。切換到MyScene.m文件中,并將下面這行代碼添加到touchesEnded:withEvent:方法的頂部:

    1 [self runAction:[SKAction playSoundFileNamed:@"pew-pew-lei.caf" waitForCompletion:NO]];

    如上,一行代碼就可以播放音效了,很簡(jiǎn)單吧!

    下面,我們創(chuàng)建一個(gè)新的創(chuàng)建和layer,用來(lái)顯示你贏了(You Win)或你輸了(You Lose)。用模板iOS\Cocoa Touch\Objective-C class創(chuàng)建一個(gè)新的文件,將其命名為GameOverScene,并讓其繼承自SKScene,然后點(diǎn)擊Next和Create。

    接著用如下代碼替換GameOverScene.h中的內(nèi)容:

    1 2 3 4 5 6 7 #import <SpriteKit/SpriteKit.h> @interface GameOverScene : SKScene -(id)initWithSize:(CGSize)size won:(BOOL)won; @end

    在上面的代碼中導(dǎo)入了Sprite Kit頭文件,并聲明了一個(gè)特定的初始化方法,該方法的第一個(gè)參數(shù)用來(lái)定位顯示的位置,第二個(gè)參數(shù)won用來(lái)判斷用戶是否贏了。

    接著用下面的代碼替換GameOverLayer.m中的內(nèi)容:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #import "GameOverScene.h" #import "MyScene.h" @implementation GameOverScene -(id)initWithSize:(CGSize)size won:(BOOL)won { if (self = [super initWithSize:size]) { // 1 self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0]; // 2 NSString * message; if (won) { message = @"You Won!"; } else { message = @"You Lose :["; } // 3 SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"]; label.text = message; label.fontSize = 40; label.fontColor = [SKColor blackColor]; label.position = CGPointMake(self.size.width/2, self.size.height/2); [self addChild:label]; // 4 [self runAction: [SKAction sequence:@[ [SKAction waitForDuration:3.0], [SKAction runBlock:^{ // 5 SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5]; SKScene * myScene = [[MyScene alloc] initWithSize:self.size]; [self.view presentScene:myScene transition: reveal]; }] ]] ]; } return self; } @end

    上面的代碼可以分為4部分內(nèi)容,我們來(lái)分別看看:

  • 將背景色設(shè)置為白色(與主場(chǎng)景一樣顏色)。
  • 根據(jù)won參數(shù),將信息設(shè)置為”You Won”或”You Lose”。
  • 這里的代碼是利用Sprite Kit將一個(gè)文本標(biāo)簽顯示到屏幕中。如代碼所示,只需要選擇一個(gè)字體,并設(shè)置少量的參數(shù)即可,也非常簡(jiǎn)單。
  • 設(shè)置并運(yùn)行有個(gè)有兩個(gè)action的sequence。為了看起來(lái)方便,此處我將它們放到一塊(而不是為每個(gè)action創(chuàng)建單獨(dú)的一個(gè)變量)。首先是等待3秒,然后是利用runBlockaction來(lái)運(yùn)行一些代碼。
  • 演示了在Sprite Kit中如何過(guò)渡到新的場(chǎng)景。首先可以選擇任意的一種不同的動(dòng)畫過(guò)渡效果,用于場(chǎng)景的顯示,在這里選擇了翻轉(zhuǎn)效果(持續(xù)0.5秒)。然后是創(chuàng)建一個(gè)想要顯示的場(chǎng)景,接著使用self.view的方法presentScene:transition:來(lái)顯示出場(chǎng)景。
  • OK,萬(wàn)事俱備,只欠東風(fēng)了!現(xiàn)在只需要在主場(chǎng)景中,適當(dāng)?shù)那闆r下加載game over scene就可以了。

    首先,在MyScene.m中導(dǎo)入新的場(chǎng)景:

    1 #import "GameOverScene.h"

    然后,在addMonster中,用下面的代碼替換最后一行在怪物上運(yùn)行action的代碼:

    1 2 3 4 5 6 SKAction * loseAction = [SKAction runBlock:^{ SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5]; SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO]; [self.view presentScene:gameOverScene transition: reveal]; }]; [monster runAction:[SKAction sequence:@[actionMove, loseAction, actionMoveDone]]];

    上面創(chuàng)建了一個(gè)”lose action”,當(dāng)怪物離開屏幕時(shí),顯示game over場(chǎng)景。

    在這里為什么loseAction要在actionMoveDone之前運(yùn)行呢? 原因在于如果將一個(gè)精靈從場(chǎng)景中移除了,那么它就不在處于場(chǎng)景的層次結(jié)構(gòu)中了,也就不會(huì)有action了。所以需要過(guò)渡到lose場(chǎng)景之后,才能將精靈移除。不過(guò),實(shí)際上actionMoveDone永遠(yuǎn)都不會(huì)被調(diào)用——因?yàn)榇藭r(shí)已經(jīng)過(guò)渡到新的場(chǎng)景中了,留在這里就是為了達(dá)到教學(xué)的目的。

    現(xiàn)在,需要處理一下贏了的情況。在private interface中添加一個(gè)新的屬性:

    1 @property (nonatomic) int monstersDestroyed;

    然后將如下代碼添加到projectile:didCollideWithMonster:的底部:

    1 2 3 4 5 6 self.monstersDestroyed++; if (self.monstersDestroyed > 30) { SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5]; SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:YES]; [self.view presentScene:gameOverScene transition: reveal]; }

    編譯并運(yùn)行程序,嘗試一下贏了和輸了會(huì)看到的畫面!

    何去何從?

    至此Sprite Kit教程:初學(xué)者結(jié)束!這里可以下到完整的代碼。

    希望本文能幫助你學(xué)習(xí)Sprite Kit,并寫出你自己的游戲!

    如果你希望學(xué)習(xí)更多相關(guān)Sprite Kit內(nèi)容,可以看看這本書:iOS Games by Tutorials。本書會(huì)告訴你需要知道的內(nèi)容——從物理,到tile map,以及特定的系統(tǒng),甚至是制作自己的關(guān)卡編輯器。

    ……Sprite Kit教程:初學(xué)者 3 結(jié)束……

    總結(jié)

    以上是生活随笔為你收集整理的ios游戏开发 Sprite Kit教程:初学者 3的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。