SA-MP Forums Archive
NPC chase the nearest player - Printable Version

+- SA-MP Forums Archive (https://sampforum.blast.hk)
+-- Forum: SA-MP Scripting and Plugins (https://sampforum.blast.hk/forumdisplay.php?fid=8)
+--- Forum: Scripting Help (https://sampforum.blast.hk/forumdisplay.php?fid=12)
+--- Thread: NPC chase the nearest player (/showthread.php?tid=659045)



NPC chase the nearest player - matje - 21.09.2018

Hi guys.
First of all, I ******d, searched multiple forums but could not find solution to this.
I'm using FCNPC. How can I create so the NPC's recognize and chase the closest player?
Can somebody shed some light on this please? Thank you.


Re: NPC chase the nearest player - CodeStyle175 - 21.09.2018

you create timer what loops throw players, when player is near to npc for example 5.0 units, then npc idle state changes to walk state and npc starts to follow player.


Re: NPC chase the nearest player - Ritzy2K - 21.09.2018

https://sampforum.blast.hk/showthread.php?tid=432342

Код:
FCNPC_GoToPlayerEx
I believe this is what you're looking for!


Re: NPC chase the nearest player - ZiGGi - 21.09.2018

Just look at the bodyguard script: https://github.com/ziggi/FCNPC/blob/...bodyguards.pwn
Especially on the BG_FollowPlayer function.


Re: NPC chase the nearest player - matje - 21.09.2018

Thanks everyone, with your help I got the NPC to recognize the closest player and chase him.
Now the issue is that the NPC's target doesn't change. They will always chase the one initial player even though other players are closer to them. I've used timer to update the closest player every half second, but the NPC does not change the target.


Re: NPC chase the nearest player - NaS - 21.09.2018

Quote:
Originally Posted by matje
Посмотреть сообщение
Thanks everyone, with your help I got the NPC to recognize the closest player and chase him.
Now the issue is that the NPC's target doesn't change. They will always chase the one initial player even though other players are closer to them. I've used timer to update the closest player every half second, but the NPC does not change the target.
Could you post the related code? Otherwise we have to guess what could be the cause


Re: NPC chase the nearest player - matje - 21.09.2018

Quote:
Originally Posted by NaS
Посмотреть сообщение
Could you post the related code? Otherwise we have to guess what could be the cause
Sorry about that, you are right

Код:
for(new i=0; i < MAX_PLAYERS; i++){
	    new Float:xp, Float: yp, Float: zp;
	    GetPlayerPos(playerid, xp, yp, zp);
        for(new iz = 0; iz < WaveZombies; iz++){
    		if(FCNPC_IsValid(Zombies[iz])){
		        if(IsPlayerInRangeOfPoint(Zombies[iz], 10, xp, yp, zp)){
		             FCNPC_GoToPlayer(Zombies[iz], playerid, FCNPC_MOVE_TYPE_RUN, FCNPC_MOVE_SPEED_RUN, false, 0.0, true, 0.0, 1.5, 250);



Re: NPC chase the nearest player - NaS - 21.09.2018

Quote:
Originally Posted by matje
Посмотреть сообщение
Sorry about that, you are right

Код:
for(new i=0; i < MAX_PLAYERS; i++){
	    new Float:xp, Float: yp, Float: zp;
	    GetPlayerPos(playerid, xp, yp, zp);
        for(new iz = 0; iz < WaveZombies; iz++){
    		if(FCNPC_IsValid(Zombies[iz])){
		        if(IsPlayerInRangeOfPoint(Zombies[iz], 10, xp, yp, zp)){
		             FCNPC_GoToPlayer(Zombies[iz], playerid, FCNPC_MOVE_TYPE_RUN, FCNPC_MOVE_SPEED_RUN, false, 0.0, true, 0.0, 1.5, 250);
This code does not determine the closest player.

It will select everyone in range as target, the highest playerid will then be the final target as it is set last.

To make it actually search for closest player, you can declare two variables before the loop.
One for the target playerid and one for the distance.

Then use GetPlayerDistanceToPoint instead of IsPlayerInRangeOfPoint. If that distance is lower than the current target's distance, update the target variable and the distance.

After the loop, the target variable will contain the closest playerid.

Something like this:

Код:
new target_id = -1, Float:distance = 10.0; // max distance can be configured here

for(new i = 0; i < MAX_PLAYERS; i ++)
{
	new Float:x, Float:y, Float:z, Float:tmp_distance;
	GetPlayerPos(i, x, y, z);
	tmp_distance = GetPlayerDistanceFromPoint(ZombieID, x, y, z);

	if(tmp_distance < distance)
	{
		distance = tmp_distance;
		target_id = i;
	}
}

if(target_id != -1)
{
	// target_id is the closest player
}
else
{
	// No target found, do something else
}
This should be your inner loop, the outter loop should be the loop for the zombies (ZombieID).

Also you might want to consider using foreach in combination with the streamer plugin.
foreach will allow for more efficient loops.

With the Streamer Plugin you can create a dynamic area and attach it to the zombies. Then you can just loop through players that are already in those areas instead of checking all zombies vs all players. That will considerably lower the number of distance checks, as it's highly unlikely that all players are always near all zombies.


Re: NPC chase the nearest player - matje - 21.09.2018

Quote:
Originally Posted by NaS
Посмотреть сообщение
This code does not determine the closest player.

It will select everyone in range as target, the highest playerid will then be the final target as it is set last.

To make it actually search for closest player, you can declare two variables before the loop.
One for the target playerid and one for the distance.

Then use GetPlayerDistanceToPoint instead of IsPlayerInRangeOfPoint. If that distance is lower than the current target's distance, update the target variable and the distance.

After the loop, the target variable will contain the closest playerid.

Something like this:

Код:
new target_id = -1, Float:distance = 10.0; // max distance can be configured here

for(new i = 0; i < MAX_PLAYERS; i ++)
{
	new Float:x, Float:y, Float:z, Float:tmp_distance;
	GetPlayerPos(i, x, y, z);
	tmp_distance = GetPlayerDistanceFromPoint(ZombieID, x, y, z);

	if(tmp_distance < distance)
	{
		distance = tmp_distance;
		target_id = i;
	}
}

if(target_id != -1)
{
	// target_id is the closest player
}
else
{
	// No target found, do something else
}
This should be your inner loop, the outter loop should be the loop for the zombies (ZombieID).

Also you might want to consider using foreach in combination with the streamer plugin.
foreach will allow for more efficient loops.

With the Streamer Plugin you can create a dynamic area and attach it to the zombies. Then you can just loop through players that are already in those areas instead of checking all zombies vs all players. That will considerably lower the number of distance checks, as it's highly unlikely that all players are always near all zombies.
Holy fuck you are my hero
Thank you so much, it works!

I've used

Код:
foreach(Player, i)
{
    //stuff
}
Instead of

Код:
for(new i = 0; i < MAX_PLAYERS; i++)
{
    if(IsPlayerConnected(i))
    {
        //stuff
    }
}
because (I think) foreach loops only through players, not NPCS.

Also thank you for the great tips.