Bagaimana cara membuat permukaan melengkung dari blok persegi panjang?

12

Untuk gim yang mirip Peggle , saya ingin membuat blok yang mengikuti kurva, seperti ini:

blok sepanjang kurva

Balok kemudian akan menghilang saat bola mengenai mereka.

Saya berhasil menggambar beberapa secara horizontal, tetapi saya kesulitan membuat mereka mengikuti jalan:

upaya saya di blok yang mengikuti jalur

Bagaimana saya melakukan ini? Apakah saya perlu membuat objek Box2D dengan simpul khusus?

Moerin
sumber
Apakah Anda ingin kotak tidak hanya tumpang tindih atau Anda ingin tidak ada celah di mana pun? (Saya tidak yakin apa yang Anda maksud dengan "mengimbangi sumbu objek Y sesuai dengan sudut objek").
Roy T.
1
Anda tidak bisa mengisi kurva dengan persegi panjang yang tidak tumpang tindih , jadi Anda harus membuat beberapa geomety khusus jika Anda tidak ingin ada celah.
Anko
@ Roy. Kesenjangan itu tidak penting. Masalah sebenarnya saya adalah menghitung posisi blok yang saling mengikuti dengan sudut yang berbeda.
Moerin
Cara saya mendekati ini adalah dengan menentukan serangkaian simpul yang bertindak sebagai sudut umum antara setiap kotak. Bahkan menggunakan jalur untuk mendefinisikannya, Anda masih memerlukan parameter tambahan untuk menentukan jarak antara simpul dan berapa lama setiap kotak.
4
"Kotak" pada gambar pertama bukan kotak, mereka adalah pasangan segitiga: i.stack.imgur.com/Tzuql.png
egarcia

Jawaban:

14

Diberikan kurva "root", inilah cara Anda dapat menghasilkan simpul blok.

Bézier dengan balok

Kurva root ada di tengah, hitam. Titik kontrolnya ditunjukkan dengan Xs merah .

Singkatnya : Saya membuat Bézier dan mengambil sampelnya (pada tingkat yang dapat dikonfigurasi). Saya kemudian menemukan vektor tegak lurus vektor dari setiap sampel ke sampel berikutnya, dinormalisasi , dan diskalakan ke setengah lebar (dapat dikonfigurasi), pertama ke kiri, kemudian berbanding terbalik ke kanan. Lalu menggambarnya.

Hal yang dapat Anda tambahkan ke ini:


Ini kode saya. Itu ditulis dalam Lua (untuk kerangka permainan LÖVE ), tapi saya pikir itu bisa dibaca oleh siapa pun.

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

Jika Anda ingin bermain dengannya: Dapatkan LÖVE dan masukkan kode di atas ke main.luadalam direktori sendiri. Letakkan vector.luadari HUMPperpustakaan di direktori yang sama. Jalankan sebagai love <that-directory>dari baris perintah.

Gerakkan mouse! Titik kontrol tengah diatur ke lokasi mouse:

Mengatur titik kontrol dengan mouse

Anko
sumber
Anko sudahkah kamu mencoba LibGdx? Jika demikian, apakah Anda lebih suka Löve? Saya pindah dari menggunakan API android standar setelah permainan saya saat ini dan saya mencoba untuk memutuskan antara LibGdx dan Löve. Jawaban menarik di atas seperti biasa
Green_qaue
@Anko Terima kasih banyak, ini lebih dari yang saya harapkan. Lebih saya pikir saya dapat dengan mudah memahami kode Anda karena saya menggunakan MonkeyX untuk permainan saya yang mirip dengan LUA.
Moerin
1
@ iQ Saya belum pernah menggunakan Libgdx, tapi saya sudah membaca banyak tentangnya dan saya tahu Java dengan baik. Libgdx besar . (Ini memiliki dukungan accelerometer, built in generator kurva dan segalanya), sementara Love2D sangat kecil (tidak memiliki salah satu dari itu, tidak ada dukungan shader, dll). Berkat kesederhanaannya, Love2D telah bagus untuk prototipe cepat dan game kecil, tetapi mungkin terlalu minimalis untuk beberapa proyek. Siapa tahu. (Ya! Coba dan lihat.: D)
Anko
Jawaban yang bagus, dan GIF itu benar-benar bonus yang bagus!
Roy T.