遊戲實作部分
一、遊戲關卡實作
這裡就隻放兩個關卡(其餘大部分重複性,還不好看:( ),關卡設計圖的草紙找不到了,就不放出來了。
初始情況下,玩家控制的膠體方塊角色出現在螢幕左下角的盒子中,上方的白字是遊戲目前關卡的倒計時,左上方的房子圖示是傳回主界面的按鈕,右上方是本關卡的重新開始按鈕。在這個關卡中,四周的邊界被剛體覆寫,地圖中有障礙物的箱子以及剛體性質的綠球,以及右下角的通關旗幟。在第一關,主要是幫助玩家熟悉各種操作,了解膠體角色的運動方式和操控效果,觀察膠體角色與剛體球的碰撞效果。總的來說,第一關是所有關卡中,最簡單的一關。

這關是特别設定的特殊關卡。因為遊戲引用的第三方LiquidFun庫也有對流體的模拟,是以又增加了一個粒子組,用來模拟水粒子,制造出水池。水池的特點是,距離水面越遠,受到的阻力就越大。在本關中,玩家需操控膠體角色,進入模拟的水池中,通過水粒子的阻擋,到達右下角的終點。此關的設定,不僅僅是為了提高遊戲的可玩性,還能在遊戲中看到膠體和流體粒子的碰撞效果,是設定較耗費時間的一個關卡。
二、詳細實作
2.1 定義重力
要建立實體世界,我們首先需要定義實體世界的重力值,定義一個力向量作為實體世界的重力值。其次,因為CocosCreator遊戲引擎的結構限制,為了保證world為全局變量,能在各個場景都能使用同一個實體世界,是以将實體世界的定義放入word.js中,并将其作為插件導入項目中。代碼實作如下:
var gravity = new b2Vec2(0, -10);//方向沿着Y軸豎直向下,大小為10N
window.world=new b2World(gravity,true);
var world=window.world;
2.2 實體剛體的建立
見下圖所示。在實體世界已存在的情況下,所有剛體建立的瞬間即具有實體特性,成為實體世界的一部分。
2.3 實體剛體的建立
剛體又被叫做實體實體,是實體世界的基本單元。要想建立一個剛體,就需要先建立一個剛體定義類來定義這個剛體,代碼實作如下:
var bd = new b2BodyDef();
var body = world.CreateBody(bd);//建立剛體
通過剛體定義類,我們能夠設定剛體的初始位置,類型,旋轉角度等其他屬性。剛體類型有b2_staticBody、b2_kinematicBody和b2_dynamicBody三種,詳細内容見下面的表格所示。
剛體定義類内容表:
剛體定義類 | 類型内容 |
b2_kinematicBody | 運動學物體,具有無限大的品質,會進行移動并與自身的移速有關。且不受力的作用,不能和同類或靜态物體發生碰撞。 |
b2_dynamicBody | 動态物體,是擁有有限的非零品質。此類物體可以和任何物體碰撞。 |
b2_staticBody | 靜态物體,不能移動,但是擁有無限大的品質。此類物體不能和同類或運動學物體碰撞。 |
在剛體定義類設定完成後,我們就可以建立出剛體。然後通過建立形狀定義類來設定剛體的形狀。形狀定義類包括b2PolygonShape、b2Circle、b2EdgeShape和b2ChainShape,詳細内容見下面表格所示。
形狀定義類内容表:
形狀定義類 | 類型内容 |
b2PolygonShape | 多邊形形狀。隻能表示凸多邊形,可以通過添加節點的方式定制多邊形形狀,預設頂點數不超過8個。 |
b2Circle | 圓形形狀。圓形不能是空心的。 |
b2EdgeShape | 邊緣形狀。邊緣形狀由多條線段組成,不能與邊緣形狀與鍊形狀發生碰撞。 |
b2ChainShape | 鍊形狀。鍊形狀是一個自由形式序列的線段,具有雙面碰撞,但不能與邊緣形狀與鍊形狀發生碰撞。它提供了一種高效的方法建立多邊形和環,鍊形狀不能自身交叉,那樣可能會出現未定義行為。 |
在形狀定義完成後,即可将其設定為剛體設定形狀,剛體即建立完成,代碼實作如下:
body.CreateFixtureFromShape(shape, 1);
函數的第一個參數為形狀定義類,第二個參數為該剛體的密度。
在剛體建立完畢後,因為實體世界的坐标與我們使用的CC世界裡的坐标是不一樣的。是以我們在建立剛體後,還要将坐标轉換,代碼實作如下:
bd.position = new b2Vec2(position.x,position.y);
2.4 實體膠體和流體的建立
實體膠體的建立與剛體的建立類似。不同的是,我們需要先建立一個粒子系統定義類。粒子系統定義類中定義了粒子系統中單個粒子的半徑,摩擦力等屬性。定義完成後即可建立粒子系統,代碼實作如下:
var psd = new b2ParticleSystemDef();
var particleSystem = world.CreateParticleSystem(psd);
粒子系統建立完成後,需要建立粒子系統分組。我們在遊戲中,隻使用一個粒子系統。但是因為要再建立水粒子,是以我們需要兩個粒子組,對兩個粒子組進行不同的渲染。粒子系統分組定義類中必須定義分組的形狀,分組形狀與剛體形狀通用,決定了粒子分組在實體世界的初始形狀與位置。建立粒子系統分組定義類,代碼如下:
var pd = new b2ParticleGroupDef();
pd.shape = shape;
Let group=particleSystem.CreateParticleGroup(pd);
粒子系統成功建立後,通過使用遊戲引擎自帶的渲染元件graphics,即可使粒子系統的粒子獲得顔色。然後我們要在視覺效果上,讓粒子系統具有膠體或者是流體的效果,粒子類型可以通過b2ParticleFlag來進行定義,定義完成後,即可在實體世界中創造出膠體效果。粒子類型更詳細的内容見下面表格所示,代碼實作如下:
pd.flags=b2_elasticParticle|b2_staticPressureParticle|b2_repulsiveParticle|b2_elasticParticle ;
粒子類型内容表:
粒子類 | 類型内容 |
b2_waterParticle | 水顆粒。 |
b2_springParticle | 粒子系統通過伸展可以恢複原狀。 |
b2_elasticParticle | 粒子系統随着變形可以恢複原狀。 |
b2_powderParticle | 粒子之間沒有各向同性的壓力 |
b2_repulsiveParticle | 粒子之間具有很高的排斥力。 |
b2_staticPressureParticle | 壓縮性較差。 |
實體膠體在實體世界建立完成後,我們需要對其進行實時繪制。LiquidFun提供了一個接口,幫助我們實時擷取粒子系統各粒子的目前坐标。下面中的particles是一個浮點數型數組,以兩個浮點數為機關,存儲了所有粒子的目前坐标值。代碼實作如下:
var particles = particleSystems.GetPositionBuffer();
var maxParticles = particles.length;
但是想要在關卡已有一個膠體角色的場景中,再建立一個水池的流體效果,就還需要建立一個粒子組。代碼實作如下:
var pd1 = new b2ParticleGroupDef();//粒子組定義包含構造粒子組所需的所有資料
pd1.shape = shape1;//一組形狀,其中将添加粒子
pd1.flags=b2_waterParticle;//流體效果
在繪制判斷時,我們還需要要獲得不同粒子組的粒子數,這樣才能對兩個粒子組分别進行渲染繪制,代碼實作如下:
for (let i=system.particleGroups[1].GetBufferIndex()*2; i<maxParticles;i += 2);
2.5 實體膠體的控制及銷毀
在膠體角色建立完成之後,我們要實作對角色的控制,就要通過監聽鍵盤事件來控制膠體角色。定義事件監聽函數Listener,并将其加入到事件管理器中。在每次更新時,根據不同的按鍵,在不同的方向上給膠體角色,在實體世界内給膠體的粒子系統施加力,使其在遊戲畫面中能産生移動效果,代碼實作如下:
cc.eventManager.addListener(listener,self.node);
if(world.particleSystems.accLeft){
group.ApplyLinearImpulse(new b2Vec2(-1000,0));}
if(world.particleSystems.accRight){
group.ApplyLinearImpulse(new b2Vec2(1000,0));}
if(world.particleSystems.accUp){
group.ApplyLinearImpulse(new b2Vec2(0,5000));}
if(world.particleSystems.accDown){
group.ApplyLinearImpulse(new b2Vec2(0,-5000));}
遊戲的實體世界是在world.js中建立的,是以我們隻有一個實體世界。但是因為我們不隻有一個關卡,在每個關卡加載時,我們都會建立一個新的粒子系統,并對其進行渲染繪制。為了避免在同一個場景出現兩個膠體的情況,我們在每次場景轉換時都要對建立的剛體、膠體和流體進行銷毀,代碼實作如下:
while (world.joints.length > 0) {
world.DestroyJoint(world.joints[0]);}
while (world.bodies.length > 0) {
world.DestroyBody(world.bodies[0]);}
while (world.particleSystems.length > 0) {
world.DestroyParticleSystem(world.particleSystems[0]);}
2.6 背景伺服器
本遊戲背景伺服器使用Node.js搭建,監聽端口設定為7456。對于玩家發送的伺服器請求,伺服器共有以下幾個子產品處理:
注冊子產品:
注冊子產品負責遊戲的注冊功能。浏覽器端發送的資料集包括玩家申請的使用者名與密碼。伺服器會先查詢資料庫判定使用者名是否被占用,如果被占用則會傳回一個失敗信号給浏覽器端。否則,向資料庫中插入新玩家的資料,并向浏覽器端傳回成功信号。
登入子產品:
登入子產品負責遊戲的登入功能。浏覽器端發送的資料集包括玩家填寫的使用者名與密碼。伺服器會先查詢資料庫判定使用者名是否存在,如果已經存在,再判斷使用者密碼是否符合,如果密碼正确則傳回該使用者的使用者名與最大通關數。反之,傳回的資料為null。
得分更新子產品:
得分更新子產品負責遊戲的關卡得分更新。當玩家通過關卡時,系統自動發送得分更新請求給伺服器。如果該玩家第一次通過該關卡,該關卡的得分資料直接插入資料庫中。反之,伺服器會對目前得分與資料庫中記錄的該玩家在該關卡中的最高得分進行比較,新的得分如果更高,則更新資料庫中的得分資料。
排行榜子產品:
排行榜子產品負責遊戲的排行榜查詢。當玩家檢視排行榜時,浏覽器端會發送排行榜查詢請求。伺服器得到關卡号後,查詢資料庫,從高到低列出前20條資料,存儲在數組中傳回給浏覽器端。數組中的每個元素包含對應玩家的使用者名與其在該關卡中的得分。
如果對你有幫助的話,就點個贊吧:)
系列已結束,其餘部分見:
(一)https://blog.csdn.net/packdge_black/article/details/103464278
(二)https://blog.csdn.net/packdge_black/article/details/106242955
(四)https://blog.csdn.net/packdge_black/article/details/107466701