A. html5中怎麼畫菱形,多邊形
使用transform的skew(),例如 transform:skewX(10deg)
B. 如何用Box2D Library製作2D物理游戲
作者:Juan Felipe Belon Perez
從最熱門游戲排行榜和flash游戲網站上,你能看到什麼?許多2D游戲都有非常出色的物理學和美術設計。現在我們要學習那些游戲使用了什麼物理學以及如何用Box2D製作它們。
除了知道是「什麼」,更重要的是知道「如何做」,首先,我想問讀者一個問題:如果你想復制物理游戲的機制或行為,你需要什麼技術和方法?
一年以前,我問了自己同樣的問題,《6 Dimensions》就是問題的答案。這款游戲是一個創意的盒子,每一面都包含一組使用Box2D物理學再加上視覺美學技術製作的不同的游戲機制。在此,我將與大家分享這款游戲。我做這款游戲是為了改進游戲引擎Codea(是由Crabitron開發的),而我寫了這篇教程是為了向大家介紹寫實物理學、美術和游戲設計……共同提高我們的游戲開發水平。
在我的游戲中,我設計了6個面,借同樣的思路,我將給大家介紹我運用了哪些從其他游戲中復制而來的物理、機制和美術技術。
1、形狀
《Thomas was alone》、《憤怒的小鳥》、《蠟筆物理學》
crayon physics(from gamasutra)
在《蠟筆物理學》中,你可以在屏幕上用手指或滑鼠作畫,比如畫圓、三角形、矩形等,當你松開滑鼠/拿開手指,線條就會變成立體物理對象(在虛擬世界中)。
這是怎麼做的?
事實上相當簡單,你要把滑鼠/手指從開始到結束的繪畫路徑的各個坐標點保存起來,當釋放事件發生,你就調用Box2D的一個根據這些點生成多邊形的功能:
local body = physics.body(POLYGON, unpack( points ) )
你得先認識一下Box2D中的有什麼形狀:
POLYGON(多邊形):
用於封閉形狀如基本幾何圖形(非圓形),它使用一系列按各個API指定的順序排列的頂點(x,y)
CIRCLE(圓):
可以做球、水珠、星體,等等。
EDGE(邊):
用於製作牆、地面、只有起點和終點的線段。
CHAIN(鏈):
與邊相同,但你可以閉合它(像多邊形但不是凸多邊形)或不閉合它(像邊但點超過2)
知道了剛體形狀(body shape)後,你還要了解它們的不同行為,或叫作剛體類型(body types):
STATIC(靜態):如名稱所示,這種剛體會在指定的x,y(地面、牆、柱基或繩基,等等)上保持靜止不動。
DYNAMIC(動態):它與其他對象碰撞並移動
KINEMATIC(運動):碰撞但不隨著動態對象移動,你只能通過改變它的x,y或者賦給它一個線性速度或對它施加力來使它移動。
真正的含義要在API的執行中理解,在本文中我使用這個是因為它是我能找到的最簡單的代碼了。但改變成任何語言的代碼都非常簡單,Box2D有幾乎所有的語言版本(Flash as3、c++、objc、java、javascript、java+processing,等等)。
你得保存那個功能的結果為自定義變數如body.position(位置)、body.radius(半徑)、body.linearVelocity(線性速度)、body.angularVelocity(角速度)、body.mass(質量),等等。
當剛體製作出來時,你可能想給它定義一些屬性如restitution(恢復)、gravityScale(重力大小)和damping(衰減)等,這些屬性可以賦給物理對象彈跳或漂浮狀態。
Box2D的復雜度當然不止這些,具有這種物理游戲機制的其他游戲(《Magic Pen》)也比較復。在《Magic Pen》中,你可以畫一些東西看起來像「node(節點)」的東西,但開發者叫它們「joint(關節)」,它們是用於連接剛體的,有若干種,取決於你想要的機制;還可以用於製作連接著的剛體之間的行為:
physics.joint(REVOLUTE,bodyA, bodyB,)
剛體圍繞著一個固定點(anchor)旋轉
例如:小車的車輪、《蠟筆物理學》和《Magic Pen》中的紅色節點
physics.joint( PRISMATIC, bodyA, bodyB, anchorA, direction )
在剛體各自的固定點之間保持固定距離。兩個joint之間的初始距離取決於虛擬空間中的這兩個固定點之間的初始距離。給joint設置frequency率和damping率可以使它產生軟彈簧的行為。
physics.joint(DISTANCE, bodyA, bodyB, anchorA, anchorB )
旋轉joint迫使兩個剛體沿著某兩個固定點之間的軸作運動。允許伸縮運動,但限制兩個剛體之間的相對旋轉。
physics.joint( WELD, bodyA, bodyB, anchor )
接合joint限制兩個剛體之間的運動和相對旋轉,實際上使它們變成一個剛體。因為求解器的迭代性質,當置於壓力之下時接合joint可能會變形;當承受的力太大或幾個接合joint被鏈接成一個更大的對象時,接合joint可能會完全失效。
physics.joint( ROPE, bodyA, bodyB, anchorA, anchorB, maxLength )
繩子joint限制兩個剛體之間的最大距離
例如:《割繩子》中的繩子
概述:
1)創建:帶有觸點剛體或盒子或任何其他多邊形幾何體(一組2D點:x,y),給它設置我們需要的物理屬性(如《Thomas was alone》中的不同行為),比如,如果剛體是static類型,那麼就可以設置它的質量、密度、重力大小,等等。
2)可選屬性:依附(attach)到另一個剛體上,比如說,你可以把一個剛體依附到另一個被設置為感測器的static剛體(不影響游戲世界的物理,但有碰撞事件),然後激活REVOLUTE joint的enableMotor(能動)屬性,這還需要motorSpeed(速度)、maxMotorTorque(轉矩)和maxMotorForce(力量),才能確定這個對象的旋轉情況。
3)美術(Visual Art):有了剛體後,如果你想繪制它,不是作為形狀繪制出來,而是具有顏色或紋理的實體,你就要把這些點三角化生成多邊形網格模型(mesh)並給它設置顏色和貼材質。
例子:
Box2D_POLYGONS(from gamasutra)
thomas Was Alone Boxes(from gamasutra)
對於《Thomas Was Alone》中的盒子的行為,你可以設置一個簡單的「juice」系統動畫(從「中間幀」演化來的),這樣,當你選擇方塊並按下跳躍鍵(或它與其他不同的物理剛體發生碰撞),它就會觸發「juice command= animation」命令——產生擠壓、搖晃等動畫效果,各個動作都有自己的動畫參數,比如質量、線性速度和衰減等物理屬性。
box Examples(from gamasutra)
對於《憤怒的小鳥》,你可以通過給盒子定義不同的屬性來製作一個關卡,繪制不同的子畫面或製作不同材質的mesh,這樣,在碰撞事件中,盒子剛體就會更加生動,通過改變盒子的紋理使之與當前狀態更加協調(斷掉的木頭、快碎的玻璃,等)。
你可以用簡單的剛體applyForce(vec2(x,y)) 函數做出小鳥的發射。各種小鳥也都有自己的質量、衰減等屬性……
2、水體
《Where is my water?》、《Sprinkle Ilsands》……
當你問網上的代碼達人,如何製作上述游戲那樣的水體物理時,他們會跟你談Metaball(變形球):
Metaball_contact_sheet(from gamasutra)
但在游戲中使用Metaball技術既麻煩也不容易,而且要進行大量計算,除非你發現一些技巧和給它貼上一些美術材質。
那就是為什麼運用水體物理學的游戲並不多見。幾個月前我談到這個問題,多虧了許多人的幫助,我得到了一個很棒的水體物理模型。在那個模型中,我用Box2D lib中的CIRCLE剛體做出動態球。
模型的代碼很容易理解,球就是物理剛體,這些剛體具有使它產生水滴行為的參數如estitution(復原)、friction(摩擦)、damping(衰減)、linear velocity(線性速度),然後,我們用著色器(GLSL)的技術和材質繪制這些球,需要一個mesh,就像波紋fx或使用材質的其他GLSL著色器樣本,我們把這個mesh的寬和高設為整個屏幕,從中間開始:
mesh:addRect(WIDTH / 2, HEIGHT / 2, WIDTH, HEIGHT)
這樣,我們可以使用各個球的位置(x,y)在虛擬空間中繪制它們,各個球都有漸變的紋理效果。
for k,b in ipairs(balls) do
sprite(ballTexture, b.x, b.y)
end
然後,你得使用額外的扭曲模式,給這些著色的球添加材質,並與背景混合。
例子:
Box2D_water Physics(from gamasutra)
正如我所說的,各個球都有紋理(程序生成的漸變),可以與其他使用低級過濾器的球材質相融合。
where is my water(from gamasutra)
《Where is my water?》
你可以對各種行為使用不同的層,或者把所有液體或所有動態地形做成同一層來做出相同的水體fx,然後在著色器中改變過濾值和顏色(水體、岩漿,等等)。
舉一個碰撞的例子,當兩個剛體發生碰撞時,你必須查看碰撞的bodyA和bodyB是什麼類型的剛體,如果一個是氣體(gravityScale/mass/density值實際上是0,所以它會飄浮)而另一個是「冰」,那麼你就把這個球變成水……
再舉一個例子,如果bodyA是岩漿,那麼bodyB就變成氣體……就像改變球的屬性一樣簡單,所以它會改變在box2d中響應,你要重新繪制游戲狀態。
地形的例子:
靜態地形可以是一個POLYGON剛體,它是用一個讀取整個地形圖象和建立一系列非透明像素的x,y (vec2)的函數製作的,然後返回給box2d函數。
動態地形可以只是一個mesh,當你碰它時,你會移除座標x,y上的觸點,你必須用新的mesh重製這個物理剛體。
例如,當一個水滴(物理剛體CIRCLE)濺到一隻鴨子(具有激活的感測器的物體剛體),你必須刪除那個水滴,並改變鴨子的動畫,使新狀態呈現,直到它完全被水充滿,然後刪除鴨子並記錄結果。
水滴有很小的痕跡,這些是用linearVelocity和angularVelocity屬性繪制的,你可以得到方向和速度,這樣你就可以計算痕跡的角度和距離。
事實上,你想要什麼行為都有。
sprinkle_islands_boss(from gamasutra)
在《Sprinkle Ilsands》中,水體著色器跟我們所學習的那個是不同的,它除了使用粒子fx,還多了linearVelocity屬性。但行為可能還是一樣的,當水球(剛體CIRCLE)擊中火感測器,那麼火就會熄滅,海里的水mesh也一樣。至於岩石,你可以添加一些細節如顆粒效果等。
在這一面,我們找不到任何joint,那就是為什麼它可能不必要,在《Sprinkle Ilsands》,軟管就是繩子,這是我們在下一面中要分析的。
3、橡皮筋
《Contre Jour》、《割繩子》、《水果忍者》
我花了一個月時間才做出上述游戲的繩子原型,但我做完繩子後,我就覺得軟剛體很容易做了,因為我更加理解接頭了。
要製作一個逼真的繩子,你得創建一組剛體(CIRCLE或者POLYGON都行),把它們都依附在作為基座的STATIC剛體上。用於結合這些繩子剛體的joint有兩種,DISTANCE或者REVOLUTE,但處於最末端(DYNAMIC)的連接基座(STATIC)的joint只能是製作彈力繩的ROPE joint。通過restitution 和frequency屬性來調整response(反應)/damping(衰減)/elasticity(彈性)。
例子:
Box2D_ElasticRopes(from gamasutra)
為了製作一個軟剛體,你得圍繞另一個中心剛體(可以是STATIC或DYNAMIC)製作一系列CIRCLE剛體,它當然會影響其他剛體,如果你改變joint的類型,你會發現這個剛體會自動變形,你必須用mesh繪制整組剛體。
Contre-Jour(from gamasutra)
《Contre Jour》
在這款游戲中,你可以找到軟剛體:可變形的地形;兩種類型的繩子:彈性繩和固定繩。這些固定繩使用的技術比彈性繩的更高級。
snotDiagram(from gamasutra)
js Rope Segmented(from gamasutra)
《割繩子》
cut-the-rope(from gamasutra)
這是Box2d物理做繩子的最佳案例。游戲中的繩子也是動態的,你可以看到沿著基座到球的mesh,球的一端是連著糖果的。
你可以像上一個例子一樣做出這種繩子,設置球(糖果)的物理屬性—-mass、density、gravityScale,可以做出泡泡效果。你可以用多層混合模式繪制出泡泡。另一種方法是把剛體變成感測器,並且你自己的重力演算法移動它,但我們到第五面時才學習這種技術。
如果泡泡-剛體-球與青蛙或蜘蛛碰撞,或者玩家觸擊到泡泡,泡泡就會爆炸,為此你要給泡泡添加爆炸動畫並再次改變糖果的物理屬性……
案例代碼:
if (vec2:distance( bFrog_Mouth, bCandy ) < maxDistance) then
– 把青蛙的動畫從「空閑」改為「吃」
– 暫停輸入
– 補間並觸發游戲結束動畫
end
4、重力
在這一面,我們可以發現許多使用力來對抗重力的游戲,但這是一種游戲玩法。例如,你可以根據box2d的正弦函數生成簡單的地形,它會返回鏈或邊形狀的STATIC剛體。
tiny wings 2(from gamasutra)
你可以用Box2d做出你自己的《Tiny Wings》。基本原理就是,球(CIRCLE剛體)在重力的作用下下落,你可以通過觸擊屏幕增加下落的linearVelocity(線性速度),當觸擊在山丘合適的部分(你可以查看你的正弦函數的高度)釋放時,下落速度會增加……另一種方法是只使用力。
例子:
Box2D_JumpRun(from gamasutra)
為了繪制循環,給拾取、發熱狀態等添加顆粒效果。材質可以用程序成生隨機顏色圖像做出來,用高斯雜訊添加細節、邊界,等等……
Jetpack-Joyride(from gamasutra)
《Jetpack Joyride》
你可以看出這款游戲的特徵嗎?如果你已經讀過前面的例子了,那麼你應該知道角色剛體球有相同的行為,你一定是用力對抗重力、各個飛行器的不同物理屬性、導彈和各種交通工具,等等。
《Madcoaster》、《Rocket Chicken》、《Whale Trail》等游戲都是一樣的。
但這個面還有其他機制,如行星物理、引力。
你可以使用簡單的公式來模擬零重力physics.gravity(0,0),行量的吸引力如下圖所示:
Box2D_Forces_Gravity(from gamasutra)
function Planet:attract(m)
– Direction of the force
local force = self.body.position – m.body.position
local d = force:len() — = m.body.position:dist(self.body.position)
force = force:normalize()
local dir = vec2(self.mass/m.body.mass, self.mass/m.body.mass)
– Magnitude of the force
local strength = (GRAVITY * self.mass * m.body.mass)/(d*d)
force = force * strength
m.body:applyForce(force)
stroke((1+math.floor(force.y))*110, (1+math.floor(force.x))*110, 10, 255)
– draw line between attractor/mover
line(m.body.x+force.x, m.body.y+force.y, (self.body.x), (self.body.y))
end
這個函數會使角色球繞著行星轉。
5、線面
《拯救種子》、《蠟筆物理學》……
只有線:通過繪制線條,你可以做出形狀類CHAIN的剛體和剛體類STATIC或DYNAMIC。
對於關卡設計,障礙物也是STATIC,可以是EDGE或POLYGON……
saving-seeds-hd-doodle-physics-screenshot(from gamasutra)
用那種結構,你可以復制出一款像《拯救種子》一樣的游戲。
Box2D_Lines(from gamasutra)
代碼和第一面的是一樣的,但你必須改變游戲的規則,你要從暫停的物理引擎開始,然後繪制和生成CHAIN靜止形狀,當玩家按下開始鍵時,游戲必須生成玩家的球(以及恢復、重力、質量等參數),重新開啟物理引擎,只要一個指令(physics.pause() and physics.resume())就能完成了。
它只留在游戲循環中,用於確認碰撞和線性速率、改變游戲狀態……
你可以通過打開或關閉重力,來改變整個游戲的現實,就像《Thomas was alone》或《ibb and obb》那樣。
6、交通工具
《小輪車冒險》、《登山賽車》
如果你已經看到這里了,那麼做一款關於瘋狂交通工具的游戲吧。
做交通工作,只要把接頭和輪子想成CIRCLE剛體,用錨點正確的旋轉接頭把POLYGON(小車、自行車等的形狀)和它們連接起來。
用帶紋理的mesh繪制自行車/小車的主要剛體、車輪的子畫面,除非你使用軟剛體做這些,否則添加痕跡、顆粒fx等。
代碼生成的例子:
Box2D_BezierRampage(from gamasutra)
對於道路,使用一些噪點或正弦,可以是STATIC或DYNAMIC,你可以使用Bezier曲線。
code example(from gamasutra)
《小輪車冒險》
我會知道這款游戲和它的物理,多虧看了某人的一篇文章。
但文章作者沒有提到任何有關Box2D的東西,但我猜這款游戲就是使用了Cocos2d(和Corona SDK)。無論如何,你現在知道怎麼製作交通工具和橫沖直撞的效果了。
在《Canvas Rider》中,有兩種自行車模型,你可以在游戲中改變,你會發現自行車的剛體是一個允許一定damping的接頭結構,當你改變自行車時,這個動態剛體就被破壞了,然後游戲就生成新的自行車類型。
另外,你在游戲中的自行車可以觸到的線是靜態CHAIN,當你設計道路時,滑鼠觸擊的是x,y……像我們之前做的那樣。
以上。希望你能用Box2D做出一些成果。
當然,使用Box2D,通過不同的方法製作的游戲還有很多,但它們可能綜合使用了上述幾種,例如,《時空幻境》、《超級食肉男孩》等,用可以用合適的剛體、機制和著色器製作出來。