Autor Wątek: Tip: info o skrótach klawiaturowych podczas tworzenia/debuggowania gry ala IMGUI  (Przeczytany 2423 razy)

Offline Koshmaar

  • Użytkownik
    • Homepage

  • +10
# Grudzień 17, 2013, 01:47:01
Hej, chciałbym podzielić się małym odkryciem, o triku ułatwiającym tworzenie i debuggowanie gry. Wpierw krótkie wprowadzenie historyczne i motywacyjne.

Nie wiem czy wy też tak macie, ale kiedy robię jakąś grę, często dodaję do niej mnóstwo skrótów klawiaturowych - powiedzmy że z kilkadziesiąt. Działania na postaci gracza, przeciwnikach, mapie, kamerze itp. Skróty obejmują zarówno zwykłe litery, cyfry, przyciski F_, specjalne (np tab, home, backspace) a także kombinacje z ctrl, shift, alt. Czasami trudno się w tym połapać. Szczególnie taki problem miałem w Ninja Kocie, gdzie ich obecność zależała od trybu (można to sobie wyobrazić jako #define) w jakim gra została skompilowana - np debug+editor-deploy miał najwięcej, sam debug bez edytora nie miał części itd. Było to bardzo przydatne, bo niekiedy za dużo skrótów i możliwości przeszkadzało (np podczas testowania), ale nie chciałem usuwać sobie *wszystkich* możliwości posiadania wglądu i interwencji w co się dzieje na ekranie, bo dzięki temu np mogłem złapać na gorącym uczynku jakiegoś buga. Minusem było to, że często łapałem się na tym że nie wiem co w tym momencie mogę zrobić, wciskałem przyciski i denerwowałem się , albo w ogóle zapominałem o jakiejś funkcjonalności ukrytej w mniej widocznych miejscach.

Teraz już konkretnie jak sobie z tym poradzić. Najłatwiej po prostu wyświetlić listę wszystkich skrótów w aplikacji po wciśnięciu jakiegoś przycisku. Ale nikomu nie chciałoby się ręcznie przygotowywać takiej listy, utrzymywać jej aktualnej itp. tym bardziej że można zrobić to w zautomatyzowany sposób. Wymyśliłem coś podobnego w implementacji do Immediate Mode GUI (https://mollyrocket.com/861 - zaczyna się od 0:50), tzn. informacje o skrótach są w zautomatyzowany sposób zbierane podczas dzialania aplikacji.

Jak wygląda typowy kod ze skrótami:


// klasa Enemies, funkcja Update:

if (CONFIG::debug)
{
if (FlxG.keys.SHIFT && FlxG.keys.justPressed("D"))
{
for each ( var enemy : Enemy in members)
{
if (enemy.alive && enemy.exists)
enemy.baloon.TypedEverything();
}
}
}


Wszystko jasne. Teraz dodajmy jeden dodatkowy element:

if (CONFIG::debug)
{

  if (Game.info_keyboard_shortcuts_show)
  {
  Game.info_keyboard_shortcuts_list += "SHIFT+D = kill all enemies\n";
  }

if (FlxG.keys.SHIFT && FlxG.keys.justPressed("D"))
        ...
}

// gdzie w klasie Game:
public static var info_keyboard_shortcuts_show : Boolean = false;
public static var info_keyboard_shortcuts_list : String;


Ponieważ kod znajduje się w ifie odpowiadającym danej konfiguracji, którego wnętrze wywoła się tylko jeśli przy danym mixie definów jest on dostępny, to w ten sposób na ekranie pokaże się lista tylko dostępnych w danym buildzie. Wiemy że takie skróty są dostępne, wiemy że inne są niedostępne. Co więcej, te define'y można łączyć z normalnymi stanami gry np. w menu są inne, w grze spauzowanej są inne niż w grze trwającej, w danym trybie edytora może być jeszcze coś innego itp.

Implementacja całości jest trywialna:


// raz na klatkę wywołać funkcję która sprawdzi czy chcesz pokazać listę.
// jeśli tak to wypisze na ekranie listę skrótów, skompletowaną w zwykłym stringu
// podczas updatowania klatki
static public function ShowKeyboardShortcuts():void
{
info_keyboard_shortcuts_show = FlxG.keys.H;

if (info_keyboard_shortcuts_show)
{
var shortcuts_list : FlxText = new FlxText(200, 10, 350, info_keyboard_shortcuts_list, true, true, false);
shortcuts_list.shadow = 0x000001;
shortcuts_list.draw();

info_keyboard_shortcuts_list = "";
}
}



Tak wygląda gotowy efekt w praktyce:



U mnie po przytrzymaniu H pokazuje się lista na górze ekranu (jak na razie wpisałem tylko kilka skrótów).

Mało roboty, prosty i elastyczny kod, działa zawsze i wszędzie, rozwiązuje konkretny problem. "Utrzymywalność" jest wysoka ze względu na to że kod obsługi skrótu oraz informujący o nim jest obok siebie. Wg mnie bardzo fajna sprawa :) Polecam i czekam na komentarze.
« Ostatnia zmiana: Grudzień 17, 2013, 01:48:59 wysłana przez Koshmaar »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Raptor

  • Użytkownik

  • +2
# Grudzień 19, 2013, 23:11:49
To jak nikt nie komentuje to ja tylko napiszę, że świetnie nadawałoby się to na artykuł na warsztatowej wiki, gdyby taka działała :P

Offline Koshmaar

  • Użytkownik
    • Homepage

  • +2
# Grudzień 21, 2013, 15:50:36
Dzięki :) Na artykuł na stronę mnie za krótki, wiki nie działa (?od lat nie wchodziłem), to na forum wrzuciłem jako "tipa"... chciałem się podzielic wg mnie fajnym pomysłem.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

  • +3
# Grudzień 22, 2013, 00:42:29
Cytuj
if (CONFIG::debug)
{

        if (Game.info_keyboard_shortcuts_show)
        {
                Game.info_keyboard_shortcuts_list += "SHIFT+D = kill all enemies\n";
        }

        if (FlxG.keys.SHIFT && FlxG.keys.justPressed("D"))
        ...
}
Trochę za dużo kodu per skrót, jeżeli miało by się w tym wygodnie pisać.

Proponuję zredukować to do postaci:
IF_DEBUG_KEY( SHIFT+'D', "kill all enemies" )
{
   ... kod ...
}

Gdzie IF_DEBUG_KEY (i wywoływane przezeń funkcje) załatwia wewnętrznie wszystko, włącznie z testami czy wyświetlać skróty i kompilacją do "if(0)" w trybie release.

Efekt ten sam a kodu mniej. :)

Offline Koshmaar

  • Użytkownik
    • Homepage

# Grudzień 30, 2013, 10:01:15
Rzeczywiście, dla jednego skrótu trochę sporo kodu i można to próbować w ten sposób rozwiązać.

U mnie zazwyczaj takie fragmenty dotyczą większych ilości skrótów na raz, i wtedy wolę mieć to rozpisane:

if (!CONFIG::deploy)
{

if (Game.info_keyboard_shortcuts_show)
{
Game.info_keyboard_shortcuts_list += "F4 = EnemyZone.enabled | F5 = player.toggle_path_direction\n";
Game.info_keyboard_shortcuts_list += "F6 = player.setGravity(0)  |  F7 = finish level\n";
Game.info_keyboard_shortcuts_list += "Home/End = timescale +/- 0.25  |  F11 = difficulty++\n";
Game.info_keyboard_shortcuts_list += "Numpad Plus, Minus, Slash = camera target zoom\n";
Game.info_keyboard_shortcuts_list += "ctrl+G = godmode  |  ctrl+T = reset player pos";

}

if (FlxG.keys.justReleased("F4"))
EnemyZone.enabled = !EnemyZone.enabled;

if (FlxG.keys.justReleased("F5"))
Game.player.walker.togglePathDirection();

if (FlxG.keys.justReleased("F6"))
FlxControl.player1.setGravity(0, 0);

                               ...

Btw zaraz przetłumaczę tego tipsa na angielski i wrzucę na swojego bloga... z twoją poprawką/uwagą Krzysiek :)

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Grudzień 30, 2013, 10:42:20
Cytuj
U mnie zazwyczaj takie fragmenty dotyczą większych ilości skrótów na raz, i wtedy wolę mieć to rozpisane
Blisko, czy daleko, nadal masz dwa fragmenty kodu które musisz napisać, a potem pamiętać by były zsynchronizowane, zamiast użyć do tego mechanizmów języka, napisać raz porządnie otoczkę a potem korzystać bez stresu. :)

Offline toxic

  • Użytkownik

# Grudzień 30, 2013, 17:38:16
Blisko, czy daleko, nadal masz dwa fragmenty kodu które musisz napisać, a potem pamiętać by były zsynchronizowane, (...)
Ale jak to pamiętać? Po co?
Zdarza się Wam zmieniać istniejące skróty-czity? Dodawać nowe - tak, na pewno, ale zmieniać już istniejące? Dziwne...

Offline Dab

  • Redaktor
    • blog

# Grudzień 30, 2013, 18:23:22
Proponuję zredukować to do postaci:
IF_DEBUG_KEY( SHIFT+'D', "kill all enemies" )
{
   ... kod ...
}

Gdzie IF_DEBUG_KEY (i wywoływane przezeń funkcje) załatwia wewnętrznie wszystko, włącznie z testami czy wyświetlać skróty i kompilacją do "if(0)" w trybie release.

Efekt ten sam a kodu mniej. :)

Zgoda, ale można po prostu po prostu dać

if (debug_key("shift+d", "kill all enemies")) { ... }
bo nie ma tu sensu dodatkowo zaciemniać ifa, a i nie bardzo widzę po co łączyć debug/release z obecnością cheatów.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Grudzień 30, 2013, 18:44:33
Dab: fakt, nie ma po co ifa w to mieszac, a i w Twojej wershi da sie to makrami zrobic. A mieszanie debug/release sie moze przydac jesli tych cheatow nie chcesz udostepniac, albo kompilujesz wersje na platforme ktora klawiatury nie ma w standardzie. :)