How to create a boomerang-a-like path?

For the GitHub Game Off Jam, I plan to create a small game with a boomerang. But I don't know how to build the equation that will update the boomerang position.

I try to build a direction vector and rotate it a little to each update. But it generate each time a circle.

Is a bezier curve a good alternative? Or is it too complex? • Béziers are pretty common — have you had any specific trouble with them that you'd like help overcoming? Nov 4 '17 at 20:33
• Got some trouble to understand how to move the object allong. Using LibGdx, I can get the position regarding a percentage of a curve. To mix it with speed, I just find the percentage corresponding to the lenght already travelled. Example found in libgdx repository : github.com/libgdx/libgdx/blob/master/tests/gdx-tests/src/com/… Nov 13 '17 at 14:32
• It sounds like you should edit your question to include more details about what you've tried and what specifically isn't yet working the way you want. Nov 13 '17 at 14:34

What about one side of a lemniscate (polar) or a rose curve (also polar)?

You can find a refresher on polar curves (and the equations of the curves described above) here (which is where I got the equation for the lemniscate. This was just one of the first sites that came up when I searched "polar curves"):

http://math.tutorvista.com/geometry/polar-graphs.html

How this would be implemented in C (the equation for a lemniscate is r^2 = a^2sin2(theta)):

Since r^2 = a^2sin(2theta), then r = +-sqrt(a^2sin(2theta)), which can then be simplified to r = +-asqrt(sin(2theta)). We will only focus on the right side, which means that we can just assume the equation is positive instead of +-. a just alters the shape of the lemniscate slightly, so let's just set it to 1. We end up having r = sqrt(sin(2theta)).

float theta = .0F; // a global theta variable to store the position of the boomerang in each frame

void draw() { //or whatever function you are using for drawing each frame
float r = sqrt(sin(2 * theta));
//"Base Coords" refers to the boomerang's coordinates right before it is thrown
float xTransformFromBaseCoords = r * sin(theta); // In order to turn a polar radius into an x Rectangular coordinate, multiply r by sin(theta). In order to obtain the y-coordinate, multiply r by cos(theta).
float yTransformFromBaseCoords = r * cos(theta);
glTranslate4f(xTransformFromBaseCoords, yTransformFromBaseCoords, .0f); // The ".0f" is the z-transform
theta += .01F; //increase the value being added to theta in order to make the boomerang move faster
//draw the shape
}

If you don't need a perfect lemniscate curve, and want to improve performance, then you can approximate sine and cosine using taylor polynomials that have up to two parts (I tested that on my intel pc, and the native sine function ended up being faster than Taylor polynomials of degree three and higher. However, if your coordinates are normalized (from -1F to 1F), then your theta value will most likely be very close to 0, meaning that the error will be relatively small.

• Good idea but some code (or pseudocode) would improve this answer immensely :) Nov 5 '17 at 1:36
• @Charanor Is this better? Nov 5 '17 at 22:08
• I suggest wrapping formulas with code tags to improve readability. Nov 13 '17 at 16:01

I can create a path based on bezier curve or use a rose curve.

Because I want my path to be modified by the player strenght or some environmental behavious, I use a path based on bezier curves:

• the player strenght can scale the curve
• environmnental behavious just achange a local part of the curve

But because the rose curve will allways be the same shape, i now use bezier curve instead.

So I build a bezier curve by "hand". But environmental behavious will be able to move points from this bezier curve. And the player movement will update the strenght of the curve.

The next issue I got with Bezier curve is : how to move an objet allong at a constant speed the path? I use LibGdx and you can get a position regarding a percentage of the curve.

To achieve this, I compute the lenght of a displacement. Then I compute the percentage that this displacement represent for my bezier curve. Now I got the percentage of the curve from my displacement, so I can get the position of my objet of my bezier curve.

val dst = accumulatedDistance + (speed * delta)
val percent = curve..approxLength(500) / dst
val position = Vector2()
// will set in position the value at percent of the curve
myCurve.valueAt(position, percent)

This comment is inspired from this LibGDX source code (which manage several curves to create one path).

tl;dr: Do what you want. But sure, béziers are fine.

Realistically, a boomerang goes on a very weird, unnatural path which depends on the boomerang's individual form but is definitively not a circle, nor anything like circle-shaped, with its wings describing a hypocycloid around its center of mass. Which is, admittedly, a very pretty pattern, and sheer hell to simulate. You can easily hold an one-hour lecture on that topic if you want.

A game is a game, is a game, is a game.

Bézier curves are easy to implement and can be evaluated efficiently. So, if you want your boomerang to go on a somewhat bent path, do that.

In the easiest case, you can model the control points of your bézier curve in a SVG editor (so you see that the result will look approximately like what you want!) or in another tool (Blender will do, for example), then hardcode the control points in your game, and apply a simple rotation matrix to them depending on what direction your character faces. Then, just evaluate the polynomial for any desired t, and that's it.

You can do something much more complicated, but why. Modelling the curve once WYSIWYG and then rotating it is mighty fine, no user will complain about lacking realism. And it's easy...

If you think a boomerang goes in a straight line and then returns, then even that is mighty fine. Do that then. Whatever you like.

Really, there is no right and no wrong, but bézier curves most definitively are a good plan.