Steamworks-dokumentation
Spilhandlingsfil

Oversigt


Udviklere skal levere en spilhandlingsfil (IGA), som definerer handlinger, handlingssæt og den grundlæggende struktur i deres spils inputkonfiguration. Denne artikel beskriver den overordnede struktur i en sådan fil og giver flere konkrete eksempler fra forskellige spil.

Fileksempler


Manuel oprettelse af handlingsfiler i spil

Start med at downloade den første spilhandlingsfil (IGA, in-game actions), som er linket i eksemplerne ovenfor. Opret derefter en "controller_config"-mappe i Steam-mappen, normalt C:/Programmer (x86)/Steam/controller_config, og konfigurer filen i mappen. I Steam-mappen vil der i forvejen være en mappe med et lignende navn, så kontrollér, at du lægger den i mappen "controller_config" og ikke mappen "controller_base". Omdøb filen til "game_actions_X.vdf", hvor X er dit spils app-ID på Steam. Hvis du ikke kender dit spils app-ID på Steam, kan du finde det ved at logge på Steamworks-partnersiden.

Åbn filen i din foretrukne teksteditor. Filen er i Valves standardformat "KeyValues", som er et enkelt og letlæseligt format. Det kan også være nyttigt at downloade en af vores skabeloner til handlingsfiler i spil eller Portal 2-IGA'en til reference.

Generering af en IGA-fil fra et eksisterende spil, som bruger Steam Input-API'en.


Hvis du gemmer en konfiguration for et spil på Steam som en lokal konfiguration, kan du efterfølgende finde en tilsvarende fil i:
[SteamMappe]\UserData\[bruger-ID]\241100\remote\controller_config\[appid]\[filnavn].vdf

Her er et eksempel på, hvor mine lokale konfigurationer for Defender's Quest er gemt på en typisk Windows 10-maskine:

whereisvgf.png

Bemærk, at disse filer ikke er nøjagtige kopier af IGA-masterfilen, som udvikleren har uploadet, men du kan få en idé om den originale struktur ved at se på blokkene "actions" og "localization", som kommer direkte fra masterfilen.

Her er et downloadlink til filen #library_controllersavedefaulttitle_0.vdf, som er vist i ovenstående skærmbillede. Det kan være nyttigt at sammenligne den med IGA-masterfilen til Defender's Quest.

IGA-format


IGA-filen er et VDF-dokument, som er Valves eget dataformat til strukturerede objektdata med nøgle-/værdistrengepar.

Skelet


Filens grundlæggende struktur er et wrapper-objekt med navnet "In Game Actions" og to underobjekter kaldet "actions" og "localization":

"In Game Actions" { "actions" { } "localization" { } }

Handlingssæt

Lad os se nærmere på objektet "actions". Dette objekt indeholder dine handlingssæt. Strukturen i et "actions"-objekt ser således ud:
"actions" { "IndsætNavnPåHandlingssætHer" { "title" "#IndsætTitelHer "StickPadGyro" { } "AnalogTrigger" { } "Button" { } } }

Strengene "IndsætNavnPåHandlingssætHer" og "#IndsætTitelHer" er de eneste strenge i ovenstående eksempel, som brugeren skal erstatte. Resten er reserverede nøgleord.

Den værdi, du erstatter "IndsætNavnPåHandlingssætHer" med, vil være navnet på det handlingssæt, som du bruger i Steam Input-API'en. Og den værdi, du erstatter "#IndsætTitelHer" med, vil være det lokaliseringstoken, som du bruger i sektionen "localization" senere i filen. Bemærk, at tegnet # er obligatorisk her.

Hvert handlingssæt skal have et unikt strengnavn, og du kan tilføje flere ved at oprette flere objekter inden for rammerne af "actions"-beholderobjektet. Det er ikke nødvendigt at bruge kommaer eller kantede parenteser – dette er VDF, ikke JSON.

Der er tre mulige underobjekter for hvert handlingssætobjekt: "StickPadGyro", "AnalogTrigger" og "Button". Disse objekter er de eneste, du kan definere, og de vil indeholde dine individuelle handlingsdefinitioner. Men du behøver ikke at have alle tre kategorier.

For eksempel er denne struktur helt gyldig:
"actions" { "Handlingssætnavn1" { "title" "#Titel1" "AnalogTrigger" { } "Button" { } } "Handlingssætnavn2" { "title" "#Titel2" "StickPadGyro" { } } "Handlingssætnavn3" { "title" "#Titel3" "Button" { } } }

StickPadGyro

Denne blok af handlingssæt er til analoge handlinger, som har op til to bevægelsesakser – det, man normalt ville binde til et joystick, en trackpad eller et gyroskop. Også ting, som du vil styre med en mus, eller andet, som hører til her.

AnalogTrigger

Denne blok af handlingssæt er til analoge handlinger, som kun har én bevægelsesakse – det, man ville binde til en analog aftrækker.

Button

Denne blok af handlingssæt er udelukkende til digitale handlinger, som kun overfører til-/fra-tilstande. Selvom denne blok hedder "button,", kan digitale handlinger bindes til stort set alle fysiske input – inklusive input, som oprindeligt er designet til at producere analoge data (for eksempel joysticks, trackpads osv.).

Handlinger


En IGA-fil gør ingenting, før der er defineret nogle handlinger, så lad os komme i gang!

StickPadGyro-handlinger

Lad os starte med at tilføje nogle analoge StickPadGyro-handlinger (to bevægelsesakser). Noget til at flytte karakteren rundt med – lad os kalde det "Move". Og noget til at styre kameraet – lad os kalde det "Camera".

"actions" { "FPSControls" { "title" "#Set_FPSControls" "StickPadGyro" { "Move" { "title" "#Action_Move" "input_mode" "joystick_move" } "Camera" { "title" "#Action_Camera" "input_mode" "absolute_mouse" } } } }

Som du kan se, er den abstrakte struktur for en StickPadGyro-handling som følger:
"HandlingsnavnHer" { "title" "#HandlingstitelHer" "input_mode" "<analog_mode>" }

De eneste værdier i denne struktur, som brugeren kan redigere, er dem, som er markeret "HandlingsnavnHer", "HandlingstitelHer" og "<analog_mode>". De svarer til henholdsvis handlingens strengnavn til Steam Input-API'en, lokaliseringsnøglen til lokaliseringssektionen i denne fil og inputkildekoden, som bestemmer, hvordan analoge data behandles og fortolkes.

Egenskaben "input_mode" har to mulige værdier for StickPadGyro-handlinger:

  • "joystick_move"
  • "absolute_mouse"

Du bør bruge "joystick_move" til handlinger, hvis værdier fortolkes som et joystick (konstant afvigelse fra et midterpunkt), og du bør bruge "absolute_mouse" til mere fleksible handlinger til generelle formål. Brug "absolute_mouse", hvis du er i tvivl.

"joystick_move" vs. "absolute_mouse"

Vi kan ikke understrege nok, at når du opretter kamerainput for dit første- eller tredjepersonsspil eller andet, som er markørdrevet, at så skal du altid bruge typen "absolute_mouse" og reagere på forskelle, som om det var en mus.

API'en gør automatisk det rigtige her for input fra styrepinden, så du stadig får brugerdefineret input, hvis dit kamera anvendes på en analog styrepind (a la PS4/Xbox) med fulde dødszoner/responskurver/osv., som du kan angive i din standardkonfiguration. Samme input vil derefter fungere med joysticks, trackpads, bevægelsesstyrede gyroer (Steam Controller/PS4) samt fremtidig understøttelse af mus.

Du bør ikke bruge inputmetoden "joystick_move" til dit kamera, da det ikke er muligt at tilknytte den modsatte retning for at få nyttige 1:1-DATA for pad/gyro/mus/bevægelsesstyring.

Dette gælder også for markørbaseret input: "absolute_mouse" som markør vil fungere fint til styrepindsbaseret input, så du behøver ikke at oprette din egen styrepindsbaserede markør, hvis du får brug for en sådan.

Hvis du vil, kan du sende lavniveau-museevents sammen med dine analoge data. Dit spil vil ikke kunne skelne disse museevents fra dem, der genereres af dit operativsystem. Du kan gøre dette ved at tilføje værdien "os_mouse" og tildele den værdien 1.

Her er et eksempel:
"StickPadGyro" { "Mouse" { "title" "#Action_Mouse" "input_mode" "absolute_mouse" "os_mouse" "1" } }


AnalogTrigger-handlinger
AnalogTrigger-handlinger er endimensionelle analoge handlinger, som kan bindes til aftrækkere. Hvis du bruger en simpel aftrækkertærskel for f.eks. affyring af et våben eller aktivering af sigte, kan du bruge en Button-handling i stedet for en AnalogTrigger-handling, så brugerne har større fleksibilitet til at konfigurere bindinger.

AnalogTrigger-handlingerne har en konfigurerbar dødszone i konfigurationsgrænsefladen og kan skaleres fra 0 til 1.0f mellem disse værdier. Controllere med digitale aftrækkerknapper såsom Nintendo Switch Pro-controlleren sender enten 0 eller 1.0, så du kan kontrollere, at du ikke har spilkode, som er afhængig af gradvise aftrækkerændringer over tid.

AnalogTrigger-handlinger har et simpelt format og bruger navnet på handlingen som nøgle og lokaliseringstokenet som værdi. Sådan her:
"AnalogTrigger" { "AccelerationAxis" "#Action_Accelerate" "BreakingAxis" "#Action_Brake" }

Button-handlinger

Button-handlinger har et lignende format og bruger navnet på handlingen og lokaliseringstokenet:
"Button" { "digital_action_1_name_here" "#DigitalAction1TitleHere" "digital_action_2_name_here" "#DigitalAction2TitleHere" }

Hvis det er nødvendigt, kan du definere et indbygget lavniveau-hardwareinput (for eksempel indbygget museklik), som udløses med handlingen. Dette er nyttigt i visse grænsetilfælde, hvor dit spil af afhængigt af for eksempel en pertentlig inputstak på syv lag, som aldrig helt behandler simulerede museevents fra dit anvendelseslag på samme måde som dem, der genereres direkte af operativsystemet.

"Button" { "simple_click" "#simple_click" "fancy_click" "#fancy_click, mouse_button LEFT" }

Dette sikrer, at spillet udsender en reel venstre museknap-event på operativsystemniveau, hver gang "fancy_click"-handlingen udløses.

Advarsel!

Brug aldrig dette trick som en krykke for at gennemtvinge bestemte faste inputbindinger for dine handlinger. Det modarbejder hele formålet med "handlinger, ikke input"-paradigmet og med at give brugeren fuld kontrol over brugerens konfiguration. Hvis du bruger denne funktion til andet end at rette et par sjældne grænsetilfælde, bruger du den nok for meget.

Handlingssætlag

Udover handlingssæt kan du også overlejre gradvise ændringer på det aktive handlingssæt med et handlingssætlag. Du kan bruge dette til at håndtere specialiseringer af en generel tilstand såsom et snigskyttelag ovenpå styringen, når spilleren er til fods, eller til at håndtere tilfælde, hvor du har en brugergrænseflade i spillet, som vises over det almindelige gameplay såsom afstemningsskærme. Lagene angives i deres egen sektion, f.eks.:
"action_layers" { "IngameModalLayer" { "title" "#Layer_IngameModal" "legacy_set" "0" "set_layer" "1" "parent_set_name" "InGame" "AnalogTrigger" { } "Button" { "Modal_Accept" "#Action_Modal_Accept" "Modal_Decline" "#Action_Modal_Decline" } } }

Lokalisering


IGA-masterfilen bør inkludere en lokaliseringssektion sammen med handlingssætdefinitionerne. De individuelle underordnede objekter i lokaliseringsobjektet vil være en af de sprogstrenge, som Steam understøtter. Sørg for, at du inkluderer mindst én blok, som indeholder engelske handlingstitler.

"localization" { "english" { "move" "Move" "camera" "Camera" } }

Bemærk, at navnene på egenskaberne skal svare til de lokaliseringsnøgler, som du angav i tidligere sektioner men uden tegnet "#".

Hvis du vil tilføje yderligere sprog, skal du blot tilføje flere sprogblokke med lokaliseret tekst for hver post:

"localization" { "english" { "move" "Move" "camera" "Camera" } "spanish" { "move" "Mover" "camera" "Cámara" } "norwegian" { "move" "Bevege" "camera" "Kamera" } }
Tokenet for hvert sprog skal matche værdien i "API-sprogkoden", f.eks. "schinese" for forenklet kinesisk. Den komplette liste over understøttede sprog kan findes her.

Sådan bruger Steam din IGA-fil


Den IGA-masterfil, du opretter, vil kun blive brugt under udvikling (men den skal stadig gemmes, vedligeholdes og lagres i dit versionsstyringssystem osv.). Når du opretter en officiel inputkonfiguration for dit spil under udviklingen, bruger Steam-klienten IGA-masterfilen til at generere en skabelon til at starte med.