Computer Science Canada Programming C, C++, Java, PHP, Ruby, Turing, VB   Username:   Password: Wiki   Blog   Search   Turing   Chat Room  Members
Modelling a specific sort of curve
Author Message
Insectoid

Posted: 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?

Zren

Posted: 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

Posted: 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

Posted: 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

Posted: 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

Posted: 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

Posted: 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

Posted: 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

Insectoid

Posted: 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

Posted: 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: All Posts1 Day7 Days2 Weeks1 Month3 Months6 Months1 Year Oldest FirstNewest First

Page 1 of 1  [ 10 Posts ]
 Jump to:  Select a forum  CompSci.ca ------------ - Network News - General Discussion     General Forums   -----------------   - Hello World   - Featured Poll   - Contests     Contest Forums   -----------------   - DWITE   - [FP] Contest 2006/2008   - [FP] 2005/2006 Archive   - [FP] 2004/2005 Archive   - Off Topic     Lounges   ---------   - User Lounge   - VIP Lounge     Programming -------------- - General Programming     General Programming Forums   --------------------------------   - Functional Programming   - Logical Programming   - C     C   --   - C Help   - C Tutorials   - C Submissions   - C++     C++   ----   - C++ Help   - C++ Tutorials   - C++ Submissions   - Java     Java   -----   - Java Help   - Java Tutorials   - Java Submissions   - Ruby     Ruby   -----   - Ruby Help   - Ruby Tutorials   - Ruby Submissions   - Turing     Turing   --------   - Turing Help   - Turing Tutorials   - Turing Submissions   - PHP     PHP   ----   - PHP Help   - PHP Tutorials   - PHP Submissions   - Python     Python   --------   - Python Help   - Python Tutorials   - Python Submissions   - Visual Basic and Other Basics     VB   ---   - Visual Basic Help   - Visual Basic Tutorials   - Visual Basic Submissions     Education ----------- - Student Life   Graphics and Design ----------------------- - Web Design     Web Design Forums   ---------------------   - (X)HTML Help   - (X)HTML Tutorials   - Flash MX Help   - Flash MX Tutorials   - Graphics     Graphics Forums   ------------------   - Photoshop Tutorials   - The Showroom   - 2D Graphics   - 3D Graphics     Teams ------ - dTeam Public

 Style: Appalachia blueSilver eMJay subAppalachia subBlue subCanvas subEmjay subGrey subSilver subVereor Search: