In my space trading game prototype I have also NPCs who run errands in such way:
- A new random mission is assigned to them, from the system they are currently on, to a random system (different from the one they are on)
- They are "flagged" as being on mission
- They travel from ORIGIN to TARGET
- Upon arrival on TARGET they are "flagged" as being NOT on mission
- A new random mission is assigned to them
- Go to point 2
The problem I have is that this "routine" does not seem to happen "endlessly" as it should. It randomly lasts an average 3 to - maybe - 5 cycles, then the NPC will get a new mission, with new coords, and just sit there, although they are flagged as being "on mission".
I have double checked and the coords are always within the bounds and "real", so I'm not sure what I'm getting wrong. Maybe someone here can provide some feedback?
Here comes the code in the order in which it is compiled:
// Movement uses a pretty basic algorithm.
// Manhattan distance to calculate the distance between the NPC and its target
function Person::Move(int toX, int toY)
{
int x1 = this.X;
int y1 = this.Y;
int x2 = toX;
int y2 = toY;
float tx = IntToFloat(x2 - x1);
float ty = IntToFloat(y2 - y1);
int dist = GetDistance(this.X, this.Y, x2, y2);
if (dist > 0)
{
tx = tx/IntToFloat(dist);
ty = ty/IntToFloat(dist);
this.X += FloatToInt(Maths.Ceil(tx));
this.Y += FloatToInt(Maths.Ceil(ty));
}
}
/// Move People who are flagged as being on mission towards their destination
function MovePerson(int who)
{
// The ID of the mission an NPC is on (always 0 in this test)
int mission_id = People[who].MissionID;
// The ID of the target planet
int target_planet = Missions[mission_id].TargetPlanet;
// The current X/Y coords of the NPC
int pX = People[who].X;
int pY = People[who].Y;
// The X/Y coords of the target planet
int toX = planetarySystem[target_planet].X;
int toY = planetarySystem[target_planet].Y;
// If the NPC is on the target planet
if (pX == toX && pY == toY)
{
// Then is not on mission anymore
People[who].IsOnMission = false;
// Former target planet becomes new starting position
People[who].Where = Missions[mission_id].TargetPlanet;
}
else
{
// Move towards the target planet
People[who].Move(toX, toY);
}
}
// This is the main function who controls the routine
function NextTurn(int turns)
{
for (int t = 0; t < turns; t++)
{
// If NPC (always 0 in this test) is flagged as being on mission
if (People[0].IsOnMission)
{
// Then move NPC (always 0 in this test)
MovePerson(0);
}
else
{
// Check that this code is actually being executed
Display("New Mission!");
int person = 0; // Always 0 in this test
// Select a random type of mission
int type = Random(MISSION_TYPES-1);
// Select the starting planet to be the same as the one the NPC is sitting on
int startPlanet = People[person].Where;
// Select a random target planet
int targetPlanet = Random(TOTAL_SYSTEMS-1);
// Repeat if start and target planets are the same
if ((targetPlanet == startPlanet))
{
do
{
targetPlanet = Random(TOTAL_SYSTEMS-1);
} while ((targetPlanet == startPlanet));
}
Missions[0].AssignedTo = 0; // The ID of the NPC to which this mission is assigned
Missions[0].ID = 0; // The ID of the mission
Missions[0].OriginPlanet = startPlanet;
Missions[0].TargetPlanet = targetPlanet;
Missions[0].Type = type;
People[0].MissionID = 0; // The same as Mission[0].ID
People[0].IsOnMission = true;
}
// Draw the pixels on the screen!
map.DrawPixelPeople();
}
}
// This is the debug function I'm using to test the whole thing
function on_key_press(eKeyCode keycode)
{
if (keycode == eKey1)
{
for (int i = 0; i < 1500; i++)
{
NextTurn(1);
Wait(1); // I want to see it moving on the screen!
}
}
}
Thanks in advance and I hope I have made everything clear!
EDIT:
The issue is apparently solved by changing Math.Ceil() to Math.Round() in the Person::Move() function.
vga256 suggested me to go deeper with the debug and I just did that. I'm not sure why the calculation caused the problem, but now it seems to be working as intended!