Calculating points on a semi circle

Hi all,
I have a question regarding calculating points on a semi circle, with increasing radius. I managed to create a semi circle from X amount of points (in this case 8), but the point don’t start on the right place (the whole thing needs to rotate a certain angle, starting from the npc in random direction).

Here is the code and some explanation:
It uses a random direction (clockwise or counterclockwise) by randomly using +1 or -1.
radius for the npc->player is the initial radius, and stepwise (radius increment) this should increases up to the fleedistance radius.

direction = 1 * (Random.Range(0, 2) * 2 - 1);
int amountOfPoints = 8;
Vector3 playerPos = player.transform.position;
Vector3 npcPos = npc.transform.position;
Vector3 playerPosProj = new Vector3(playerPos.x, npcPos.y, playerPos.z); //only consider x and z axis, it should all take place on the ground.
float radius = Vector3.Distance(playerPosProj, npcPos);
float fleedistance = NPCProperties.fleeDistance;

for (int i = 0; i < amountOfPoints; i++)
{
    //logic to calculate the specific points.
    Vector3 dirToPlayer = npc.transform.position - player.transform.position;
    float correctionAngle = Vector3.Angle(dirToPlayer, player.position);
    float angle = 180 / amountOfPoints * i + (direction * correctionAngle);

    //radius should be gradually calculated. From beginning it should start with the distance player->npc and increase up to the fleedistance (+correction).
    //last i should have multiply of fleedistance+radius, first should have 1/amountOfPoints th of the fleedistance added to the current distance.
    float radiusIncrement = fleedistance * ((i / amountOfPoints));
    float incrementingRadius = radius + radiusIncrement;
    //float randomDirection = either -1 or +1;
    float radian = Mathf.Deg2Rad * angle;
    float x = incrementingRadius * Mathf.Cos(radian) + incrementingRadius * Mathf.Sin(radian) + playerPosProj.x;
    float z = -incrementingRadius * Mathf.Sin(radian) + incrementingRadius * Mathf.Cos(radian) + playerPosProj.z;

    Vector3 subpoint = new Vector3(x, npcPos.y, z);

    //Creates an object on the place for debugging
    GameObject sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    sphere.transform.position = subpoint;
    sphere.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);

    points.Add(subpoint);
}

I haven’t tested your code, but from just looking at it I see a few things:

  • line 13: dirToPlayer should probaby be player.transform.position - npc.transform.position; (to fit the variable name at least, this would give a vector pointing from the NPC’s position to the player)
  • line 14: not sure what the intention is here, but calculating the angle between a vector describing a direction and a vector describing a position is odd to me
  • line 15 & 19: in both these lines part of the calculations are done with integers so the resulting values might not be what you expect, specifically the last part in line 19 (i / amountOfPoints) is a division of two integer values, so as long as i is smaller than amountOfPoints, that part will always evaluate to 0 (because integer division simply cuts off the part after the comma, no rounding - you can see what I mean by running e.g. Debug.Log(4 / 5); and Debug.Log(6 / 5);). To get a float result, one of the two values has to be a float. Since both are integers (and rightfully so) you have to cast one of them to a float for that calculation like so: (i / (float)amountOfPoints). For the same reason line 15 doesn’t do what you are likely expecting it to: looking at operator precedence, the part within the braces is evaluated first, no trouble there. Next in line are the * and / operators: the result of 180 / numberOfPoints * i won’t have decimal places and thus might not be what you expect (here 180 / 8 evaluates to 22, not the mathematically correct 22.5).

Check if adjusting those lines helps.
Regarding the point about line 14, I’ll summarize how I would do it (not to say that is the best way):

  • Calculate the vector from player to npc (npc.transform.position - player.transform.position) and normalize it
  • In the loop, multiply that vector by your incrementingRadius
  • In the loop, calculate the current angle as 180f / amountOfPoints * i; (notice the f after 180, making it a float literal and thus ensuring the whole calculation use floating point arithmetic)
  • In the loop, calculate the “subpoint” by multiplying the scaled vector from above by a rotation of the angle from above about the y axis (assuming that’s “up” in your game world) using Quaternion.AngleAxis(angle, Vector3.up);

Hope that helps

2 Likes

Super, thank you! I will test it :slight_smile: