ฉันจะทำให้พื้นผิวโค้งออกมาจากบล็อกสี่เหลี่ยมได้อย่างไร


12

สำหรับเกมที่เหมือนPeggleฉันต้องการสร้างบล็อกที่ตามหลังโค้งเช่นนี้:

บล็อกตามแนวโค้ง

บล็อกจะหายไปเมื่อลูกบอลกระทบกับพวกเขา

ฉันจัดการเพื่อวาดแนวนอน แต่ฉันมีปัญหาในการทำตามเส้นทาง:

ความพยายามของฉันที่บล็อกติดตามเส้นทาง

ฉันจะทำสิ่งนี้ได้อย่างไร ฉันจำเป็นต้องสร้างวัตถุBox2Dด้วยจุดยอดที่กำหนดเองหรือไม่?


คุณต้องการให้กล่องไม่ทับซ้อนกันหรือคุณต้องการให้ไม่มีช่องว่างหรือไม่? (ฉันไม่แน่ใจว่าสิ่งที่คุณหมายถึงโดย "ชดเชยแกน Y วัตถุตามมุมวัตถุ")
Roy T.

1
คุณไม่สามารถเติมเส้นโค้งด้วยรูปสี่เหลี่ยมผืนผ้าที่ไม่ทับซ้อนกันดังนั้นคุณจะต้องสร้างรูปทรงเรขาคณิตเองหากคุณไม่ต้องการช่องว่าง
Anko

@RoyT ช่องว่างไม่สำคัญ ปัญหาที่แท้จริงของฉันคือการคำนวณตำแหน่งของบล็อกซึ่งตามมาด้วยมุมที่แตกต่างกัน
Moerin

วิธีที่ฉันจะเข้าใกล้สิ่งนี้คือการกำหนดชุดของจุดยอดที่ทำหน้าที่เป็นมุมร่วมระหว่างแต่ละกล่อง แม้จะใช้พา ธ เพื่อกำหนดพวกเขาคุณยังต้องการพารามิเตอร์เพิ่มเติมเพื่อกำหนดระยะห่างระหว่างจุดยอดและระยะเวลาแต่ละกล่อง

4
"กล่อง" ในภาพแรกไม่ใช่กล่องพวกเขาเป็นคู่ของรูปสามเหลี่ยม: i.stack.imgur.com/Tzuql.png
egarcia

คำตอบ:


14

ให้โค้ง "ราก" นี่คือวิธีที่คุณอาจสร้างจุดยอดบล็อก

เบซิเยร์กับบล็อก

เส้นโค้งของรากอยู่ตรงกลางเป็นสีดำ จุดควบคุมมันจะแสดงด้วยสีแดงXs

กล่าวโดยย่อ : ฉันทำBézierและทดลองมัน (ในอัตราที่กำหนดได้) จากนั้นฉันก็พบเวกเตอร์ตั้งฉากของเวกเตอร์จากตัวอย่างแต่ละตัวอย่างไปยังเวกเตอร์ถัดไปทำให้เป็นมาตรฐานและปรับให้เป็นความกว้างครึ่งหนึ่ง (กำหนดค่าได้) เริ่มจากซ้ายไปซ้ายแล้วกลับไปทางขวา จากนั้นดึงมัน

สิ่งที่คุณสามารถเพิ่มในสิ่งนี้:


นี่คือรหัสของฉัน มันเขียนในLua (สำหรับกรอบเกมLÖVE ) แต่ฉันคิดว่ามันอ่านได้สำหรับทุกคน

local v = require "vector"

-- A function that makes bezier functions
-- Beziers have start point     p0
--              control point   p1
--              end point       p2
local function makeBezierFunction(p0,p1,p2)
    return function (t)
        local pow = math.pow
        return pow( (1-t),2 ) * p0
               + 2 * (1-t) * t * p1
               + pow(t,2) * p2
    end
end

love.graphics.setBackgroundColor(255, 255, 255)
function love.draw()
    local line = love.graphics.line
    local colour = love.graphics.setColor

    -- Bezier sampling parameters
    local nSegments = 10
    local segIncr = 1/nSegments

    -- Bezier definition: Start (`p0`), control (`p1`) and end `p2`) point
    local p0 = v(100,100)
    local p1 = v( love.mouse.getX(), love.mouse.getY() )
    local p2 = v(500,100)
    local controlPoints = {p0,p1,p2}
    local bez = makeBezierFunction(p0,p1,p2)

    -- Sample the bezier
    for i=0,1-segIncr,segIncr do
        colour(0, 0, 0)
        local x1,y1 = bez(i        ):unpack()
        local x2,y2 = bez(i+segIncr):unpack()
        line(x1,y1,x2,y2)

        -- Find left and right points.
        local center = v(x1, y1)
        local forward = v(x2, y2) - center
        local left = center + forward:perpendicular():normalize_inplace() * 10
        local right = center - forward:perpendicular():normalize_inplace() * 10

        -- Draw a line between them.
        line(left.x, left.y, right.x, right.y)

        -- Find *next* left and right points, if we're not beyond the end of
        -- the curve.
        if i + segIncr <= 1 then
            local x3, y3 = bez(i+segIncr*2):unpack()
            local center2 = v(x2, y2)
            local forward2 = v(x3, y3) - center2
            local left2 = center2 + forward2:perpendicular():normalize_inplace() * 10
            local right2 = center2 - forward2:perpendicular():normalize_inplace() * 10

            -- Connect the left and right of the current to the next point,
            -- forming the top and bottom surface of the blocks.
            colour(0, 0xff, 0)
            line(left.x, left.y, left2.x, left2.y)
            colour(0, 0, 0xff)
            line(right.x, right.y, right2.x, right2.y)
        end
    end

    -- Draw an X at the control points
    for _,p in ipairs(controlPoints) do
        local x,y = p:unpack()
        colour(0xff,0x00,0x00)
        line(x-5,y-5, x+5,y+5)
        line(x-5,y+5, x+5,y-5)
    end
    -- Draw lines between control points
    for i=1,#controlPoints do
        colour(0xff,0x00,0x00, 100)
        local cp1 = controlPoints[i]
        local cp2 = controlPoints[i+1]
        if cp1 and cp2 then
            line(cp1.x, cp1.y
                ,cp2.x, cp2.y)
        end
    end
end

หากคุณต้องการเล่นกับมัน: รับLÖVEและใส่รหัสด้านบนลงmain.luaในไดเรกทอรีของตัวเอง วางvector.luaจากHUMPห้องสมุดในไดเรกทอรีเดียวกัน เรียกใช้love <that-directory>จากบรรทัดคำสั่ง

เลื่อนเมาส์ไปรอบ ๆ ! จุดควบคุมตรงกลางถูกตั้งค่าไว้ที่ตำแหน่งเมาส์:

การตั้งจุดควบคุมด้วยเมาส์


Anko คุณลองใช้ LibGdx แล้วหรือยัง ถ้าเป็นเช่นนั้นคุณชอบLöveไหม ฉันย้ายออกจากการใช้ API Android มาตรฐานหลังจากเกมปัจจุบันของฉันและฉันพยายามที่จะตัดสินใจระหว่าง LibGdx และLöve คำตอบที่น่าสนใจข้างต้นเช่นเคย btw
Green_qaue

@ Anko ขอบคุณมากมันมากกว่าที่ฉันคาดไว้ ยิ่งกว่านั้นฉันคิดว่าฉันสามารถเข้าใจรหัสของคุณได้ง่ายขึ้นเนื่องจากฉันใช้ MonkeyX สำหรับเกมของฉันซึ่งคล้ายกับ LUA
Moerin

1
@iQ ฉันไม่ได้ใช้ Libgdx แต่ฉันได้อ่านมากมายเกี่ยวกับเรื่องนี้และฉันรู้ Java ดี LibGDX เป็นใหญ่ (มันมีการรองรับ accelerometer, สร้างขึ้นในเครื่องกำเนิดโค้งและทุกอย่าง) ในขณะที่ Love2D มีขนาดเล็กมาก (มันไม่มีอะไรเลย, ไม่มีการรองรับ shader ฯลฯ ) ด้วยความเรียบง่ายของมัน Love2D นั้นยอดเยี่ยมสำหรับต้นแบบที่รวดเร็วและเกมเล็ก ๆ แต่มันอาจจะมินิมอลสำหรับบางโครงการ ใครจะรู้. (คุณทำ! ลองและดู: D)
Anko

คำตอบที่ยอดเยี่ยมและ GIF นั้นเป็นโบนัสที่ดีจริงๆ!
รอยต.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.