2012-01-04 10 views
8

Zwykle elementy i komponenty lub inne części kodu gry w projekcie opartym na danych będą miały nazwy, które zostaną sprawdzone, jeśli chcesz dowiedzieć się, który obiekt masz do czynienia dokładnie.Jakie są dobre metody zastępowania nazw łańcuchów haszami całkowitymi

void Player::Interact(Entity *myEntity) 
{ 
    if(myEntity->isNearEnough(this) && myEntity->GetFamilyName() == "guard") 
    { 
     static_cast<Guard*>(myEntity)->Say("No mention of arrows and knees here"); 
    } 
} 

Jeśli ignorować możliwości, że może to być przedwczesna optymalizacja, to całkiem jasne, że patrząc podmiotów byłoby o wiele szybciej, jeśli ich „name” był prosty wartość 32 bit zamiast rzeczywisty ciąg.

Obliczanie skrótów z nazw łańcuchów jest jedną z możliwych opcji. Nie próbowałem go, ale z zakresem funkcji 32-bitowej i dobrej funkcji mieszania, ryzyko kolizji powinno być minimalne.

Pytanie brzmi następująco: oczywiście potrzebujemy jakiegoś sposobu na konwersję w kodzie (lub w jakimś zewnętrznym pliku) nazw łańcuchów na te liczby całkowite, ponieważ osoba pracująca nad tymi nazwanymi obiektami będzie nadal chciała odwołać się do obiekt jako "strażnik" zamiast "0x2315f21a".

Zakładając, że używamy C++ i chcemy zamienić wszystkie ciągi występujące w kodzie, czy można to osiągnąć za pomocą wbudowanych funkcji językowych, czy też musimy zbudować zewnętrzne narzędzie, które ręcznie przegląda wszystkie pliki i wymiany wartości?

+1

+ LOL dla wiadomości strażnika: D – Petruza

+0

Powiedziałbym, że naprawdę chcesz "dynamic_cast " tutaj. RTTI może mieć złą sławę w tworzeniu gier, ale z pewnością będzie to znacznie wolniejsze, nie wspominając o trudniejszych do utrzymania. – MSalters

Odpowiedz

10

Jason Gregory napisał na his book:

W Naughty Dog, użyliśmy wariant algorytmu CRC-32, aby zahaczyć o nasze struny i nie napotkaliśmy ani jednej kolizji w ciągu ponad dwóch lat rozwoju w grze Uncharted: Drake's Fortune.

Możesz więc zajrzeć do tego.

I o kroku budowy, o którym wspomniałeś, również o tym mówił. Są to przede wszystkim hermetyzacji struny, które muszą być zakodowane w coś takiego:

_ID("string literal") 

I użyć zewnętrznego narzędzia w czasie kompilacji do mieszania wszystkich wystąpień. W ten sposób unikasz wszelkich kosztów runtime.

+1

W C++ 11, powinieneś być w stanie użyć funkcji 'constexpr' do wykonania mieszania w czasie kompilacji, eliminując potrzebę użycia zewnętrznego narzędzia. –

+0

@MikeSeymour To naprawdę fajne, nie miałem pojęcia. Naprawdę nie wyglądało jeszcze na C++ 11. Zawiedziony na VS [brak wsparcia] (http://blogs.msdn.com/b/vcblog/archive/2011/09/12/10209291.aspx) .. –

+0

To całkiem niesamowite Mike, całkowicie zapomniał o constexpr. Dodaj to jako odpowiedź, a ja to zaakceptuję. – TravisG

1

Do tego służą wyroki. Nie odważy się zdecydować, który jest najlepszy dla zasobów tematu, ale jest wiele do wyboru: https://www.google.com/search?q=c%2B%2B+enum

+1

Problem z wyliczeniami polega na tym, że są one "naprawione" i nie działają dobrze z rozszerzalnym systemem skryptowym lub projektem opartym na danych. –

+0

Możesz to zrobić w staroświecki sposób za pomocą makr, dzięki czemu masz pełną kontrolę nad procesem. – aaaaaaaaaaaa

+1

Czy możesz rozwinąć nieco tę myśl? Może nie myślimy o podobnych scenariuszach. Na przykład załóżmy, że utworzysz jednostkę o nazwie "level1_garden_door" w edytorze poziomów. Następnie chcesz odwołać się do tego elementu w pliku skryptu, aby dodać trochę interaktywności. Dla łatwości użycia powinieneś być w stanie powołać się na twój podmiot po imieniu. Jednak wyszukiwanie ciągów znaków jest powolne, więc mieszanie tych identyfikatorów w ints w czasie kompilacji zapewnia przyzwoity środek między użytecznością a szybkością. Wyliczenie musi znać wszystkie wartości, które może reprezentować, ale tutaj te wartości są używane. Jakie jest rozwiązanie? –

0

Powiedziałbym, że idę z wyliczeniami!

Ale jeśli masz już dużo kodu już za pomocą strun, dobrze, albo po prostu zachować je w ten sposób (proste i zwykle dość szybko na komputerze tak) lub mieszania go za pomocą jakiegoś CRC lub MD5 do liczby całkowitej.

0

Jest to w zasadzie rozwiązane przez dodanie indeksu na górze mapy skrótu.

Powiedzmy, że chcesz przekonwertować ciągi do liczb całkowitych:

  • Napisz klasa owija zarówno tablicę i HashMap. Nazywam te słowniki klas.
  • Tablica zawiera ciągi.
  • hash MAP klucz to ciąg (wspólne wskaźniki lub stabilne macierze, gdzie surowe wskaźniki są bezpieczną pracę również)
  • wartość hash MAP jest wskaźnikiem do tablicy napis znajduje się, co jest również nieprzezroczysta poradzić powraca do kodu wywołującego.
  • Po dodaniu nowego ciągu do systemu, jest ono wyszukiwane już istniejące w mapie mieszającej, zwraca uchwyt, jeśli jest obecny.
  • Jeśli uchwyt nie jest obecny, dodaj ciąg do tablicy, indeks jest uchwytem.
  • Ustaw ciąg i uchwyt na mapie, a następnie przestaw uchwyt.

Uwagi/Ostrzeżenia:

  • Strategia ta sprawia coraz ciąg z powrotem w biegu rączką w stałym czasie (jest to jedynie szacunek array).
  • Identyfikatory uchwytów są wyświetlane w pierwszej kolejności, ale jeśli serializuje się ciągi znaków zamiast wartości, nie ma to znaczenia.
  • Przeciążenia operatora [] dla klucza i wartości są dość proste (rejestrowanie nowych ciągów lub odzyskiwanie łańcucha), ale zawijanie klamki za pomocą klasy zdefiniowanej przez użytkownika (zawijanie liczby całkowitej) dodaje wiele potrzebnych wpisz bezpieczeństwo, a także unikaj niejednoznaczności, jeśli chcesz, aby klucz i wartości były tymi samymi typami (przeładowana kompilacja [] przyzwyczajeń i itp.)
  • Musisz przechowywać ciągi w pamięci RAM, co może być problemem.
Powiązane problemy