1. 程式人生 > >GamePlayKit的ECS“實體-元件-系統”

GamePlayKit的ECS“實體-元件-系統”

如有侵犯,請來信[email protected]

QQ截圖20160229095915.png

蘋果去年釋出了GameplayKit的程式碼框架,為遊戲開發者提供了很多超級實用的API及工具,來提升遊戲開發者的效率,使得製作遊戲能更加聚焦在遊戲本身-也就是遊戲性的策劃和創意上了。

業餘時間會用Spritekit做些小遊戲demo,GameplayKit出來後感覺給了極大的方便,我就藉由蘋果提供的Maze的Sample程式碼,來跟大家介紹下GameplayKit提供的新功能,希望大家能夠喜歡!

一、樸素的遊戲程式設計的陷阱

之前小武並不是做遊戲開發出身的,所以並沒有學習很多遊戲開發裡面已經成熟的演算法或者程式設計模式來提升開發效率。僅僅憑藉愛好和隨性的編寫,完成遊戲程式碼(還真是隨便啦)。

1.需求描述

比如小武以前曾經制作過一款類似“合金裝備”的逃脫類遊戲:

(1)戰士需要躲避敵人的監視,逃到制定的出口。

(2)敵人巡邏有規定路線,敵人的能力也有些變化。

(2)戰士能夠利用各種道具,來完成逃離。

2.樸素的程式設計

樸素的程式設計設計(其實就是不過腦子,嘿嘿!):

(1)對“戰士”,和“敵人”做了一個公共的類“人”作為祖先,然後“戰士”和“敵人”類分別繼承自“人”,根據各自需要擴充套件私有部分。

(2)其它操作、移動、AI等都在各自私有類中完成。

(3)後續需求增加了,我想做更多型別的“敵人”,不同“敵人”的能力不盡相同。一開始,將相同部分的能力,放到一個“敵人”的公共類中,所有“敵人”都繼承自這個公共類。後來,隨著“敵人”型別的不同,可以有很多種能力搭配。“敵人”公共類的程式碼就越來越多,類也越來越大了。

(4)有時候,同樣的能力也想為“戰士”提供,要在“戰士”和“敵人”類裡重複Copy很多程式碼。不管怎麼樣,隨著遊戲越來越複雜,裡面重複的程式碼也有可能越來越多。

3.具體分析

(1)一開始“戰士”和“敵人”繼承自“人”,“人”提供基本的移動能力和精靈(負責實體影象);“戰士”和“敵人”分別有隱藏,跑動和偵查,射擊等功能。

如下圖所示:

QQ截圖20160229100045.png

最初的類繼承圖

(2)現在,“敵人”的種類加了3種,分別具有狙擊,透視,噴火這些能力的組合。而且,戰士升級了,需要有射擊能力了。此時,只能將公共的狙擊,透視和噴火能力,提升到“敵人”的公共類;而射擊能力,要提到“人”這個公共類。

如下圖所示:

QQ截圖20160229100132.png

需求變化後的類繼承圖

因為不是專職做遊戲,僅僅是業餘時間玩一下,所以寫個小Demo後,也就沒有繼續開發,繼續深究下去(其實是實在寫不下去了,擴充套件性和可維護性太差了!)。

小武有一顆積極向好的心,但是懶癌重度,放著吧~~!

二、GameplayKit的“實體-元件-系統”

直到蘋果推出了GameplayKit框架,我又持續對遊戲開發有點興致。開始學習後,發現遊戲開發裡面,早就有很多事實上的開發模式和方法了。其中“系統-實體-元件”是比較好的解決以上問題的方法。(因為小武水平有限,且比較懶,惡意吐槽傷害作者玻璃心的。。。。。也懶得理你們!)

上面小武所做的那個遊戲Demo,實際上是一種面向物件的繼承(Inheritance)體系,按照這個體系組織遊戲程式碼會造成公共祖先類巨大無比,子孫類也默默繼承了很多無用的程式碼,程式碼明顯有“壞味道”。

實際上,有很多能力是可以抽象出來的,同時給“戰士”和不同型別的“敵人”使用,比如渲染,移動,AI,特殊技能等。這些功能通過不同元件的組合,就構成了戰士和不同型別敵人。這是一種組合(Composite)體系。也就是下面需要介紹的ECS模式了。

1.“實體-元件-系統”:ECS(Entity,Component,System)

ECS(Entity,Component,System)即“實體-元件-系統”。實體,是可以容納很多元件的容器。元件代表一種功能和行為,不同的元件代表不同的功能。實體可以根據自己的需求來加入相應的元件。

比如上面的那個遊戲,我們將遊戲角色的移動,精靈,隱藏,跑動,偵查,設計,狙擊,透視,跑步等都作為元件類,每一個元件都描述了一個實體某些屬性特徵。我們的實體根據自己的實際需要,來組合這些元件,讓對應的實體獲得元件所代表的功能。

現在實體“戰士” “敵人1”“敵人2”“敵人3”“敵人4”實體與功能元件之間的對應關係如下圖所示:

QQ截圖20160229100217.png

ECS模式下游戲物件管理方式

從繼承(Inheritance)體系到組合(Composite)體系好處顯而易見:

(1)方便通過聚合多種元件,構建複雜的新實體。

(2)不同的實體,通過聚合不同種類的元件來實現。

(3)不必重複寫元件,元件可以複用,也易於擴充套件。

(4)實體可以實現動態新增元件,以動態獲得或者刪除某些功能。

2.遊戲執行的發動機

我們需要將“戰士”“敵人”這些實體放入到遊戲中執行,遊戲需要驅動這些實體的元件發揮功能。我們如何驅動遊戲執行呢?我來跟大家來八一八。

遊戲引擎(如SpriteKit和SceneKit,也包括客戶定製的引擎及直接使用Metal或者OpenGL)在一個稱為“更新/渲染”迴圈裡,執行遊戲有關的程式碼邏輯。這個迴圈貫穿遊戲的生命週期,按字面意思分為更新(Update)階段和渲染(Render)階段。在更新階段,與遊戲邏輯相關所有的狀態更新,數值計算,操作指令,執行序列計算,AI處理,動畫排程等都在該階段完成。在渲染階段,遊戲引擎部分進行自動處理,主要處理動畫渲染和物理引擎的執行,基於當前狀態渲染畫出所有遊戲的場景。通常,遊戲引擎的設計,是讓遊戲開發者完成更新階段的所有邏輯,然後引擎負責遊戲渲染階段的所有工作。蘋果的SpriteKit和SceneKit就是這樣設計的,從蘋果提供的SpriteKit遊戲引擎的執行Loop圖中可以略窺一二。

具體用SpriteKit引擎來驗證下上面的描述。遊戲時看到的每一幀畫面,展示在我們面前時,遊戲引擎都會經歷下面這個Loop圖所示的處理:

QQ截圖20160229100251.png

SpriteKit的生命週期

(1)每一幀(Frame)在SKScene裡會呼叫update:來進行更新操作,遊戲開發者在這裡放入所有的遊戲邏輯層面的程式碼。

(2)後面的Action,Physics,Render階段分別負責Action執行,物理引擎檢測處理,和遊戲影象的繪製渲染處理,這些工作都是交由SpriteKit來進行。

驅動遊戲執行的動力:更新階段,開發者在update裡面計算出所有遊戲邏輯和遊戲狀態;渲染階段,物理檢測,影象渲染由遊戲引擎完成。

3.GameplayKit裡的ECS執行方式

因此,驅動實體和元件在遊戲裡面執行可以放在更新階段,在SpriteKit引擎裡的update方法裡。GameplayKit提供了GKEntity類、GKComponent類及GKComponetSystem類來實現ECS模式。GKEntity提供介面新增GKComponent元件,並管理這些元件(增,刪,查操作)。GKComponentSystem也能對GKComponent提供同樣的管理操作。

遊戲執行時,每一次呼叫update的更新操作時(spriteKit的update:操作和senceKit的renderer:updateAtTime:方法),呼叫遊戲實體的更新方法,實體會將更新訊息分發給元件(GKComponent),元件執行updateWithDeltaTime來驅動元件執行。

GameplayKit提供了兩種分發策略:

(1)實體更新:如果一個遊戲僅有很少的遊戲實體,遍歷所有活動的實體,執行實體(GKEntity)的updateWithDeltaTime方法。實體(GKEntity)物件會將updateWithDeltaTime訊息轉發給該實體的所有元件(GKComponent),驅動元件執行updateWithDeltaTime方法。

(2)元件更新:在一個更加複雜的遊戲裡面,不需要跟蹤所有實體和元件對應關係,同類型元件能按順序獨立更新更加有用。為了滿足此種情況,可以建立GKComponetSystem對像,GKComponetSystem管理一具體型別的元件,當每次遊戲更新的時候,呼叫GKComponetSystem的updateWithDeltaTime的方法,系統(GKComponetSystem)物件會將updateWithDeltaTime訊息轉發給該系統的所有元件(GKComponent),驅動元件執行updateWithDeltaTime。

在方式(2)裡面,GKComponetSystem系統(System)出現了,它可以被認為是管理同一類元件的容器,並驅動它更新所有該型別的更新操作(Update)。

綜合以上說明,就是ECS模式。

三、Maze遊戲程式碼評鑑

Ok,我們回到正題,蘋果為我們更好的進入蘋果開發這個大坑,提供各種便利。程式碼的Sample是個非常好的手段。Maze遊戲是一個類似吃豆人的簡化版,只是這裡沒有吃豆豆,就是一個菱形與四個方形敵人的捕獵和反捕獵的迴圈。Maze遊戲程式碼下載地址

1.Maze遊戲的需求分析

Maze遊戲的實體很少,就是player(菱形)和enemies(四個方塊)。分析下它們的需求:

(1)player和enemies都需要在遊戲中顯示,很顯然,它們需要顯示渲染的元件。

(2)player需要受到控制,在Maze迷宮裡面運動。它需要一個控制組件。

(3)enemies的控制需要計算機來給,因此要一個元件來給出enemies的狀態。

(4)enemies需要一個系統物件來管理狀態的更新。

所以,我們現在至少需要:

(1)2個實體,player(菱形)和enemies(四個方塊)。

(2)3個元件,負責渲染的元件SpriteComponent,負責player控制的。PlayerControlComponent,負責enemies的AI的IntelligenceComponent。

(3)1個系統,負責AI即IntelligenceComponent的控制。

如下圖所示意:

QQ截圖20160229100425.png

Maze遊戲ECS設計架構

2,程式碼實現

(1)實體entity實現:程式碼裡面,實體部分因為僅僅是個容器,所以比較簡單,直接繼承了GKEntity。在Maze遊戲裡面,每個實體其實在迷宮(Maze)裡面移動,都會有位置資訊,因此,在公共的AAPLEntity類中,加入gridPosition資訊(此資訊為迷宮座標值,並非SKScence裡面的sprite位置)。

1 2 3 4 5 6 7 @import GameplayKit; @interface AAPLEntity : GKEntity @property vector_int2 gridPosition; @end

(2)元件component實現:

a.元件都是繼承的GKComponent物件,該物件僅提供了誰持有該元件的變數entity和系統System物件。

b.實現更新階段,呼叫的updateWithDeltaTime方法以及其他Helper方法。

Sprite元件:繼承GKComponent,相關變數和方法負責持有該元件實體的影象表現和計算控制運動表現兩部分。Sprite部分的渲染和影象展示方法可查閱我之前寫的相關的SpriteKit引擎教程,學習使用。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @interface AAPLSpriteComponent : GKComponent @property AAPLSpriteNode *sprite; ... #pragma mark - Appearance // 重生時候心跳動畫 @property (nonatomic) BOOL pulseEffectEnabled; // 捕獵狀態外在 - (void)useNormalAppearance; ... #pragma mark - Movement // 移動相關方法 @property (nonatomic) vector_int2 nextGridPosition; - (void)followPath:(NSArray *)path completion:(void(^)(void))completionHandler; @end

 PlayerControl元件:實現play的控制邏輯,在更新階段,通過實體Entity執行updateWithDeltaTime方法來實現對Player實體的控制的計算,這裡可以用手勢(Mobile系統),也可以用鍵盤(iMac系統)來確定移動的方向,PlayerControl元件來完成實際控制操作。

在Player實體的控制移動過程中,實際上也要呼叫Sprite元件。Sprite元件控制實體在遊戲場景中的move渲染,即運動表現部分。

所以這是元件間配合,PlayerControl元件,僅負責處理告訴Player實體該怎麼移動,具體移動渲染表現,還是交給Sprite元件來負責。其實執行示意圖如下所示:

QQ截圖20160229100541.png

PlayerControl元件處理邏輯

Enemies的AI元件:通過狀態機來實現enemies實體狀態的遷移。狀態機在後面的系列文章裡面會具體描述,這裡僅理解為控制敵人方塊行為的演算法即可。狀態機初始化程式碼如下所示:

1 2 3 4 5 6 7 8 9 10 // 初始化enemies的四種不同狀態  AAPLEnemyChaseState *chase = [[AAPLEnemyChaseState alloc] initWithGame:game entity:enemy]; AAPLEnemyFleeState *flee = [[AAPLEnemyFleeState alloc] initWithGame:game entity:enemy]; AAPLEnemyDefeatedState *defeated = [[AAPLEnemyDefeatedState alloc] initWithGame:game entity:enemy]; defeated.respawnPosition = origin; AAPLEnemyRespawnState *respawn = [[AAPLEnemyRespawnState alloc] initWithGame:game entity:enemy]; // 初始化狀態機,並進入chase狀態 _stateMachine = [GKStateMachine stateMachineWithStates:@[chase, flee, defeated, respawn]]; [_stateMachine enterState:[AAPLEnemyChaseState class]];

enemies的AI元件需要加入到intelligenceSystem的系統進行管理,因為所有的AI都需要在更新階段進行執行,使用System管理,更加方便。系統的初始化程式碼如下所示(在遊戲初始化過程程式碼裡):

相關推薦

A-Frame簡明教程之實體元件系統

本文為A-Frame簡明教程系列文章的第三篇,大家可以到專題裡瞭解更多。 實體元件系統 1. 概述 實體-元件-系統(Entity Component System, ECS)是三維遊戲中常見且理想的設計模式,A-Frame同樣採用了ECS模式。 EC

GamePlayKit的ECS“實體-元件-系統

如有侵犯,請來信[email protected] 蘋果去年釋出了GameplayKit的程式碼框架,為遊戲開發者提供了很多超級實用的API及工具,來提升遊戲開發者的效率,使得製作遊戲能更加聚焦在遊戲本身-也就是遊戲性的策劃和創意上了。 業餘時間會用

關於Unity 2018的實體元件系統(ECS)二

孫廣東  2018.5.20關於Unity 2018的實體元件系統(通用名稱ECS)二 將介紹如何在Unity上使用實體元件系統(通常稱為ECS)。 這次的內容是Unity提供的ECS API的基本用法,一個小應用程式和並行化。

Vue框架之元件系統

1,Vue元件系統之全域性元件 1.1Vue全域性元件的在例項化呼叫Vue的模板中匯入元件的名稱 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8">

談談Unity實體元件ECS與Jobs System

Unity2018版本提供了ECS和Jobs System功能,網上也有很多這方面的技術介紹,本篇部落格從Unity架構優化的角度給讀者介紹關於ECS和Jobs System的使用,結合著實際案例希望讓讀者更容易理解它們,尤其是在IT遊戲行業工作了兩年以上的開發

理解 元件-實體-系統 (ECS \CES)遊戲程式設計模型

一般來說,我們實現遊戲實體都是採用面向物件的方法進行程式設計。每一個實體都是一個物件,並且需要一個基於類的例項化系統,允許實體通過多型來擴充套件。但是,這樣的方法,往往導致系統中出現大量的類,造成類爆炸的情況出現。隨著新的實體出現,我們發現很難在類繼承圖中新增新的實體,

電商系統Broadleaf文檔翻譯(六) - 主要實體main entities

這就是 顏色 tex cep 實現 target tro 定價 間接 主要實體 原文標題:main entities 原文出處:http://www.broadleafcommerce.com/docs/core/current/broadleaf-concepts

EF基礎知識小記六(使用Code First建模自引用關系,常用於系統菜單、文件目錄等有層級之分的實體)

-1 一個數 div 基礎知識 text col 菜單 hasmany roo 日常開發中,經常會碰到一些自引用的實體,比如系統菜單、目錄實體,這類實體往往自己引用自己,所以我們必須學會使用Code First來建立這一類的模型. 以下是自引用表的數據庫關系圖: ok,下

銀行儲蓄系統的數據流程圖及實體-聯系圖

jpg 技術 logs 技術分享 http 系統 實體 數據流 .cn 數據流圖: 實體-聯系圖: 銀行儲蓄系統的數據流程圖及實體-聯系圖

系統管理模塊_崗位管理_實現CRUD功能的具體步驟並設計Role實體

xtend delet 實現 result action == b- actions asto 系統管理模塊_崗位管理_實現CRUD功能的具體步驟並設計Role實體 1,設計實體/表   設計實體 --> JavaBean --> hbm.xml -->

實體店如何增加流量 利用采寶新支付系統引流

實體店流量 采寶新支付系統 杭州采寶 現如今,我們有很多途徑找到流量,但是這些都不是精準流量,我們要從中篩選出對我們的產品感興趣,達成交易,達成復購的精準流量。我們把這種轉化的流量叫——訪問量。 哪麽要如何提高訪問了,要怎麽做? 方法很簡單,提供價

系統數據結構設計(ER模式圖、實體圖)

http 實體 畢業論文 clas img 技術分享 OS pos 模型 畢業論文系統的設計類圖 ER模型 系統數據結構設計(ER模式圖、實體圖)

kali折騰日記之實體機安裝(win10與kali雙系統

建議 解決 沒有 cef 上推 區號 等待 方法 ica 這次咱們來折騰一下實體機安裝雙系統下面就是準備工作了:首先用磁盤管理工具將你的某個盤分出一塊來,我使用的是分區助手來進行的這裏官方說的是20個G就可以安裝kali了,但我還是推薦大家盡量分大一點,畢竟以後還可以安裝一

.NET快速資訊化系統開發框架 V3.2-&gt;Web版本“產品管理”事例編輯介面新增KindEditor覆文本編輯控制元件

  KindEditor是一套開源的HTML視覺化編輯器,主要用於讓使用者在網站上獲得所見即所得編輯效果,相容IE、Firefox、Chrome、Safari、Opera等主流瀏覽器。KindEditor使用JavaScript編寫,可以無縫的於Java、.NET、PHP、ASP等程式接合。Ki

談談企業資訊系統tag標籤資料庫設計及基於多選元件bootstrap-select的實現

一、摘要 Tag標籤類似於分類,可以用於標記、區分事物,但又不同於分類,通常分類是單一所屬,而Tag往往是多個。如純淨水596ml它屬於純淨水分類,可以標記:596ml、純淨水、掃碼有獎等tag。本文討論限於企業資訊系統中的tag標籤應用,涉及2部分內容:tag標籤資料庫設計,前端頁面如

系統分層和可拔插式的元件

系統分層和可拔插式的元件 系統分層: 主要按功能來劃分,經典的三層架構 展示層(mvc架構就屬於展示層) 業務層service層 資料服務層(dao層或者mapper層) 可拔插式的元件 主要是對外提供一組介面。 然後看使用者選擇哪種介面的實現方式,比較JDBC的標準介面

風河虛擬化元件使用說明(15)—— 為Windows系統安裝VNIC驅動及共享記憶體驅動(on target)

參考Guest Guide文件"Windows VNIC Driver Overview"和"Windows Shared Memory Driver Overview" 首先將Windows 10作為GuestOS啟動:  進入WindShare網站(http://wind

風河虛擬化元件使用說明(10)—— 在目標機上配置Windows 10系統(on target)

參考Guest Guide 文件"Configuring Windows 7 for Use with Virtualization Profile for VxWorks"和"Installing Board-specific Drivers for Windows" 先以管理員模式執行命令列

風河虛擬化元件使用說明(9)—— 在目標機上安裝Windows 10系統(on target)

參考Guest Guide文件"Installing Native Windows 7 on the Target" 製作Windows 10的U盤啟動盤:      插入Windows 10 U盤啟動盤,開啟工控機,按DEL進入BIO

風河虛擬化元件使用說明(7)—— 為目標機建立檔案系統(on target)

參考Guest Guide 文件"Creating File Systems for Hard Drive Partitions"。 使用mkfs.vfat命令對將要安裝RootOS的分割槽1和GuestOS VxWorks的分割槽2進行格式化:   注意安裝RootOS