Czy rozsądnie jest napisać silnik gry w C? [Zamknięte]

53

Mimo że C ++ wydaje się być królem, z tego, co mi powiedziano, C jest nadal szeroko stosowany w grach, zwłaszcza na konsolach. Czy jednak pisanie całego silnika gry w C byłoby dziś nieuzasadnione? Jakie są jakieś zalety C w porównaniu z C ++? Dlaczego ktoś miałby chcieć używać C zamiast C ++?

Slurps Mad Rips
źródło
1
Gry konsolowe używają C ++ FYI!
Alan Wolfe
Właściwie uważam, że C byłoby łatwiej pisać gry w pewnej skali, powiedzmy dziesiątki tysięcy LOC lub więcej, głównie dlatego, że pozwala to skupić się na bitach i bajtach bez złożonych typów danych i buduje się bardzo szybko w porównaniu do C ++. Ale po pewnej skali (powiedzmy osiągnięciu setek tysięcy LOC) zacznę chcieć sięgnąć po C ++, w którym zacznę naprawdę potrzebować złożonych typów danych, większego bezpieczeństwa typów, ewentualnie wyjątków, szablonów, a nawet zwiększyć się w skalę (powiedzmy miliony), aby rzeczy inne niż C ++ mogły łączyć się z kodem C i C ++.
C ma również tę dodatkową zaletę, że jest szeroko przenośny nawet dla ABI, więc bardzo łatwo jest pobrać istniejący kod C, a następnie zacząć go używać w innych językach, powiedzmy, FFI. C ++ jest nieco bardziej niezręczny z manglingiem nazw, niezdolnością do bezpiecznego przekraczania granic modułów, powtarzalności vtable w różnych kompilatorach, standardowymi implementacjami bibliotek różniącymi się między dostawcami itp. Ogólnie rzecz biorąc, biblioteki C, które piszę, trwają dłużej bez potrzeby wprowadzania zmian i wychodzenie ze stylu, choć pisanie nim przy użyciu skali zajmuje więcej czasu.

Odpowiedzi:

49

Czy jednak pisanie całego silnika gry w C byłoby dziś nieuzasadnione?

To rozsądne, ale pytanie brzmi: co kupuje? Prawdopodobnie nie potrzebujesz ekstremalnych możliwości przenoszenia, jakie oferuje C, i szkoda, że ​​rezygnujesz ze wszystkich funkcji, jakie oferuje C ++, chyba że naprawdę przeciwstawiłeś się temu filozoficznie.

Jakie są jakieś zalety C w porównaniu z C ++?

Lepszy czas kompilacji?

Dlaczego ktoś miałby chcieć używać C zamiast C ++?

Myślę, że jest to głównie wybór estetyczny. Wiele osób lubi C, ponieważ jest prosty i minimalny oraz wydaje się czysty. C ++ ma wiele fajnych funkcji (same przestrzenie nazw sprawiają, że warto z niego korzystać), ale jest również duży i niechlujny.

hojny
źródło
3
Aż do Id Tech 4
optyk
9
@Josh: Łatwiej debugować !? Programy C są niezwykle trudne do debugowania, głównie ze względu na wskaźniki i zarządzanie pamięcią. Programy C ++ (przy użyciu prawdziwych idiomów programowania C ++, które w miarę możliwości unikają wskaźników i zarządzania pamięcią),łatwiejsze do debugowania o kilka rzędów wielkości .
BlueRaja - Danny Pflughoeft
14
C mogą zrozumieć zwykli śmiertelnicy. Wydaje się, że C ++ ma wiele funkcji i doświadczonych programistów, o których dowiadują się nawet po dekadzie codziennego korzystania z niego.
Jari Komppa
13
C ++ jest dużym językiem, ale jego przerażająca reputacja jest rozpowszechniana głównie przez ludzi, którzy właśnie przeczytali horrory i nie poświęcili czasu na naukę. Jest wiele do nauczenia się, ale dostajesz za to dużą wartość. C ++ pozwala wyrazić wiele rzeczy, których C po prostu nie potrafi.
wspaniałomyślny
2
@ BlueRaja-DannyPflughoeft, #define malloc(x) my_malloc(x) #define free(x) my_free(x)a teraz debugujesz pamięć. Dzięki C ++ nigdy nie wiesz, co zostanie przydzielone, ponieważ istnieje wiele sposobów alokacji pamięci (nowe, malloc, konstruktory klas itp.)
YoYoYonnY
59

Pracowałem intensywnie z silnikiem do gier czysto C, który dostarczył kilka produktów, więc jest to absolutnie możliwe. Oto moje osobiste doświadczenie z pracą w obu silnikach C vs C ++:

  1. Korzystanie ze struktur czystego C umożliwia wykorzystanie wiedzy na temat wyrównywania struktur, a następnie można wykorzystać te informacje do zbudowania trwałości obiektów i warstw serializacji. Silnik, z którym pracowałem, miał kilka prostych parserów nagłówków, które automatycznie tworzyłyby te metadane o strukturach, a niektóre rodzaje operacji na danych były trywialne. Analiza dowolnych plików nagłówkowych C ++ jest w zasadzie niemożliwa, a po dodaniu dziedziczenia i funkcji wirtualnych tracisz możliwość dokładnego określenia, gdzie są rzeczy w pamięci
  2. Czas kompilacji jest znacznie krótszy, ponieważ możesz zachować kompaktowość plików nagłówkowych i korzystać z deklaracji struktur do przodu.
  3. Debugowanie można ulepszyć, ponieważ bez użycia szablonów i dziedziczenia bardzo łatwo jest dokładnie ustalić, czym jest dany obiekt i co robi.

Wszystkie te korzyści można również osiągnąć równie łatwo, stosując powściągliwy kod c ++, który powstrzymuje się od używania szablonów i dziedziczenia na obiektach serializowanych, ale decyzja CTO była łatwiejsza do egzekwowania prostoty, gdyby bardziej mylące elementy C ++ nie były dostępny.

Osobiście uważam, że było to nieco ekstremalne, ponieważ naprawdę brakowało mi możliwości zdrowego deklarowania zmiennych w pętlach for i wielu całkowicie uzasadnionych zastosowań dziedziczenia. Ale tak naprawdę nie kosztowało nas to dużo produktywności, biorąc pod uwagę wszystko

Ben Zeigler
źródło
5
Naprawdę nic nie stoi na przeszkodzie, aby wdrożyć dziedziczenie w C. A jeśli użyjesz C99, możesz zadeklarować zmienne dla pętli.
jsimmons,
15
Nie zgadzam się z punktem 3. Pisanie niechlujnego, trudnego do debugowania kodu w C jest tak samo łatwe jak w C ++. Lepsze debugowanie nie jest czymś nieodłącznym w języku C.
Dan Olson
7
Nawet czysty kod może być trudniejszy do zrozumienia w C ++ - przy przeciążeniu, szablonach, funkcjach wirtualnych i wyjątkach, znacznie trudniej jest zobaczyć na pierwszy rzut oka, jaki będzie rzeczywisty przepływ sterowania.
Kylotan
6
@Dan: Po prostu mając więcej rzeczy, C ++ jest trudniejszy do debugowania. Możesz oczywiście ograniczyć się do korzystania z tych rzeczy, w którym to przypadku debugowanie staje się tak łatwe jak C - ponieważ staje się C.
Mniej rzeczy jest właściwie powodem, dla którego lubię C. Na przykład w CI można po prostu kopiować bity i bajty za pomocą memcpycokolwiek, ponieważ system typów nie pozwala na kopiowanie liczników i kropek. Mogę pisać kod, wiedząc, że nie będę musiał cofać skutków ubocznych w prawie każdym wierszu kodu, ponieważ nie mogę niejawnie wyjść z funkcji, chyba że wyraźnie z niej wyjdę; nie ma żadnych wyjątków. Wszystko to sprawia, że ​​pisanie struktur danych jest o wiele łatwiejsze - w C ++ pisanie zgodnych ze standardami vectorjest bardzo czasochłonne, szczególnie jeśli chcesz, aby ...
18

Przepisuję silnik gry 2D napisany w C ++ i Lua do C i Lua. Jak dotąd doświadczenie było całkiem dobre. Oczywiście wykonywanie operacji wektorowych i macierzowych nie kończy się tak ładnie w C. Ale poza tym doświadczenie to było całkiem odświeżające po ponad 10 latach pracy jako programista C ++.

C ma wiele zalet w stosunku do C ++:

  1. Kompilator upewni się, że w czasie inicjalizacji statycznej nie zostanie uruchomiony żaden kod. To sprawia, że ​​całkowicie bezpieczne jest statyczne przydzielanie globalnych danych, takich jak łańcuchy używane jako klucze, np
  2. Przezroczystość. Przypisanie C, przydzielenie lub zdefiniowanie zmiennej nie spowoduje uruchomienia dużej ilości kodu. C ++ automatycznie wygeneruje dla ciebie konstruktory kopiowania, dzięki czemu masz mniejszą kontrolę nad tym, co zostanie wykonane podczas wykonywania przypisania.
  3. Dużo debugowania może być łatwiejszych z uwagi na brak zniekształcania nazw funkcji
  4. Zazwyczaj używanie C memcpy jest w porządku , ale w C ++ łatwo spowoduje problemy, ponieważ konstruktory kopiowania nie będą uruchamiane. Biorąc pod uwagę, że memcpy jest znacznie szybszy niż std :: copy, który ma znaczenie.

Oprócz tego istnieje wiele korzyści z wejścia w sposób myślenia w języku C. W C ++ często robię to, co robię, trochę uogólnione i abstrakcyjne. W CI zwykle wycinają metody takie jak get-set i często wstępnie przydzielają tablice o stałej wielkości zamiast używać tablic dynamicznych. Często kończę na krótszym i łatwiejszym do debugowania kodzie w C. Struktury danych są zwykle bardziej płaskie i łatwiejsze do przeglądania w debuggerze.

Szczerze mówiąc, nigdy nie stworzyłbym aplikacji wyłącznie w C. Powód, dla którego to działa, łączę ją z językiem wyższego poziomu, takim jak Lua, który może bardzo dobrze uzupełniać C, gdyby C nie był tak silny.

Oprogramowanie Id pisze, że większość ich silników w CI wierzy, możesz spojrzeć na Return to castle Wolfenstein, który został napisany w C.

Pisałem o niektórych moich doświadczeniach dotyczących skalowalności C w porównaniu z C ++ i wadach wektora STL w porównaniu do zwykłych tablic.

Erik Engheim
źródło
11
FYI, w każdym przypadku, który sprawdziłem (co, jak sądzę, darwin gcc i vc2008), std :: copy po prostu kompiluje się z wywołaniem memcpy, jeśli oba typy są POD.
BRaffle,
3
Również wektor RE: STL vs. tablice proste, dlaczego nie użyć ładnych części wektora i użyć normalnych wskaźników C zamiast iteratorów, jeśli ich nie lubisz? Możesz po prostu zrobić i myvector [N]. To jak najlepsze z obu światów, zakładając, że twój kod C dokonuje alokacji pamięci w ten sam sposób. Lub w przypadku pętli sprawdź BOOST_FOREACH. Sprawia, że ​​jest to jeszcze prostsze niż C.
BRaffle
1
Dzięki za wskazówkę na temat std :: copy memcpy. Nie wiedziałem tego Kiedy Alexandrescu potraktował to kilka lat temu, tak nie było. O iteratorach C ++. Chodzi głównie o filozofię, staram się zaprogramować, w jaki sposób C ++ miał być programowany zarówno dla ludzi, z którymi współpracuję, jak i dla korzystania z funkcji C ++. Zostało głównie zaznaczone, że niektóre ulepszenia C ++, takie jak kontenery STL, nie zawsze są lepsze niż robienie tego w stary sposób C.
Erik Engheim,
7

Jak ktoś zauważył, C ++ ma tę zaletę, że ma duże ramiona, na których możesz stać (BOOST, STL itp.). Ostatecznie jest to osobisty wybór, ale wybrałbym C ++ ze względu na dostępne zasoby. Jeśli w C ++ są funkcje, których nie chcesz używać, nie używaj ich.

użytkownik266
źródło
1
Należy pamiętać, że 99% komercyjnych i wewnętrznych silników gier steruje z różnych powodów Boost i STL (gwarancja wydajności, debugowanie, bezpieczeństwo wątków, kontrola).
Kaj
42
A 99% statystyk składa się.
BRaffle,
Wydaje mi się, że cytowanie wszystkich statystyk powinno być w pewnym sensie regułą.
Matt Jensen
3

Nie sądzę, żeby ktokolwiek używa obecnie wyłącznie języka C, zwykle jest on mieszany z językiem wyższego poziomu.

Programowanie w C ma pewne zalety w stosunku do, powiedzmy, programowania w C ++. C ++ potrafi robić wiele rzeczy niewidocznych dla użytkownika, co może zaszkodzić wydajności, jeśli nie będziesz ostrożny. C ++ może być również okropny, jeśli chodzi o użycie pamięci podręcznej, co ponownie może obniżyć wydajność.

Może więc przynieść pewne korzyści napisanie krytycznych pod względem wydajności części gry w sposób podobny do C, a nie w tradycyjny sposób C ++. Jednak nigdy nie słyszałem o nikim, kto pisałby całą grę w C.

Na niektórych platformach, takich jak iPhone, użycie C ++ może zwiększyć rozmiar pliku wykonywalnego o pewną porcję kilobajtów (zapomniałem, ile, przepraszam), dlatego niektórzy programiści iPhone'a wybierają pisanie kodu w kombinacji C i Objective -DO.

Sander van Rossen
źródło
3

Podam jeszcze kilka powodów, dla których dzisiaj byłoby nierozsądnie pisać silnik gry w C zamiast w C ++: STL i BOOST.

Nie wyobrażam sobie, jak warto byłoby napisać kolejną listimplementację, skoro można polegać na kodzie, który działa od razu (i że nie trzeba pisać!)

Loris
źródło
1
Czy jakieś duże studio faktycznie używa boosta? Nawet użycie STL jest nadal przedmiotem dyskusji, ze względu na przenośność. Przynajmniej dla silników konsolowych.
slicedlime
2
Osobiście używam Boost.FunctionTypes do interakcji c ++ / lua (patrz gamedev.net/reference/programming/features/CPPLuaExport/... ) i bibliotekę liczb losowych Boost do jednolitego generowania liczb losowych (dla układów cząstek). Również Boost.Foreach jest schludny. BTW, kogo to obchodzi, jeśli duże studia nie używają BOOST? Mają siłę roboczą do pisania od podstaw własnych bibliotek STL, nie mam.
Loris,
1
Tak, ale także zdaj sobie sprawę, że istnieją również podobne biblioteki dla C.
jsimmons,
2
Uważam, że wiele osób korzysta ze wzmocnienia w grach. Ale dla wielu z nas nie jest to wymóg (a nawet pożądany).
Dan Olson
6
Ludzie, w co wierzysz, nie ma znaczenia: albo wiesz, albo nie wiesz .
o0 ”.
3

Pisanie silnika gry w C jest rozsądne. Jest szybki i można go przenieść do wielu systemów. Na przykład możesz użyć dla Androida (z użyciem NDK). Możesz użyć go na iPhonie (Cel c jest tylko rozszerzeniem c). Możesz także użyć go w głównym systemie operacyjnym, takim jak Linux, Mac lub Windows. Jeśli czujesz się komfortowo z c, proponuję spróbować!

Luke Taylor
źródło
2

Oczywiście, że to rozsądne. Osobiście bym tego nie zrobił, a większość fanów C, których znam, po prostu pisze kod podobny do C w plikach .cpp. Ale języki są wystarczająco podobne do tego, gdzie tak naprawdę nie ma znaczenia.

Jeśli chodzi o to, dlaczego ktoś chciałby to zrobić, myślę, że jest to głównie spowodowane filozofią anty-C ++. Osobiście nadal nie uważam, że to dobry powód, aby wybrać C zamiast „C-style C ++”. typedef struct szaleństwo jest wystarczająco dobrym powodem, aby omijać C, a jest wiele innych.

Niestety zarówno C, jak i C ++ są dość okropnymi językami, kiedy do tego dochodzimy. To jeden z powodów, dla których ludzie próbowali w ciągu ostatnich lat dużo kodu napisać.

Jeśli szukasz przykładów ludzi pracujących w C, możesz zignorować id, ponieważ przypominam sobie, że już dawno porzucili C. Cryptic Studios (Star Trek Online) rozwija cały silnik w C. O ile mogę powiedzieć, tak, to bardziej z powodu filozofii niż z jakiejkolwiek konkretnej korzyści.

Dan Olson
źródło
0

Tak i nie. Tak, zrobiłem to kilka lat temu, ale potrzebowałem, aby moja gra działała w 3D na 64-bitowym serwerze zdalnym unix (nie Linux) z graczami na głupich terminalach. To nie było trywialne. C może być fajne, jeśli chcesz zintegrować LUA, ale w końcu mam lua do pracy w C ++, więc powiedziałbym, że tak, jest to możliwe, ale nie rób tego.

Jeff
źródło
0

Czy możliwą dobrą odpowiedzią może być „użyj obu”?

Słyszałem, że projekty panda3d można zoptymalizować, zabijając wąskie gardło, albo używając jakiegoś cytonu, albo albo przekodowując te części.

W większości przypadków części, które należy zoptymalizować, to część z wieloma iteracjami i zagnieżdżaniem lub z dużą ilością obliczeń numerycznych, więc (dzikie) przypuszczam, że jednym uczciwym kompromisem byłoby użycie obu języków przy użyciu C dla części, które zawierają dużo programowania niskopoziomowego, więc nie można niewłaściwie używać języka C ++ dla części, która wymaga prędkości, i C ++ do końca gry.

Idealnie robisz szybką część silnika, mając na uwadze wysoki poziom, a następnie używasz języka skryptowego lub C ++, który zużyje znacznie mniej nest / loopów.

Oczywiście nigdy nie można stworzyć takiego silnika, który pasowałby do wszystkich gier, które musieliby zrobić programiści, chyba że poświęcisz swój silnik specjalnemu rodzajowi gry ...

Ale nie bierz mojej rady za pewnik, ponieważ nie jestem doświadczonym twórcą gier ani doświadczonym programistą ... Myślę, że C zmusza cię do pisania szybkiego kodu, jednocześnie pisząc dobry i szybki kod C ++ dla projektu tak dużego jak gra to inna sprawa ...

żart
źródło
0

C pracował dla Johna Carmacka , możesz uzyskać wiele korzyści, używając C, ale dopóki nie dotrzesz tam, aby z nich skorzystać, może to trochę potrwać.

Tutaj możesz znaleźć listę silników gier, niektóre z nich są napisane w C, być może możesz dowiedzieć się, jak zrobić silnik gry C, przeglądając ich kod źródłowy.


źródło
0

Kod C jest zwykle prawidłowym kodem C ++.

Główne problemy z C ++ używają go niepoprawnie ( Linus Torvalds nienawidzi go z tego powodu , miał również kilka innych problemów z przenośnością biblioteki, więc przy zakupie pracuje na poziomie systemów operacyjnych i musi być w stanie uruchamiać rzeczy na każdym losowym chip tam).

Na przykład prawie nie ma przewagi przy użyciu tablicy stylów [] nad c ++ std :: vector <> (lub podobnym pojemnikiem).

Wektory są bezpieczne dla typów i można je sprawdzić (można uzyskać dostęp do elementów za pomocą metody get () lub [], nawet jeśli nie używasz metody sprawdzania tablic, możesz nadal sprawdzać rozmiar, zamiast umieszczać go wskaźnikiem).

Ale wektory mogą być wolniejsze, jeśli na przykład nie zadeklarujesz domyślnego rozmiaru w konstruktorze. Również dodawanie elementów do wektora może powodować spowolnienia, jeśli będzie on wymagał zmiany rozmiaru. C ++ 11 ma także wiele zalet, takich jak jednolita inicjalizacja (możesz teraz deklarować i inicjować wektory za pomocą tej samej składni), a istnieją konstruktory ruchu, które pozwalają ci uniknąć kopiowania. Możesz nawet tworzyć własne niestandardowe inicjalizatory (jeśli z jakiegoś powodu chcesz zrobić coś innego niż użycie malloc).

Lub oczywiście, jeśli musisz zmienić rozmiar rzeczy, to wektory są jeszcze łatwiejsze do zrobienia, nie musisz bawić się w malloc, ręcznie kopiować rzeczy i tak dalej.

C ++ daje ci kod zorientowany obiektowo. Po skompilowaniu będzie równie wydajna, ponieważ jest to po prostu abstrakcja dla ludzi pracujących z kodem. Chociaż rzeczy takie jak konstruktory mogą spowolnić tworzenie obiektów. Ale albo będziesz potrzebował konstruktora, aby ustawić wartości domyślne, albo w inny sposób możesz zainicjować obiekty bez użycia konstruktora (pomijając ()).

Ale orientacja obiektowa znacznie ułatwia programowanie gier . Gry często dotyczą przedmiotów.

David C. Bishop
źródło