Суть системы: игрок может лазать по лестницам и стенам, по любым поверхностям и вообще везде, где вы захотите. Реализовано в виде связки анимций, телепорта и работы с текстдравами. Пока готовится к релизу мой ФС, решил накидать такое решение, чтобы потом не было вопросов типа: "как добавить ещё лестницы?", "как выставить угол?" и т.п. Конструктив системы был взят с моего решения Chinatown Wars Teleport.
Для начала создадим необходимые переменные. У нас это связка текстдравов и координаты одной из поверхностей.
Как вы видите, угол поворота игрока тоже включён в массив. Пренебрегать им крайне не рекомендуется, т.к. сама система распределения поворотов и анимаций строится именно на нём.
Создадим текстдравы, элементы которых мы обозначили выше. На всякий пожарный добавил пикап с инфой (здание находится в СФ - с чёрными стенами, возле Cluckin' Bell):
Кому нужно - напишите отдельный код выгрузки текстдравов, пикапа и 3д-текста.
Теперь самое интересное. У меня начало движения начинается по нажатию клавиши (можете сделать и команду).
Ну и сами управляющие таймеры:
Вот и вся система. Аналогов, особенного такого уровня, не существует.
Автор: OKStyle
Для начала создадим необходимые переменные. У нас это связка текстдравов и координаты одной из поверхностей.
PHP:
new Text:BlackScreen[6], Float:LadderCoords[2][4] = {
{-1844.9794, 581.0343, 35.1683, 237.8849}, // подножие поверхности
{-1844.0436, 580.2306, 242.0142, 237.8849} // конечная точка
};
Создадим текстдравы, элементы которых мы обозначили выше. На всякий пожарный добавил пикап с инфой (здание находится в СФ - с чёрными стенами, возле Cluckin' Bell):
PHP:
CreatePickup(1239, 23, -1844.9794, 581.0343, 35.1683, -1);
Create3DTextLabel("Встаньте на пикап\nи нажмите ~k~~SNEAK_ABOUT~", 0x008080FF, -1844.9794, 581.0343, 35.1683, 40.0, 0, 0);
BlackScreen[0] = TextDrawCreate(642.0, 1.0, "~n~");
TextDrawLetterSize(BlackScreen[0], 0.5, 49.5);
TextDrawUseBox(BlackScreen[0], 1);
TextDrawBoxColor(BlackScreen[0], 0x000000AA);
TextDrawTextSize(BlackScreen[0], -2.0, 0.0);
BlackScreen[1] = TextDrawCreate(642.0, 1.0, "~n~");
TextDrawLetterSize(BlackScreen[1], 0.5, 49.5);
TextDrawUseBox(BlackScreen[1], 1);
TextDrawBoxColor(BlackScreen[1], 0x000000BB);
TextDrawTextSize(BlackScreen[1], -2.0, 0.0);
BlackScreen[2] = TextDrawCreate(642.0, 1.0, "~n~");
TextDrawLetterSize(BlackScreen[2], 0.5, 49.5);
TextDrawUseBox(BlackScreen[2], 1);
TextDrawBoxColor(BlackScreen[2], 0x000000CC);
TextDrawTextSize(BlackScreen[2], -2.0, 0.0);
BlackScreen[3] = TextDrawCreate(642.0, 1.0, "~n~");
TextDrawLetterSize(BlackScreen[3], 0.5, 49.5);
TextDrawUseBox(BlackScreen[3], 1);
TextDrawBoxColor(BlackScreen[3], 0x000000DD);
TextDrawTextSize(BlackScreen[3], -2.0, 0.0);
BlackScreen[4] = TextDrawCreate(642.0, 1.0, "~n~");
TextDrawLetterSize(BlackScreen[4], 0.5, 49.5);
TextDrawUseBox(BlackScreen[4], 1);
TextDrawBoxColor(BlackScreen[4], 0x000000EE);
TextDrawTextSize(BlackScreen[4], -2.0, 0.0);
BlackScreen[5] = TextDrawCreate(642.0, 1.0, "~n~");
TextDrawLetterSize(BlackScreen[5], 0.5, 49.5);
TextDrawUseBox(BlackScreen[5], 1);
TextDrawBoxColor(BlackScreen[5], 0x000000FF);
TextDrawTextSize(BlackScreen[5], -2.0, 0.0);
Теперь самое интересное. У меня начало движения начинается по нажатию клавиши (можете сделать и команду).
PHP:
if(newkeys & KEY_WALK) // если клавиша - идти пешком
{
for(new i = 0; i < sizeof(LadderCoords); i++) // пробегаемся по массиву с координатами
{
if(IsPlayerInRangeOfPoint(playerid, 1, LadderCoords[i][0], LadderCoords[i][1], LadderCoords[i][2])) // если находимся в радиусе ближайших координат
{
SetPlayerPos(playerid, LadderCoords[i][0], LadderCoords[i][1], LadderCoords[i][2]); // выравниваем позицию
SetCameraBehindPlayer(playerid); // сбрасываем камеру
SetPVarInt(playerid, "Iteration", 15); // выставляем задержку перед телепортом на конечные координаты
SetTimerEx("Ladder", 100, 0, "i", playerid); // запускаем систему подъёма
SetPVarInt(playerid, "LadderID", i); // указываем порядковый номер лестницы/поверхности
break; // обрываем цикл, т.к. ближайшие координаты найдены и нужные нам действия уже выполняются
}
}
}
PHP:
forward Ladder(playerid);
public Ladder(playerid)
{
new iter = GetPVarInt(playerid, "Iteration"), ladderid = GetPVarInt(playerid, "LadderID");
if(iter > 0)
{
switch(iter)
{
case 12:
{
new Float:a;
GetPlayerFacingAngle(playerid, a);
if(a > LadderCoords[ladderid][3] - 181.0 && a < LadderCoords[ladderid][3] + 1.0) // если угол в правую сторону
{
SetPlayerFacingAngle(playerid, LadderCoords[ladderid][3] + 90.0); // выставляем нужный угол для адекватной анимации
ApplyAnimation(playerid, "DOZER", "DOZER_Align_LHS", 3.5, 0, 1, 1, 1, 1000, 1);
}
else
{
SetPlayerFacingAngle(playerid, LadderCoords[ladderid][3] - 90.0);
ApplyAnimation(playerid, "DOZER", "DOZER_Align_RHS", 3.5, 0, 1, 1, 1, 1000, 1);
}
SetTimerEx("NoAnim", 1000, 0, "i", playerid); // выставляем таймер сброса анимации, чтобы не было фриза по её окончанию
}
case 6: TextDrawShowForPlayer(playerid, BlackScreen[0]); // отсюда начинается затемнение экрана текстдравами
case 5:
{
TextDrawHideForPlayer(playerid, BlackScreen[0]);
TextDrawShowForPlayer(playerid, BlackScreen[1]);
}
case 4:
{
TextDrawHideForPlayer(playerid, BlackScreen[1]);
TextDrawShowForPlayer(playerid, BlackScreen[2]);
}
case 3:
{
TextDrawHideForPlayer(playerid, BlackScreen[2]);
TextDrawShowForPlayer(playerid, BlackScreen[3]);
}
case 2:
{
TextDrawHideForPlayer(playerid, BlackScreen[3]);
TextDrawShowForPlayer(playerid, BlackScreen[4]);
}
case 1:
{
TextDrawHideForPlayer(playerid, BlackScreen[4]);
TextDrawShowForPlayer(playerid, BlackScreen[5]);
SetPlayerPos(playerid, LadderCoords[ladderid + 1][0], LadderCoords[ladderid + 1][1], LadderCoords[ladderid + 1][2]); // Выставляем игроку конечную позицию
}
}
SetPVarInt(playerid, "Iteration", iter - 1); // понижаем итерацию (круг обхода таймера)
SetTimerEx("Ladder", 100, 0, "i", playerid); // заново запускаем таймер
}
else if(iter == 0) // если итерации закончились
{
SetPlayerFacingAngle(playerid, LadderCoords[ladderid][3]); // выставляем нужный угол (обычно такой же, как и в начальной точке)
TextDrawHideForPlayer(playerid, BlackScreen[5]); // прячем текстдрав
ApplyAnimation(playerid, "PED", "CLIMB_Stand", 4.1, 0, 1, 1, 1, 1000, 1); // проигрываем конечную анимацию
SetTimerEx("NoAnim", 500, 0, "i", playerid); // выставляем таймер очистки анимации
DeletePVar(playerid, "LadderID"); // Удаляем ненужные PVar'ы
DeletePVar(playerid, "Iteration");
}
return 1;
}
forward NoAnim(playerid);
public NoAnim(playerid) return ClearAnimations(playerid);
Автор: OKStyle