整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          用HTML5的canvas來畫一個(gè)夢幻星空,來學(xué)習(xí)一下吧

          隨著HTML5的火熱,越來越多的人投入到HTML5開發(fā)中了,canvas作為HTML5中比較重要的一個(gè)元素,在很多官網(wǎng)的主頁面中被使用到。今天我們一起來看看如何使用canvas畫出一個(gè)夢幻的星空背景,還會(huì)有流星運(yùn)動(dòng)。

          本文的代碼已經(jīng)放到Github上了,感興趣的可以自取,Github地址如下。

          https://github.com/zhouxiongking/article-pages/blob/master/articles/starry/starry.html

          HTML5

          實(shí)現(xiàn)效果

          首先我們來看看通過canvas實(shí)現(xiàn)的星空效果圖,如下所示。

          效果圖

          代碼實(shí)現(xiàn)

          接下來我們看看這個(gè)效果是如何通過代碼一步步實(shí)現(xiàn)的。

          首先來看看頁面上的HTML代碼,只有一個(gè)Div元素。

          HTML代碼

          Javascript代碼

          首先我們需要定義一些常量,比如畫布的寬和高,星星數(shù)量,流星個(gè)數(shù)。在這個(gè)星空中流星其實(shí)是星星的一個(gè),只是添加了動(dòng)態(tài)效果。

          頁面初始化

          然后是設(shè)定一個(gè)定時(shí)器,通過一段隨機(jī)時(shí)間生成一個(gè)流星的索引號(hào)。

          流星索引號(hào)

          緊接著來看看生成一個(gè)星星的方法,該方法返回一個(gè)星星的各項(xiàng)參數(shù),包括x,y軸坐標(biāo),透明度,x,y軸偏移量。

          生成星星的參數(shù)

          然后是最重要的render方法,通過該方法可以將星星渲染至畫布上,我們將這個(gè)方法拆開看,首先是對流星的繪制,流星索引號(hào)通過上面metor方法獲得。

          畫流星

          然后是對于星星各項(xiàng)參數(shù)的處理,比如有的星星生成的點(diǎn)坐標(biāo)超出了屏幕寬高,有的透明度是負(fù)數(shù),都要將其處理成正常參數(shù)。

          各項(xiàng)參數(shù)判斷

          最后是在畫布中進(jìn)行繪制。

          畫布繪制

          至此,這個(gè)畫面效果的講解完畢,如果代碼正確的話,就可以看到文中出現(xiàn)的效果圖。

          結(jié)束語

          今天這篇文章主要是借助HTML5中的canvas畫出了一個(gè)夢幻星空的效果,你學(xué)會(huì)了嗎?

          、前言

          在瀏覽一些圖片網(wǎng)站的時(shí)候,經(jīng)常會(huì)看到很多的漂亮的星空圖,比如,下面的圖片。其實(shí)這種星星圖片的效果,也可以通過html+css樣式和js的方式來實(shí)現(xiàn)。今天教大家如何實(shí)現(xiàn)星星圖的效果。


          二、項(xiàng)目準(zhǔn)備

          軟件:Dreamweaver


          三、實(shí)現(xiàn)的目標(biāo)

          每次刷新產(chǎn)生隨機(jī)的星星個(gè)數(shù)。顯示畫布上。


          四、項(xiàng)目實(shí)現(xiàn)

          1. 創(chuàng)建canvas畫布

          <body>
              <canvas id='canvas'></canvas>
          </body>

          2. 添加css樣式。

          給canva 畫布加上邊框,方便觀察。

          <style type="text/css">
              canvas{
                  border:2px solid #f00;
          }
          </style>

          3.添加js樣式

          3.1 設(shè)置canvas畫布大小 ,定義需要變量。

          <script type="text/javascript">
               var _canvas=document.getElementById("canvas")
              _canvas.width=500;
              _canvas.height=500;
          var r,g ,b,a;
          </script>

          3.2 產(chǎn)生隨機(jī)圓。

          for (var j = 0; j < 150; j++) {
                  arc.x=Math.floor(Math.random()*_canvas.width);
                  arc.y=Math.floor(Math.random()*_canvas.height);
                  arc.r=Math.floor(Math.random()*31+10);
                  r=Math.ceil(Math.random()*256);
                  g=Math.ceil(Math.random()*256);
                  b=Math.ceil(Math.random()*256);
                  a=Math.random();
          
          
                  darw();
          }

          3.3 定義draw()方法,通過畫星星公式,將圓形轉(zhuǎn)換成星星狀 for 循環(huán)產(chǎn)生隨機(jī)位置星星。

          如何畫星星?(公式解析)(圖片來源百度)


          星星有內(nèi)切圓和外切圓,每兩個(gè)點(diǎn)之間的角度是固定的,因此可得到星星的每個(gè)點(diǎn)的坐標(biāo),畫出星星。


          /* 隨機(jī)產(chǎn)生星星*/
          for (var i = 0; i < 5; i++) {
          
          
                  _ctx.lineTo(Math.cos((18+72*i)/180*Math.PI)*arc.r+arc.x, -Math.sin((18+72*i)/180*Math.PI)*arc.r+arc.y);
          
          
                   _ctx.lineTo(Math.cos((54+72*i)/180*Math.PI)*arc.r/2+arc.x, -Math.sin((54+72*i)/180*Math.PI)*arc.r/2+arc.y);
               
          }

          3.4 隨機(jī)產(chǎn)生顏色。

          Math函數(shù)隨機(jī)產(chǎn)生0-225的RGB值。

          /* 隨機(jī)顏色*/ 
              _ctx.fillStyle="rgba(" + r + "," + g + "," + b + "," + a + ")"; 
              _ctx.fill();
                  _ctx.strokeStyle="rgba(" + r + "," + g + "," + b + "," + a + ")";
                _ctx.stroke();
                }

          3.5. 調(diào)用draw()方法實(shí)現(xiàn)功能。

          darw();


          五、效果展示

          1、點(diǎn)擊f12運(yùn)行到瀏覽器

          2、每次刷新網(wǎng)頁,隨機(jī)產(chǎn)生不一樣的星星和隨機(jī)顏色。


          六、總結(jié)

          1. 本項(xiàng)目利用canvas畫布,實(shí)現(xiàn)星星圖的效果,以及在運(yùn)用javascript產(chǎn)生星星效果時(shí),遇到的一些難點(diǎn)進(jìn)行了分析及提供解決方案。
          2. 歡迎大家積極嘗試,有時(shí)候看到別人實(shí)現(xiàn)起來很簡單,但是到自己動(dòng)手實(shí)現(xiàn)的時(shí)候,總會(huì)有各種各樣的問題,切勿眼高手低,勤動(dòng)手,才可以理解的更加深刻。
          3. 代碼很簡單,希望對你有所啟發(fā)。

          想學(xué)習(xí)更多前端、Python爬蟲、大數(shù)據(jù)等計(jì)算機(jī)知識(shí),請前往:http://pdcfighting.com/

          ocos Creator 開發(fā)游戲的一個(gè)核心理念就是讓內(nèi)容生產(chǎn)和功能開發(fā)可以流暢的并行協(xié)作,我們在上個(gè)部分著重于處理美術(shù)內(nèi)容,而接下來就是通過編寫腳本來開發(fā)功能的流程,之后我們還會(huì)看到寫好的程序腳本可以很容易的被內(nèi)容生產(chǎn)者使用。

          如果您從沒寫過程序也不用擔(dān)心,我們會(huì)在教程中提供所有需要的代碼,只要復(fù)制粘貼到正確的位置就可以了,之后這部分工作可以找您的程序員小伙伴來解決。下面讓我們開始創(chuàng)建驅(qū)動(dòng)主角行動(dòng)的腳本吧。

          創(chuàng)建腳本

          1. 首先在 資源管理器 中右鍵點(diǎn)擊 assets 文件夾,選擇 新建 -> 文件夾


          1. 右鍵點(diǎn)擊 New Folder,選擇 重命名 將其重命名為 scripts,之后我們所有的腳本都會(huì)存放在這里
          2. 右鍵點(diǎn)擊 scripts 文件夾,選擇 新建 -> JavaScript,創(chuàng)建一個(gè) JavaScript 腳本
          3. 將新建腳本的名字改為 Player,雙擊這個(gè)腳本,打開代碼編輯器

          注意: Cocos Creator 中腳本名稱就是組件的名稱,這個(gè)命名是大小寫敏感的!如果組件名稱的大小寫不正確,將無法正確通過名稱使用組件!

          編寫組件屬性

          在打開的 Player 腳本里已經(jīng)有了預(yù)先設(shè)置好的一些代碼塊,如下所示:

          cc.Class({
           extends: cc.Component,
           properties: {
           // foo: {
           // // ATTRIBUTES:
           // default: null, // The default value will be used only when the component attaching
           // // to a node for the first time
           // type: cc.SpriteFrame, // optional, default is typeof default
           // serializable: true, // optional, default is true
           // },
           // bar: {
           // get () {
           // return this._bar;
           // },
           // set (value) {
           // this._bar = value;
           // }
           // },
           },
           // LIFE-CYCLE CALLBACKS:
           // onLoad () {},
           start () {
           },
           // update (dt) {},
          });
          

          我們來大概了解一下這些代碼的作用。首先我們可以看到一個(gè)全局的 cc.Class() 方法,什么是 cc呢?cc 是 Cocos 的簡稱,Cocos 引擎的主要命名空間,引擎代碼中所有的類、函數(shù)、屬性和常量都在這個(gè)命名空間中定義。而 Class() 就是 cc 模塊下的一個(gè)方法,這個(gè)方法用于聲明 Cocos Creator 中的類。為了方便區(qū)分,我們把使用 cc.Class 聲明的類叫做 CCClass。Class() 方法的參數(shù)是一個(gè)原型對象,在原型對象中以鍵值對的形式設(shè)定所需的類型參數(shù),就能創(chuàng)建出所需要的類。

          例如:

           var Sprite = cc.Class({
           name: "sprite"
           });
          

          以上代碼用 cc.Class() 方法創(chuàng)建了一個(gè)類型,并且賦給了 Sprite 變量。同時(shí)還將類名設(shè)為 sprite。類名用于序列化,一般可以省略。

          對于 cc.Class 的詳細(xì)學(xué)習(xí)可以參考 使用 cc.Class 聲明類型。

          現(xiàn)在我們回到腳本編輯器看回之前的代碼,這些代碼就是編寫一個(gè)組件(腳本)所需的結(jié)構(gòu)。具有這樣結(jié)構(gòu)的腳本就是 Cocos Creator 中的 組件(Component),他們能夠掛載到場景中的節(jié)點(diǎn)上,提供控制節(jié)點(diǎn)的各種功能。我們先來設(shè)置一些屬性,然后看看怎樣在場景中調(diào)整他們。

          找到 Player 腳本里的 properties 部分,將其改為以下內(nèi)容并保存:

          // Player.js
           //...
           properties: {
           // 主角跳躍高度
           jumpHeight: 0,
           // 主角跳躍持續(xù)時(shí)間
           jumpDuration: 0,
           // 最大移動(dòng)速度
           maxMoveSpeed: 0,
           // 加速度
           accel: 0,
           },
           //...
          

          Cocos Creator 規(guī)定一個(gè)節(jié)點(diǎn)具有的屬性都需要寫在 properties 代碼塊中,這些屬性將規(guī)定主角的移動(dòng)方式,在代碼中我們不需要關(guān)心這些數(shù)值是多少,因?yàn)槲覀冎髸?huì)直接在 屬性檢查器 中設(shè)置這些數(shù)值。以后在游戲制作過程中,我們可以將需要隨時(shí)調(diào)整的屬性都放在 properties 中。

          現(xiàn)在我們可以把 Player 組件添加到主角節(jié)點(diǎn)上。在 層級管理器 中選中 Player 節(jié)點(diǎn),然后在 屬性檢查器 中點(diǎn)擊 添加組件 按鈕,選擇 添加用戶腳本組件 -> Player,為主角節(jié)點(diǎn)添加 Player 組件。

          現(xiàn)在我們可以在 屬性檢查器 中(需要選中 Player 節(jié)點(diǎn))看到剛添加的 Player 組件了,按照下圖將主角跳躍和移動(dòng)的相關(guān)屬性設(shè)置好:

          這些數(shù)值除了 jumpDuration 的單位是秒之外,其他的數(shù)值都是以像素為單位的,根據(jù)我們現(xiàn)在對 Player組件的設(shè)置:我們的主角將能夠跳躍 200 像素的高度,起跳到最高點(diǎn)所需的時(shí)間是 0.3 秒,最大水平方向移動(dòng)速度是 400 像素每秒,水平加速度是 350 像素每秒。

          這些數(shù)值都是建議,一會(huì)等游戲運(yùn)行起來后,您完全可以按照自己的喜好隨時(shí)在 屬性檢查器 中修改這些數(shù)值,不需要改動(dòng)任何代碼。

          編寫跳躍和移動(dòng)代碼

          下面我們添加一個(gè)方法,來讓主角跳躍起來,在 properties: {...}, 代碼塊的下面,添加叫做 setJumpAction 的方法:

          // Player.js
           properties: {
           //...
           },
           setJumpAction: function () {
           // 跳躍上升
           var jumpUp = cc.moveBy(this.jumpDuration, cc.v2(0, this.jumpHeight)).easing(cc.easeCubicActionOut());
           // 下落
           var jumpDown = cc.moveBy(this.jumpDuration, cc.v2(0, -this.jumpHeight)).easing(cc.easeCubicActionIn());
           // 不斷重復(fù)
           return cc.repeatForever(cc.sequence(jumpUp, jumpDown));
           },
          

          這里就需要了解一下 Cocos Creator 的 動(dòng)作(Action)系統(tǒng) 了。由于動(dòng)作系統(tǒng)比較復(fù)雜,這里就簡單的介紹一下。

          在 Cocos Creator 中,動(dòng)作 簡單來說就是 節(jié)點(diǎn)的位移、縮放和旋轉(zhuǎn)

          例如在上面的代碼中,moveBy() 方法的作用是在規(guī)定的時(shí)間內(nèi)移動(dòng)指定的一段距離,第一個(gè)參數(shù)就是我們之前定義主角屬性中的跳躍時(shí)間,第二個(gè)參數(shù)是一個(gè) Vec2(表示 2D 向量和坐標(biāo))類型的對象,為了更好的理解,我們可以看看官方給的函數(shù)說明:

          /**
           * !#en
           * Moves a Node object x,y pixels by modifying its position property. <br/>
           * x and y are relative to the position of the object. <br/>
           * Several MoveBy actions can be concurrently called, and the resulting <br/>
           * movement will be the sum of individual movements.
           * !#zh 移動(dòng)指定的距離。
           * @method moveBy
           * @param {Number} duration duration in seconds
           * @param {Vec2|Number} deltaPos
           * @param {Number} [deltaY]
           * @return {ActionInterval}
           * @example
           * // example
           * var actionTo = cc.moveBy(2, cc.v2(windowSize.width - 40, windowSize.height - 40));
           */
          cc.moveBy = function (duration, deltaPos, deltaY) {
           return new cc.MoveBy(duration, deltaPos, deltaY);
          };
          

          可以看到,方法 moveBy 一共可以傳入三個(gè)參數(shù),前兩個(gè)參數(shù)我們已經(jīng)知道,第三個(gè)參數(shù)是 Number 類型的 Y 坐標(biāo),我們可以發(fā)現(xiàn)第二個(gè)參數(shù)是可以傳入兩種類型的,第一種是 Number 類型,第二種才是 Vec2類型,如果我們在這里傳入的是 Number 類型,那么默認(rèn)這個(gè)參數(shù)就是 X 坐標(biāo),此時(shí)就要填第三個(gè)參數(shù),為 Y 坐標(biāo)。上面的例子中 cc.moveBy(this.jumpDuration, cc.v2(0, this.jumpHeight)) 第二個(gè)參數(shù)傳入的是使用 cc.v2 方法構(gòu)建的 Vec2 類型對象,這個(gè)類型表示的是一個(gè)坐標(biāo),即有 X 坐標(biāo)也有 Y 坐標(biāo),因?yàn)椴恍枰賯魅氲谌齻€(gè)參數(shù)!同時(shí)注意官方的一段話 x and y are relative to the position of the object.,這句話的意思是傳入的 X、Y 坐標(biāo)都是相對于節(jié)點(diǎn)當(dāng)前的坐標(biāo)位置,而不是整個(gè)坐標(biāo)系的絕對坐標(biāo)。

          了解了參數(shù)的含義之后,我們再來關(guān)注 moveBy() 方法的返回值,看官方說明可以知道,這個(gè)方法返回的是一個(gè) ActionInterval 類型的對象,ActionInterval 在 Cocos 中是一個(gè)表示時(shí)間間隔動(dòng)作的類,這種動(dòng)作在一定時(shí)間內(nèi)完成。到這里我們就可以理解代碼 cc.moveBy(this.jumpDuration, cc.v2(0, this.jumpHeight)).easing(cc.easeCubicActionOut()) 前一部分 的意思了,它的意思就是構(gòu)造一個(gè) ActionInterval 類型的對象,這個(gè)對象表示在 jumpDuration 的時(shí)間內(nèi),移動(dòng)到相對于當(dāng)前節(jié)點(diǎn)的 (0,this.jumpHeight) 的坐標(biāo)位置,簡單來說,就是一個(gè)向上跳躍的動(dòng)作。

          那么 后半部分 easing(cc.easeCubicActionOut()) 的作用是什么呢?easing 是 ActionInterval 類下的一個(gè)方法,這個(gè)方法可以讓時(shí)間間隔動(dòng)作呈現(xiàn)為一種緩動(dòng)運(yùn)動(dòng),傳入的參數(shù)是一個(gè)緩動(dòng)對象,返回一個(gè) ActionInterval 類型對象,這里傳入的是使用 easeCubicActionInOut 方法構(gòu)建的緩動(dòng)對象,EaseCubicInOut 是按三次函數(shù)緩動(dòng)進(jìn)入并退出的動(dòng)作,具體曲線可參考下圖:

          詳細(xì)內(nèi)容可參考 API。

          接下來在 onLoad 方法里調(diào)用剛添加的 setJumpAction 方法,然后執(zhí)行 runAction 來開始動(dòng)作:

          // Player.js
           onLoad: function () {
           // 初始化跳躍動(dòng)作
           this.jumpAction = this.setJumpAction();
           this.node.runAction(this.jumpAction);
           },
          

          onLoad 方法會(huì)在場景加載后立刻執(zhí)行,所以我們會(huì)把初始化相關(guān)的操作和邏輯都放在這里面。我們首先將循環(huán)跳躍的動(dòng)作傳給了 jumpAction 變量,之后調(diào)用這個(gè)組件掛載的節(jié)點(diǎn)下的 runAction 方法,傳入循環(huán)跳躍的 Action 從而讓節(jié)點(diǎn)(主角)一直跳躍。保存腳本,然后我們就可以開始第一次運(yùn)行游戲了!

          點(diǎn)擊 Cocos Creator 編輯器上方正中的 預(yù)覽游戲 按鈕

          ,Cocos Creator 會(huì)自動(dòng)打開您的默認(rèn)瀏覽器并開始在里面運(yùn)行游戲,現(xiàn)在應(yīng)該可以看到我們的主角——紫色小怪獸在場景中間活潑的蹦個(gè)不停了。

          移動(dòng)控制

          只能在原地傻蹦的主角可沒前途,讓我們?yōu)橹鹘翘砑渔I盤輸入,用 A 和 D 來控制他的跳躍方向。在 setJumpAction 方法的下面添加鍵盤事件響應(yīng)函數(shù):

          // Player.js
           setJumpAction: function () {
           //...
           },
           onKeyDown (event) {
           // set a flag when key pressed
           switch(event.keyCode) {
           case cc.macro.KEY.a:
           this.accLeft = true;
           break;
           case cc.macro.KEY.d:
           this.accRight = true;
           break;
           }
           },
           onKeyUp (event) {
           // unset a flag when key released
           switch(event.keyCode) {
           case cc.macro.KEY.a:
           this.accLeft = false;
           break;
           case cc.macro.KEY.d:
           this.accRight = false;
           break;
           }
           },
          

          然后修改 onLoad 方法,在其中加入向左和向右加速的開關(guān),以及主角當(dāng)前在水平方向的速度。最后再調(diào)用 cc.systemEvent,在場景加載后就開始監(jiān)聽鍵盤輸入:

          // Player.js
           onLoad: function () {
           // 初始化跳躍動(dòng)作
           this.jumpAction = this.setJumpAction();
           this.node.runAction(this.jumpAction);
           // 加速度方向開關(guān)
           this.accLeft = false;
           this.accRight = false;
           // 主角當(dāng)前水平方向速度
           this.xSpeed = 0;
           // 初始化鍵盤輸入監(jiān)聽
           cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
           cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this); 
           },
           onDestroy () {
           // 取消鍵盤輸入監(jiān)聽
           cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
           cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
           },
          

          有 Android 開發(fā)經(jīng)驗(yàn)的同學(xué)比較好理解,這里的監(jiān)聽器實(shí)質(zhì)上就和 Android 里的 OnClickListener 差不多,在 cocos 中通過 systemEvent 來監(jiān)聽系統(tǒng) 全局 事件。(鼠標(biāo)、觸摸和自定義事件的監(jiān)聽和派發(fā)的詳細(xì)內(nèi)容請參考 監(jiān)聽和發(fā)射事件。)這里通過向 systemEvent 注冊了一個(gè)鍵盤響應(yīng)函數(shù),在函數(shù)中通過 switch 判斷鍵盤上的 A 和 D 是否被按下或松開,若按下就執(zhí)行對應(yīng)的操作。

          最后修改 update 方法的內(nèi)容,添加加速度、速度和主角當(dāng)前位置的設(shè)置:

          // Player.js
           update: function (dt) {
           // 根據(jù)當(dāng)前加速度方向每幀更新速度
           if (this.accLeft) {
           this.xSpeed -= this.accel * dt;
           } else if (this.accRight) {
           this.xSpeed += this.accel * dt;
           }
           // 限制主角的速度不能超過最大值
           if ( Math.abs(this.xSpeed) > this.maxMoveSpeed ) {
           // if speed reach limit, use max speed with current direction
           this.xSpeed = this.maxMoveSpeed * this.xSpeed / Math.abs(this.xSpeed);
           }
           // 根據(jù)當(dāng)前速度更新主角的位置
           this.node.x += this.xSpeed * dt;
           },
          

          update 在場景加載后就會(huì)每幀調(diào)用一次,我們一般把需要經(jīng)常計(jì)算或及時(shí)更新的邏輯內(nèi)容放在這里。在我們的游戲中,根據(jù)鍵盤輸入獲得加速度方向后,就需要每幀在 update 中計(jì)算主角的速度和位置。

          保存腳本后,點(diǎn)擊 預(yù)覽游戲 來看看我們最新的成果。在瀏覽器打開預(yù)覽后,用鼠標(biāo)點(diǎn)擊一下游戲畫面(這是瀏覽器的限制,要點(diǎn)擊游戲畫面才能接受鍵盤輸入),然后就可以按 A 和 D 鍵來控制主角左右移動(dòng)了!

          感覺移動(dòng)起來有點(diǎn)遲緩?主角跳的不夠高?希望跳躍時(shí)間長一些?沒問題,這些都可以隨時(shí)調(diào)整。只要為 Player 組件設(shè)置不同的屬性值,就可以按照您的想法調(diào)整游戲。這里有一組設(shè)置可供參考:

          Jump Height: 150
          Jump Duration: 0.3
          Max Move Speed: 400
          Accel: 1000
          

          這組屬性設(shè)置會(huì)讓主角變得靈活無比,至于如何選擇,就看您想做一個(gè)什么風(fēng)格的游戲了。

          制作星星

          主角現(xiàn)在可以跳來跳去了,我們要給玩家一個(gè)目標(biāo),也就是會(huì)不斷出現(xiàn)在場景中的星星,玩家需要引導(dǎo)小怪獸碰觸星星來收集分?jǐn)?shù)。被主角碰到的星星會(huì)消失,然后馬上在隨機(jī)位置重新生成一個(gè)。

          制作 Prefab

          對于需要重復(fù)生成的節(jié)點(diǎn),我們可以將他保存成 Prefab(預(yù)制) 資源,作為我們動(dòng)態(tài)生成節(jié)點(diǎn)時(shí)使用的模板。關(guān)于 Prefab 的更多信息,請閱讀 預(yù)制資源(Prefab)。

          首先從 資源管理器 中拖拽 assets/textures/star 圖片到場景中,位置隨意,我們只是需要借助場景作為我們制作 Prefab 的工作臺(tái),制作完成后會(huì)我們把這個(gè)節(jié)點(diǎn)從場景中刪除。

          我們不需要修改星星的位置或渲染屬性,但要讓星星能夠被主角碰觸后消失,我們需要為星星也添加一個(gè)專門的組件。按照和添加 Player 腳本相同的方法,添加名叫 Star 的 JavaScript 腳本到 assets/scripts/中。

          接下來雙擊這個(gè)腳本開始編輯,星星組件只需要一個(gè)屬性用來規(guī)定主角距離星星多近時(shí)就可以完成收集,修改 properties,加入以下內(nèi)容并保存腳本。

          // Star.js
           properties: {
           // 星星和主角之間的距離小于這個(gè)數(shù)值時(shí),就會(huì)完成收集
           pickRadius: 0,
           },
          

          將這個(gè)腳本添加到剛創(chuàng)建的 star 節(jié)點(diǎn)上,在 層級管理器 中選中 star 節(jié)點(diǎn),然后在 屬性檢查器 中點(diǎn)擊 添加組件 按鈕,選擇 添加用戶腳本組件 -> Star,該腳本便會(huì)添加到剛創(chuàng)建的 star 節(jié)點(diǎn)上。然后在 屬性檢查器中把 Pick Radius 屬性值設(shè)為 60:

          Star Prefab 需要的設(shè)置就完成了,現(xiàn)在從 層級管理器 中將 star 節(jié)點(diǎn)拖拽到 資源管理器 中的 assets 文件夾下,就生成了名叫 star 的 Prefab 資源。

          現(xiàn)在可以從場景中刪除 star 節(jié)點(diǎn)了,后續(xù)可以直接雙擊這個(gè) star Prefab 資源進(jìn)行編輯。

          接下去我們會(huì)在腳本中動(dòng)態(tài)使用星星的 Prefab 資源生成星星。

          添加游戲控制腳本

          星星的生成是游戲主邏輯的一部分,所以我們要添加一個(gè)叫做 Game 的腳本作為游戲主邏輯腳本,這個(gè)腳本之后還會(huì)添加計(jì)分、游戲失敗和重新開始的相關(guān)邏輯。

          添加 Game 腳本到 assets/scripts 文件夾下,雙擊打開腳本。首先添加生成星星需要的屬性:

          // Game.js
           properties: {
           // 這個(gè)屬性引用了星星預(yù)制資源
           starPrefab: {
           default: null,
           type: cc.Prefab
           },
           // 星星產(chǎn)生后消失時(shí)間的隨機(jī)范圍
           maxStarDuration: 0,
           minStarDuration: 0,
           // 地面節(jié)點(diǎn),用于確定星星生成的高度
           ground: {
           default: null,
           type: cc.Node
           },
           // player 節(jié)點(diǎn),用于獲取主角彈跳的高度,和控制主角行動(dòng)開關(guān)
           player: {
           default: null,
           type: cc.Node
           }
           },
          

          這里初學(xué)者可能會(huì)疑惑,為什么像 starPrefab 這樣的屬性會(huì)用 {} 括起來,括號(hào)里面還有新的 “屬性” 呢?其實(shí)這是屬性的一種完整聲明,之前我們的屬性聲明都是不完整的,有些情況下,我們需要為屬性聲明添加參數(shù),這些參數(shù)控制了屬性在 屬性檢查器 中的顯示方式,以及屬性在場景序列化過程中的行為。例如:

          properties: {
           score: {
           default: 0,
           displayName: "Score (player)",
           tooltip: "The score of player",
           }
          }
          

          以上代碼為 score 屬性設(shè)置了三個(gè)參數(shù) default、 displayName 和 tooltip。這幾個(gè)參數(shù)分別指定了 score的默認(rèn)值(default)為 0,在 屬性檢查器 里,其屬性名(displayName)將顯示為 Score (player),并且當(dāng)鼠標(biāo)移到參數(shù)上時(shí),顯示對應(yīng)的 tooltip。

          下面是常用參數(shù):

          default:設(shè)置屬性的默認(rèn)值,這個(gè)默認(rèn)值僅在組件第一次添加到節(jié)點(diǎn)上時(shí)才會(huì)用到

          type:限定屬性的數(shù)據(jù)類型,詳見 CCClass 進(jìn)階參考:type 參數(shù)

          visible:設(shè)為 false 則不在屬性檢查器面板中顯示該屬性

          serializable: 設(shè)為 false 則不序列化(保存)該屬性

          displayName:在屬性檢查器面板中顯示成指定名字

          tooltip:在屬性檢查器面板中添加屬性的 tooltip

          所以上面的代碼:

          starPrefab: {
           default: null,
           type: cc.Prefab
          },
          

          就容易理解了,首先在 Game 組件下聲明了 starPrefab 屬性,這個(gè)屬性默認(rèn)值為 null,能傳入的類型必須是 Prefab 預(yù)制資源類型。這樣之后的 ground、player 屬性也可以理解了。

          保存腳本后將 Game 組件添加到 層級管理器 中的 Canvas 節(jié)點(diǎn)上(選中 Canvas 節(jié)點(diǎn)后,拖拽腳本到 屬性檢查器 上,或者點(diǎn)擊 屬性檢查器添加組件 按鈕,并從 添加用戶腳本組件 中選擇 Game。)

          接下來從 資源管理器 中拖拽 star 的 Prefab 資源到 Game 組件的 Star Prefab 屬性中。這是我們第一次為屬性設(shè)置引用,只有在屬性聲明時(shí)規(guī)定 type 為引用類型時(shí)(比如我們這里寫的 cc.Prefab 類型),才能夠?qū)①Y源或節(jié)點(diǎn)拖拽到該屬性上。

          接著從 層級管理器 中拖拽 ground 和 Player 節(jié)點(diǎn)到 Canvas 節(jié)點(diǎn) Game 組件中相對應(yīng)名字的屬性上,完成節(jié)點(diǎn)引用。

          然后設(shè)置 Min Star Duration 和 Max Star Duration 屬性的值為 3 和 5,之后我們生成星星時(shí),會(huì)在這兩個(gè)之間隨機(jī)取值,就是星星消失前經(jīng)過的時(shí)間。

          在隨機(jī)位置生成星星

          接下來我們繼續(xù)修改 Game 腳本,在 onLoad 方法 后面 添加生成星星的邏輯:

          // Game.js
           onLoad: function () {
           // 獲取地平面的 y 軸坐標(biāo)
           this.groundY = this.ground.y + this.ground.height/2;
           // 生成一個(gè)新的星星
           this.spawnNewStar();
           },
           spawnNewStar: function() {
           // 使用給定的模板在場景中生成一個(gè)新節(jié)點(diǎn)
           var newStar = cc.instantiate(this.starPrefab);
           // 將新增的節(jié)點(diǎn)添加到 Canvas 節(jié)點(diǎn)下面
           this.node.addChild(newStar);
           // 為星星設(shè)置一個(gè)隨機(jī)位置
           newStar.setPosition(this.getNewStarPosition());
           },
           getNewStarPosition: function () {
           var randX = 0;
           // 根據(jù)地平面位置和主角跳躍高度,隨機(jī)得到一個(gè)星星的 y 坐標(biāo)
           var randY = this.groundY + Math.random() * this.player.getComponent('Player').jumpHeight + 50;
           // 根據(jù)屏幕寬度,隨機(jī)得到一個(gè)星星 x 坐標(biāo)
           var maxX = this.node.width/2;
           randX = (Math.random() - 0.5) * 2 * maxX;
           // 返回星星坐標(biāo)
           return cc.v2(randX, randY);
           },
          

          這里需要注意幾個(gè)問題:

          1. 節(jié)點(diǎn)下的 y 屬性對應(yīng)的是錨點(diǎn)所在的 y 坐標(biāo),因?yàn)殄^點(diǎn)默認(rèn)在節(jié)點(diǎn)的中心,所以需要加上地面高度的一半才是地面的 y 坐標(biāo)
          2. instantiate 方法的作用是:克隆指定的任意類型的對象,或者從 Prefab 實(shí)例化出新節(jié)點(diǎn),返回值為 Node 或者 Object
          3. Node 下的 addChild 方法 作用是將新節(jié)點(diǎn)建立在該節(jié)點(diǎn)的下一級,所以新節(jié)點(diǎn)的顯示效果在該節(jié)點(diǎn)之上
          4. Node 下的 setPosition 方法 作用是設(shè)置節(jié)點(diǎn)在父節(jié)點(diǎn)坐標(biāo)系中的位置,可以通過兩種方式設(shè)置坐標(biāo)點(diǎn)。一是傳入兩個(gè)數(shù)值 x 和 y,二是傳入 cc.v2(x, y)(類型為 cc.Vec2 的對象)
          5. 通過 Node 下的 getComponent 方法可以得到該節(jié)點(diǎn)上掛載的組件引用

          保存腳本以后點(diǎn)擊 預(yù)覽游戲 按鈕,在瀏覽器中可以看到,游戲開始后動(dòng)態(tài)生成了一顆星星!用同樣的方法,您可以在游戲中動(dòng)態(tài)生成任何預(yù)先設(shè)置好的以 Prefab 為模板的節(jié)點(diǎn)。

          添加主角碰觸收集星星的行為

          現(xiàn)在要添加主角收集星星的行為邏輯了,這里的重點(diǎn)在于,星星要隨時(shí)可以獲得主角節(jié)點(diǎn)的位置,才能判斷他們之間的距離是否小于可收集距離,如何獲得主角節(jié)點(diǎn)的引用呢?別忘了我們前面做過的兩件事:

          1. Game 組件中有個(gè)名叫 player 的屬性,保存了主角節(jié)點(diǎn)的引用。
          2. 每個(gè)星星都是在 Game 腳本中動(dòng)態(tài)生成的。

          所以我們只要在 Game 腳本生成 Star 節(jié)點(diǎn)實(shí)例時(shí),將 Game 組件的實(shí)例傳入星星并保存起來就好了,之后我們可以隨時(shí)通過 game.player 來訪問到主角節(jié)點(diǎn)。讓我們打開 Game 腳本,在 spawnNewStar 方法最后面添加一句 newStar.getComponent('Star').game = this;,如下所示:

          // Game.js
           spawnNewStar: function() {
           // ...
           // 在星星組件上暫存 Game 對象的引用
           newStar.getComponent('Star').game = this;
           },
          

          保存后打開 Star 腳本,現(xiàn)在我們可以利用 Game 組件中引用的 player 節(jié)點(diǎn)來判斷距離了,在 onLoad 方法后面添加名為 getPlayerDistance 和 onPicked 的方法:

          // Star.js
           getPlayerDistance: function () {
           // 根據(jù) player 節(jié)點(diǎn)位置判斷距離
           var playerPos = this.game.player.getPosition();
           // 根據(jù)兩點(diǎn)位置計(jì)算兩點(diǎn)之間距離
           var dist = this.node.position.sub(playerPos).mag();
           return dist;
           },
           onPicked: function() {
           // 當(dāng)星星被收集時(shí),調(diào)用 Game 腳本中的接口,生成一個(gè)新的星星
           this.game.spawnNewStar();
           // 然后銷毀當(dāng)前星星節(jié)點(diǎn)
           this.node.destroy();
           },
          

          Node 下的 getPosition() 方法 返回的是節(jié)點(diǎn)在父節(jié)點(diǎn)坐標(biāo)系中的位置(x, y),即一個(gè) Vec2 類型對象。同時(shí)注意調(diào)用 Node 下的 destroy() 方法 就可以銷毀節(jié)點(diǎn)。

          然后在 update 方法中添加每幀判斷距離,如果距離小于 pickRadius 屬性規(guī)定的收集距離,就執(zhí)行收集行為:

          // Star.js
           update: function (dt) {
           // 每幀判斷和主角之間的距離是否小于收集距離
           if (this.getPlayerDistance() < this.pickRadius) {
           // 調(diào)用收集行為
           this.onPicked();
           return;
           }
           },
          

          保存腳本,再次預(yù)覽測試,通過按 A 和 D 鍵來控制主角左右移動(dòng),就可以看到控制主角靠近星星時(shí),星星就會(huì)消失掉,然后在隨機(jī)位置生成了新的星星!

          添加得分

          小怪獸辛辛苦苦的收集星星,沒有獎(jiǎng)勵(lì)怎么行?現(xiàn)在讓我們來添加在收集星星時(shí)增加得分獎(jiǎng)勵(lì)的邏輯和顯示。

          添加分?jǐn)?shù)文字(Label)

          游戲開始時(shí)得分從 0 開始,每收集一個(gè)星星分?jǐn)?shù)就會(huì)加 1。要顯示得分,首先要?jiǎng)?chuàng)建一個(gè) Label 節(jié)點(diǎn)。在 層級管理器 中選中 Canvas 節(jié)點(diǎn),右鍵點(diǎn)擊并選擇菜單中的 創(chuàng)建新節(jié)點(diǎn) -> 創(chuàng)建渲染節(jié)點(diǎn) -> Label(文字),一個(gè)新的 Label 節(jié)點(diǎn)會(huì)被創(chuàng)建在 Canvas 節(jié)點(diǎn)下面,而且順序在最下面。接下來我們要用如下的步驟配置這個(gè) Label 節(jié)點(diǎn):

          1. 將該節(jié)點(diǎn)名字改為 score
          2. 將 score 節(jié)點(diǎn)的位置(position 屬性)設(shè)為 (0, 180)。
          3. 選中該節(jié)點(diǎn),編輯 屬性檢查器 中 Label 組件的 string 屬性,填入 Score: 0 的文字。
          4. 將 Label 組件的 Font Size 屬性設(shè)為 50。
          5. 資源管理器 中拖拽 assets/mikado_outline_shadow 位圖字體資源(注意圖標(biāo)是

          1. )到 Label 組件的 Font 屬性中,將文字的字體替換成我們項(xiàng)目資源中的位圖字體。

          注意: Score: 0 的文字建議使用英文冒號(hào),因?yàn)?Label 組件的 String 屬性加了位圖字體后,會(huì)無法識(shí)別中文的冒號(hào)。

          完成后效果如下圖所示:

          在 Game 腳本中添加得分邏輯

          我們將會(huì)把計(jì)分和更新分?jǐn)?shù)顯示的邏輯放在 Game 腳本里,打開 Game 腳本開始編輯,首先在 properties 區(qū)塊的 最后 添加分?jǐn)?shù)顯示 Label 的引用屬性:

          // Game.js
           properties: {
           // ...
           // score label 的引用
           scoreDisplay: {
           default: null,
           type: cc.Label
           }
           },
          

          接下來在 onLoad 方法 里面 添加計(jì)分用的變量的初始化:

          // Game.js
           onLoad: function () {
           // ...
           // 初始化計(jì)分
           this.score = 0;
           },
          

          然后在 update 方法 后面 添加名叫 gainScore 的新方法:

          // Game.js
           gainScore: function () {
           this.score += 1;
           // 更新 scoreDisplay Label 的文字
           this.scoreDisplay.string = 'Score: ' + this.score;
           },
          

          保存 Game 腳本后,回到 層級管理器,選中 Canvas 節(jié)點(diǎn),然后把前面添加好的 score 節(jié)點(diǎn)拖拽到 屬性檢查器 里 Game 組件的 Score Display 屬性中。

          在 Star 腳本中調(diào)用 Game 中的得分邏輯

          下面打開 Star 腳本,在 onPicked 方法中加入 gainScore 的調(diào)用:

          // Star.js
           onPicked: function() {
           // 當(dāng)星星被收集時(shí),調(diào)用 Game 腳本中的接口,生成一個(gè)新的星星
           this.game.spawnNewStar();
           // 調(diào)用 Game 腳本的得分方法
           this.game.gainScore();
           // 然后銷毀當(dāng)前星星節(jié)點(diǎn)
           this.node.destroy();
           },
          

          保存后預(yù)覽,可以看到現(xiàn)在收集星星時(shí)屏幕正上方顯示的分?jǐn)?shù)會(huì)增加了!

          失敗判定和重新開始

          現(xiàn)在我們的游戲已經(jīng)初具規(guī)模,但得分再多,不可能失敗的游戲也不會(huì)給人成就感。現(xiàn)在讓我們加入星星定時(shí)消失的行為,而且讓星星消失時(shí)就判定為游戲失敗。也就是說,玩家需要在每顆星星消失之前完成收集,并不斷重復(fù)這個(gè)過程完成玩法的循環(huán)。

          為星星加入計(jì)時(shí)消失的邏輯

          打開 Game 腳本,在 onLoad 方法的 spawnNewStar 調(diào)用 之前 加入計(jì)時(shí)需要的變量聲明:

          // Game.js
           onLoad: function () {
           // ...
           // 初始化計(jì)時(shí)器
           this.timer = 0;
           this.starDuration = 0;
           // 生成一個(gè)新的星星
           this.spawnNewStar();
           // 初始化計(jì)分
           this.score = 0;
           },
          

          然后在 spawnNewStar 方法最后加入重置計(jì)時(shí)器的邏輯,其中 this.minStarDuration 和 this.maxStarDuration 是我們一開始聲明的 Game 組件屬性,用來規(guī)定星星消失時(shí)間的隨機(jī)范圍:

          // Game.js
           spawnNewStar: function() {
           // ...
           // 重置計(jì)時(shí)器,根據(jù)消失時(shí)間范圍隨機(jī)取一個(gè)值
           this.starDuration = this.minStarDuration + Math.random() * (this.maxStarDuration - this.minStarDuration);
           this.timer = 0;
           },
          

          在 update 方法中加入計(jì)時(shí)器更新和判斷超過時(shí)限的邏輯:

          // Game.js
           update: function (dt) {
           // 每幀更新計(jì)時(shí)器,超過限度還沒有生成新的星星
           // 就會(huì)調(diào)用游戲失敗邏輯
           if (this.timer > this.starDuration) {
           this.gameOver();
           return;
           }
           this.timer += dt;
           },
          

          最后,在 gainScore 方法后面加入 gameOver 方法,游戲失敗時(shí)重新加載場景。

          // Game.js
           gameOver: function () {
           this.player.stopAllActions(); //停止 player 節(jié)點(diǎn)的跳躍動(dòng)作
           cc.director.loadScene('game');
           }
          

          這里需要初學(xué)者了解的是,cc.director 是一個(gè)管理你的游戲邏輯流程的單例對象。由于 cc.director 是一個(gè)單例,你不需要調(diào)用任何構(gòu)造函數(shù)或創(chuàng)建函數(shù),使用它的標(biāo)準(zhǔn)方法是通過調(diào)用 cc.director.methodName(),例如這里的 cc.director.loadScene('game') 就是重新加載游戲場景 game,也就是游戲重新開始。而節(jié)點(diǎn)下的 stopAllActions 方法就顯而易見了,這個(gè)方法會(huì)讓節(jié)點(diǎn)上的所有 Action 都失效。

          以上,對 Game 腳本的修改就完成了,保存腳本,然后打開 Star 腳本,我們需要為即將消失的星星加入簡單的視覺提示效果,在 update 方法最后加入以下代碼:

          // Star.js
           update: function() {
           // ...
           // 根據(jù) Game 腳本中的計(jì)時(shí)器更新星星的透明度
           var opacityRatio = 1 - this.game.timer/this.game.starDuration;
           var minOpacity = 50;
           this.node.opacity = minOpacity + Math.floor(opacityRatio * (255 - minOpacity));
           }
          

          保存 Star 腳本,我們的游戲玩法邏輯就全部完成了!現(xiàn)在點(diǎn)擊 預(yù)覽游戲 按鈕,我們在瀏覽器看到的就是一個(gè)有核心玩法、激勵(lì)機(jī)制、失敗機(jī)制的合格游戲了。

          加入音效

          盡管很多人玩手游的時(shí)候會(huì)無視聲音,我們?yōu)榱私坛陶故镜墓ぷ髁鞒瘫M量完整,還是要補(bǔ)全加入音效的任務(wù)。

          跳躍音效

          首先加入跳躍音效,打開 Player 腳本,添加引用聲音文件資源的 jumpAudio 屬性:

          // Player.js
           properties: {
           // ...
           // 跳躍音效資源
           jumpAudio: {
           default: null,
           type: cc.AudioClip
           },
           },
          

          然后改寫 setJumpAction 方法,插入播放音效的回調(diào),并通過添加 playJumpSound 方法來播放聲音:

          // Player.js
           setJumpAction: function () {
           // 跳躍上升
           var jumpUp = cc.moveBy(this.jumpDuration, cc.v2(0, this.jumpHeight)).easing(cc.easeCubicActionOut());
           // 下落
           var jumpDown = cc.moveBy(this.jumpDuration, cc.v2(0, -this.jumpHeight)).easing(cc.easeCubicActionIn());
           // 添加一個(gè)回調(diào)函數(shù),用于在動(dòng)作結(jié)束時(shí)調(diào)用我們定義的其他方法
           var callback = cc.callFunc(this.playJumpSound, this);
           // 不斷重復(fù),而且每次完成落地動(dòng)作后調(diào)用回調(diào)來播放聲音
           return cc.repeatForever(cc.sequence(jumpUp, jumpDown, callback));
           },
           playJumpSound: function () {
           // 調(diào)用聲音引擎播放聲音
           cc.audioEngine.playEffect(this.jumpAudio, false);
           },
          

          這里需要強(qiáng)調(diào)的是回調(diào)函數(shù)的作用,我們首先來看官方對 callFunc() 方法的定義:

          /**
           * !#en Creates the action with the callback.
           * !#zh 執(zhí)行回調(diào)函數(shù)。
           * @method callFunc
           * @param {function} selector
           * @param {object} [selectorTarget=null]
           * @param {*} [data=null] - data for function, it accepts all data types.
           * @return {ActionInstant}
           * @example
           * // example
           * // CallFunc without data
           * var finish = cc.callFunc(this.removeSprite, this);
           *
           * // CallFunc with data
           * var finish = cc.callFunc(this.removeFromParentAndCleanup, this._grossini, true);
           */
          cc.callFunc = function (selector, selectorTarget, data) {
           return new cc.CallFunc(selector, selectorTarget, data);
          };
          

          我們可以看到 callFunc 方法可以傳入三個(gè)參數(shù),第一個(gè)參數(shù)是方法的 selector,我們可以理解為方法名。第二個(gè)參數(shù)是 Object 類型,一般填入 this。第三個(gè)參數(shù)為帶回的數(shù)據(jù),可以是所有的數(shù)據(jù)類型,可以不填。我們再注意到這個(gè)方法的返回值 —— ActionInstant,這是一個(gè)瞬間執(zhí)行的動(dòng)作類。到這里我們就可以理解了,使用 callFunc 調(diào)用回調(diào)函數(shù)可以讓函數(shù)轉(zhuǎn)變?yōu)?cc 中的 Action(動(dòng)作),這一用法在 cc 的動(dòng)作系統(tǒng)里非常實(shí)用!例如在上面我們將播放聲音的函數(shù)傳入 callFunc 賦值給 callback,讓 callback 成為了一個(gè)播放聲音的動(dòng)作 Action,那么我們之后就能通過 cc.sequence 將跳躍和播放聲音的動(dòng)作組合起來,實(shí)現(xiàn)每跳一次就能播放音效的功能!

          得分音效

          保存 Player 腳本以后打開 Game 腳本,來添加得分音效,首先仍然是在 properties 中添加一個(gè)屬性來引用聲音文件資源:

          // Game.js
           properties: {
           // ...
           // 得分音效資源
           scoreAudio: {
           default: null,
           type: cc.AudioClip
           }
           },
          

          然后在 gainScore 方法里插入播放聲音的代碼:

          // Game.js
           gainScore: function () {
           this.score += 1;
           // 更新 scoreDisplay Label 的文字
           this.scoreDisplay.string = 'Score: ' + this.score.toString();
           // 播放得分音效
           cc.audioEngine.playEffect(this.scoreAudio, false);
           },
          

          保存腳本,回到 層級管理器 ,選中 Player 節(jié)點(diǎn),然后從 資源管理器 里拖拽 assets/audio/jump 資源到 Player 組件的 Jump Audio 屬性上。

          然后選中 Canvas 節(jié)點(diǎn),把 assets/audio/score 資源拖拽到 Game 組件的 Score Audio 屬性上。

          這樣就大功告成了!完成形態(tài)的場景層級和各個(gè)關(guān)鍵組件的屬性如下:

          現(xiàn)在我們可以盡情享受剛制作完成的游戲了,您能打到多少分呢?別忘了您可以隨時(shí)修改 Player 和 Game 組件里的移動(dòng)控制和星星持續(xù)時(shí)間等游戲參數(shù),來快速調(diào)節(jié)游戲的難度。修改組件屬性之后需要保存場景,修改后的數(shù)值才會(huì)被記錄下來。

          總結(jié)

          恭喜您完成了用 Cocos Creator 制作的第一個(gè)游戲!希望這篇快速入門教程能幫助您了解 Cocos Creator 游戲開發(fā)流程中的基本概念和工作流程。如果您對編寫和學(xué)習(xí)腳本編程不感興趣,也可以直接從完成版的項(xiàng)目中把寫好的腳本復(fù)制過來使用。


          主站蜘蛛池模板: 无码一区二区三区中文字幕| 久久久久久人妻一区精品| 免费无码VA一区二区三区| 在线视频精品一区| 亚洲福利一区二区| 国产精品一区二区电影| 精品一区二区视频在线观看| 人妻无码一区二区三区四区| 无码人妻一区二区三区av| 国产福利电影一区二区三区,亚洲国模精品一区 | 亚洲日韩一区精品射精| 中文字幕亚洲一区二区三区| 国产亚洲无线码一区二区| 亚洲av午夜精品一区二区三区| 国产精品一区二区四区| 国产精品无码一区二区在线观| 亚洲熟女综合色一区二区三区| 91精品一区二区三区久久久久 | 亚洲国产精品一区第二页| 成人无码一区二区三区| 中文字幕日韩人妻不卡一区| 成人午夜视频精品一区| 免费无码一区二区三区蜜桃| 亚洲色无码一区二区三区| 久久精品国产一区二区三区肥胖 | 色国产精品一区在线观看| 亚洲美女一区二区三区| 国产成人精品日本亚洲专一区 | 亚洲综合一区二区精品导航| 久久精品黄AA片一区二区三区 | 精品一区二区高清在线观看| 国产一区二区在线|播放| 国产精品亚洲不卡一区二区三区 | 视频一区二区三区在线观看| 一区二区视频在线免费观看| 国产午夜精品一区二区三区嫩草| 亚洲AV无码一区东京热久久| 韩国理伦片一区二区三区在线播放| 国产福利无码一区在线| 亚洲日本中文字幕一区二区三区| 日韩欧国产精品一区综合无码|