咱們先介紹輕量級的物理引擎——Chipmunk。Chipmunk物理引擎,由Howling Moon Software的Scott Lebcke開發,用純C編寫。Chipmunk的下載地址是http://code.google.com/p/chipmunk-physics/,技術論壇是http://chipmunk-physics.net/forum。
Chipmunk核心概念
Chipmunk物理引擎有一些本身的核心概念,這些核心概念主要有:
空間(space)。物理空間,全部物體都在這個空間中發生。
物體(body)。物理空間中的物體。
形狀(shape)。物體的形狀。
關節(joint)。用於鏈接兩個物體的約束。
使用Chipmunk物理引擎的通常步驟
使用Chipmunk物理引擎進行開發的通常步驟,以下圖所示。
javascript
使用Chipmunk物理引擎的通常步驟html
從圖中可見使用Chipmunk引擎步驟仍是比較簡單的。咱們還須要本身在遊戲循環中將鏈接精靈與物體起來,這可以使得精靈與物體的位置和角度等狀態同步。最後的檢測碰撞是根據業務需求而定,也多是使用關節。
實例:HelloChipmunk
咱們經過一個實例介紹一下,在Cocos2d-JS中使用Chipmunk物理引擎的開發過程,熟悉這些API的使用。這個實例運行後的場景以下圖所示,當場景啓動後,玩家能夠觸摸點擊屏幕,每次觸摸時候,就會在觸摸點生成一個新的精靈,精靈的運行自由落體運動。
html5
HelloChipmunk實例java
下面咱們看一下代碼部分,app.js文件中HelloWorldLayer初始化相關代碼以下:
json
[html] view plaincopy瀏覽器
var SPRITE_WIDTH = 64; ① 微信
var SPRITE_HEIGHT = 64; ② app
var DEBUG_NODE_SHOW = true; ③ 函數
var HelloWorldLayer = cc.Layer.extend({ ④ 網站
space: null, ⑤
ctor: function () {
this._super();
this.initPhysics(); ⑥
this.scheduleUpdate(); ⑦
}
… …
});
上述第①行代碼是定義精靈寬度常量SPRITE_WIDTH,第②行代碼是定義精靈高度常量SPRITE_HEIGHT,第③行代碼是定義是否繪製調試遮罩開關常量DEBUG_NODE_SHOW。
第④行代碼是聲明HelloWorldLayer層。第⑤行代碼聲明物理空間成員變量space。第⑥行代碼是在構造函數中調用this.initPhysics()語句實現初始化物理引擎。第⑦行代碼是在構造函數中調用this.scheduleUpdate()語句開啓遊戲循環,一旦開啓遊戲循環就開始回調update(dt)函數。
HelloWorldLayer中調試相關函數setupDebugNode代碼以下:
setupDebugNode: function () {
this._debugNode = new cc.PhysicsDebugNode(this.space); ①
this._debugNode.visible = DEBUG_NODE_SHOW; ②
this.addChild(this._debugNode); ③
}
上述代碼第①行建立PhysicsDebugNode對象,它是一個物理引擎調試Node對象,參數是this.space物理空間成員變量。第②行代碼是設置繪製調試遮罩visible屬性。第③行代碼是將調試遮罩對象添加到當前層,以下圖所示是設置visible屬性true。
繪製調試遮罩
注意 繪製調試遮罩在JSB本地方式下運行沒有效果,在Web瀏覽器下運行纔可以看到效果。
HelloWorldLayer中觸摸事件相關的代碼以下:
[html] view plaincopy
onEnter: function () {
this._super();
cc.log("onEnter");
cc.eventManager.addListener({
event: cc.EventListener.TOUCH_ONE_BY_ONE,
onTouchBegan: this.onTouchBegan
}, this);
},
onTouchBegan: function (touch, event) {
cc.log("onTouchBegan");
var target = event.getCurrentTarget();
var location = touch.getLocation();
target.addNewSpriteAtPosition(location); ①
return false;
},
onExit: function () {
this._super();
cc.log("onExit");
cc.eventManager.removeListeners(cc.EventListener.TOUCH_ONE_BY_ONE);
}
上述代碼第①行是調用當前層的addNewSpriteAtPosition函數實現是在觸摸點添加精靈對象,其中target是當前層對象,注意這裏不能使用this。
HelloWorldLayer中初始化物理引擎initPhysics()函數代碼以下:
[html] view plaincopy
initPhysics: function () {
var winSize = cc.director.getWinSize();
this.space = new cp.Space(); ①
this.setupDebugNode(); ②
// 設置重力
this.space.gravity = cp.v(0, -100); ③
var staticBody = this.space.staticBody; ④
// 設置空間邊界
var walls = [ new cp.SegmentShape(staticBody, cp.v(0, 0),
cp.v(winSize.width, 0), 0), ⑤
new cp.SegmentShape(staticBody, cp.v(0, winSize.height),
cp.v(winSize.width, winSize.height), 0), ⑥
new cp.SegmentShape(staticBody, cp.v(0, 0),
cp.v(0, winSize.height), 0), ⑦
new cp.SegmentShape(staticBody, cp.v(winSize.width, 0),
cp.v(winSize.width, winSize.height), 0) ⑧
];
for (var i = 0; i < walls.length; i++) {
var shape = walls[i];
shape.setElasticity(1); ⑨
shape.setFriction(1); ⑩
this.space.addStaticShape(shape); ⑪
}
}
代碼第①行new cp.Space()是建立物理空間。第②行代碼this.setupDebugNode()是設置調試Node對象。第③行代碼this.space.gravity = cp.v(0, -100)是爲空間設置重力,cp.v(0, -100)是建立一個cp.v結構體,cp.v是Chipmunk中的二維矢量類型,參數(0, -100)表示只有重力做用物體,-100表示沿着y軸向下,其中的100也是一個經驗值。
第④行代碼var staticBody = this.space.staticBody得到從物理空間中得到靜態物體。
代碼第⑤~⑧是建立物理空間,它是由4條邊線段形狀構成的,從上到下分別建立了這4個線段形狀(cp.SegmentShape),new cp.SegmentShape語句能夠建立一條線段形狀,它的構造函數有4個參數,第一個形狀所附着的物體,因爲是靜態物體,本例中使用this.space.staticBody表達式得到靜態物體。第二個參數是線段開始點,第三個參數是線段結束點,第四個參數是線段的寬度。
代碼第⑨~⑪行是設置線段形狀屬性,因爲有4個邊須要進行循環。其中第⑨行代碼是經過函數shape.setElasticity(1)設置彈性係數屬性爲1。第⑩行代碼shape.setFriction(1)設置摩擦係數。
第⑪行代碼this.space.addStaticShape(shape)是將靜態物體與形狀關聯起來。
HelloWorldLayer中建立精靈addNewSpriteAtPosition()函數代碼以下:
[html] view plaincopy
addNewSpriteAtPosition: function (p) {
cc.log("addNewSpriteAtPosition");
var body = new cp.Body(1, cp.momentForBox(1, SPRITE_WIDTH, SPRITE_HEIGHT)); ①
body.setPos(p); ②
this.space.addBody(body); ③
var shape = new cp.BoxShape(body, SPRITE_WIDTH, SPRITE_HEIGHT); ④
shape.setElasticity(0.5);
shape.setFriction(0.5);
this.space.addShape(shape); ⑤
//建立物理引擎精靈對象
var sprite = new cc.PhysicsSprite(res.BoxA2_png); ⑥
sprite.setBody(body); ⑦
sprite.setPosition(cc.p(p.x, p.y));
this.addChild(sprite);
}
上述代碼第①行代碼是使用cp.Body構造函數建立一個動態物體,構造函數第一個參數質量,這裏的1是一個經驗值,咱們能夠經過改變它的大小而改變物體的物理特性。第二參數慣性值,它決定了物體運動時受到的阻力,設置慣性值使用cp.momentForBox函數。cp.momentForBox函數是計算多邊形的慣性值,它的第一個參數是慣性力矩[ 慣性力矩,也叫「MOI」,是Moment Of Inertia的縮寫,慣性力矩是用來判斷一個物體在受到力矩做用時,容不容易繞着中心軸轉動的數值。——引自於百度百科 http://www.baike.com/wiki/慣性力矩],這裏的1也是一個經驗值,第二個參數是設置物體的寬度,第三個參數是設置物體的高度,相似的函數還有不少,如cp.momentForBox、cp.momentForSegment和cp.momentForCircle等。
第②行代碼body.setPos(p)是設置物體重心(物體的幾何中心)的座標。第③行代碼this.space.addBody(body)是把物體添加到物理空間中。
第④行代碼是建立cp.BoxShape形狀對象。第⑤行代碼this.space.addShape(shape)是添加形狀到空間中。
第⑥行代碼是建立物理引擎精靈對象,其中cc.PhysicsSprite是由Cocos2d-JS提供的物理引擎精靈對象,採用cc.PhysicsSprite類自動地將精靈與物體位置和旋轉角度同步起來,咱們在遊戲循環函數中須要簡單的語句就能夠實現它們的同步了。代碼第⑦行sprite.setBody(body)是設置精靈所關聯的物體。
HelloWorldLayer中建立精靈update函數代碼以下:
[html] view plaincopy
update: function (dt) {
var timeStep = 0.03; ①
this.space.step(timeStep); ②
}
上述代碼第①行的timeStep表示自上一次循環過去的時間,它影響到物體本次循環將要移動的距離和旋轉的角度。咱們不建議使用update 的dt參數做爲timeStep,由於dt時間是上下浮動的,因此使用dt做爲timeStep時間,物體的運動速度就不穩定。咱們建議使用固定的timeStep時間。
第②行代碼this.space.step(timeStep)更新物理引擎世界。
最後咱們要修改project.json文件,添加模塊聲明,代碼以下:
[html] view plaincopy
{
"project_type": "javascript",
"debugMode" : 1,
"showFPS" : true,
"frameRate" : 60,
"id" : "gameCanvas",
"renderMode" : 2,
"engineDir":"frameworks/cocos2d-html5",
"modules" : ["cocos2d", "external"], ①
"jsList" : [
"src/resource.js",
"src/app.js"
]
}
咱們在第①行"modules"配置中添加external模塊,external模塊包含了chipmunk等子模塊,這些模塊的定義你們能夠打開<工程目錄>\frameworks\cocos2d-html5\ moduleConfig.json,這裏Cocos2d-JS的全部模塊,以及每一個模塊所包含的js文件。
更多內容請關注最新Cocos圖書《Cocos2d-x實戰:JS卷——Cocos2d-JS開發》
本書交流討論網站:http://www.cocoagame.net
歡迎加入Cocos2d-x技術討論羣:257760386
更多精彩視頻課程請關注智捷課堂Cocos課程:http://v.51work6.com
智捷課堂現推出Cocos會員,敬請關注:http://v.51work6.com/courseInfoRedirect.do?action=netDetialInfo&courseId=844465&categoryId=0
《Cocos2d-x實戰 JS卷》現已上線,各大商店均已開售:
京東:http://item.jd.com/11659698.html
歡迎關注智捷iOS課堂微信公共平臺,瞭解最新技術文章、圖書、教程信息