Dikdörtgen bloklardan nasıl kavisli bir yüzey oluştururum?


12

Bir İçin peggle benzeri oyun, böyle bir eğriyi takip blokları yapmak istiyorum:

eğri boyunca bloklar

Toplar vurduğunda bloklar kaybolurdu.

Bazılarını yatay olarak çizmeyi başardım, ancak bir yolu izlemede sorun yaşıyorum:

yolu takip eden blokları denemem

Bunu nasıl yaparım? Özel köşeleri olan Box2D nesneleri oluşturmam gerekir mi?


Kutuların üst üste binmemesini mi yoksa hiçbir yerde boşluk olmamasını mı istiyorsunuz? ("Y nesnesini nesne açısına göre dengeleyerek" ne demek istediğinizden tam olarak emin değilim).
Roy T.

1
Bir eğriyi üst üste binmeyen dikdörtgenlerle dolduramazsınız , bu nedenle boşluk istemiyorsanız bazı özel geometriler oluşturmanız gerekir .
Anko

@RoyT. Boşluklar önemli değil. Asıl sorunum, birbirini takip eden bloğun pozisyonunu farklı açı ile hesaplamak.
Moerin

Buna yaklaşma şeklim, her bir kutu arasındaki ortak köşeler olarak hareket eden bir dizi köşe tanımlamaktır. Bunları tanımlamak için bir yol kullansanız bile, köşeler arasındaki mesafeyi ve her kutunun ne kadar uzun olduğunu tanımlamak için ek parametrelere ihtiyacınız vardır.

4
İlk görüntüdeki "kutular" kutular değil, üçgen çiftleridir: i.stack.imgur.com/Tzuql.png
egarcia

Yanıtlar:


14

"Kök" eğri verildiğinde, blok köşelerini nasıl oluşturabileceğiniz aşağıda açıklanmıştır.

Bézier bloklu

Kök eğrisi ortada siyah renktedir. Kontrol noktaları kırmızı Xs ile gösterilmiştir .

Kısacası : Ben bir Bézier yaptım ve onu (yapılandırılabilir bir oranda) örnekledim. Daha sonra vektörün her bir numuneden diğerine dik vektörünü buldum , normalleştirdim ve önce (sonra sağa, sonra tersine) (yapılandırılabilir) yarım genişliğe ölçeklendirdim . Sonra çizdi.

Buna ekleyebileceğiniz şeyler:


İşte kodum. Bu yazılmış oluyor Lua (için Aşk oyun çerçevesi), ama herkes için okunabilir olduğunu düşünüyorum.

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

Bununla oynamak istiyorsanız: LÖVE'yi edinin ve yukarıdaki kodu main.luakendi dizinine yerleştirin. Put vector.luagelen HUMPaynı dizinde kütüphanede. love <that-directory>Komut satırından olduğu gibi çalıştırın .

Fareyi hareket ettirin! Orta kontrol noktası fare konumuna ayarlanır:

Fare ile kontrol noktasını ayarlama


Anko LibGdx'i denediniz mi? öyleyse, Löve'yi tercih ediyor musunuz? Mevcut oyunumdan sonra standart android API kullanmaktan uzaklaşıyorum ve LibGdx ve Löve arasında karar vermeye çalışıyorum. Her zaman olduğu gibi yukarıdaki ilginç cevap btw
Green_qaue

@Anko Çok teşekkürler, beklediğimden daha fazla. Daha ben LUA benzer benim oyun için MonkeyX kullandığım için ben kolayca kodunuzu anlayabiliyorum düşünüyorum.
Moerin

1
@ iQ Libgdx kullanmadım, ama bunun hakkında çok şey okudum ve Java'yı çok iyi biliyorum. Libgdx büyük . (İvmeölçer desteğine sahiptir, eğri üreteçleri ve her şeyi içerir), Love2D çok küçüktür (bunlardan hiçbirine sahip değildir, gölgelendirici desteği yoktur, vb.). Basitliği sayesinde, Love2D hızlı prototipler ve küçük oyunlar için harikaydı, ancak bazı projeler için çok minimalist olabilir. Kim bilir. (Siz yapın! Deneyin ve görün.: D)
Anko

Harika cevap ve bu GIF gerçekten güzel bir bonus!
Roy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.