用Swift做個游戲Lecture05 —— 真實的物理世界

系列:用Swift作個游戲
作者:pmst(1345614869)
微博:PPPPPPMST

友情提示:為了方便大家快速上手項目沪编,我上傳了課時的教程至github行楞,請找到Code文件夾中->L05文件夾->FlappyBird-Start下載岭接。

倘若你覺得文章還不錯,請關(guān)注我并點擊喜歡,這是對我寫文章最大的鼓勵。

游戲的雛形已經(jīng)基本實現(xiàn)得哆,呈現(xiàn)了背景,地面持續(xù)滾動哟旗,Player上下跳竄以及源源不斷的仙人掌贩据。不過細心的你也應當發(fā)現(xiàn)有以下幾個不足:

  1. Player可以通過不斷點擊升高到屏幕外栋操。
  2. 仙人掌表示不服:你丫想穿越我就穿越,當我是透明嗎饱亮?

因此本節(jié)的任務是設(shè)置場景精靈的物理體矾芙,當課時完畢,Player一旦觸碰到仙人掌就會下落近上,不能繼續(xù)游戲剔宪。

01.設(shè)置場景內(nèi)精靈的物體形狀

暫且對游戲內(nèi)容按下不表,先談談咱們真實的世界壹无,重力加速度9.8g,非透明的物體之間碰撞會發(fā)生形變葱绒。而在Sprite Kit中的物理世界,首先我需要引出Physics Shapes —— 物體形狀斗锭,就拿人來說哈街,倘若我粗略地來形容一個人的物理體,我就會給出一個x*y*z(長寬高計算體積)的長方體拒迅,一旦外物觸碰輪廓表面骚秦,我就說兩者發(fā)生了接觸;不過若已精確角度來說璧微,形容人的物理體以其皮膚表面為輪廓勾勒出一個體積作箍,顯然這比先前的立方體來的精確太多了;當然有時候嫌麻煩前硫,指定頭部(姑且就當成一個球體吧)作為人的物理體胞得,因此除頭部外的身體都相當于是透明的,外物接觸了手屹电、腿等都不算發(fā)生接觸阶剑,只有與頭部接觸才算。

講了那么多危号,現(xiàn)在回到游戲牧愁,開始塑造真實的物理世界,首先找到didMoveToView()方法,在最上方添加一行代碼設(shè)置場景物理世界的重力為(0,0)外莲,原因是我們打算使用自定義設(shè)置的參數(shù):

override func didMoveToView(view: SKView) {
    physicsWorld.gravity = CGVector(dx: 0, dy: 0)
    //... 以下為早前內(nèi)容
}

接著咱們要說physicsBody猪半,譯為物理體。我們可以設(shè)置每個節(jié)點的物理體偷线,那樣它就可以和其他同樣設(shè)置了物理體的節(jié)點發(fā)生碰撞磨确、檢測接觸等,它有三個屬性声邦,值均為UInt32類型:

  • categoryBitMask: 表明當前body屬于哪個類別乏奥。
  • collisionBitMask: 當前物體可以與哪些類別發(fā)生碰撞。
  • contactTestBitMask:用于告知當前物體與哪些類別物理發(fā)生接觸時亥曹。

游戲中類似這種邓了,我們往往用二進制數(shù)來表示物體盏檐,譬如0b1表明是Player,0b10表明障礙物,0b100表明地面驶悟。想必編程男都不陌生吧胡野。OK,請在enum Layer:CGFLoat{}下方新增一個結(jié)構(gòu)體用于表明分類痕鳍,注意里面均為類型屬性:

struct PhysicsCategory {
  static let None: UInt32 = 0
  static let Player: UInt32 =     0b1 // 1
  static let Obstacle: UInt32 =  0b10 // 2
  static let Ground: UInt32 =   0b100 // 4
}

對于類型屬性硫豆,調(diào)用方法形如:PhysicsCategory.None,更多關(guān)于類型屬性笼呆,請參看官方文檔Type properties一節(jié)熊响。

接下來我們主要添加以下物理體到場景中:

  1. Player,這里我們將借助一個勾勒工具來繪制其物理體诗赌。
  2. 障礙物,同上汗茄。
  3. 地面,其實就是一條水平線铭若。

為啥要設(shè)置以上三個物理體呢洪碳?因為設(shè)置完物理體后,我們才能知道誰和誰發(fā)生了接觸contact叼屠,如此進行下一步計算瞳腌。至于collision咱們是不關(guān)心的,不需要設(shè)置镜雨。

設(shè)置地面的物理體

找到setupBackground()方法 在方法最下方添加如下內(nèi)容:

func setupBackground(){
    //...
    //===以上為早前內(nèi)容===
    //===以下為新增內(nèi)容===
   let lowerLeft = CGPoint(x: 0, y: playableStart)//地板表面的最左側(cè)一點
   let lowerRight = CGPoint(x: size.width, y: playableStart) //地板表面的最右側(cè)一點
   // 1
   self.physicsBody = SKPhysicsBody(edgeFromPoint: lowerLeft, toPoint: lowerRight)
   self.physicsBody?.categoryBitMask = PhysicsCategory.Ground
   self.physicsBody?.collisionBitMask = 0
   self.physicsBody?.contactTestBitMask = PhysicsCategory.Player
}

對于1中嫂侍,我們用一條平行線來實例化物理體,然后是三部曲荚坞,分別設(shè)置了其分類為Ground挑宠;不予其他任何物理發(fā)生碰撞(因為設(shè)置了0);設(shè)置了能與其發(fā)生接觸的物體有Player颓影。

設(shè)置Player的物理體

找到setupPlayer()方法 同樣新增以下內(nèi)容到方法最后:

func setupPlayer(){
   player.position = CGPointMake(size.width * 0.2, playableHeight * 0.4 + playableStart)
   player.zPosition = Layer.Player.rawValue
    // 注意我們將worldNode.addChild(player)移到了最下方各淀。
    
    //=========以下為新增內(nèi)容===========
   let offsetX = player.size.width * player.anchorPoint.x
   let offsetY = player.size.height * player.anchorPoint.y
   
   let path = CGPathCreateMutable()
   
   CGPathMoveToPoint(path, nil, 17 - offsetX, 23 - offsetY)
   CGPathAddLineToPoint(path, nil, 39 - offsetX, 22 - offsetY)
   CGPathAddLineToPoint(path, nil, 38 - offsetX, 10 - offsetY)
   CGPathAddLineToPoint(path, nil, 21 - offsetX, 0 - offsetY)
   CGPathAddLineToPoint(path, nil, 4 - offsetX, 1 - offsetY)
   CGPathAddLineToPoint(path, nil, 3 - offsetX, 15 - offsetY)
   
   CGPathCloseSubpath(path)
   
   player.physicsBody = SKPhysicsBody(polygonFromPath: path)
   player.physicsBody?.categoryBitMask = PhysicsCategory.Player
   player.physicsBody?.collisionBitMask = 0
   player.physicsBody?.contactTestBitMask = PhysicsCategory.Obstacle | PhysicsCategory.Ground
   
   worldNode.addChild(player)// hey 我現(xiàn)在在這里!2t空。揪阿×莆遥?}

我們通過繪制路徑來勾勒出Player的自定義物理體咆畏,別吃驚,我只不過借助了某些工具吴裤,地址在這里,ps:可能需要翻墻旧找。

設(shè)置仙人掌的物理體

同理我們只需要在產(chǎn)生仙人掌的實例方法中添加其物理體即可,請定位到createObstacle()->SKSpriteNode方法:

func createObstacle() -> SKSpriteNode {
  let sprite = SKSpriteNode(imageNamed: "Cactus")
  sprite.zPosition = Layer.Obstacle.rawValue
  
  //========以下為新增內(nèi)容=========
  let offsetX = sprite.size.width * sprite.anchorPoint.x
  let offsetY = sprite.size.height * sprite.anchorPoint.y

  let path = CGPathCreateMutable()

  CGPathMoveToPoint(path, nil, 3 - offsetX, 0 - offsetY)
  CGPathAddLineToPoint(path, nil, 5 - offsetX, 309 - offsetY)
  CGPathAddLineToPoint(path, nil, 16 - offsetX, 315 - offsetY)
  CGPathAddLineToPoint(path, nil, 39 - offsetX, 315 - offsetY)
  CGPathAddLineToPoint(path, nil, 51 - offsetX, 306 - offsetY)
  CGPathAddLineToPoint(path, nil, 49 - offsetX, 1 - offsetY)

  CGPathCloseSubpath(path)
  
  sprite.physicsBody = SKPhysicsBody(polygonFromPath: path)
  sprite.physicsBody?.categoryBitMask = PhysicsCategory.Obstacle
  sprite.physicsBody?.collisionBitMask = 0
  sprite.physicsBody?.contactTestBitMask = PhysicsCategory.Player
  
  return sprite
}

注意到不管是哪種方式設(shè)置物理體麦牺,我們都需要設(shè)置其分類钮蛛,碰撞掩碼以及測試接觸掩碼鞭缭,不過這里我們并不需要碰撞,所以全部設(shè)為0魏颓,即None岭辣。

最后請點擊運行,你會發(fā)現(xiàn)場景中的Player甸饱、仙人掌以及地面表層都有一層輪廓沦童。沒錯!這就是其各自的物理體叹话。我們在GameViewCOntroller中通過設(shè)置了skView.showsPhysics = true來顯示的偷遗。

下文我將更新如何處理物體與物體之間的接觸事件。 倘若覺得文章不錯驼壶,點擊喜歡或者關(guān)注我吧氏豌。.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市热凹,隨后出現(xiàn)的幾起案子泵喘,更是在濱河造成了極大的恐慌,老刑警劉巖般妙,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涣旨,死亡現(xiàn)場離奇詭異,居然都是意外死亡股冗,警方通過查閱死者的電腦和手機霹陡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來止状,“玉大人烹棉,你說我怎么就攤上這事∏影蹋” “怎么了浆洗?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長集峦。 經(jīng)常有香客問我伏社,道長,這世上最難降的妖魔是什么塔淤? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任摘昌,我火速辦了婚禮,結(jié)果婚禮上高蜂,老公的妹妹穿的比我還像新娘聪黎。我一直安慰自己,他們只是感情好备恤,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布稿饰。 她就那樣靜靜地躺著锦秒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪喉镰。 梳的紋絲不亂的頭發(fā)上旅择,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天,我揣著相機與錄音侣姆,去河邊找鬼砌左。 笑死,一個胖子當著我的面吹牛铺敌,可吹牛的內(nèi)容都是我干的汇歹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼偿凭,長吁一口氣:“原來是場噩夢啊……” “哼产弹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起弯囊,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤痰哨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后匾嘱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體斤斧,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年霎烙,在試婚紗的時候發(fā)現(xiàn)自己被綠了撬讽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡悬垃,死狀恐怖游昼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尝蠕,我是刑警寧澤烘豌,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站看彼,受9級特大地震影響廊佩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜靖榕,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一标锄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧序矩,春花似錦鸯绿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至租幕,卻和暖如春舷手,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劲绪。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工男窟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贾富。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓歉眷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親颤枪。 傳聞我的和親對象是個殘疾皇子汗捡,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容