Draw a Circle curve similar to the game Steambirds

Hello guys,
I am trying to make a turn based game that use similar control mechanic as Steambird survival on iOS. Basically, I want players to be able to draw a line/curve from their character, and at the end of the turn the character would move, following that line.

There are several requirements for the control:

  • The line/curve has to have a specified length (which is different between various characters)
  • The line/curve has to have a minimum angle (which is different between various characters)
  • When player slides their finger outside the maximum length of the curve, the curve stops being drawn, but if players move their finger towards a different position, the angle of the curve will keep changing according to the new position of their finger. Exactly like the Steambird game.


I have been stuck at this problem for more than 2 weeks.

What I have done is the following: (The triangle is the character, facing upwards in this example).

  1. Calculate the blue lines (normal and forward direction of the triangle).
  2. Calculate the orange line (line between the triangle and the user’s finger).
  3. Calculate the mid point of the orange line (green point).
  4. Draw a line normal to the orange line that passes through the green point (green line).
  5. Find the intersection of the green line and the normal blue line. This is the centre of the circle (black circle).
  6. Having the centre, I can now start to draw a circle from the triangle position up to the red dot (user’s finger).

The way I implemented in unity is basically calculate 10 points of the grey line, add them to a LineRenderer and draw a line between them. However, this doesn’t seem like the correct approach because I am having so many problems. To name a few:

  • I cannot think of a way to limit the line length, or the angle of the circle.
  • Even if I could limit the length, I don’t know how I would still adjust the line when my finger is already outside the maximum length.
  • I cannot easily add and remove point from the Line renderer, which is makes the line always lag behind the finger at high finger speeds.
  • And I haven’t even consider moving the triangle following the curve.

I have attached 3 screenshots above of the Steambird game, where the red dots are where I placed my finger. As you can see, the line is still drawn in the direction of my finger, but it has a limit length.

I really think there is a better method to accomplish this behaviour, because my approach looks very complex for such a “simple” mechanic.

So the question is/are:

  1. Is there a better way to accomplish this behaviour? any built-in functions/components that I missed?
  2. If the above is not true, any algorithm or strategies or any help at all to some of the problems mentioned.

here is some of my code:

Anyway, Thank you a lot for any help that you guys can give me.

Well the first thing that comes to mind would be “bezier curve”. If you google that you should find plenty on the subject with lots of unity specific tutorials.

Thank you for your response LeftyRighty.

In the first iteration of this problem I actually used a brezier curve to link the character to the finger of the user. I can post the code if someone is interested. However, that does not solve or simplify any of the problems that I mentioned, it simply draws a a different shaped curve.

I had to do something similar in my own game, and it turns out the answer is pretty simple. I also first tried a Bezier curve but it requires you to calculate control points (adding a lot of complexity to the problem) and they have significant limitations to the types of curves they can draw (for example you can’t draw a half-circle).

The first step is to address the user input requirements.

The maximum length is just a radius around the starting point. It’s a simple distance calculation – if the distance from the starting point to the ending point is greater than this distance, you don’t update anything. Unity provides Vector3.Distance for this (or if you’re targeting mobile, SqrDistance will be faster).

I’m not clear about what you mean by the “specified length” – is this different from the maximum length?

You state that the arc must have a minimum angle, but I suspect you really mean a maximum angle – the greatest rate of turn possible, no? So if the character doesn’t change direction at all, the angle is zero degrees, but the character (presumably) has an upper limit of how sharp a turn they can make in one turn, that is +/- n-degrees, a maximum angle. Unity provides Vector3.Angle to calculate the minimum angle between two points, so again, if that offset angle is greater than their maximum possible rate of turn, you don’t update anything.

That leaves drawing the line. You could probably further optimize the code below by keeping the List outside the function; set it up once in Awake or something, which would minimize allocs (you mentioned finger position so I’m guessing you’re on mobile). Note I haven’t tested this, I quickly rewrote my own function (which was loaded with a bunch of constants specific to my game), but it should get you pointed in the right direction… No pun intended. :slight_smile:

Edit: In my game I’m plotting points on the XZ plane, so rotation is around the Y axis. Tweak accordingly.

public int PlotPoints = 20; // list will be +1, since [0] is the starting point

public List<Vector3> PlotMovePoints(GameObject startingPoint, float angle, float distance)
{
    List<Vector3> plot = new List<Vector3>(PlotPoints + 1);
    Vector3 pos = startingPoint.transform.position;
    Vector3 fwd = startingPoint.transform.forward;
    plot.Add(pos); // start the curve at the startingPoint
    Quaternion rotation = Quaternion.Euler(0f, angle / PlotPoints, 0f);
    float distancePerStep = distance / PlotPoints;
    for(int i = 0; i < PlotPoints; i++)
    {
        fwd = (rotation * fwd).normalized;
        pos += fwd * distancePerStep;
        plot.Add(pos);
    }
    return plot;
}
1 Like

One more thing… in my game the user is clicking left/right buttons to change the turning orders. Since you’re using mouse position, you’ll need to know whether that offset angle is to the left or to the right. (The angle input to the function above should be positive for… I think a right turn, if I remember correctly, and negative for left.)

Anyway, you can figure out whether the mouse is to the left or right of the character position as shown here:

http://answers.unity3d.com/answers/13036/view.html

Hello MV10,

First of all, I apologise for the delayed reply, I was just implementing the advice you gave me.

I really cannot thank you enough for your help. Everything you told me helped me solve the problems I had, and the code you posted works perfectly, after changing the Z/Y orientation as you said.

Yes, I am targeting mobile platforms.

As you guessed, I meant maximum length. I used the words “specified length” because different characters would have different maximum lengths.

And again, yes, I meant maximum angle, instead of minimum angle.

Now I will work on getting the character moving following the curve, but I assume that should be easy: simple move the character from point to point in the curve.

Edit: I’ll probably post here again if this turns out more difficult than I expect, but hopefully it is easy :slight_smile:

Oh, and I just thought I should also thank you for the awkward stares at me in the bus when I literally laughed out loud reading your “not intended” pun xD

1 Like

lol, glad to help. Good luck.

If you need smooth movement, it’s pretty cheap to generate that list of points. You could even make a variation on the method that outputs them on the fly instead of building a list – you won’t need the “old” points after the character moves to them.

So you could build the initial list to draw the line (you could optimize the number of list entries based on the scale of your game and maybe the distance, but still initialize the list capacity once to the maximum size for best performance), then use the other function with much greater “resolution” (more steps) to make movement appear very smooth. And you can apply the rotation from that function to the character so that they also turn to face the correct direction throughout the move cycle.

2 Likes