全套源碼丨Cocos Creator 3.0 開發 io 類遊戲關鍵技術點詳解

2021-12-23 COCOS

App Store 曾經將 io 遊戲列為「值得關注的四個趨勢」之一。io 類遊戲在國內又被稱為休閒競技類遊戲、大作戰遊戲、大亂鬥遊戲等,以操作規則簡單、多人在線對抗、死後即刻復活等為特點,曾經風靡一時的《球球大作戰》、《貪吃蛇大作戰》都屬於這一類型,廣受玩家喜愛。

Cocos 引擎官方於上周正式推出一款 io 類玩法遊戲源碼《奔跑吧小仙女》。本項目源碼包裡包含了完整策劃文檔、項目源碼、美術源文件,且官方支持免費提供微信小遊戲上線源碼授權服務

遊戲中角色會自動前進,玩家需要滑動屏幕控制角色移動的方向,通過收集木板來跨域水域達到抄近路的目的。遊戲一共5人參與,最快到達終點的玩家即為勝利。

《奔跑吧小仙女》在不使用物理的基礎上進行開發。同時,我們也配置了完整的教程,包括如何啟動場景、攝像機跟隨、水面和天空球的設置、玩家與 AI 的控制,以及如何加載數據,相關配置文件等。除此之外我們還有地圖編輯器,供玩家擴展使用。

今天主要從以下四個方面對本項目進行關鍵技術點解析

遊戲場景與地圖生成

玩家控制與 AI

地圖編輯器

性能優化

《奔跑吧小仙女》設定在一個水上樂園,為這美麗的環境,我們給場景中添加了天空球和水面效果。

我們只需要簡單的圖片和簡單的模型就能實現好看的效果!

天空球由以下組成:

球模型

一張貼圖

一個旋轉動畫

 一個 builtin-unlit 無光照材質

平面模型(四方形)

噪聲貼圖(用於顯示水紋)

深度貼圖(控制水的顏色,中心到邊緣的變化)

一小段 shader 代碼

頂點偏移動畫,上下起伏:

    #if USE_WAVE
      vec3 offset;
      vec3 tangent;
      vec3 bitangent;
      gerstnerWaves(worldPos.xyz, waveVisuals.xyz, waveDirections, offset, v_normal, tangent, bitangent);
      worldPos.xyz += offset;

      #if USE_NORMAL_MAP
        v_tangent = tangent;
        v_bitangent = bitangent;
      #endif
    #endif

水基礎顏色:

// color
vec4 waterColor = shallowColor;

計算水紋:

    // caustic
    vec4 finalCausticColor = vec4(0.);
    #if USE_CAUSTIC
      float causticDepth = causticParams2.x;
      vec3 causticColor = causticParams2.yzw;

      finalCausticColor.rgb = caustic() * causticColor;
    #endif

計算深度顏色:

    #if USE_DEPTH
      float waterDepth = texture(surfaceWaterDepth, v_uv).r;
      float depth = clamp(1. - waterDepth / depthMaxDistance, 0., 1.);
      vec4 depthColor = mix(depthGradientShallow, depthGradientDeep, depth);
      waterColor = alphaBlend(depthColor, waterColor);
    #endif

最終顏色:

    // final
    vec4 finalColor = waterColor + finalFoamColor + finalCausticColor;

地圖在設計時採用了地圖塊的方式。先預設幾個地圖塊,接著根據配置表中的地圖塊的位置縮放等信息,生成完整地圖。  

// 根據配置表信息布置地圖塊
ndItem.position = gameUtils.setStringToVec3(itemData.position);
ndItem.scale = gameUtils.setStringToVec3(itemData.scale);
ndItem.eulerAngles = new Vec3(0, Number(itemData.eulY), 0);

小仙女的跑動怎麼能少了攝影師?為了能更好的拍攝小仙女的運動,這裡設計了跟隨相機。  

只需小小的 lookAt 加上平緩的插值預算,相機跟隨如你所願! 

/**
 * 移動攝像機位置/角度 每幀運行
 * @param lerpPosNum 坐標修改的lerp參數
 * @param lerpEulNum 角度修改的lerp參數
 */
private followTarget(lerpPosNum: number, lerpEulNum: number ) {
    // 目標節點的位置
    const targetPos = this.ndTarget.getPosition();
    // 目標節點在y軸的旋轉
    const eulerY = this.ndTarget.eulerAngles.y;
    const _quat = Quat.fromEuler(new Quat(), 0, eulerY, 0);
    // 相對目標節點的位置y旋轉矩陣,用於偏移向量轉到該坐標系
    const _mat4 = Mat4.fromRT(new Mat4(), _quat, targetPos);
    // 相機位置偏移向量
    v3_pos.set(this.offsetPos);
    // 求出在目標節點坐標系的偏移向量
    v3_pos.transformMat4(_mat4);
    // 求一個插值
    v3_selfPos.lerp(v3_pos, lerpPosNum);
    // 設置相機的位置
    this.node.position = v3_selfPos;

    // 求出lookAt的目標點坐標
    v3_pos.set(targetPos.add(this.offsetLookAtPos));
    // 求一個插值
    v3_look.lerp(v3_pos, lerpEulNum);
    // 設置相機 lookAt
    this.node.lookAt(v3_look);
}

小仙女目前是在一個水平面奔跑的,所以小仙女的移動位置可以根據速度和角色朝向去控制。  

// 下落移動
this._nowSpeedY += gameConstants.ROLE_GRAVITY_JUMP * dt;
pos.y += this._nowSpeedY * dt;

// 前進移動
let speed = dt * this._speed;
const eulYAngle = eul.y * macro.RAD;
const addX = speed * Math.sin(eulYAngle);
const addZ = speed * Math.cos(eulYAngle);
pos = pos.subtract3f(addX, 0, addZ); //角色前進方向為當前朝向的反向
this.node.setPosition(pos);

因為有些路塊的形狀比較特殊,我們為小仙女和路塊添加了碰撞觸發器。可以通過設置分組與掩碼來控制觸發器的觸發。

https://docs.cocos.com/creator/3.0/manual/zh/physics/physics-group-mask.html

//只要以下條件為真就會進行檢測
//(GroupA & MaskB) && (GroupB & MaskA)
//碰撞分組/掩碼
COLLIDER_GROUP_LIST: { 
    DEFAULT: 1 << 0,
    PLAYER: 1 << 1,
    FLOOR: 1 << 2,
    AI: 1 << 3,
},
// 設置地板的 分組,掩碼
let colliderList = ndItem.getComponents(Collider)!;
for (let j = 0; j < colliderList.length; j++) {
    colliderList[j].setGroup(gameConstants.COLLIDER_GROUP_LIST.FLOOR);
    colliderList[j].setMask(gameUtils.getAiAndPlayerGroup());
}
// 設置角色分組,掩碼
const rbAi = this.node.addComponent(RigidBody);
rbAi.setGroup(gameConstants.COLLIDER_GROUP_LIST.AI);
rbAi.setMask(gameConstants.COLLIDER_GROUP_LIST.FLOOR);

小仙女是否到達終點和腳下的路面的信息都是根據觸發器的事件去記錄。

// 觸發器事件
collider.on('onTriggerEnter', this._triggerEnter, this);
collider.on('onTriggerExit', this._triggerExit, this);

_triggerEnter(event: ITriggerEvent) {
   if (ndOther.name === gameConstants.CSV_MAP_ITEM_NAME.FINISH_LINE) {
        // 到達終點
        return;
    }
    //角色與地面接觸,加入列表
    this._onFloorList.push(ndOther);
}

_triggerExit(event: ITriggerEvent) {
    if (!event.otherCollider) return;
    let ndOther = event.otherCollider.node;
    let findIndex = this._onFloorList.indexOf(ndOther);
    if (findIndex !== -1) {
        //角色離開地面,移除列表
        this._onFloorList.splice(findIndex, 1);
    }
}

當然,小仙女的主要邏輯採用的是狀態機的模式去控制和設計。  

set roleState(state: number) {
    this._roleState = state;
    // 播放對應的動作
    this._aniRole.play(gameConstants.ROLE_STATE_NAME[this._roleState]);
}

AI 小仙女大部分邏輯與玩家控制的小仙女的邏輯相通,與之不同的是,AI是讀取配置,生成一條路徑。  

移動時,根據速度計算兩個路徑點間的插值,算出最終位置。  

//通過貝塞爾路徑點xz軸移動
this._bezierNowId += dt * this._speed;
let bezierNowId = Math.floor(this._bezierNowId);

if (bezierNowId >= this._bezierList.length - 1) {
    this._isOver = true;
    // 到達終點
    return;
}

if (bezierNowId !== this._bezierlastId) {
    // 處理朝向
    this._bezierlastId = bezierNowId;
    const sub = this._bezierList[bezierNowId].clone().subtract(this._bezierList[bezierNowId + 1]);
    this._nextEul.set(0, Math.atan2(sub.x, sub.y) * macro.DEG, 0)
}

// 插值
const subIndex = this._bezierNowId - bezierNowId;
this.node.setRotationFromEuler(this._nextEul);
const nextPos = this._bezierList[bezierNowId].clone().lerp(this._bezierList[bezierNowId + 1], subIndex)
this.node.setPosition(nextPos.x, pos.y, nextPos.y);

this._checkSpeed(dt);

上面提到了地圖配置,AI 路徑配置,這些並不是憑空去配置的。

為此在 Cocos Creator 編輯器中,專門添加了一個 map.scene 場景,為策劃提供可視化的配置。 

策劃只需要在指定節點編輯地圖塊(或 AI 位置),點擊導出按鈕即可。 

程序根據節點的信息,生成對應的配置數據。  

//當前項目文件路徑
const projectPath = window.cce.project as string; 
projectPath.replace("\\", " / ");

const filePath = `${projectPath}/` + MAP_PATH;
// 一鍵引入文件操作
const fs = require('fs');
//關卡數據處理
let data = MAP_DATA_FIRST + '';
for (let i = 0; i < this.node.children.length; i++) {
    let ndItem = this.node.children[i];
    //坐標/大小/旋轉均以最多兩位小數存儲
    const pos = this._getNumberToFixed2(ndItem.getPosition());
    const scale = this._getNumberToFixed2(ndItem.getScale());
    const eulY = ndItem.eulerAngles.y;//this._getNumberToFixed2(ndItem.eulerAngles.clone());
    //生成sting型數據  數據之間以,隔開 在最後加上換行\n
    let itemData = `${i + 1},${ndName},${pos},${scale},${eulY}` + '\n';
    data += itemData;
}
// 寫文件
fs.writeFile(filePath + MAP_PREFIX + this.mapNameSave + '.csv', data, (err: Error) => {
    //...
});

// 讀文件
const path = `${projectPath}/` + MAP_PATH + MAP_PREFIX + this.mapNameLoad + '.csv';
fs.readFile(path, 'utf-8', (err: Error, data: any) => {
    //...
})

對於還不需要使用的碰撞體,並且會與多個分組發生碰撞,產生計算的模型。可先暫時關閉模型上的碰撞體,根據距離判斷模型是否需要開啟碰撞體。亦或是,節省不必要的碰撞體,使用距離計算,適用於場景中的道具類型物品。

當前項目中:

分以下幾步處理:

1、計算當前z對應的磚塊所在區間(例:當前將所有磚塊根據z軸的距離1進行劃分);

public static checkNowBrickIndex(posZ: number) {
    //對當前坐標z值進行對gameConstants.BRICK_CAN_GET_INTERVAL取餘並四捨五入取整
    return Math.abs(Math.floor(posZ / gameConstants.BRICK_CAN_GET_INTERVAL));
}

let nowRow = gameUtils.checkNowBrickIndex(pos.z);
if (!GameManager.canGetBrickList[nowRow]) {
//判斷是否不存在 不存在則需要聲明為數組
GameManager.canGetBrickList[nowRow] = [];
}
GameManager.canGetBrickList[nowRow].push(ndNowBrick);

const pos = this.node.getPosition();
let index = gameUtils.checkNowBrickIndex(pos.z)
let nowBrickList = GameManager.canGetBrickList[index];
if (!nowBrickList) return;
for (let i = nowBrickList.length - 1; i > -1; i--) {
//進一步判斷當前磚塊與主角的距離是否拾取
}

update(){
    const num = 3;  //間隔num幀執行一次方法
    //director.getTotalFrames() 獲取 director 啟動以來遊戲運行的總幀數
 if (director.getTotalFrames() % num === 0) {
      //執行相應操作
     }    
}

https://store.cocos.com/app/detail/3126

https://store.cocos.com/document/zh/

《Creator 3.x <奔跑吧小仙女> 3D源碼分析與實戰》

https://bycwedu.vipwan.cn/course/56/Creator-3-x-ben-pao-ba-mei-shao-nv-3D-yuan-ma-fen-xi-yu-shi-zhan

感謝社區大神「博毅創為」Blake 老師的激情爆肝!視頻教程共9課時,全免費,現已全部上線。

《奔跑吧小仙女》目前正在 Cocos StoreCocos 官方微店同步熱賣中,點擊【閱讀原文】即可跳轉查看詳情。

另外,8月20日中午12:00,我們將為評論區留言點讚前3名送出《奔跑吧小仙女》全套源碼~

相關焦點

  • Cocos Creator 3D 物理模塊介紹
    但物理模擬始終是模擬,在遊戲中這類需要實時交互的場景裡,需要將表現力和實時交互能力平衡。如果需要更佳的實時性能,那麼可以嘗試對物理結構簡化。0 = new Vec3(); update (deltaTime: number) { const now = performance.now() / 1000; _v3_0.x = this.a * Math.cos(now); _v3_0.z = this.b * Math.sin(now); this.node.setPosition
  • cocos creator快速集成原生微信登錄分享功能源碼分享
    wechat-quick簡介wechat-quick是基於cocos creator對原生微信登錄和分享功能的一個封裝。項目包含2部分,creator模塊和原生模塊。>3.保存登錄token方便下次快捷登錄;原生模塊是通過反射和js模塊互調。
  • CocosCreatorv1.7正式版本發布!
    Cocos Creator 全新版本,此次新增了 JSB 2.0 大幅優化原生平臺的性能、一鍵導出到 Cocos2d-x(支持 C++ 和 Lua 原生遊戲開發工作流)、支持原生平臺的功能模塊裁剪減小包體和集成數據統計等更加方便遊戲開發的亮點功能。
  • 精品教程|Cocos Creator資源熱更新
    tid=457274網絡接口文檔:http://cocos.com/docs/creator/scripting/network.html第三方模塊引用文檔:http://cocos.com/docs/creator/scripting/third-party-module.html根據這段時間開發者的反饋,我們發現開發者們已經急不可耐得想用
  • 基於 FFmpeg 的 Cocos Creator 視頻播放器
    背景騰訊開心鼠項目使用的遊戲引擎是 Cocos Creator,由於引擎提供的視頻組件實現方式問題導致視頻組件和遊戲界面分了層,從而導致了以下若干問題:核心問題就是分層問題,對於開心鼠項目帶來的最大弊端就是:一套設計,Android,iOS,Web 三端需要各自實現,開發和維護成本高,又因為平臺差異化
  • Cocos2D-X 4.0遊戲框架學習之路(三)
    在想創建新項目的地方調用終端,輸入命令cocos new PROJECT-NAME -p com.coco2dx.org -l cpp -d PROJECT-PATH 注意指令:PROJECT-NAME指項目名稱,自己擬定;PROJECT-PATH表示項目存放到的目錄地址;-l表示指定語言(cpp,lua,js),這裡是指定C++語言開發,-p 是指定工程的包名com.coco2dx.org
  • cocoscreator 2.4.x版本 drawcall優化 第一期(掌握控制drawcall數量的必要知識)
    「哪些組件支持渲染:」 因為一個drawcall是一次cpu調用圖形繪製接口命令 gpu進行圖形繪製渲染的過程,所以需要了解cocoscreator中哪些組件支持渲染,才能更好的控制drawcall** * !
  • 用 Cocos Creator 實現時間回溯
    第一次接觸到電子遊戲中的時間倒退玩法,著實被驚豔的表現震驚到了,那種掌控時間的感覺,讓人意猶未盡。可是這類遊戲並不是很多,其中有個原因就在於,時間倒退的功能會對遊戲機制的設計要求極高,程序處理也較為複雜。本文將使用 Cocos Creator 3.3,實現一個很酷的時間回溯的效果。
  • Cocos Creator 多語言組件實現
    簡介基於cocos creator 2.4.3 的一個手遊項目模板, 提供一些自定義組件以及 Demo。項目地址:https://github.com/yanjifa/game-template本次著重介紹多語言組件Demo在線查看:https://yanjifa.github.io/web-desktop/
  • 主流遊戲引擎都是用什麼語言來開發?
    1.unity 3d這是目前最火的遊戲引擎之一,像王者榮耀和仙劍六都是unity 3d開發的,這個引擎開發效率很高。這個引擎要用C#來開發。2.虛幻引擎如果說unity 3d是第一的遊戲引擎的話,那虛幻引擎能稱第二。這是一個開源的引擎,它製作的遊戲在畫質上比unity 3d精美的多,但開發效率不如unity 3d。《絕地求生》就是這個引擎開發的。
  • Cocos2d-x v3.3-RC0 發布說明! - OSCHINA - 中文開源技術交流社區
    Cocos2d-x v3.3-RC0下載地址:http://cn.cocos2d-x.org/download關於v3.3各個版本的特性和改動的話,可以參考這篇文檔。v3.3-RC0新特性 3D:增加了光照,包括平行光、點光源、聚光燈和環境光 新的音頻系統支持增加Mac OS X和Windows的支持 Spine的runtime更新到了最新版本v2.0.18 增加了Application::openURL(),用於打開一個URL連結
  • qt creator連接資料庫並實現用戶登錄和註冊相關的開發源碼詳解
    項目最終實現效果圖具體代碼詳解1 如何給qt界面設置相關的圖片呢?首先我們新建一個基於對話框的程序,名字自己定義即可。其次我們需要將自己的背景圖做好,保存為png或者img或者jpg等相關的格式,然後右鍵點擊creator,選擇添加現有文件,將圖片添加到creator界面如上圖所示。這樣的話,我們的基本文件已經存在了,接下來就是需要調用代碼進行相關的圖像的關聯了。
  • 火石軟體高薪誠聘遊戲技術開發人員
    火石軟體高新誠聘遊戲技術開發人員1.1廣州職位:   PHP工程師(急聘)1.2廣州職位:  高級cocos2d-x遊戲開發工程師1.3廣州職位:  cocos2d-x遊戲開發工程師(急聘)
  • Cocos Creator
    最近剛好在《Cocos Creator遊戲開發實戰》中看到物理系統有一個射線檢測,於是,基於這個射線檢測,寫了一個反覆橫跳的瞄準線效果。一起往下看吧!國際慣例,先上最終效果!在講解之前我們需要一些向量的知識,簡單地介紹一些吧!
  • Cocos Creator 籃球物理遊戲開發實戰
    ,學會本篇文章知識點,寫出一款籃球物理遊戲分分鐘的事情。依次創建其它三個點:3)添加碰撞組件:添加組件 -> 物理組件 -> Collider -> Chain。(注意:該組件在 v3.0 已移除)給外圍線條添加上碰撞組件。
  • 編程貓「kitten源碼編輯器」0到1的關鍵點設計
    而今天筆者從另外一個視角進行一次產品分析,老話說打蛇打七寸,做事抓關鍵,今天我們嘗試做一次產品設計關鍵點分析,推演一下一款工具類產品0到1過程當中的幾個關鍵點應當如何思考與規劃。在17、18年,編程貓還被稱為少兒編程教育行業當中的一匹黑馬,短短兩年時間,它已經成長為了這個行業當中的佼佼者。
  • cocos 使用圖集 - CSDN
    對於圖像資源,為什麼要用圖集,cocos官網的解釋:1.合成圖集時會去除每張圖片周圍的空白區域,加上可以在整體上實施各種優化算法,合成圖集後可以大大減少遊戲包體和內存佔用2.多個 在本地開發的時候,還是用單個的圖片,跟圖集沒有關係,只是在構建之前,在圖片文件夾下創建圖集。構建之後,cocos creator會生成對於的圖集。
  • cocos 自動圖集 - CSDN
    對於圖像資源,為什麼要用圖集,cocos官網的解釋:1.合成圖集時會去除每張圖片周圍的空白區域,加上可以在整體上實施各種優化算法,合成圖集後可以大大減少遊戲包體和內存佔用2.多個 在本地開發的時候,還是用單個的圖片,跟圖集沒有關係,只是在構建之前,在圖片文件夾下創建圖集。構建之後,cocos creator會生成對於的圖集。
  • 微信小程序中如何使用WebSocket實現長連接(含完整源碼)
    (說明:本文完整源碼請從文末附件下載,52im.net/thread-1703-1-1.html)2、相關文章《新手入門貼:史上最全Web端即時通訊技術原理詳解》《Web端即時通訊技術盤點:短輪詢、Comet、Websocket、SSE》《新手快速入門:WebSocket簡明教程》《WebSocket詳解(一):初步認識WebSocket技術》《WebSocket詳解(二
  • 觸控科技: 搭建技術橋梁 Cocos 2d-x首次赴臺辦沙龍
    9月5日晚,大陸領先的手遊開發/運營商觸控科技將攜旗下的開源遊戲引擎Cocos 2d-x跨越海峽,赴臺灣舉辦分享沙龍。這是Cocos 2d-x引擎第一次在臺灣舉辦開發者沙龍,也將是「觸控開發者平臺」首次在臺灣公開亮相。