Skip to content

6.13. fejezet: Input rendszer ​


Bevezetés ​

A DayZ input rendszer hardveres bemeneteket --- billentyűzet, egér és gamepad --- köt össze nevesített akciókkal, amelyeket a szkriptek lekérdezhetnek. Két rétegben működik:

  1. inputs.xml (konfigurációs réteg) --- nevesített akciókat deklarál, alapértelmezett billentyűkötéseket rendel hozzájuk, és csoportokba szervezi őket a játékos Vezérlők beállítások menüjéhez. Részletes leírásért lásd az 5.2. fejezetet: inputs.xml.

  2. UAInput API (szkript réteg) --- futásidőben kérdezi le a bemenet állapotát. Ezt hívják meg a szkriptjeid minden képkockában a lenyomások, elengedések, nyomvatartások és analóg értékek érzékeléséhez.

Ez a fejezet a szkript réteget tárgyalja: az osztályokat, metódusokat és mintákat, amelyeket a bemenetek olvasásához és vezérléséhez használsz az Enforce Scriptből.


Alaposztályok ​

Az input rendszer három fő osztályra épül:

UAInputAPI         Globális singleton (GetUApi()-n keresztül érhető el)
├── UAInput        Egyetlen nevesített input akciót képvisel
└── Input          Alacsonyabb szintű input hozzáférés (GetGame().GetInput()-on keresztül érhető el)
OsztályForrásfájlCél
UAInputAPI3_Game/inputapi/uainput.cGlobális input menedzser. Inputokat kér le név/ID alapján, kezeli a kizárásokat, előbeállításokat és háttérvilágítást.
UAInput3_Game/inputapi/uainput.cEgyetlen input akció. Állapotkérdezéseket (lenyomás, tartás, elengedés) és vezérlést (letiltás, elnyomás, zárolás) biztosít.
Input3_Game/tools/input.cMotor szintű input osztály. Szöveg-alapú állapotkérdezések, eszközkezelés, játékfókusz vezérlés.
InputUtils3_Game/tools/inpututils.cStatikus segédosztály. Gombnév/ikon feloldás UI megjelenítéshez.

Az Input API elérése ​

UAInputAPI (ajánlott) ​

Az inputok elérésének elsődleges módja. A GetUApi() egy globális függvény, amely a UAInputAPI singletont adja vissza:

c
// A globális input API lekérése
UAInputAPI inputAPI = GetUApi();

// Adott input akció lekérése név alapján (ahogy az inputs.xml-ben definiálva van)
UAInput input = inputAPI.GetInputByName("UAMyAction");

// Adott input akció lekérése numerikus ID alapján
UAInput input = inputAPI.GetInputByID(someID);

Input osztály (alternatíva) ​

Az Input osztály szöveg-alapú állapotkérdezéseket biztosít közvetlenül, anélkül, hogy előbb UAInput referenciára lenne szükség:

c
// Az Input példány lekérése
Input input = GetGame().GetInput();

// Kérdezés akciónév szöveggel
if (input.LocalPress("UAMyAction", false))
{
    // A billentyű éppen le lett nyomva
}

A bool check_focus paraméter (második argumentum) azt vezérli, hogy az ellenőrzés figyelembe veszi-e a játék fókuszát. true (alapértelmezett) esetén false-t ad vissza, ha a játék ablaka nem fókuszált. false esetén mindig a nyers input állapotot adja vissza.

Mikor melyiket használd ​

  • GetUApi().GetInputByName() --- Használd, amikor ugyanazt az inputot többször kell lekérdezned, elnyomnod/letiltanod, vagy meg kell vizsgálnod a kötéseit. Egy UAInput objektumot kapsz, amelyet újra felhasználhatsz.
  • GetGame().GetInput().LocalPress() --- Használd egyszeri ellenőrzésekhez, ahol nem kell manipulálnod magát az inputot. Egyszerűbb szintaxis, de ismételt lekérdezéseknél kicsit kevésbé hatékony.

Input állapot olvasása --- UAInput metódusok ​

Miután van egy UAInput referenciád, ezek a metódusok kérdezik le az aktuális állapotát:

c
UAInput input = GetUApi().GetInputByName("UAMyAction");

// Képkocka-pontos ellenőrzések
bool justPressed   = input.LocalPress();        // True az ELSŐ képkockán, amikor a gomb lenyomódik
bool justReleased  = input.LocalRelease();       // True az ELSŐ képkockán, amikor a gomb felenged
bool holdStarted   = input.LocalHoldBegin();     // True az első képkockán, amikor a tartási küszöb elérésekor
bool isHeld        = input.LocalHold();          // True MINDEN képkockán, amíg a gomb a küszöbön túl tartva van
bool clicked       = input.LocalClick();         // True nyomás-és-elengedés esetén a tartási küszöb előtt
bool doubleClicked = input.LocalDoubleClick();   // True dupla koppintás érzékelésekor

// Analóg érték
float value = input.LocalValue();                // 0.0 vagy 1.0 digitálisnál; 0.0-1.0 analóg tengelyeknél

Input állapot olvasása --- Input osztály metódusok ​

Az Input osztály (a GetGame().GetInput()-ból) egyenértékű szöveg-alapú metódusokat kínál:

c
Input input = GetGame().GetInput();

bool pressed  = input.LocalPress("UAMyAction", false);
bool released = input.LocalRelease("UAMyAction", false);
bool held     = input.LocalHold("UAMyAction", false);
bool dblClick = input.LocalDbl("UAMyAction", false);
float value   = input.LocalValue("UAMyAction", false);

Figyelj a kis elnevezési különbségre: LocalDoubleClick() az UAInput-on vs LocalDbl() az Input-on.

Az Input osztály _ID variánsokat is biztosít, amelyek egész szám akció ID-kat fogadnak szövegek helyett (pl. LocalPress_ID(int action, bool check_focus = true)). Az UAInput-nak nincsenek _ID túlterhelései; metódusai (LocalPress() stb.) nem fogadnak paramétert.


Input lekérdezés metódusok referencia ​

UAInput metódusok ​

MetódusVisszatérésMikor trueHasználati eset
LocalPress()boolAz első képkockán, amikor a gomb lenyomódikKapcsoló akciók, egyszeri triggerek
LocalRelease()boolAz első képkockán, amikor a gomb felengedFolyamatos akciók befejezése
LocalClick()boolGomb lenyomva és elengedve a tartási időzítő előttGyors koppintás érzékelés
LocalHoldBegin()boolAz első képkockán, amikor a tartási küszöb elérésekorTartás-alapú akciók indítása
LocalHold()boolMinden képkockán, amíg a küszöbön túl tartva vanFolyamatos tartási akciók
LocalDoubleClick()boolDupla koppintás érzékelésekorSpeciális/alternatív akciók
LocalValue()floatMindig (aktuális értéket adja vissza)Egér tengelyek, gamepad triggerek, analóg input

Input osztály metódusok ​

MetódusVisszatérésSzignatúraEgyenértékű UAInput metódus
LocalPress()boolLocalPress(string action, bool check_focus = true)UAInput.LocalPress()
LocalRelease()boolLocalRelease(string action, bool check_focus = true)UAInput.LocalRelease()
LocalHold()boolLocalHold(string action, bool check_focus = true)UAInput.LocalHold()
LocalDbl()boolLocalDbl(string action, bool check_focus = true)UAInput.LocalDoubleClick()
LocalValue()floatLocalValue(string action, bool check_focus = true)UAInput.LocalValue()

Fontos időzítési megjegyzések ​

  • A LocalPress() pontosan egy képkockán aktiválódik --- azon a képkockán, amikor a gomb fentről lentre vált. Ha bármely más képkockán ellenőrzöd, false-t ad vissza.
  • A LocalClick() akkor aktiválódik, amikor a gombot lenyomják és gyorsan elengedik (a tartási időzítő aktiválása előtt). NEM ugyanaz, mint a LocalPress(). Használd a LocalPress()-t az azonnali gomb-lenyomás érzékeléshez.
  • A LocalHold() NEM aktiválódik azonnal. Megvárja, amíg a motor tartási küszöbe elérésekor. Használd a LocalPress()-t, ha azonnali választ szeretnél.
  • A LocalHoldBegin() egyszer aktiválódik, amikor a tartási küszöb először elérésekor. A LocalHold() ezután minden további képkockán aktiválódik.

Inputok ellenőrzése az OnUpdate-ben ​

Az egyéni inputok lekérdezésének standard mintája a MissionGameplay.OnUpdate()-en belül van:

c
modded class MissionGameplay
{
    override void OnUpdate(float timeslice)
    {
        super.OnUpdate(timeslice);

        // Védelem: élő játékos szükséges
        PlayerBase player = PlayerBase.Cast(GetGame().GetPlayer());
        if (!player)
            return;

        // Védelem: nincs input, amíg menü nyitva van
        if (GetGame().GetUIManager().GetMenu())
            return;

        UAInput myInput = GetUApi().GetInputByName("UAMyModOpenMenu");
        if (myInput && myInput.LocalPress())
        {
            OpenMyModMenu();
        }
    }
}

Az Input osztály használata helyette ​

c
modded class MissionGameplay
{
    override void OnUpdate(float timeslice)
    {
        super.OnUpdate(timeslice);

        Input input = GetGame().GetInput();

        if (input.LocalPress("UAMyModOpenMenu", false))
        {
            OpenMyModMenu();
        }
    }
}

Hol máshol ellenőrizheted az inputokat? ​

Az inputokat technikailag bármely képkockánkénti callbackben ellenőrizni lehet, de a MissionGameplay.OnUpdate() a kanonikus helyszín. Egyéb érvényes helyek:

  • PlayerBase.CommandHandler() --- minden képkockán fut a helyi játékos számára
  • ScriptedWidgetEventHandler.OnUpdate(Widget w) --- UI-specifikus inputhoz (de előnyben részesítsd a widget eseménykezelőket)
  • PluginBase.OnUpdate() --- plugin hatókörű inputhoz

Kerüld az inputok ellenőrzését szerver oldali kódban, entitás konstruktorokban vagy egyszeri eseménykezelőkben, ahol a képkocka időzítés nem garantált.


Alternatíva: OnKeyPress és OnKeyRelease ​

Egyszerű beégetett billentyűérzékeléshez a MissionBase biztosítja az OnKeyPress() és OnKeyRelease() callbackeket:

c
modded class MissionGameplay
{
    override void OnKeyPress(int key)
    {
        super.OnKeyPress(key);

        if (key == KeyCode.KC_F5)
        {
            // F5 le lett nyomva --- nem átköthető!
            ToggleDebugOverlay();
        }
    }

    override void OnKeyRelease(int key)
    {
        super.OnKeyRelease(key);

        if (key == KeyCode.KC_F5)
        {
            // F5 felengedve
        }
    }
}

UAInput vs OnKeyPress: Mikor melyiket használd ​

JellemzőUAInput (GetUApi)OnKeyPress
A játékos átköthetiIgenNem
Módosítókat támogatIgen (Ctrl+billentyű kombók inputs.xml-en keresztül)Kézi ellenőrzés szükséges
Gamepad támogatásIgenNem
Megjelenik a Vezérlők menübenIgenNem
Analóg értékekIgenNem
Egyszerűséginputs.xml beállítás szükségesCsak ellenőrizd a KeyCode-ot
Legjobb ehhezMinden játékos-felé néző akcióDebug eszközök, beégetett fejlesztői gyorsgombok

Ökölszabály: Ha egy játékos valaha is meg fogja nyomni ezt a billentyűt, használd a UAInput-ot inputs.xml-lel. Csak belső debug eszközökhöz vagy prototípus teszteléshez használd az OnKeyPress-t.


KeyCode referencia ​

A KeyCode enum az 1_Core/proto/ensystem.c-ben van definiálva. Ezeket a konstansokat az OnKeyPress(), OnKeyRelease(), KeyState() és DisableKey() metódusokkal használjuk.

Gyakran használt billentyűk ​

KategóriaKonstansok
EscapeKC_ESCAPE
FunkcióbillentyűkKC_F1-től KC_F12-ig
SzámsorKC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0
BetűkKC_A-tól KC_Z-ig (pl. KC_Q, KC_W, KC_E, KC_R, KC_T)
MódosítókKC_LSHIFT, KC_RSHIFT, KC_LCONTROL, KC_RCONTROL, KC_LMENU (bal Alt), KC_RMENU (jobb Alt)
NavigációKC_UP, KC_DOWN, KC_LEFT, KC_RIGHT
SzerkesztésKC_SPACE, KC_RETURN, KC_TAB, KC_BACK (Backspace), KC_DELETE, KC_INSERT
LapozásKC_HOME, KC_END, KC_PRIOR (Page Up), KC_NEXT (Page Down)
NumpadKC_NUMPAD0-tól KC_NUMPAD9-ig, KC_NUMPADENTER, KC_ADD, KC_SUBTRACT, KC_MULTIPLY, KC_DIVIDE, KC_DECIMAL
ZárolásokKC_CAPITAL (Caps Lock), KC_NUMLOCK, KC_SCROLL (Scroll Lock)
ÍrásjelekKC_MINUS, KC_EQUALS, KC_LBRACKET, KC_RBRACKET, KC_SEMICOLON, KC_APOSTROPHE, KC_GRAVE, KC_BACKSLASH, KC_COMMA, KC_PERIOD, KC_SLASH

MouseState enum ​

Nyers egérgomb állapot ellenőrzéshez (nem a UAInput rendszeren keresztül):

c
enum MouseState
{
    LEFT,
    RIGHT,
    MIDDLE,
    X,        // Vízszintes tengely
    Y,        // Függőleges tengely
    WHEEL     // Görgetőkerék
};

// Használat:
int state = GetMouseState(MouseState.LEFT);
// A 15. bit (MB_PRESSED_MASK) be van állítva lenyomáskor

Alacsony szintű billentyűállapot ​

c
// Nyers billentyűállapot ellenőrzése (bitmaszk, 15. bit = jelenleg lenyomva)
int state = KeyState(KeyCode.KC_LSHIFT);

// Billentyűállapot törlése (megakadályozza az automatikus ismétlést a következő fizikai lenyomásig)
ClearKey(KeyCode.KC_RETURN);

// Billentyű letiltása az aktuális képkocka hátralévő részére
GetGame().GetInput().DisableKey(KeyCode.KC_RETURN);

Inputok elnyomása és letiltása ​

Elnyomás (inputonként, egy képkocka) ​

Megakadályozza, hogy az input a következő képkockán aktiválódjon. Hasznos átmenetek során (menü bezárása), hogy megakadályozza az egy képkockás input átszivárgást:

c
UAInput input = GetUApi().GetInputByName("UAMyAction");
input.Supress();  // Megjegyzés: egy 's' a metódus nevében

Összes input elnyomása (globális, egy képkocka) ​

Elnyomja az ÖSSZES inputot a következő képkockára. Hívd meg, amikor menüket hagysz el vagy input kontextusok között váltasz:

c
GetUApi().SupressNextFrame(true);

Ezt általában a vanilla használja, amikor bezárja a főmenüt, hogy megakadályozza, hogy az Escape billentyű azonnal újra megnyisson valamit.

ForceDisable (inputonként, tartós) ​

Teljesen letiltja az adott inputot az újra engedélyezésig. Az input nem vált ki semmilyen eseményt, amíg le van tiltva:

c
// Letiltás, amíg a menü nyitva van
GetUApi().GetInputByName("UAMyAction").ForceDisable(true);

// Újra engedélyezés, amikor a menü bezárul
GetUApi().GetInputByName("UAMyAction").ForceDisable(false);

Lock / Unlock (inputonként, tartós) ​

Hasonló a ForceDisable-hoz, de más mechanizmust használ. Légy óvatos --- ha több rendszer zárolja/feloldja ugyanazt az inputot, zavarhatják egymást:

c
UAInput input = GetUApi().GetInputByName("UAMyAction");
input.Lock();    // Letiltás az Unlock() hívásáig
input.Unlock();  // Újra engedélyezés

bool locked = input.IsLocked();  // Állapot ellenőrzése

A motor dokumentációja a legtöbb esetben kizárási csoportok használatát javasolja Lock/Unlock helyett.

Összes input letiltása (tömeges) ​

Teljes képernyős UI megnyitásakor tiltsd le az összes játék inputot, kivéve amiket a UI-od igényel. Ez a COT és az Expansion által használt minta:

c
void DisableAllInputs(bool state)
{
    TIntArray inputIDs = new TIntArray;
    GetUApi().GetActiveInputs(inputIDs);

    // Aktívan tartandó inputok, még akkor is, amikor UI nyitva van
    TIntArray skipIDs = new TIntArray;
    skipIDs.Insert(GetUApi().GetInputByName("UAUIBack").ID());

    foreach (int inputID : inputIDs)
    {
        if (skipIDs.Find(inputID) == -1)
        {
            GetUApi().GetInputByID(inputID).ForceDisable(state);
        }
    }

    GetUApi().UpdateControls();
}

Fontos: Mindig hívd meg a GetUApi().UpdateControls()-t az input állapotok tömeges módosítása után.

Input kizárási csoportok ​

A mission rendszer nevesített kizárási csoportokat biztosít, amelyek a motor specific.xml-jében vannak definiálva. Aktiváláskor inputkategóriákat tiltanak le:

c
// Játékmenet inputok elnyomása, amíg menü nyitva van
GetGame().GetMission().AddActiveInputExcludes({"menu"});

// Inputok visszaállítása bezáráskor
GetGame().GetMission().RemoveActiveInputExcludes({"menu"}, true);

Metódus szignatúrák a Mission osztályon:

c
void AddActiveInputExcludes(array<string> excludes);
void RemoveActiveInputExcludes(array<string> excludes, bool bForceSupress = false);
void EnableAllInputs(bool bForceSupress = false);
bool IsInputExcludeActive(string exclude);

A bForceSupress paraméter a RemoveActiveInputExcludes-on belül SupressNextFrame-et hív, hogy megakadályozza az input átszivárgást az újra engedélyezéskor.

Az Expansion saját egyéni kizárási csoportot használ, amelyet a motornál regisztrált:

c
GetUApi().ActivateExclude("menuexpansion");
GetUApi().UpdateControls();

Az inputs.xml és a szkript összekapcsolása ​

Az XML konfigurációs réteg és a szkript réteg közötti kapcsolat az akciónév szöveg.

A folyamat ​

inputs.xml                              Szkript
──────────────                          ──────────────────────────────
<input name="UAMyModOpenMenu" />   -->  GetUApi().GetInputByName("UAMyModOpenMenu")
       │                                         │
       │  A motor indításkor betölti             │  UAInput objektumot ad vissza
       │  Regisztrálja a UAInputAPI-ban          │  az XML-ből kötött billentyűkkel
       ▼                                         ▼
A játékos látja a Beállítások > Vezérlők-   input.LocalPress() true-t ad vissza,
ben és átkötheti a billentyűt               amikor a játékos megnyomja a kötött billentyűt
  1. Indításkor a motor beolvassa az összes inputs.xml fájlt a betöltött modokból
  2. Minden <input name="..."> UAInput-ként regisztrálódik a globális UAInputAPI-ban
  3. A <preset>-ből származó alapértelmezett billentyűkötések alkalmazódnak (hacsak a játékos nem módosította őket)
  4. A szkriptben a GetUApi().GetInputByName("UAMyModOpenMenu") lekéri a regisztrált inputot
  5. A LocalPress() stb. hívása ellenőrzi a játékos által kötött billentyűt

A név szövegnek pontosan egyeznie kell (kis-nagybetű érzékeny) az XML és a szkript hívás között.

A teljes inputs.xml szintaxisért lásd az 5.2. fejezetet: inputs.xml.

Futásidejű regisztráció (haladó) ​

Az inputok futásidőben is regisztrálhatók szkriptből, inputs.xml fájl nélkül:

c
// Új csoport regisztrálása
GetUApi().RegisterGroup("mymod", "My Mod");

// Új input regisztrálása a csoportban
UAInput input = GetUApi().RegisterInput("UAMyModAction", "STR_MYMOD_ACTION", "mymod");

// Később, ha szükséges:
GetUApi().DeRegisterInput("UAMyModAction");
GetUApi().DeRegisterGroup("mymod");

Ez ritkán használt. Az inputs.xml megközelítés az előnyös, mert megfelelően integrálódik a Vezérlők beállítások menüvel és az előbeállítási rendszerrel.


Gyakori minták ​

Panel megnyitás/bezárás kapcsoló ​

c
modded class MissionGameplay
{
    protected bool m_MyPanelOpen;

    override void OnUpdate(float timeslice)
    {
        super.OnUpdate(timeslice);

        if (!GetGame().GetPlayer())
            return;

        UAInput input = GetUApi().GetInputByName("UAMyModPanel");
        if (input && input.LocalPress())
        {
            if (m_MyPanelOpen)
                CloseMyPanel();
            else
                OpenMyPanel();
        }
    }

    void OpenMyPanel()
    {
        m_MyPanelOpen = true;
        // UI megjelenítése...

        // Játékmenet inputok letiltása, amíg a panel nyitva van
        GetGame().GetMission().AddActiveInputExcludes({"menu"});
    }

    void CloseMyPanel()
    {
        m_MyPanelOpen = false;
        // UI elrejtése...

        // Játékmenet inputok visszaállítása
        GetGame().GetMission().RemoveActiveInputExcludes({"menu"}, true);
    }
}

Tartás az aktiváláshoz, elengedés a deaktiváláshoz ​

c
override void OnUpdate(float timeslice)
{
    super.OnUpdate(timeslice);

    Input input = GetGame().GetInput();

    if (input.LocalPress("UAMyModSprint", false))
    {
        StartSprinting();
    }

    if (input.LocalRelease("UAMyModSprint", false))
    {
        StopSprinting();
    }
}

Módosító + billentyű kombó ellenőrzés ​

Ha Ctrl+billentyű kombót definiáltál az inputs.xml-ben, a UAInput rendszer automatikusan kezeli. De ha manuálisan kell ellenőrizned a módosító állapotot egy UAInput mellett:

c
override void OnUpdate(float timeslice)
{
    super.OnUpdate(timeslice);

    UAInput input = GetUApi().GetInputByName("UAMyModAction");
    if (input && input.LocalPress())
    {
        // Ellenőrizd, hogy a Shift lenyomva van-e nyers KeyState-en keresztül
        bool shiftHeld = (KeyState(KeyCode.KC_LSHIFT) != 0);

        if (shiftHeld)
            PerformAlternateAction();
        else
            PerformNormalAction();
    }
}

Input elnyomása, amikor a UI felhasználja ​

Amikor a UI-od kezel egy billentyű lenyomást, nyomd el az alatta lévő játék akciót, hogy megakadályozd mindkettő aktiválódását:

c
class MyMenuHandler extends ScriptedWidgetEventHandler
{
    override bool OnClick(Widget w, int x, int y, int button)
    {
        if (w == m_ConfirmButton)
        {
            DoConfirm();

            // A játék input elnyomása, amely megoszthatja ezt a billentyűt
            GetUApi().GetInputByName("UAFire").Supress();
            return true;
        }
        return false;
    }
}

Kötött billentyű megjelenítési nevének lekérése ​

Annak megjelenítéséhez, hogy a játékos milyen billentyűt kötött egy akcióhoz (UI felszólításokhoz):

c
UAInput input = GetUApi().GetInputByName("UAMyModAction");
string keyName = InputUtils.GetButtonNameFromInput("UAMyModAction", EUAINPUT_DEVICE_KEYBOARDMOUSE);
// Lokalizált billentyűnevet ad vissza, mint "F5", "Left Ctrl" stb.

Kontroller ikonokhoz és rich-text formázáshoz:

c
string richText = InputUtils.GetRichtextButtonIconFromInputAction(
    "UAMyModAction",
    "Open Menu",
    EUAINPUT_DEVICE_CONTROLLER
);
// Kép taget + címkét ad vissza UI megjelenítéshez

Játékfókusz ​

Az Input osztály játékfókusz-kezelést biztosít, amely azt vezérli, hogy az inputok feldolgozódnak-e, amikor a játék ablaka nem fókuszált:

c
Input input = GetGame().GetInput();

// Hozzáadás a fókuszszámlálóhoz (pozitív = fókusz nélküli, inputok elnyomva)
input.ChangeGameFocus(1);

// Eltávolítás a fókuszszámlálóból
input.ChangeGameFocus(-1);

// Fókuszszámláló visszaállítása 0-ra (teljes fókusz)
input.ResetGameFocus();

// Ellenőrizd, hogy a játéknak jelenleg van-e fókusza (számláló == 0)
bool hasFocus = input.HasGameFocus();

Ez egy referenciaszámolt rendszer. Több rendszer is kérhet fókuszváltozást, és az inputok csak akkor folytatódnak, amikor mindegyik elengedte.


Gyakori hibák ​

Input lekérdezés a szerveren ​

Az inputok csak kliensnek szólnak. A szervernek nincs fogalma a billentyűzet, egér vagy gamepad állapotáról. Ha a GetUApi().GetInputByName()-t hívod a szerveren, az eredmény értelmetlen.

c
// HIBÁS --- ez a szerveren fut, itt nem léteznek inputok
modded class MissionServer
{
    override void OnUpdate(float timeslice)
    {
        super.OnUpdate(timeslice);
        UAInput input = GetUApi().GetInputByName("UAMyAction");
        if (input.LocalPress())  // A szerveren mindig false!
        {
            DoSomething();
        }
    }
}

// HELYES --- ellenőrizd az inputot a kliensen, küldj RPC-t a szervernek
modded class MissionGameplay  // Kliens oldali mission osztály
{
    override void OnUpdate(float timeslice)
    {
        super.OnUpdate(timeslice);
        UAInput input = GetUApi().GetInputByName("UAMyAction");
        if (input && input.LocalPress())
        {
            // RPC küldése a szervernek a művelet végrehajtásához
            GetGame().RPCSingleParam(null, MY_RPC_ID, null, true);
        }
    }
}

OnKeyPress használata játékos-felé néző akciókhoz ​

c
// HIBÁS --- beégetett billentyű, a játékos nem tudja átkötn
override void OnKeyPress(int key)
{
    super.OnKeyPress(key);
    if (key == KeyCode.KC_Y)
        OpenMyMenu();
}

// HELYES --- inputs.xml-t használ, a játékos átkötheti a Beállításokban
override void OnUpdate(float timeslice)
{
    super.OnUpdate(timeslice);
    UAInput input = GetUApi().GetInputByName("UAMyModOpenMenu");
    if (input && input.LocalPress())
        OpenMyMenu();
}

Input elnyomás hiánya, amikor UI nyitva van ​

Amikor a modod megnyit egy UI panelt, a játékos WASD billentyűi továbbra is mozgatják a karaktert, az egér továbbra is céloz, és a kattintás tüzel --- hacsak nem tiltod le a játék inputokat:

c
// HIBÁS --- a karakter sétálgat a menü mögött
void OpenMenu()
{
    m_MenuWidget.Show(true);
}

// HELYES --- mozgás letiltása, amíg a menü nyitva van
void OpenMenu()
{
    m_MenuWidget.Show(true);
    GetGame().GetMission().AddActiveInputExcludes({"menu"});
    GetGame().GetUIManager().ShowCursor(true);
}

void CloseMenu()
{
    m_MenuWidget.Show(false);
    GetGame().GetMission().RemoveActiveInputExcludes({"menu"}, true);
    GetGame().GetUIManager().ShowCursor(false);
}

Annak elfelejtése, hogy a LocalPress csak EGY képkockán aktiválódik ​

A LocalPress() pontosan egy képkockán ad vissza true-t --- azon a képkockán, amikor a billentyű felengedettből lenyomottra vált. Ha a kódútvonalad nem fut le pontosan azon a képkockán, elszalasztod az eseményt.

c
// HIBÁS --- ha a DoExpensiveCheck() időt vesz igénybe vagy képkockákat ugrik, elszalasztod a lenyomást
void SomeCallback()
{
    if (GetUApi().GetInputByName("UAMyAction").LocalPress())
    {
        // Ez soha nem aktiválódhat, ha a SomeCallback nem hívódik meg minden képkockán
    }
}

// HELYES --- mindig képkockánkénti callbackben ellenőrizd
override void OnUpdate(float timeslice)
{
    super.OnUpdate(timeslice);
    if (GetUApi().GetInputByName("UAMyAction").LocalPress())
    {
        DoAction();
    }
}

A LocalClick és LocalPress összetévesztése ​

A LocalClick() NEM ugyanaz, mint a LocalPress(). A LocalClick() akkor aktiválódik, amikor egy billentyűt lenyomnak ÉS gyorsan elengednek (a tartási küszöb előtt). A LocalPress() azonnal aktiválódik a gomb lenyomásakor. A legtöbb mod a LocalPress()-t akarja.

c
// Nem feltétlenül aktiválódik, ha a játékos túl sokáig tartja a billentyűt
if (input.LocalClick())  // Gyors koppintást igényel

// Azonnal aktiválódik a gomb lenyomásakor, a tartás időtartamától függetlenül
if (input.LocalPress())  // Általában ezt akarod

Az UpdateControls elfelejtése tömeges változtatások után ​

Amikor több inputon ForceDisable()-t hívogatsz, meg kell hívnod az UpdateControls()-t, hogy a változások érvénybe lépjenek:

c
// HIBÁS --- a változások nem feltétlenül lépnek azonnal érvénybe
GetUApi().GetInputByName("UAFire").ForceDisable(true);
GetUApi().GetInputByName("UAMoveForward").ForceDisable(true);

// HELYES --- változások érvényesítése
GetUApi().GetInputByName("UAFire").ForceDisable(true);
GetUApi().GetInputByName("UAMoveForward").ForceDisable(true);
GetUApi().UpdateControls();

A Supress elírása ​

A motor metódusa Supress() egy 's'-sel (nem Suppress). A globális metódus SupressNextFrame() szintén egy 's'-t használ. Ez a motor API furcsasága:

c
// HIBÁS --- nem fordul le
input.Suppress();

// HELYES --- egy 's'
input.Supress();
GetUApi().SupressNextFrame(true);

Gyors referencia ​

c
// === Inputok lekérése ===
UAInputAPI api = GetUApi();
UAInput input = api.GetInputByName("UAMyAction");
Input rawInput = GetGame().GetInput();

// === Állapotkérdezések (UAInput) ===
input.LocalPress()        // Billentyű éppen lenyomva (egy képkocka)
input.LocalRelease()      // Billentyű éppen felengedve (egy képkocka)
input.LocalClick()        // Gyors koppintás érzékelve
input.LocalHoldBegin()    // Tartási küszöb éppen elérve (egy képkocka)
input.LocalHold()         // Küszöbön túl tartva (minden képkocka)
input.LocalDoubleClick()  // Dupla koppintás érzékelve
input.LocalValue()        // Analóg érték (float)

// === Állapotkérdezések (Input, szöveg-alapú) ===
rawInput.LocalPress("UAMyAction", false)
rawInput.LocalRelease("UAMyAction", false)
rawInput.LocalHold("UAMyAction", false)
rawInput.LocalDbl("UAMyAction", false)
rawInput.LocalValue("UAMyAction", false)

// === Elnyomás ===
input.Supress()                    // Ez az input, következő képkocka
api.SupressNextFrame(true)         // Összes input, következő képkocka

// === Letiltás ===
input.ForceDisable(true)           // Tartós letiltás
input.ForceDisable(false)          // Újra engedélyezés
input.Lock()                       // Zárolás (használj kizárásokat helyette)
input.Unlock()                     // Feloldás
api.UpdateControls()               // Változások érvényesítése

// === Kizárási csoportok ===
GetGame().GetMission().AddActiveInputExcludes({"menu"});
GetGame().GetMission().RemoveActiveInputExcludes({"menu"}, true);
GetGame().GetMission().EnableAllInputs(true);

// === Nyers billentyűállapot ===
int state = KeyState(KeyCode.KC_LSHIFT);
GetGame().GetInput().DisableKey(KeyCode.KC_RETURN);

// === Megjelenítési segédek ===
string name = InputUtils.GetButtonNameFromInput("UAMyAction", EUAINPUT_DEVICE_KEYBOARDMOUSE);

Ez a fejezet a szkript oldali Input System API-t tárgyalja. A billentyűkötéseket regisztráló XML konfigurációért lásd az 5.2. fejezetet: inputs.xml.


Bevált gyakorlatok ​

  • Mindig használd a UAInput-ot inputs.xml-en keresztül a játékos-felé néző billentyűkötésekhez. Ez lehetővé teszi a játékosoknak a billentyűk átkötését, megmutatja az akciókat a Vezérlők menüben és támogatja a gamepad inputot. Az OnKeyPress-t csak debug gyorsgombokhoz tartsd fenn.
  • Hívd meg az AddActiveInputExcludes({"menu"})-t teljes képernyős UI megnyitásakor. Enélkül a játékos mozgásbillentyűi (WASD), egér célzás és fegyvertüzelés aktívak maradnak a menüd mögött, véletlen műveleteket okozva.
  • Inputokat csak képkockánkénti callbackekben ellenőrizz, mint az OnUpdate(). A LocalPress() pontosan egy képkockán ad vissza true-t. Ha olyan eseménykezelőkben vagy callbackekben ellenőrzöd, amelyek nem futnak minden képkockán, billentyűlenyomásokat fogsz elszalasztani.
  • Hívd meg a GetUApi().UpdateControls()-t tömeges ForceDisable() változtatások után. E nélkül az érvényesítő hívás nélkül a letiltás/engedélyezés állapotváltozások nem feltétlenül lépnek érvénybe a következő képkockáig, egy képkockás input átszivárgást okozva.
  • Emlékezz, hogy a Supress() egy "s"-t használ. A motor API Supress()-nak és SupressNextFrame()-nek írja. A helyes angol Suppress írásmód nem fordul le.

Kompatibilitás és hatás ​

  • Multi-Mod: Az input akciónevek globálisak. Ha két mod ugyanazt az UAInput nevet regisztrálja (pl. "UAOpenMenu"), ütközni fognak. Mindig előtagozd a mod neveddel: "UAMyModOpenMenu". Az input kizárási csoportok megosztottak --- ha egy mod aktiválja a "menu" kizárásokat, az minden modot érint.
  • Teljesítmény: Az input lekérdezés könnyűsúlyú. A GetUApi().GetInputByName() hash keresést végez. Az UAInput referencia tagváltozóban való gyorsítótárazása elkerüli az ismételt kereséseket, de nem feltétlenül szükséges a teljesítményhez.
  • Szerver/Kliens: Az inputok csak a kliensen léteznek. A szervernek nincs billentyűzet, egér vagy gamepad állapota. Mindig a kliensen érzékeld az inputot és küldj RPC-ket a szervernek a mérvadó műveletekhez.

Released under CC BY-SA 4.0 | Code examples under MIT License