PDA

Просмотр полной версии : [Include] Передвижение статичных NPC (Sa-mp 0.3.7.) - moveactors.inc



NewGreen
30.04.2015, 14:19
Приветствую вас.

Как стало недавно известно, новая версия SA-MP 0.3.7. будет поддерживать создание статичных NPC, которые не будут занимать слоты на сервере, и в отличии от прежних более просты в управлении и создании.
Цель их добавления очевидна, их можно использовать как продавцов в магазине, продавцов хотдогами и т.п. но они не умеют ходить т.е. передвигаться (т.к. они статичные).
Я решил, что можно добавить возможность хотьбы для статичных NPC, и создал группу функций для этого.

Представляю вам moveactors.inc - данный include позволяет статичным NPC передвигаться (ходить) по заданным координатам.

Описание основных функций:

MoveActorToPos - основная функция для передвижения статичного NPC


MoveActorToPos(actorid,X,Y,Z,action)

actorid - номер (ID) - передвигаемого NPC
X,Y,Z - координаты (точка) к которым NPC должен подойти
action - переключатель режима 0 - ходьба, 1 - бег.

IsActorMoving - функция (макрозамена) проверяющая достиг ли NPC конечной точки назначения


IsActorMoving(actorid)

actorid - номер (ID) - передвигаемого NPC
Функция IsActorMoving возвращает:
true - если NPC находится в пути
false - если NPC не двигается


Описание вспомогательных функций:

IsActorInCube - проверка нахождения NPC в заданных координатах (в кубе) (не работает при движении NPC)

IsActorInCube(actorid, x, y, z, edge)
actorid - номер (ID) - NPC
x,y,z - координаты (точка) места проверки
edge - радиус проверки (вернее говоря длина ребер куба)
Функция ActorInPoint возвращает:
true - если NPC находится в координатах
false - если NPC не находится в координатах

SetActorFacingPos - поворот NPC лицом к заданным координатам

SetActorFacingPos(actorid, x,y)
actorid - номер (ID) - NPC
x,y - координаты (точка) к которым NPC должен повернутся

Подключение:

Включите include после a_samp


#include <moveactors>


Использование:

Применение функции зависит целиком и полностью от вашей фантазии, но не стоит ждать чудес, приведу простой пример:
Команда - передвижение NPC к вашим координатам:


new id = CreateActor(...);
...
if (strcmp("/moveactor", cmd, true,10))
{
if(IsActorMoving(id)) SendClientMessage(playerid,-1,"Ваш NPC все еще идет к вам"); // id - номер созданного ранее NPC
new Float:X, Float:Y, Float:Z;
GetPlayerPos(playerid, X, Y, Z);
MoveActorToPos(id,X, Y, Z, 0); // id - номер созданного ранее NPC
return 1;
}
...


Достоинства и недостатки:

+ Гарантированное достижение NPC заданной точки

- Передвижение происходит по времени
- Передвижение только по прямым линиям*
- Небольшая неточность анимации при движении*

* - (возможно будет исправлено в след. версии)


UPD 1 (07.05.2015):

- Оптимизация кода;
- Изменены названия пользовательских функций и порядок их параметров:
ActorInPoint(Float:r, actorid, Float:x, Float:y, Float:z) на IsActorInCube(actorid, Float:x, Float:y, Float:z, Float:edge)
SetActorFaceToPos(Float:X,Float:Y, actorid) на SetActorFacingPos(actorid, Float:x, Float:y)
Функция OnActorMakeIt(actorid) заменена на макрос IsActorMoving(actorid)

UPD 2 (12.05.2015):

- Добавлена возможность бега для NPC
- В функцию MoveActorToPos добавлен параметр action для переключения режимов NPC (ходьба, бег)

UPD 3 (12.05.2015):

- Исправлена ошибка проверки параметра action в функции MoveActorToPos

Скачивание:

Rghost.ru (http://rghost.ru/7gBvChJxk)
Pastebin.com (http://pastebin.com/tkxhzSFm)

Спасибо за внимание!
Автор: NewGreen

Desulaid
30.04.2015, 14:45
В принципе с ними можно будет сделать штат оживленнее + добавить ЭРПЭшности на сервер. Уже придумал куда можно парочку засунуть :)

L0ndl3m
01.05.2015, 17:09
Насчёт передвижений по прямой линии, то я бы не сказал, что это это минус. Можно несколько раз вызвать функцию для перемещения бота, создав массив с координатами, и переменную ( для счётчика ).

Daniel_Cortez
01.05.2015, 21:33
stock Float:GetDistanceBetweenCoords(actorid,Float:x2,Float:y2,Float:z2)
Сразу бросается в глаза обобщённое название функции - "GetDistanceBetweenCoords" - оно совершенно не говорит о том, что она возвращает расстояние между актёром и точкой.
В качестве решения могу предложить название "GetDistanceFromActorToPoint".




return floatsqroot(floatpower(floatabs(floatsub(x2,x1)),2)+...
1. Зачем вычислять модуль числа, если оно возводится в квадрат?
2. Явное указание floatsub совершенно не нужно - всё равно компилятор заменит знак "-" на вызов нативной функции (подчёркиваю, именно нативной, а не какой-то функции-"обёртки" на Pawn).




stock ActorInPoint(Float:r, actorid, Float:x, Float:y, Float:z)
Здесь я так и не понял, чего вы пытались добиться в этой функции.
Во-первых, если функция возвращает булевое значение, логично было бы начать её название с "Is".
Во-вторых, перепутан порядок аргументов функции - по логике сначала должен указываться актёр, а затем уже радиус и координаты.
Возьмите для сравнения любые функции SA:MP для работы с транспортом - везде первым указывается ID машины.

GetVehicleModelInfo
GetVehicleHealth
GetVehiclePos

В-третьих, название функции говорит о том, что для возврата true игрок должен находиться именно в указанной точке, а не возле неё.
Для последнего было бы логичнее использовать название IsActorNearPoint.
В-четвёртых, настораживает реализация функции. Вы проверяете вхождение координат игрока не в шар с указанным радиусом, а в куб.
Тогда так и назовите функцию: IsActorInCube(actorid, x, y, z, edge).
Здесь edge - это длина ребра куба. Соответственно, вместо r можно будет использовать edge/2.






stock SetActorFaceToPos(Float:X,Float:Y, actorid) // This function allows you to change the actor's face turn to the coordinates
{
new Float:pX,Float:pY,Float:pZ,Float:ang;
GetActorPos(actorid, pX, pY, pZ);
if( Y > pY ) ang = (-acos((X - pX) / floatsqroot((X - pX)*(X - pX) + (Y - pY)*(Y - pY))) - 90.0);
else if( Y < pY && X < pX ) ang = (acos((X - pX) / floatsqroot((X - pX)*(X - pX) + (Y - pY)*(Y - pY))) - 450.0);
else if( Y < pY ) ang = (acos((X - pX) / floatsqroot((X - pX)*(X - pX) + (Y - pY)*(Y - pY))) - 90.0);
if(X > pX) ang = (floatabs(floatabs(ang) + 180.0));
else ang = (floatabs(ang) - 180.0);
SetActorFacingAngle(actorid, ang);
return false;
}


Опять же, перепутаны местами аргументы.
Реализовать функцию можно было куда проще:

http://pro-pawn.ru/showthread.php?12246
В чём смысл возвращаемого функцией значения (false)?





stock OnActorMakeIt(actorid) {
return actorMakeIt[actorid] ? true:false;
}

Египетские скобки (K&R)? Ну вы уж определитесь-то со стилем...
С "On" обычно начинаются названия автовызываемых функций.
Гораздо логичнее было бы сделать функцию "IsActorMoving".
Зачем усложнять возврат тернарным выражением?
Для чего вообще нужна функция, если массив actorMakeIt и без того доступен вне инклуда?
Вы уж либо задайте массиву атрибут static, чтобы он был виден только в пределах инклуда, либо хотя бы уберите функцию.






public MoveActorToPos(actorid,Float:X,Float:Y,Float:Z) {
if(actorTimers[actorid] != -1) {
ApplyActorAnimation(actorid,"CARRY","crry_prtial",4.0,0,0,0,0,0);
KillTimer(actorTimers[actorid]);
actorTimers[actorid] = -1;
}
actorMakeIt[actorid] = true;
SetActorFaceToPos(X,Y, actorid);
ApplyActorAnimation(actorid, "ped", "WALK_civi", 4.1, 1, 1, 1, 0, 0);
actorTimers[actorid] = SetTimerEx("StopMoveActorToPos", floatround((GetDistanceBetweenCoords(actorid,X,Y,Z)/1.5357)*918), false, "ifff", actorid,X,Y,Z);
return false;
}

Зачем в if сбрасывается анимация, если потом всё равно будет задана анимация бега?
Присвоение -1 в actorTimers[actorid] бессмысленно по аналогичной причине.





public StopMoveActorToPos(actorid,Float:X,Float:Y,Float:Z) {
KillTimer(actorTimers[actorid]);
SetActorPos(actorid,X,Y,Z-0.1);
actorMakeIt[actorid] = false;
ApplyActorAnimation(actorid,"CARRY","crry_prtial",4.0,0,0,0,0,0);
return false;
}


"StopActor"?
actorTimers[actorid] не сбрасывается в -1.

NewGreen
01.05.2015, 23:28
Сразу бросается в глаза обобщённое название функции - "GetDistanceBetweenCoords" - оно совершенно не говорит о том, что она возвращает расстояние между актёром и точкой.
В качестве решения могу предложить название "GetDistanceFromActorToPoint".



1. Зачем вычислять модуль числа, если оно возводится в квадрат?
2. Явное указание floatsub совершенно не нужно - всё равно компилятор заменит знак "-" на вызов нативной функции (подчёркиваю, именно нативной, а не какой-то функции-"обёртки" на Pawn).



Здесь я так и не понял, чего вы пытались добиться в этой функции.
Во-первых, если функция возвращает булевое значение, логично было бы начать её название с "Is".
Во-вторых, перепутан порядок аргументов функции - по логике сначала должен указываться актёр, а затем уже радиус и координаты.
Возьмите для сравнения любые функции SA:MP для работы с транспортом - везде первым указывается ID машины.

GetVehicleModelInfo
GetVehicleHealth
GetVehiclePos

В-третьих, название функции говорит о том, что для возврата true игрок должен находиться именно в указанной точке, а не возле неё.
Для последнего было бы логичнее использовать название IsActorNearPoint.
В-четвёртых, настораживает реализация функции. Вы проверяете вхождение координат игрока не в шар с указанным радиусом, а в куб.
Тогда так и назовите функцию: IsActorInCube(actorid, x, y, z, edge).
Здесь edge - это длина ребра куба. Соответственно, вместо r можно будет использовать edge/2.





Опять же, перепутаны местами аргументы.
Реализовать функцию можно было куда проще:

http://pro-pawn.ru/showthread.php?12246
В чём смысл возвращаемого функцией значения (false)?





Египетские скобки (K&R)? Ну вы уж определитесь-то со стилем...
С "On" обычно начинаются названия автовызываемых функций.
Гораздо логичнее было бы сделать функцию "IsActorMoving".
Зачем усложнять возврат тернарным выражением?
Для чего вообще нужна функция, если массив actorMakeIt и без того доступен вне инклуда?
Вы уж либо задайте массиву атрибут static, чтобы он был виден только в пределах инклуда, либо хотя бы уберите функцию.




Зачем в if сбрасывается анимация, если потом всё равно будет задана анимация бега?
Присвоение -1 в actorTimers[actorid] бессмысленно по аналогичной причине.




"StopActor"?
actorTimers[actorid] не сбрасывается в -1.


Написал просто так ради проверки, версия beta, хотел увидеть реакцию сообщества, что, нужно ли вообще кому либо передвигать NPC, в связи чем написал все быстро, особо не обращая внимания на названия функций и некоторые недочеты.
Спасибо за адекватную критику, постараюсь в след. версии учесть недочеты.

NewGreen
07.05.2015, 12:36
UPD 1 (07.05.2015):

- Оптимизация кода;
- Изменены названия пользовательских функций и порядок их аргументов:
ActorInPoint(Float:r, actorid, Float:x, Float:y, Float:z) на IsActorInCube(actorid, Float:x, Float:y, Float:z, Float:edge)
SetActorFaceToPos(Float:X,Float:Y, actorid) на SetActorFacingPos(actorid, Float:x, Float:y)
Функция OnActorMakeIt(actorid) заменена на макрос IsActorMoving(actorid)

NewGreen
12.05.2015, 14:49
UPD 2 (12.05.2015):

- Добавлена возможность бега для NPC
- В функцию MoveActorToPos добавлен параметр action для переключения режимов NPC (ходьба, бег)

UPD 3 (12.05.2015):

- Исправлена ошибка проверки параметра action в функции MoveActorToPos

ziggi
14.05.2015, 00:34
Позиция, изменяемая анимациями, не синхронизируется, поэтому это пригодно только для однопользовательского применения.

Daniel_Cortez
14.05.2015, 06:03
Позиция, изменяемая анимациями, не синхронизируется, поэтому это пригодно только для однопользовательского применения.

Если игрок находится далеко от актёра (вне зоны стрима) и его телепортировать рядом с этим актёром (либо он сам подойдёт достаточно близко), то да, анимация и местоположение не синхронизируются. Тем не менее, позиция синхронизируется, как только актёр дойдёт до заданной точки.
Не такая уж и большая потеря... Особенно если учитывать, что другого выбора и нету (this is SAMP, just deal with it).

Gressie
08.02.2017, 14:12
Актер, не передвигается, а телепортируется.

Витёк
08.02.2017, 16:31
Актер, не передвигается, а телепортируется.

ну так сделай что-бы передвигался что сложно
(у тебя не получится сверх ряльного передвижения NPC как его кроме тп не заставить идти :blush2:)