Доступ к готовым решениям

Переход в группу "Пользователь"

300.00
Одноразовый платёж
Быстрый переход в группу "Пользователи", без надобности написания постов и ожидания.

Покупка дает возможность:
Быть полноправным участником форума
Нормальное копирование кода
Создавать темы
Скачивать файлы
Доступ к архиву Pawno-Info

Урок Изменение скорости машин

Shersula

Начинающий
Пользователь
Регистрация
30 Дек 2018
Сообщения
16
Лучшие ответы
0
Репутация
0
Приветствую всех кто наткнулся на данный урок.
Часто видел, что люди спрашивают как изменяют скорости отдельных машин, повышать максимальную и так далее.
В данном уроке я отвечу на этот вопрос, а так же подробно разжую код, чтобы даже совсем новички смогли понять это, приступим.

P.S Данный урок является примером написания системы изменения скорости машин, он не является примером написания идеально оптимизированного и красивого кода.

Хочу сказать, что в данном уроке я использовал Col_Andreas дабы реализовать проверку того, касается ли машина земли.

И так, для начала перейдём к паблику OnPlayerKeyStateChange который вызывается при нажатии игроком определённой клавиши, добавим туда эти строки
PHP:
if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER && (newkeys & KEY_HANDBRAKE || newkeys & KEY_JUMP))SetPVarInt(playerid, "Space_or_s_Pressed", 1);
else if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER && (oldkeys & KEY_HANDBRAKE || oldkeys & KEY_JUMP))SetPVarInt(playerid, "Space_or_s_Pressed", 0);
if(newkeys & KEY_SPRINT  && GetPlayerState(playerid) == PLAYER_STATE_DRIVER && !GetPVarInt(playerid, "SpeedTimer") && !GetPVarInt(playerid, "Space_or_s_Pressed"))
{
	new timerid;
	timerid = SetTimerEx("SetSpeed", 250, true, "i", playerid);
	SetPVarInt(playerid, "SpeedTimer", timerid);
}
else if(oldkeys & KEY_SPRINT && GetPlayerState(playerid) == PLAYER_STATE_DRIVER)
{
	KillTimer(GetPVarInt(playerid, "SpeedTimer"));
	DeletePVar(playerid, "SpeedTimer");
}
Разберём код по строчкам:

if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER && (newkeys & KEY_HANDBRAKE || newkeys & KEY_JUMP))SetPVarInt(playerid, "Space_or_s_Pressed", 1) - Бывает ситуация когда игрок в машине и сначала нажимает допустим space или s а после w и получится так, что игрок стоя на пробеле или нажав s перед w будет всё равно получать ускорение, для этого мы и должны будем отслеживать нажатие этих кнопок, для этой цели будем использовать переменную игрока под именем 'Space_or_s_Pressed'
else if(GetPlayerState(playerid) == PLAYER_STATE_DRIVER && (oldkeys & KEY_HANDBRAKE || oldkeys & KEY_JUMP))SetPVarInt(playerid, "Space_or_s_Pressed", 0) - Здесь мы просто ставим значение переменной 'Space_or_s_Pressed' на 0 для того чтобы знать, что игрок отпустил Space/S

if(newkeys & KEY_SPRINT && GetPlayerState(playerid) == PLAYER_STATE_DRIVER && !GetPVarInt(playerid, "SpeedTimer") && !GetPVarInt(playerid, "Space_or_s_Pressed")) - Проверка на то нажал ли игрок кнопку 'W', находится ли он в машине, проверка на то не работает ли таймер присвоения скорости для машины в момент нажатия кнопки и проверка на то не держит ли игрок space/s
new timerid - Создаем переменную timerid в которую запишем id таймера который будет вызываться каждую 0,5 секунду
timerid = SetTimerEx("SetSpeed", 500, true, "i", playerid) - Создание таймера который будет вызывать паблик SetSpeed(Разберем ниже) и присвоение id таймера в переменную timerid
SetPVarInt(playerid, "SpeedTimer", timerid) - Записываем id созданного таймера в переменную игрока 'SpeedTimer' для того что бы мы могли в будущем удалить этот таймер.

else if(oldkeys & KEY_SPRINT && GetPlayerState(playerid) == PLAYER_STATE_DRIVER) - Проверка на то отпустил ли игрок кнопку 'W' а так же проверка на то, находится ли игрок в машине.(Прекращаем выдачу ускорения если игрок игрок отпустил w в машине)
KillTimer(GetPVarInt(playerid, "SpeedTimer")) - Killtimer Удаляет таймер по id'у в данном случае id мы записали в переменную игрока 'SpeedTimer'
DeletePVar(playerid, "SpeedTimer") - удаляем переменную игрока 'SpeedTimer' так как id удаленного таймера нам не к чему

UPD: Почему-то была проблема, что когда игрок ехал и допустим нажимал пробел то после того как он отпуска его, проверка на key_sprint в newkeys срабатывала но после этого она срабатывала сразу же и в oldkeys не знаю с чем это связано, ведь по логике в момент того когда мы отпускаем пробел в old_keys должен быть key_handbrake. В общем, else if в oldkeys решил эту проблему, т.к в нашем случае если одна проверка проходит то вторую проверку можно и не делать(проверка на oldkeys)

С этой частью кода разобрались но, что за паблик SetSpeed? Сейчас разберём.
PHP:
forward SetSpeed(playerid);
public SetSpeed(playerid)
{
    new Float:Speed, carid, Float:rx, Float:ry, Float:rz, Float:x,Float:y,Float:z;
    carid = GetPlayerVehicleID(playerid);
    GetVehicleVelocity(carid,x,y,z);		
    Speed = floatsqroot(floatpower(floatabs(x),2) + floatpower(floatabs(y),2) + floatpower(floatabs(z),2))*180/1.609344;
    GetVehicleRotation(carid, rx, ry, rz);
    if(rx > 65 || rx < -65 || ry > 50 || ry < -55) return 1;
    if(Speed < 170 && CA_IsPlayerOnSurface(playerid))SetVehicleSpeed(carid, 15);
    return 1;
}
Данный паблик будет вызываться каждую 0,5 секунду после того как игрок нажал 'W' в машине.
Давайте разберём его:
new Float:Speed, carid, Float:rx, Float:ry, Float:rz, Float:x,Float:y,Float:z - Создаем переменные для общей скорости машины(speed) id машины(carid), скорости по осям x y z и поворота машины по осям x y и z
carid = GetPlayerVehicleID(playerid) - Получаем id машины в которой сидит игрок
GetVehicleVelocity(carid,x,y,z) - Получаем скорость машины по осям x y z
Speed = floatsqroot(floatpower(floatabs(x),2) + floatpower(floatabs(y),2) + floatpower(floatabs(z),2))*180/1.609344 - Получаем общую скорость машины для этого мы берем модули x y z, возводим их в квадрат, складываем и получаем квадратный корень, но заметьте мы так же умножаем полученное число на 180/1.609344 это делается для перевода нашей скорости в км/ч (Полученное число запишется в переменную speed это и будет общая скорость)
Floatabs - модуль числа, если число отрицательное, что не исключено, делает его положительным.
Floatpower - возведение числа в степень, в нашем случае в квадрат.
Floatsqroot - вычисление квадратного корня.
Если вы не поняли то как мы получили общую скорость, то советую вам урок от Urukhay о скорости он очень хорошо описал это.
GetVehicleRotation(carid, rx, ry, rz) - Получение наклона(поворота) машины по осям x y z это нужно для того что бы когда машина скользила на боку допустим и не касалась колёсами земли ей не давалось ускорение. Данной функции по стандарту нету поэтому мы разберём её ниже.
if(rx > 65 || rx < -65 || ry > 50 || ry < -55) - Проверка на то наклонена ли машина по осям x и y. Положительные значения это наклон в одну сторону, а отрицательные это наклон в противоположную сторону. Ниже прикреплю фотографию с wiki по сампу где показаны координаты x и y(если не описывать подробно то сделано это для того что бы не ускорять машину пока она скользит на боку или крыше)

if(Speed < 170 && CA_IsPlayerOnSurface(playerid))SetVehicleSpeed(carid, 15) - Проверка на скорость транспорта, если больше 170 то ускорение не выдается(можно сделать switch (GetVehicleModel(carid)) и установить каждой машине свою максимальную скорость) а также проверка из Col_Andreas (CA_IsPlayerOnSurface) на то касается ли игрок земли(Дабы не выдавать ускорение машине когда она летит, падает со скалы допустим) если условие проходит то мы вызываем сток SetVehicleSpeed (опишу его ниже) который устанавливает машине скорость выше текущей на 15(Это много для промежутка в 0,5 секунд, но это лишь пример, сюда вы должны написать своё число)


И так паблик который будет присваивать машине скорость каждые 0.5 секунд разобрали, теперь давайте разберёмся с этим GetVehicleRotation. На вики по сампу даже есть отдельная страница с данной функцией создана она IllidanS4 и суть её в том, что она находит наклон машины по осям x y z через кватернионы посредством нативной функции GetVehicleRotationQuat


Что на счет SetVehicleSpeed то вот этот сток
PHP:
stock SetVehicleSpeed(vehid, Float:speed)
{
    new Float:x1, Float:y1, Float:z1, Float:x2, Float:y2, Float:z2, Float:a;
    GetVehicleVelocity(vehid,x1,y1,z1);
    GetVehiclePos(vehid,x2,y2,z2);
    GetVehicleZAngle(vehid,a); a=360-a;
    x1=(floatsin(a,degrees)*(speed/100))+x1;
    y1=(floatcos(a,degrees)*(speed/100))+y1;
    SetVehicleVelocity(vehid,x1,y1,z1);
}
Подробно и понятно описать я его не смогу, но грубо говоря он просто получает начальную скорость по осям x y z складывает их с переданной ему скоростью, складывает с начальной скоростью машины по x и y дабы игрок не мог резко развернуться и мгновенно получить ускорение в сторону поворота, а после устанавливает ускорение машины по осям x y z

Осталось нам обработать лишь тот случай когда игрок может выпрыгнуть из машины не отпуская 'W' в данном случае нам поможет паблик OnPlayerStateChange
PHP:
if(oldstate == PLAYER_STATE_DRIVER && GetPVarInt(playerid, "SpeedTimer"))
{
	KillTimer(GetPVarInt(playerid, "SpeedTimer"));
	DeletePVar(playerid, "SpeedTimer");
       SetPVarInt(playerid, "Space_or_s_Pressed", 0);
}
Тут мы просто проверяем вышел ли игрок из машины и есть ли у игрока в переменной id таймера если есть то удаляем таймер и переменную игрока(в том числе и переменную которая отвечает за зажатые кнопки s/space), данный код я уже разбирал выше просто в другом паблике.
Ну вот вроде бы и все. Пишите если где-то ошибся, ну а если кому-то помог, то не откажусь от +

UPD Вам никто не запрещает экспериментировать, меняйте промежуток вызова SetSpeed и скорость которая прибавляется, дабы достичь более плавных и реалистичных результатов

[ВАЖНО] UPD:Спустя 3 дня понял, что в данной системе слишком много исключений, например, как я выше писал зажатые кнопки s/space перед w так же игрок может сесть в машину с уже зажатым w и из-за этого проверка на newkeys не сработает. Да можно написать еще проверки и обработать даже это, но так код станет довольно большим, поэтому сейчас пришел к выводу, что нужно выдавать скорость не когда игрок нажал w а когда он начал двигаться на машине (например запускать таймер сразу когда игрок садится в машину, но выдавать ускорение только когда игрок разогнался до 10км/ч допустим) таким образом можно будет избежать множества не очень приятных моментов
 
Сверху Снизу