物理 (Physics)

物理身體 (Physics Body)

Corona SDK 中預設的物理身體是方形,他的長寬取決於當下的顯示物件大小,有些時候,方形的物理身體無法滿足我們,像是形狀接近三角形的飛機會需要一個三角形的物理身體,更不用說其它更複雜的圖形了,在 Corona SDK 之中支援了不少物理身體形態,當然你也可以在本模板使用它們,它們分為:

圓形身體 (Circular Body)

透過 radius 半徑畫出圓形的物理身體。

    enemy:setBody({radius = enemy.width/2*0.6})

方形身體 (Rectangular Body)

預設物理身體的進階版,你可以改變身體大小與位移。

    enemy:setBody({
        box = {
            halfWidth = enemy.width/5, 
            halfHeight = enemy.height/5,
            x = 0,
            y = enemy.height * 0.3,
            angle = 45,
        }
    })

突多邊形身體 (Polygon Body)

直接帶入突多邊形的點,注意點的順序要是順時針而且不能用這個方法帶入凹多邊形。這邊用了一個迴圈去根據螢幕大小調整突多邊形大小。

    local pentagonShape =  { 0,-37, 37,-10, 23,34, -23,34, -37,-10 }

    for i = 1, #pentagonShape do
        pentagonShape[i] = pentagonShape[i] * gameConfig.scaleFactor * 0.6
    end

    enemy:setBody({
        shape = pentagonShape
    })

邊線身體 (Edge Shape (Chain) Body)

邊線身體是一個沒有被填滿的邊線,你可以透過 connectFirstAndLastChainVertex 決定第一個點是不是要和最後一個點相連。

    local chainPoints = { -120,-140, -100,-90, -80,-60, -40,-20, 0,0, 40,0, 70,-10, 110,-20, 140,-20, 180,-10 }
    for i = 1, #chainPoints do
        chainPoints[i] = chainPoints[i] * gameConfig.scaleFactor * 0.6
    end

    enemy:setBody({
        chain = chainPoints,
        connectFirstAndLastChainVertex = true
    })

Outline Body

直接透過 graphics.newOutline 方法產生可以當作邊界參數的點。由於預設的邊線中心點不同,我們需要一個 for 迴圈去調整它。graphics.newOutline 的第一個參數決定邊線的完整程度,數字越小越完整,越影響效能,反之邊線較不完整,效能較佳。

    local outline = graphics.newOutline(50, Sprite["expansion-4"].getSheet(), Sprite["expansion-4"].getFrameIndex("Ships/22"))

    for i = 1, #outline do
        if i % 2 == 1 then
            outline[i] = outline[i] - enemy.width/2
        else
            outline[i] = outline[i] - enemy.height/2
        end
    end
    enemy:setBody({
        chain = outline,
        connectFirstAndLastChainVertex = true
    })

注意當你要重新調整物理身體大小時,必須要重啟該物件的物理引擎,以下例子將敵人的大小增加至兩倍,並重新調整其物理身體大小。

local Enemy = require("Enemy")
local Sprite = require("Sprite")
local gameConfig = require("gameConfig")
local MyEnemy = {}

MyEnemy.new = function()
    local enemy = Enemy.new()
    local sprite = Sprite["expansion-4"].new("Ships/22")
    enemy:insert(sprite)
    --Circular Body

    --enemy:setBody({radius = enemy.width/2*0.6})

    --Rectangular Body 
    --[[
    enemy:setBody({
        box = {
            halfWidth = enemy.width/5, 
            halfHeight = enemy.height/5,
            x = 0,
            y = enemy.height * 0.3,
            angle = 45,
        }
    })
    --]]

    --

    --Polygon Body:
    --The coordinates must be defined in clockwise order, and the resulting shape must be convex at all angle points.
    --[[
    local pentagonShape =  { 0,-37, 37,-10, 23,34, -23,34, -37,-10 }

    for i = 1, #pentagonShape do
        pentagonShape[i] = pentagonShape[i] * gameConfig.scaleFactor * 0.6
    end

    enemy:setBody({
        shape = pentagonShape
    })
    --]]

    --Edge Shape (Chain) Body: Edge shapes are not restricted to convex angles like polygonal bodies.
    --[[
    local chainPoints = { -120,-140, -100,-90, -80,-60, -40,-20, 0,0, 40,0, 70,-10, 110,-20, 140,-20, 180,-10 }
    for i = 1, #chainPoints do
        chainPoints[i] = chainPoints[i] * gameConfig.scaleFactor * 0.6
    end

    enemy:setBody({
        chain = chainPoints,
        connectFirstAndLastChainVertex = true
    })
    --]]

    --Outline Body
    --[[
    local outline = graphics.newOutline(50, Sprite["expansion-4"].getSheet(), Sprite["expansion-4"].getFrameIndex("Ships/22"))

    for i = 1, #outline do
        if i % 2 == 1 then
            outline[i] = outline[i] - enemy.width/2
        else
            outline[i] = outline[i] - enemy.height/2
        end
    end
    enemy:setBody({
        chain = outline,
        connectFirstAndLastChainVertex = true
    })
    --]]
    enemy:enablePhysics()
    --[[
    enemy:addTimer(2000, function ()
        enemy:scaleWithChangedBody()
    end)
    --]]
    function enemy:scaleWithChangedBody()
        transition.to(self, {
            xScale = 2,
            yScale = 2,
            onComplete = function()
                enemy:setBody({
                    box = {
                        halfWidth = enemy.width, 
                        halfHeight = enemy.height,
                        x = 0,
                        y = 0,
                        angle = 0,
                    }
                })
                local vx, vy = enemy:getLinearVelocity()
                enemy:reInitPhysics()
                enemy:setLinearVelocity(vx, vy)
            end
        })
    end

    return enemy
end

return MyEnemy

results matching ""

    No results matching ""