GameMaker (SOLVED)Calling math wizards! (help making arc)

HayManMarc

Member
Hey all,

Are you ready? MATH CHALLENGE!!

Are you excited? I hope you're excited. Actually, I'm hoping someone around here is great with maths and can help me out. I do okay with math, and can usually, eventually find the answer for things that are not too complicated, but this one is spinning my brain. I'll start researching and maybe I'll figure it out before someone comes up with a solution, but I thought I'd post this here to get the ball rolling.

Here's a diagram:


I'm trying to make a script that will plot points along the red line. Here are some facts and goals of the script:
  • Known variables are shown in the diagram with values. (These variables can be different values as provided by the programmer, so the script will be like a formula.)
  • The y2 value should be determined by the script.
  • I would like the script to determine the optimal amount of plot points to make a smooth curve, down to 1 degree differences from point to point.
    • (For example, if the angle difference between the starting point and the ending point is 60, then there would be a maximum of 60 plot points in the arc. However, if the distance between the starting point and ending point is too small, we'll need fewer plot points and sharper angles.)
I hope that's all the info needed.

I'm trying to make a chain fixture along the arc. I don't think it will help, but here's my code so far:
Code:
/// @function plot_slope(x, y, width, start angle, end angle)
/// @description 
/// @param {param_type} param_name description
/// @param {param_type} param_name description


var px = argument0; // starting x position plot (ground fixture)
var py = argument1; // starting y position plot
var pw = argument2; // desired width of plot
var sa = argument3; // starting angle of plot
var ea = argument4; // ending angle of plot

var ad = angle_difference(sa, ea);

/*
I think I need to find the intersection of the perpendicular lines of the starting and ending point vectors,
when the second length equals the first.  This will be the center point of the circle that
will bisect both points.  (I know what I mean, but I don't know if I wrote this correctly -- sorry.)
*/

var cp =   // center point

/*
I assume now we need to determine the optimal number of plot points along the arc.
*/

var cs =   // number of curve sections

/*
At this point, I think we can use lengthdir with the angle difference (var ad) of the start and end points divided by the number of plot points (var cs) along the arc.
*/

// ?? Code for this ??  (This is as far as I got tonight.  I'm out of steam.)

// NOW CREATE THE CHAIN FIXTURE
var fix = physics_fixture_create();
physics_fixture_set_chain_shape(fix, false);

// ITERATE THOUGH THE POINTS AND CREATE THE CHAIN
for (i = 0; i < cs; i += 1;)
    {
         ???
    }

// physics_fixture_add_point(fix, px, py);


physics_fixture_bind(fix, id);
physics_fixture_delete(fix);
I don't know if I'm going about this the right way, or the best way. I don't even know for sure if it's even possible to make a formula for this -- if enough information is provided to support a formula. I think there is, but I could be wrong. I'll reply here with the answer if I figure it out on my own.

Here's a preemptive THANK YOU to anyone giving this a shot. :)
 

GMWolf

aka fel666
I think what you are looking at is a Bézier curve.
Specifically a quadratic Bézier curve.

The allow you to define a start and end point, as well as a start and end slope.

Plenty of information online if you know what term to look for :)


One problem: I don't think you can determine a value for y2. There are a y number of values that could work.

Do you need more constraints? Are you perhaps plotting the curve of an object falling under gravity? Do you have an initial 'velocity'?
 

NightFrost

Member
Yeah, looks more or less like a Bezier curve job. However, they need to know the positions of all the points, and they must have at least three points, because the positions determine the shape of the curve. To put it simply, the algorithm fits the curve inside a polygon designated by the points. Here for example a quadratic bezier from Wikipedia:



(EDIT - to draw your curve, you just calculate an appropriate amount of points on 0 <= t <= 1 and draw lines between them.)
(EDIT 2 - the position of the third point would be where the two lines in your illustration would cross.)
 
Last edited:

Binsk

Member
Bezier curves are good for DEFINING an arc, not calculating one.

Take a look at the highlighted answer here. It is what you need.
 

GoK

Member
y2 is easy enough to find.

Look at the line from (px, py) to (x2, y2). An angle of this line is exactly halfway between your angles.
1.png

So all you need to do is find a tangent of this angle and multiply it by pw:
Code:
// px = 100; py = 50;
// pw = 200;
// sa = 100; ea = 80;

var x2, y2;
if (pw == 0)
{
    x2 = px;
    y2 = py;
 
    //Done! No curve needed.
}
else
{
    var midAng = (sa + ea) / 2,
        slope  = -tan(degtorad(midAng));
    x2 = px + pw;
    y2 = py + pw * slope;
 
    //Draw a curve.
}
It should work for any angles between -90 and 90 unless they create some unsolvable situation:
2.png

Next question: where is the center point? (if we talking about semicircular arc)
 
Last edited:
C

Catastrophe

Guest
Unless I'm mistaken, isn't

"However, if the distance between the starting point and ending point is too small, we'll need fewer plot points and sharper angles."

undefined? In this case, are you optimizing for fewest points or smoothest angles and by how much? I think you need weights here to get an actual answer.

TBH it really helps to know the reason behind this curve xD
 

HayManMarc

Member
Thanks so much, everyone!! It looks like @GoK understands exactly what I'm trying to do.

To explain a bit further, I'm not after a bezier curve. I only need a semi-circle arc.

I was thinking about the "optimal amount of plot points" last night in bed on my way to sleep. I think just using --- min(angle difference, distance between points) --- might work.

I can find the center point of the semi-circle arc by drawing it on paper, but I don't know how to do it with code and math. If you draw perpendicular lines at the start and end points, where these lines intersect will be the center point of the semi-circle arc.

I mentioned in the original post that this was for making a chain fixture. More specifically, I'm building a level-making system for the road in my Hippie Bus game. I have scripts already for empty flat sections and flat sections with buildings. At the end of the script, I record the ending x/y position and the ending angle of the road. Then I plug those values into the next piece so the road starts at the correct position and potentially at the correct angle.

Edit:
I gotta put a new fuel pump back in my truck. Hopefully I'll have time afterwards to try some of this stuff.
 
Last edited:
C

Catastrophe

Guest
Well finding the center point given you nkow the second x/y shouldn't be too hard. Just add 180 to each line angle, then get the line formula (y = mx + b) for each line, which is easy enough with a point and an angle. Then use the two line formulas to find the intersection, also googleable.

Edit: brainfart: add 90 degrees
 
Last edited by a moderator:

HayManMarc

Member
I got it working, thanks to all your helps and some google math lessons. Here's the code:

Code:
var px = argument0; // starting x position plot (ground fixture)
var py = argument1; // starting y position plot
var pw = argument2; // desired width of plot
var sa = argument3; // starting angle of plot
var ea = argument4; // ending angle of plot

// FIND END POINT Y COORDINATE
var x2, y2;
if (pw == 0)
    {
        x2 = px;
        y2 = py;

        //Done! No curve needed.
    }
    else
    {
        var midAng = (sa + ea) / 2,
            slope  = -tan(degtorad(midAng));
        x2 = px + pw;
        y2 = py + pw * slope;  // y2 is found!
    }

// FIND THE CENTER POINT OF THE SEMI-CIRCLE ARC

// GET THE SLOPES OF THE LINES PERPENDICULAR
var m1 = -tan(degtorad(sa + 90));
var m2 = -tan(degtorad(ea + 90));

// GET THE Y INTERCEPTS OF THESE
var b1 = py - m1 * px; // b = y - m * x
var b2 = y2 - m2 * x2;

// GET THE INTERSECTION POINT
// line equation: y = mx + b
// intersect equation:  m1x + b1 = m2x + b2  --or--  x = (b2 - b1) / (m1 - m2)
var cpx = (b2 - b1) / (m1 - m2);
var cpy = m1 * cpx + b1;

var cpr = point_distance(cpx, cpy, px, py); // circle radius

// DETERMINE "OPTIMAL" AMOUNT OF CURVE SECTIONS (nope - I'm just using the angle difference.)
//var dist = point_distance(px, py, x2, y2);
var ad = angle_difference(sa, ea);
var cs = abs(ad) + 2; // min(ad, dist);  // number of curve sections
var angle_incr = 1; // ad / cs;

/*
// START THE FIXTURE
var fix = physics_fixture_create();
physics_fixture_set_chain_shape(fix, false);
*/

// PLOT THE POINTS
var xx, yy;
for (i = 0; i < cs; i += 1;)
    {
        xx = cpx + lengthdir_x(cpr, sa + (90 * sign(ad)) + i * (angle_incr * -sign(ad)) );
        yy = cpy + lengthdir_y(cpr, sa + (90 * sign(ad)) + i * (angle_incr * -sign(ad)) );
     
        //physics_fixture_add_point(fix, xx, yy);
     
        //for drawing
        global.plotx[i] = xx;
        global.ploty[i] = yy;
    }
        global.cs = cs;

/*
// END THE FIXTURE
physics_fixture_set_density(fix, 0);
physics_fixture_bind(fix, id);
physics_fixture_delete(fix);
*/
I commented out the physics stuff because I made a separate project to figure this out. It's kinda neat as it allows you to change the values of the script on the fly.

I've made this project available if you'd like to take a look. Feel free to use the code if you need it. I only ask that if you do, you try to learn from it. Here's the project export download: Arc_for_HippieBus.yyz

Here's some webpages I used to get some math...
https://www.mathsisfun.com/equation_of_line.html
http://zonalandeducation.com/mmts/intersections/intersectionOfTwoLines1/intersectionOfTwoLines1.html
http://www.webmath.com/equline2.html (if you enter some values, you get an explanation)

And here's a big THANK YOU again to you guys!
 
Top