Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Bezier Path Generator
#1
Has anyone worked with Bezier curves?

I'm attempting to write a path generator for items such as enemy ships, like when the ships form up in Galaga at the start of a level, or during a challenging stage.

The code below is a quick and dirty Bezier path maker. It works, but no matter what I set the variable Detail to the path comes up jagged, with a sort of stair step effect to it. Does anyone know how I can smooth this out if possible?

Code: (Select All)
TYPE POINT
    x AS INTEGER
    y AS INTEGER
END TYPE

DIM Curve(3) AS POINT
REDIM Path(0) AS POINT

DIM p AS POINT

Curve(0).x = 0
Curve(0).y = 479

Curve(1).x = 639
Curve(1).y = 239

Curve(2).x = 0
Curve(2).y = 239

Curve(3).x = 639
Curve(3).y = 0

SCREEN _NEWIMAGE(640, 480, 32)

Detail = .00001


FOR t = 0 TO 1 STEP Detail
    CurvePoint Curve(), p, t
    New = -1
    FOR i = 0 TO UBOUND(Path) - 1
        IF p.x = Path(i).x AND p.y = Path(i).y THEN
            New = 0
            EXIT FOR
        END IF
    NEXT i
    IF New THEN
        Path(UBOUND(Path)) = p
        REDIM _PRESERVE Path(UBOUND(Path) + 1) AS POINT
    END IF

    'PSET (p.x, p.y)
NEXT t

PSET (Path(0).x, Path(0).y)
FOR i = 1 TO UBOUND(Path) - 1
    LINE -(Path(i).x, Path(i).y)
NEXT i
PRINT UBOUND(Path)



SUB CurvePoint (c() AS POINT, p AS POINT, t AS SINGLE)

    'Quick and dirty Bezier point calculator
    'Note: only works for 4 points

    p.x = (1 - t) * (1 - t) * (1 - t) * c(0).x + 3 * (1 - t) * (1 - t) * t * c(1).x + 3 * (1 - t) * t * t * c(2).x + t * t * t * c(3).x
    p.y = (1 - t) * (1 - t) * (1 - t) * c(0).y + 3 * (1 - t) * (1 - t) * t * c(1).y + 3 * (1 - t) * t * t * c(2).y + t * t * t * c(3).y

END SUB
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#2
After playing around with some other Bezier code it would seem this is normal. I streamlined the program above to be much faster and yield different numbers of points when using AND or OR in line 30 of the code.

When using AND the curve is very smooth when connected with lines. However, some detail is lost if successive X or Y coordinates are equal, not ideal for enemy ship path following but great when connecting the points with lines.

When using OR the data points are perfect for path following.

Code: (Select All)
TYPE POINT
    x AS INTEGER
    y AS INTEGER
END TYPE

DIM Curve(3) AS POINT
REDIM Path(1) AS POINT

DIM p AS POINT

Curve(0).x = 0
Curve(0).y = 479

Curve(1).x = 639
Curve(1).y = 239

Curve(2).x = 0
Curve(2).y = 239

Curve(3).x = 639
Curve(3).y = 0

SCREEN _NEWIMAGE(640, 480, 32)

Detail = .0001

t = 0
DO
    CurvePoint Curve(), p, t
    IF p.x <> Path(UBOUND(Path) - 1).x OR p.y <> Path(UBOUND(Path) - 1).y THEN ' OR can be changed to AND for different results
        Path(UBOUND(Path)) = p
        REDIM _PRESERVE Path(UBOUND(Path) + 1) AS POINT
        PSET (p.x, p.y)
    END IF
    t = t + Detail
LOOP UNTIL t > 1

'PSET (Path(1).x, Path(1).y) '        Draw lines instead when using AND above (very smooth)
'FOR i = 2 TO UBOUND(Path) - 1 '      OR yeilds 1102 points
'    LINE -(Path(i).x, Path(i).y) '   AND yields 368 points that need to be connected with lines
'NEXT i
PRINT UBOUND(Path) - 1
SLEEP


SUB CurvePoint (c() AS POINT, p AS POINT, t AS SINGLE)

    'Quick and dirty Bezier point calculator
    'Note: only works for 4 points

    DIM a AS SINGLE
    DIM b AS SINGLE
    DIM c AS SINGLE
    DIM d AS SINGLE

    a = (1 - t) * (1 - t) * (1 - t)
    b = 3 * (1 - t) * (1 - t) * t
    c = 3 * (1 - t) * t * t
    d = t * t * t

    p.x = a * c(0).x + b * c(1).x + c * c(2).x + d * c(3).x
    p.y = a * c(0).y + b * c(1).y + c * c(2).y + d * c(3).y

    'p.x = (1 - t) * (1 - t) * (1 - t) * c(0).x + 3 * (1 - t) * (1 - t) * t * c(1).x + 3 * (1 - t) * t * t * c(2).x + t * t * t * c(3).x
    'p.y = (1 - t) * (1 - t) * (1 - t) * c(0).y + 3 * (1 - t) * (1 - t) * t * c(1).y + 3 * (1 - t) * t * t * c(2).y + t * t * t * c(3).y

END SUB
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#3
check out this mod

Code: (Select All)
defdbl a-z
sw = 800
sh = 600
screen _newimage(sw, sh, 32)

n = 8
dim x(n), y(n)
x(0)=sw/2:y(0)=sh/7
x(1)=sw/3:y(1)=2*sh/7
x(2)=2*sw/3:y(2)=3*sh/7
x(3)=sw/5:y(3)=4*sh/7
x(4)=sw/2:y(4)=5*sh/7
x(5)=sw/5:y(5)=5*sh/7
x(6)=sw/2:y(6)=6*sh/7
x(7)=4*sw/5:y(7)=6*sh/7

cls

preset (x(0), y(0))
for i=0 to n - 1
    line -(x(i), y(i)), _rgb(55,55,0)
    circle (x(i), y(i)), 3, _rgb(255,255,0)
next

preset (x(0), y(0))

dt = 0.0001
for t=0 to 1 step dt
    bx = 0
    by = 0   
   
    'dx = 0
    'dy = 0
   
    for i=0 to n - 1
        bin = 1
        for j=1 to i
            bin = bin*(n - j)/j
        next
   
        p = bin*((1 - t)^(n - 1 - i))*(t^i)
        bx = bx + p*x(i)
        by = by + p*y(i)
                     
        'q = bin*((1 - t)^(n - 2 - i))*(t^(i - 1))*(i - n*t + t)
        'dx = dx + q*x(i)
        'dy = dy + q*y(i)               
    next

    if abs(bx - ox)>1 and abs(by - oy)>1 then
        line -(bx, by), _rgb(255,0,0)

        ox = bx
        oy = by
    end if
   
    'm = sqr(dx*dx + dy*dy)
    'line -step(10*dx/m, 10*dy/m), _rgb(0,255,0)
next
line -(bx, by), _rgb(255,0,0)
Reply
#4
(10-07-2024, 06:29 AM)vince Wrote: check out this mod

Code: (Select All)
defdbl a-z
sw = 800
sh = 600
screen _newimage(sw, sh, 32)

n = 8
dim x(n), y(n)
x(0)=sw/2:y(0)=sh/7
x(1)=sw/3:y(1)=2*sh/7
x(2)=2*sw/3:y(2)=3*sh/7
x(3)=sw/5:y(3)=4*sh/7
x(4)=sw/2:y(4)=5*sh/7
x(5)=sw/5:y(5)=5*sh/7
x(6)=sw/2:y(6)=6*sh/7
x(7)=4*sw/5:y(7)=6*sh/7

cls

preset (x(0), y(0))
for i=0 to n - 1
    line -(x(i), y(i)), _rgb(55,55,0)
    circle (x(i), y(i)), 3, _rgb(255,255,0)
next

preset (x(0), y(0))

dt = 0.0001
for t=0 to 1 step dt
    bx = 0
    by = 0   
   
    'dx = 0
    'dy = 0
   
    for i=0 to n - 1
        bin = 1
        for j=1 to i
            bin = bin*(n - j)/j
        next
   
        p = bin*((1 - t)^(n - 1 - i))*(t^i)
        bx = bx + p*x(i)
        by = by + p*y(i)
                     
        'q = bin*((1 - t)^(n - 2 - i))*(t^(i - 1))*(i - n*t + t)
        'dx = dx + q*x(i)
        'dy = dy + q*y(i)               
    next

    if abs(bx - ox)>1 and abs(by - oy)>1 then
        line -(bx, by), _rgb(255,0,0)

        ox = bx
        oy = by
    end if
   
    'm = sqr(dx*dx + dy*dy)
    'line -step(10*dx/m, 10*dy/m), _rgb(0,255,0)
next
line -(bx, by), _rgb(255,0,0)
Whoa, thank you. I was wondering how to incorporate more than 4 points into the mix. So simple.
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply
#5
Thank you all for sharing it. It is all very interestingly.


Reply




Users browsing this thread: 2 Guest(s)