Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 Modelling a specific sort of curve
Index -> General Programming
View previous topic Printable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
Insectoid




PostPosted: Fri Apr 04, 2014 1:24 pm   Post subject: Modelling a specific sort of curve

I'm starting to build a game very similar to Steambirds. I'm having trouble coming up with a way to recreate the movement planning for the aircraft. I tried using Bezier curves, but they don't quite fit the problem (or I can't manipulate them correctly) and seem like overkill for this task. Anyone got any ideas?
Sponsor
Sponsor
Sponsor
sponsor
Zren




PostPosted: Fri Apr 04, 2014 4:35 pm   Post subject: RE:Modelling a specific sort of curve

Constant rotation rate + linear movement. Draw Arc + Draw Line. That might be even harder that beziers though.
Steambirds is deffinitely using a bezier though.
Insectoid




PostPosted: Fri Apr 04, 2014 5:08 pm   Post subject: RE:Modelling a specific sort of curve

I think I might have a solution.

Draw the path as a chain of 3 links (4 points) of the same length and with the same angle between them. Clicking & dragging the last point moves the whole thing to satisfy those conditions. These 4 points describe the bezier curve of the flight path. Figuring out a solver for this will be a pain, but I'm confident it will work.
Insectoid




PostPosted: Fri Apr 04, 2014 7:52 pm   Post subject: RE:Modelling a specific sort of curve

I've been playing around with it a little and came up with this solution (it's a bit messy). Ended up using a trigonometric bezier to model the path. Click & drag to move the bezier around. I can't figure out a way to make the 2 lines that define the bezier the same length.

Turing:
type Point : record
    x : real
    y : real
end record

function slope (p : Point) : real %calculates the slope of the line from (0, 0) to p
    result arcsind (p.y/sqrt (p.x**2 + p.y**2))
end slope

function slope2 (x : real, y : real) : real
    result arcsind (y/sqrt (x**2+y**2))
end slope2
   
var p0 : Point %Not really p0. Just used as a guide to show the 'original' direction
var p1 : Point %midpoint of the bezier
var p2 : Point %endpoint of the bezier

p0.x := 200 %some random initial values.
p0.y := 200

p1.x := 75
p1.y := 75
p2.x := 150
p2.y := 150

var offsetX := 0 %offset for drawing. Non-zero values kinda mess with the controls
var offsetY := 0

var keys : array char of boolean
View.Set ("offscreenonly")

%this draws the bezier given coordinates. t = time
proc drawBezier (x0 : real, y0 : real, x1 : real, y1 : real, x2 : real, y2: real, t : real)
    var x : real
    var y: real
    x := (1-t)**2*x0 + 2*(1-t)*t*x1+t**2*x2
    y := (1-t)**2*y0 + 2*(1-t)*t*y1+t**2*y2
    Draw.Dot (round (x)+offsetX, round (y)+offsetY, green)
end drawBezier
   

%var angle : real
var mx, my, mb : int

loop
Mouse.Where (mx, my, mb)

if mb = 1 then
    p2.y := my
    p2.x := mx
    p1.x := (p2.x + p0.x) /4 %these are the two lines I'm having trouble with. I need length((0, 0), p1) to match length (p1, p2). When slope (p2) = slope (p0), the bezier should be linear.
    p1.y := (p2.y + p0.y) / 4
end if

Draw.Line (0+offsetX, 0+offsetY, round (p0.x)+offsetX, round (p0.y)+offsetY, black)
Draw.Line (0+offsetX, 0+offsetY, round (p1.x)+offsetX, round (p1.y)+offsetY, red)
Draw.Line (round (p1.x)+offsetX, round (p1.y)+offsetY, round (p2.x)+offsetX, round (p2.y)+offsetY, red)

for i : 0..60
    drawBezier (0, 0, p1.x, p1.y, p2.x, p2.y, 1.0/60*i)
end for

put Math.Distance (0, 0, p1.x, p1.y)
put Math.Distance (p1.x, p1.y, p2.x, p2.y)
%Draw.Line (round (p3.x), round (p3.y), round (p4.x), round (p4.y), red)
%Draw.Line (0, 0, round (p2.x), round (p2.y), black)

View.Update
delay (10)
cls
end loop
Raknarg




PostPosted: Fri Apr 04, 2014 8:12 pm   Post subject: RE:Modelling a specific sort of curve

Just out of curiosity, why are you using Turing for this project?
Insectoid




PostPosted: Fri Apr 04, 2014 8:39 pm   Post subject: RE:Modelling a specific sort of curve

It lets you write small graphical prototypes really quickly (and I can't get Allegro to function properly). Eventually, when I get a functional prototype, I might rewrite it in something more iOS/Android friendly and really polish it up, but I'm not planning that far ahead.
Raknarg




PostPosted: Fri Apr 04, 2014 8:45 pm   Post subject: RE:Modelling a specific sort of curve

I used to think so too, but once I got used to Processing, it really changed my mind. Simplicity but with the power of Java.

Not saying you should change what you've already started, though. Just for future reference
Dreadnought




PostPosted: Fri Apr 04, 2014 11:07 pm   Post subject: Re: Modelling a specific sort of curve

Insectoid wrote:

I can't figure out a way to make the 2 lines that define the bezier the same length.


Here's how I thought of doing it. If you force the angles between some line to be the same, you can get lines of the same length.
Let L0, L1, L2 be the lines from (0,0) to p0, p1, p2 respectively.
Force the angle between L0 and L1 to be equal to the angle from L1 to L2. This gives an isosceles triangle with vertices p0, p1 and p2 and lets us solve for the length with the cosine law.

Here's what I got (just modified the way you compute p1).
Turing:
type Point :
    record
        x : real
        y : real
    end record

function slope (p : Point) : real %calculates the slope of the line from (0, 0) to p
    result arcsind (p.y / sqrt (p.x ** 2 + p.y ** 2))
end slope

% Distance from origin to p squared
fcn norm2 (p : Point) : real
    result p.x * p.x + p.y * p.y
end norm2

proc drawBezier (x0 : real, y0 : real, x1 : real, y1 : real, x2 : real, y2 : real, t : real)
    var x : real
    var y : real
    x := (1 - t) ** 2 * x0 + 2 * (1 - t) * t * x1 + t ** 2 * x2
    y := (1 - t) ** 2 * y0 + 2 * (1 - t) * t * y1 + t ** 2 * y2
    Draw.Dot (round (x), round (y), green)
end drawBezier

var p0 : Point %Not really p0. Just used as a guide to show the 'original' direction
var p1 : Point %midpoint of the bezier
var p2 : Point %endpoint of the bezier

p0.x := 200 %some random initial values.
p0.y := 200

const a0 : real := slope (p0)

p1.x := 75
p1.y := 75
p2.x := 150
p2.y := 150

var mx, my, mb : int

loop
    Mouse.Where (mx, my, mb)

    if mb = 1 then
        p2.y := my
        p2.x := mx

        % Please excuse the terrible naming, a0, a1, a2 correspond to slope() for p0, p1, p2
       
        var a2 : real := slope (p2)
        var a : real := (a0 - a2) / 2 % angle between lines from origin to p0 and p1 (equal to angle between lines from origin to p1 and p2)
        var len : real := sqrt (norm2 (p2) / (2 * (1 - cosd (180 - 2 * a))))
        var a1 : real := a2 + a

        p1.x := len * cosd (a1)
        p1.y := len * sind (a1)
    end if
    Draw.Line (0, 0, round (p0.x), round (p0.y), black)
    Draw.Line (0, 0 , round (p1.x), round (p1.y), red)
    Draw.Line (round (p1.x), round (p1.y), round (p2.x), round (p2.y), red)

    for i : 0 .. 60
        drawBezier (0, 0, p1.x, p1.y, p2.x, p2.y, 1.0 / 60 * i)
    end for
    View.Update
    delay (10)
    cls
end loop
Sponsor
Sponsor
Sponsor
sponsor
Insectoid




PostPosted: Sat Apr 05, 2014 1:48 pm   Post subject: RE:Modelling a specific sort of curve

That works pretty well, thanks. I've added a little more functionality to it, and came up with this. Same deal, click & drag the blue dot to move it. Press enter to advance the bezier, sort of.

There is an issue when p0 is pointing right-to-left; the slope gets reflected around the y axis (you'll see what I mean). Pretty sure this has something to do with the CAST rule of trig, but I can't figure it out right now. It's a long time since I did any trig.

Also, if p2 = origin (the opposite end of the bezier), the program will crash due to division by zero in the slope function. This is normal and will be fixed by limiting the values of p2 later on.

Turing:
type Point :
    record
        x : real
        y : real
    end record

function slope (p : Point) : real %calculates the slope of the line from (0, 0) to p
    var out : real := arcsind (p.y / sqrt (p.x ** 2 + p.y ** 2))
    result out
end slope

function subtractPoint (a : Point, b : Point) : Point
    var out : Point
    out.x := a.x - b.x
    out.y := a.y - b.y
    result out
end subtractPoint

% Distance from origin to p squared
fcn norm2 (p : Point) : real
    result p.x * p.x + p.y * p.y
end norm2

proc drawBezier (x0 : real, y0 : real, x1 : real, y1 : real, x2 : real, y2 : real, t : real)
    var x : real
    var y : real
    x := (1 - t) ** 2 * x0 + 2 * (1 - t) * t * x1 + t ** 2 * x2
    y := (1 - t) ** 2 * y0 + 2 * (1 - t) * t * y1 + t ** 2 * y2
    Draw.Dot (round (x), round (y), green)
end drawBezier

var p0 : Point %Not really p0. Just used as a guide to show the 'original' direction
var p1 : Point %midpoint of the bezier
var p2 : Point %endpoint of the bezier

p0.x := 200 %some random initial values.
p0.y := 200

var a0 : real := slope (p0)

p1.x := 75
p1.y := 75
p2.x := 150
p2.y := 150

var offsetX : real := 0
var offsetY : real := 0

var mx, my, mb : int
var keys : array char of boolean
var keyPressed : boolean := false
View.Set ("offscreenonly")
var s : real
var track : boolean := false

loop
    Mouse.Where (mx, my, mb)
    Input.KeyDown (keys)
    mx -= round (offsetX)
    my -= round (offsetY)
    if keys (KEY_ENTER) and keyPressed = false then
        keyPressed := true

        offsetX += p2.x
        offsetY += p2.y
        p0.x := p2.x - p1.x
        p0.y := p2.y - p1.y
        p2.x := p0.x
        p2.y := p0.y
        p1.x := p2.x/2
        p1.y := p2.y / 2
        a0 := slope (p0)
       % p1.x := 75 * cosd (a1)
       % p1.y := 75 * sind (a1)
    elsif not keys (KEY_ENTER) then
        keyPressed := false
    end if
       
    if mb = 1 and mx < p2.x +5 and mx > p2.x -5 and my < p2.y + 5 and my > p2.y - 5 then
        track := true
    elsif mb = 0 then
        track := false
    end if
   
    if track = true then
        p2.y := my
        p2.x := mx
        % Please excuse the terrible naming, a0, a1, a2 correspond to slope() for p0, p1, p2
       
        var a2 : real := slope (p2)
        var a : real := (a0 - a2) / 2 % angle between lines from origin to p0 and p1 (equal to angle between lines from origin to p1 and p2)
        var len : real := sqrt (norm2 (p2) / (2 * (1 - cosd (180 - 2 * a))))
        var a1 : real := a2 + a

        p1.x := len * cosd (a1)
        p1.y := len * sind (a1)
    end if
    %Draw.Line (round (offsetX), round (offsetY), round (p0.x+offsetX), round (p0.y+offsetY), black)
    Draw.Line (round (offsetX), round (offsetY), round (p1.x+offsetX), round (p1.y+offsetY), red)
    Draw.Line (round (p1.x+offsetX), round (p1.y+offsetY), round (p2.x+offsetX), round (p2.y+offsetY), red)
    Draw.FillOval (round (p2.x + offsetX), round (p2.y + offsetY), 5, 5, blue)
    for i : 0 .. 60
        drawBezier (offsetX, offsetY, p1.x+offsetX, p1.y+offsetY, p2.x+offsetX, p2.y+offsetY, 1.0 / 60 * i)
    end for
    View.Update
    delay (10)
    cls
end loop
Dreadnought




PostPosted: Sun Apr 06, 2014 12:44 am   Post subject: Re: Modelling a specific sort of curve

Insectoid wrote:

There is an issue when p0 is pointing right-to-left; the slope gets reflected around the y axis (you'll see what I mean). Pretty sure this has something to do with the CAST rule of trig, but I can't figure it out right now. It's a long time since I did any trig.


You could try changing the computation of a2 to something like this
Turing:
var a2 : real := slope (p2)
put dot (p2, p0)
if (p2.x < 0) then
    % The angle is greater than 90 deg (or less than -90 deg)
    % We need to adjust the value based on whether p2 is above or below the line from (offsetX, offsetY) to p0
    if (p2.x * p0.y / p0.x < p2.y) then
        a2 := 180 - a2
    else
        a2 := -180 - a2
    end if
end if


Just causes a problem if a2 = -a0 (division by zero when computing len)
Display posts from previous:   
   Index -> General Programming
View previous topic Tell A FriendPrintable versionDownload TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 1  [ 10 Posts ]
Jump to:   


Style:  
Search: