OnPlayerKeyStateChange
Опис
Ова функција се позива када се промени стање било којег подржаног тастера (притиснут/ослобођен).
Тастери за правце не активирају OnPlayerKeyStateChange (горе/доле/лево/desno).
Име | Опис |
---|---|
playerid | ID играча који је притиснуо или ослободио тастер. |
newkeys | Мапа (бит маска) тастера које тренутно држи - види овде |
oldkeys | Мапа (бит маска) тастера које је држао пре тренутне промене - види овде. |
Враћа
- Ова функција не обрађује повратне вредности.
- Увек се прво позива у гамемод-у.
Белешке
Ову повратну функцију такође може позвати NPC.
Тастери за смер (горе/доле/лево/desno) не покрећу OnPlayerKeyStateChange.
Могу се открити само помоћу GetPlayerKeys (у OnPlayerUpdate или помоћу тајмера).
Повезане функције
Следеће функције могу бити корисне, јер су на један или други начин повезане са овим позивом.
- GetPlayerKeys: Провера које дугме играч притиска(држи).
Додатне информације
Увод
Ова повратна функција се позива када играч притисне или отпусти један од подржаних тастера (погледајте тастере).
Подржани тастери нису стварни тастери на тастатури, већ функцијски тастери који су додељени у Сан Андреасу. То значи да, на пример, не можете открити када неко притисне SPACE, али можете открити када притисне свој тастер за трчање (који може или не мора бити додељен razmaknici (по подразумеваној вредности јесте)).
Параметри
Параметри ове функције су списак свих тастера који су тренутно притиснути и свих тастера који су били притиснути пре тренутне промене. Функција се позива када се стање тастера промени (тј. када се тастер притисне или отпусти) и прослеђује стања свих тастера пре и после ове промене. Ове информације се могу користити за тачно праћење шта се догодило, али променљиве се не могу користити директно као параметри других функција. Да би се смањио број променљивих, користи се само један BIT за представљање једног тастера, што значи да једна променљива може садржати више тастера одједном и једноставно упоређивање вредности неће увек функционисати.
Како НЕ проверити тастер
Да претпоставимо да желите да детектујете када играч притисне свој FIRE тастер, очигледан код би био:
if (newkeys == KEY_FIRE)
Овај код можда чак ради у вашем тестирању, али је погрешан и ваше тестирање је недовољно. Покушајте да се сачучете и притиснете ватру - ваш код ће одмах престати да ради. Зашто? Јер "newkeys" више није исто што и "KEY_FIRE", већ је исто што и "KEY_FIRE" ПОЈЕДИНОЧНО С "KEY_CROUCH".
Како проверити тастер
Дакле, ако променљива може садржати више тастера у исто време, како да проверите само један? Одговор је битно маскирање. Сваком тастеру припада његов бит у променљивој (неки тастери имају исти бит, али то су тастери за пешачење/у возилу, тако да се никада не могу притискати истовремено) и треба да проверите само тај појединачни бит:
if (newkeys & KEY_FIRE)
Напомена: један & је исправан - то је битовски AND, а не логички AND, што су два амперсанда.
Сада, ако тестирате овај код, радиће без обзира да ли чучите или стојите када притиснете тастер за пуцањ. Међутим, постоји још један мали проблем - код ће се активирати све док држите тастер. OnPlayerKeyStateChange се позива сваки пут када се тастер промени и тај код је тачан сваки пут када се тастер за пуцањ држи доле. Ако притиснете тастер, код ће се активирати, ако је тај тастер држан и притиснете тастер за чучањ - код ће се поново активирати јер се тастер (за чучањ) променио, а тастер за пуцањ је и даље држан. Како открити када је тастер први пут притиснут, али не активирати поново када је још увек држан и други тастер се промени?
Како проверити да ли је тастер притиснут
Овде долази "oldkeys". Да бисте проверили да ли је тастер управо притиснут, прво морате проверити да ли је подешен у "newkeys" - што значи да је држан доле, а затим проверите да ли није у "oldkeys" - што значи да је управо почео да се држи. Следећи код то ради:
if ((newkeys & KEY_FIRE) && !(oldkeys & KEY_FIRE))
То ће бити тачно САМО када је тастер за пуцањ први пут притиснут, не када се држи и други тастер се промени.
Како проверити када је тастер ослобођен
Тачно исти принцип као горе, али обрнуто:
if ((oldkeys & KEY_FIRE) && !(newkeys & KEY_FIRE))
Како проверити више тастера
Ако желите да проверите да ли играч држи тастер за чучањ и пуцање, онда ће следећи код добро радити:
if ((newkeys & KEY_FIRE) && (newkeys & KEY_CROUCH))
Међутим, ако желите да откријете када први пут притисну оба тастера, пуцањ и чучањ, следећи код НЕЋЕ радити. Радиће ако успеју да притисну оба тастера тачно у исто време, али ако су размаци између притиска оба тастера већи (много мањи од пола секунде), неће радити:
if ((newkeys & KEY_FIRE) && !(oldkeys & KEY_FIRE) && (newkeys & KEY_CROUCH) && !(oldkeys & KEY_CROUCH))
Зашто? Зато што се OnPlayerKeyStateChange позива сваки пут када се промени један тастер. Дакле, ако притисну "KEY_FIRE" - OnPlayerKeyStateChange се позива са "KEY_FIRE" у "newkeys" и не у "oldkeys", затим притисну "KEY_CROUCH" - OnPlayerKeyStateChange се позива са "KEY_CROUCH" и "KEY_FIRE" у "newkeys", али "KEY_FIRE" је сада такође у "oldkeys" јер је већ био притиснут, тако да "!(oldkeys & KEY_FIRE)" неће проћи. Срећом, решење је веома једноставно (у ствари једноставније од оригиналног кода):
if ((newkeys & (KEY_FIRE | KEY_CROUCH)) == (KEY_FIRE | KEY_CROUCH) && (oldkeys & (KEY_FIRE | KEY_CROUCH)) != (KEY_FIRE | KEY_CROUCH))
Ово може изгледати компликовано, али проверава да ли су оба тастера постављена у "newkeys" и да оба тастера нису била постављена у "oldkeys"; ако је један од њих био постављен у "oldkeys", то није важно јер нису оба била. Све ове ствари могу се значајно поједноставити уз помоћ дефиниција.
Поједностављење
Детекција држања тастера
Дефиниција:
// HOLDING(keys)
#define HOLDING(%0) \
((newkeys & (%0)) == (%0))
Држи једно дугме(тастер):
if (HOLDING( KEY_FIRE ))
Држи више њих(тастера):
if (HOLDING( KEY_FIRE | KEY_CROUCH ))
Детекција првог притискања тастера
Дефиниција:
// PRESSED(keys)
#define PRESSED(%0) \
(((newkeys & (%0)) == (%0)) && ((oldkeys & (%0)) != (%0)))
Притиснуо један тастер:
if (PRESSED( KEY_FIRE ))
Притиснуо више њих:
if (PRESSED( KEY_FIRE | KEY_CROUCH ))
Детекција да ли играч тренутно притиска тастер
Дефиниција:
// PRESSING(keyVariable, keys)
#define PRESSING(%0,%1) \
(%0 & (%1))
Притиска један тастер:
if (PRESSING( newkeys, KEY_FIRE ))
Притиска више тастера:
if (PRESSING( newkeys, KEY_FIRE | KEY_CROUCH ))
Детекција пуштања тастера
Дефиниција:
// RELEASED(keys)
#define RELEASED(%0) \
(((newkeys & (%0)) != (%0)) && ((oldkeys & (%0)) == (%0)))
Пушта један тастер
if (RELEASED( KEY_FIRE ))
Пушта више тастера:
if (RELEASED( KEY_FIRE | KEY_CROUCH ))
Примери
Прикачи NOS када играч притисне тастер за ватру
public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)
{
if (PRESSED(KEY_FIRE))
{
if (IsPlayerInAnyVehicle(playerid))
{
AddVehicleComponent(GetPlayerVehicleID(playerid), 1010);
}
}
return 1;
}
Супер скок
public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)
{
if (PRESSED(KEY_JUMP))
{
new
Float:x,
Float:y,
Float:z;
GetPlayerPos(playerid, x, y, z);
SetPlayerPos(playerid, x, y, z + 10.0);
}
return 1;
}
Мод Бога док држи TAB
new
Float:gPlayerHealth[MAX_PLAYERS];
#if !defined INFINITY
#define INFINITY (Float:0x7F800000)
#endif
public OnPlayerKeyStateChange(playerid, KEY:newkeys, KEY:oldkeys)
{
if (PRESSED(KEY_ACTION))
{
// Они су управо притиснули акцијски тастер, сачувајте њихово
// старо здравље за обнову.
GetPlayerHealth(playerid, gPlayerHealth[playerid]);
SetPlayerHealth(playerid, INFINITY);
}
else if (RELEASED(KEY_ACTION))
{
// Они су управо пустили акцију - обновите
// њихово старо здравље поново.
SetPlayerHealth(playerid, gPlayerHealth[playerid]);
}
return 1;
}
Образложење
Не морате се бринути о ТОМЕ како је то урађено, само да је урађено. ДРЖАЊЕ открива ако притискају тастер (или тастере), без обзира на то да ли су их притискали пре, ПРИТИСНУТО открива ако су само што су притиснули тастер(е) и ОТПУШТЕНО открива ако су управо ослободили тастер(е). Међутим, ако желите да знате више - наставите да читате.
Разлог зашто треба да радите на овај начин, а не само користећи & или ==, је да бисте прецизно детектовали тачно тастере које желите док игноришете друге који можда или можда не буду притиснути. У бинарном формату, KEY_SPRINT је:
0b00001000
и KEY_JUMP је:
0b00100000
Тако да, ОР операција на жељеним тастерима (можемо их такође додати у овом примеру, али то није увек случај) даје:
0b00101000
Ако бисмо користили само & и OnPlayerKeyStateChange се позивао за играча који притисне скок, добили бисмо следећи код:
newkeys = 0b00100000
wanted = 0b00101000
ANDed = 0b00100000
AND операција два броја није 0, тако да је резултат провере истинит, што није оно што желимо.
Ако бисмо само користили ==, два броја очигледно нису исти, тако да би провера пропала, што је оно што желимо.
Ако би играч притискао скок, сprints и чучањ, добили бисмо следећи код:
newkeys = 0b00101010
wanted = 0b00101000
ANDed = 0b00101000
ANDed верзија је иста као и захтевани тастери и такође није 0, тако да ће дати исправан одговор, међутим, два оригинална броја нису иста, тако да == неће успети. У оба примера, један од два је дао прави одговор, а један погрешан. Ако упоредимо први пример користећи & и == добијамо:
newkeys = 0b00100000
wanted = 0b00101000
ANDed = 0b00100000
Очигледно је да жељени и ANDed верзија нису исти, тако да провера неће успети, што је тачно. За други пример:
newkeys = 0b00101010
wanted = 0b00101000
ANDed = 0b00101000
Жељени и ANDed верзија су исти, тако да упоређивање као једнако ће резултирати у истинит резултат, што је такође тачно.
Коришћењем ове методе можемо прецизно проверити да ли су одређени тастери притиснути игноришући све друге тастере који могу или не морају бити притиснути. Проверa старих тастера користи != уместо == како би осигурала да захтевани тастери нису раније били притиснути, тако да знамо да је један од њих управо притиснут.