게임은 모든 캐릭터를 한 번에 처리 할 수 ​​있습니까?


31

이 질문은 게임에서 한 번에 많은 캐릭터를 처리 할 수있는 방법에 대한 지식을 얻는 것입니다. 나는 게임이 처음이므로 사면을 미리 부탁드립니다.

나는 탑이 건설되고 각 탑이 일정한 속도로 발사체를 방출 하는 15 개의 타워 슬롯 이있는 타워 방어 게임을 만들고 있습니다 . 말할 수 초마다, 2 발사체가 타워의 각에 의해 만들어지고있다 전장에서 행진 원수, 70 말할 수 그들이 움직일으로 변경되는 등 HP, 마나, 같은 속성의 10 개 종류 (각을 싸움터).

개요

탑 카운트 = 15
각 타워 초당 작성자 발사체 = 2
발사체 만든 총 수 초당 = 30 개
전장 카운트에있는 단위 = 70

이제, 게임이 그 처리합니까 (30) 발사체와 70 대 에 그 (것)들을 처리하여 100 개 다른 스레드 (A PC에 대해 너무 많이) 또는 모든 이들의 이동 등 자신의 가치를 감소시키는 것으로 1 개 스레드 (종류 느린 될 것이다 생각합니다)?

나는 이것에 대한 단서가 없으므로 누구나 어떻게 해결할 수 있는지 안내 할 수 있습니까?


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
MichaelHouse

다른 답변에 추가하면 ... 거대한 게임의 예입니다. Skyrim은 대부분 단일 스레드에서 게임 로직 업데이트를 수행했습니다. 이를 잘 관리하는 방법은 먼 NPC (마일 떨어진 NPC)가 일정에 따라 근사화되는 것입니다. 대부분의 MMO는 단일 스레드에서 게임 로직을 업데이트하지만 맵의 각 부분은 다른 스레드 또는 서버 랙에 있습니다.
moonshineTheleocat

답변:


77

이제이 게임은 30 개의 발사체와 70 개의 유닛을 100 개의 다른 스레드에서 처리하여 어떻게 처리합니까?

아니요, 절대 그렇게하지 마십시오. 리소스마다 새로운 스레드를 만들지 마십시오. 네트워킹에서는 확장되지 않으며 엔터티 업데이트에서도 확장되지 않습니다. (Java에서 소켓 당 하나의 스레드를 읽을 때 하나의 스레드를 가진 시간을 기억하십니까?)

그들 모두를 움직이는 1 실은 그들의 가치 등을 줄입니까?

예, 초보자에게는 이것이 길입니다. "큰 엔진"은 스레드간에 일부 작업을 분할하지만 타워 방어 게임과 같은 간단한 게임을 시작하는 데 필요하지 않습니다. 이 하나의 스레드에서 수행 할 모든 틱을 수행하는 데 더 많은 작업이있을 것입니다. 예, 물론 렌더링합니다.

(어느 정도 느릴 것 같아요)

음 ... slow에 대한 당신의 정의는 무엇입니까 ? 100 개의 엔터티의 경우 코드 품질과 작업중인 언어에 따라 0.5 밀리 초 이상이 걸리지 않아야합니다. 그리고 2 밀리 초가 걸리더라도 60tps (이 경우 프레임에 대해서는 이야기하지 않고 초당 틱)에 도달 할 수 있습니다.


34
이상한 일을하지 않는 한 0.5 마이크로 초와 비슷합니다. 그러나 가장 중요한 것은 작업을 여러 스레드로 나누면 모든 것이 나쁘지 않고 더 나빠질 것 입니다. 멀티 스레딩은 매우 어렵다는 것은 말할 것도 없습니다 .
Luaan

13
+1 대부분의 최신 게임 엔진은 수천 또는 수만 개의 다각형을 실시간으로 렌더링하므로 메모리에서 단지 100 개의 객체의 움직임을 추적하는 것보다 훨씬 더 집중적입니다.
phyrfox

1
"타워 방어 게임과 같은 간단한 게임." 흠 ... 혹시 방어 그리드 : 깨어 난 게임이나 그 속편을 플레이 한 적이 있습니까?
메이슨 휠러

4
"자원마다 새로운 스레드를 만들지 마십시오. 이것은 네트워킹에서 확장되지 않습니다 ..." 확장 성이 매우 뛰어난 일부 아키텍처는 정확히이 작업을 수행합니다!
NPSF3000

2
@BarafuAlbino : 말이 이상합니다. 사용 가능한 코어보다 더 많은 스레드를 작성해야하는 충분한 이유가 있습니다. 다른 디자인 결정과 마찬가지로 복잡성 / 성능 / 기타 절충점입니다.
Dietrich Epp

39

멀티 스레딩의 첫 번째 규칙은 다음과 같습니다 . 성능이나 응답 성을 위해 여러 CPU 코어에서 병렬화 할 필요 가 없으면 사용하지 마십시오 . 요구 사항 "x와 y는 사용자 관점에서 동시에 발생해야합니다"는 아직 멀티 스레딩을 사용하기에 충분한 이유가 아닙니다.

왜?

멀티 스레딩은 어렵습니다. 각 스레드가 실행되는시기를 제어 할 수 없으므로 모든 종류의 문제를 재현 할 수 없습니다 ( "경주 조건"). 이를 피할 수있는 방법 (동기화 잠금, 중요 섹션)이 있지만, 고유 한 문제 세트 ( "교착 상태")가 있습니다.

일반적으로 적은 수의 객체를 수백 개 (예 : 게임 개발에서는 그다지 중요하지 않음)로 처리하는 게임은 일반적으로 각 로직 틱을 사용하여 공통 방식을 사용하여 직렬 방식으로 처리합니다.for 루프를 .

비교적 약한 스마트 폰 CPU에서도 초당 수십억 개의 명령을 수행 할 수 있습니다 . 즉, 객체의 업데이트 논리가 복잡하고 객체 및 틱당 약 1000 개의 명령어를 사용하고 초당 100 개의 틱을 목표로 할 때도 수만 개의 객체에 충분한 CPU 용량이 있습니다. 그렇습니다. 이것은 지나치게 단순화 된 봉투 뒷면 계산이지만 아이디어를 제공합니다.

또한 게임 개발의 일반적인 지혜는 게임 로직이 게임의 병목 현상이 거의 없다는 것입니다. 성능에 중요한 부분은 거의 항상 그래픽입니다. 예, 2D 게임에서도 가능합니다.


1
"멀티 스레딩의 규칙 제 1 호는 다음과 같습니다. 성능이나 응답 성을 위해 여러 CPU 코어에서 병렬화 할 필요가 없으면 사용하지 마십시오." 게임 개발에는 맞을 수도 있습니다 (그러나 나는 그것을 의심합니다). 실시간 시스템으로 작업 할 때 스레드를 추가하는 주된 이유는 기한을 맞추고 논리적으로 단순하기 때문입니다.
Sam

6
실시간 시스템에서 @Sam 회의 마감일은 응답 성을 위해 멀티 스레딩이 필요한 경우입니다. 그러나 스레딩을 통해 도달하는 것처럼 보이는 논리적 단순성도 교착 상태, 경쟁 조건 및 리소스 고갈의 형태로 숨겨진 복잡성을 생성하기 때문에 종종 위험합니다.
Philipp

불행히도, 길 찾기 문제가있는 경우 게임 로직이 게임 전체를 뒤섞는 것을 여러 번 보았습니다.
Loren Pechtel

1
@LorenPechtel 저도 이것을 보았습니다. 그러나 일반적으로 불필요한 경로 계산 (예 : 모든 단일 틱에서 모든 단일 경로 재 계산), 자주 요청되는 경로 캐싱, 다중 계층 경로 찾기 및보다 적절한 경로 찾기 알고리즘을 사용하여 해결할 수 있습니다. 이것은 숙련 된 프로그래머가 일반적으로 많은 최적화 가능성을 찾을 수있는 곳입니다.
Philipp

1
@LorenPechtel 예를 들어 타워 디펜스 게임에서는 일반적으로 소수의 대상 지점 만 있다는 사실을 사용할 수 있습니다. 따라서 각 목적지에 대해 Dijkstra의 알고리즘 을 실행 하여 모든 단위를 안내하는 방향 맵을 계산할 수 있습니다. 매 프레임마다 이러한 맵을 재 계산해야하는 역동적 인 환경에서도 저렴한 가격입니다.
코드 InChaos

26

다른 답변은 최신 컴퓨터의 스레딩 및 성능을 처리했습니다. 더 큰 문제를 해결하기 위해 여기서 시도하는 것은 "n 제곱"상황을 피하는 것입니다.

예를 들어 1000 개의 발사체와 1000 개의 적을 보유하고있는 경우 순진한 해결책은 서로를 비교하는 것입니다.

즉, p * e = 1,000 * 1,000 = 1,000,000 개의 다른 검사로 끝납니다! 이것은 O (n ^ 2)입니다.

반면에 데이터를 더 잘 정리하면 많은 것을 피할 수 있습니다.

예를 들어, 그리드의 각 사각형에 적이있는 사각형을 나열하면 1000 개의 발사체를 반복하고 그리드의 사각형을 확인할 수 있습니다. 이제 각 발사체를 정사각형과 비교하면됩니다. 이것은 O (n)입니다. 각 프레임마다 백만 개의 검사 대신 1000 개만 필요합니다.

해당 조직으로 인해 데이터를 구성하고 효율적으로 처리하는 것은 생각할 수있는 가장 큰 단일 최적화입니다.


1
몇 개의 요소를 추적하기 위해 전체 그리드를 메모리에 저장하는 대신, 각 축마다 하나씩 b-tree를 사용하여 충돌 가능성이있는 후보를 신속하게 검색 할 수도 있습니다. 일부 엔진은 "자동으로" "; 적중 영역을 지정하고 충돌 목록을 요청하면 라이브러리가이를 제공합니다. 이것이 개발자가 처음부터 글을 쓰는 대신 엔진을 사용해야하는 많은 이유 중 하나입니다 (물론 가능하면).
phyrfox

@phyrfox 확실히, 사용 방법에 따라 다른 방법이 많이 있습니다.
Tim B

17

자원 / 객체 당 또는 프로그램 로직의 섹션 당 스레드를 작성하지 마십시오. 예를 들면 다음과 같습니다.

  1. 유닛과 발사체를 업데이트하는 스레드 - 로직 스레드
  2. 화면 렌더링을위한 스레드-GUI 스레드
  3. 네트워크 용 스레드 (예 : 멀티 플레이어) -IO 스레드

이것의 장점은 로직이 느린 경우 GUI (예 : 버튼)가 반드시 멈출 필요는 없다는 것입니다. 사용자는 여전히 게임을 일시 중지하고 저장할 수 있습니다. 또한 멀티 플레이어를 위해 게임을 준비하는 데 좋습니다. 이제 그래픽을 논리와 분리했습니다.


1
초보자에게는 별도의 그래픽 및 논리 스레드를 사용하지 않는 것이 좋습니다. 필요한 데이터를 복사하지 않으면 게임 상태를 렌더링하려면 게임 상태에 대한 읽기 액세스 권한이 필요하므로 게임 상태를 그리는 동안 수정할 수 없습니다.
코드 InChaos

1
너무 자주 그리지 않는 것 (예 : 초당 50 회 이상)은 중요하며이 질문은 성능에 관한 것입니다. 분할 프로그램은 실제 성능 이점을 위해 가장 간단한 방법입니다. 이것은 스레드에 대한 지식이 필요하지만 지식을 얻는 것이 가치가 있다는 것은 사실입니다.
Tomáš Zato-복권 모니카

프로그램 을 여러 스레드로 나누는 것은 프로그래머에게 가장 어려운 일입니다. 가장 성가신 버그는 멀티 스레딩에서 비롯되며 많은 번거 로움과 대부분 가치가 없습니다 -첫 번째 규칙 : 성능 문제가 있는지 확인한 다음 최적화하십시오. 병목 현상이있는 곳에 최적화하십시오. 복잡한 알고리즘을위한 단일 외부 스레드 일 수 있습니다. 그러나이 알고리즘을 마치는 데 3 초가 걸리면 게임 로직이 어떻게 발전 할 것인지 생각해야합니다.
Falco

@Falco 프로젝트와 프로그래머 경험 모두에서이 모델의 장기적인 장점을 감독하고 있습니다. 가장 어렵다고 생각하는 주장은 실제로 해결할 수 없으며 단지 의견 일뿐입니다. 나에게 GUI 디자인은 훨씬 더 무섭다. 모든 진화 된 언어 (C ++, Java)는 매우 명확한 멀티 스레딩 모델을 가지고 있습니다. 확실하지 않으면 초보자 멀티 스레딩 버그로 고통받지 않는 액터 모델을 사용할 수 있습니다. 대부분의 응용 프로그램이 내가 제안한대로 설계되는 이유가 있다는 것을 알고 있지만 추가로 논의 할 수 있습니다.
Tomáš Zato-복원 모니카

4

Space Invaders조차도 수십 개의 상호 작용 객체를 관리했습니다. 한 프레임의 HD H264 비디오를 디코딩하는 데는 수억 개의 산술 연산이 포함됩니다. 당신은이 많은 처리 능력이 가능합니다.

그것은 당신이 그것을 낭비하면 여전히 느리게 할 수 있다고 말했다. 충돌 테스트 횟수만큼 객체 수는 문제가 아닙니다. 서로 다른 객체에 대해 각 객체를 확인하는 간단한 방법은 필요한 계산 수를 제곱 합니다. 이러한 방식으로 1001 개의 물체에 대한 충돌 테스트는 백만 번의 비교가 필요합니다. 예를 들어 발사체가 서로 충돌하는지 확인하지 않는 경우가 종종 있습니다.


2
Space Invaders가 최고의 비교인지 확실하지 않습니다. 적을 죽일 때 속도가 느려지고 속도가 빨라지는 이유는 그런 방식으로 설계된 것이 아니라 하드웨어가 한 번에 많은 적의 렌더링을 처리 할 수 ​​없기 때문입니다. en.wikipedia.org/wiki/Space_Invaders#Hardware
Mike Kellogg

각 객체는 다음 초에 충돌 할 수있을 정도로 가까운 모든 객체의 목록을 유지하고, 1 초에 한 번 또는 방향이 바뀔 때마다 업데이트됩니까?
랜덤 832

모델링하는 대상에 따라 다릅니다. 공간 분할 솔루션은 또 다른 일반적인 접근 방식입니다. 세계를 영역으로 분할 (예 : 렌더링 목적으로 수행해야하는 BSP 또는 쿼드 트리) 한 다음 동일한 영역의 객체와 만 충돌 할 수 있습니다.
pjc50

3

나는 여기에 다른 답변들 중 일부에 동의하지 않을 것입니다. 별도의 로직 스레드는 좋은 아이디어 일뿐만 아니라 로직을 쉽게 분리 할 수있는 경우 처리 속도에 큰 도움이됩니다 .

귀하의 질문은 논리를 추가 할 수 있다면 분리 할 수있는 논리의 좋은 예입니다. 예를 들어, 특정 공간 영역에 스레드를 잠 그거나 관련된 객체를 뮤텍스 처리하여 여러 적중 감지 스레드를 실행할 수 있습니다.

스케줄러를 멈출 가능성이 있기 때문에 가능한 모든 충돌에 대해 하나의 스레드를 원하지 않을 것입니다. 스레드 생성 및 삭제와 관련된 비용도 있습니다. 시스템 코어 주위에 스레드 수를 늘리거나 (또는 ​​이전과 같은 메트릭을 사용하는 #cores * 2 + 4) 프로세스가 완료되면 재사용하는 것이 좋습니다.

그러나 모든 논리를 쉽게 분리 할 수있는 것은 아닙니다. 때로는 작업이 모든 게임 데이터에 동시에 도달 할 수있어 스레딩을 사용할 수 없게됩니다 (스레딩 문제를 피하기 위해 검사를 추가해야하기 때문에 실제로는 유해합니다). 또한 여러 단계의 논리가 특정 순서로 발생하는 서로에 크게 의존하는 경우 순서 종속 결과를 제공하지 않도록 스레드 실행을 제어해야합니다. 그러나 스레드를 사용하지 않아도 문제가 해결되지 않고 스레드가 문제를 악화시킵니다.

대부분의 게임은 보통 게임 개발자가 처음에 병목 현상이 아닌 것을 처리하고자하는 것보다 더 복잡하기 때문에 단순히 그렇게하지 않습니다. 대부분의 게임은 CPU 제한이 아닌 GPU 제한적입니다. CPU 속도를 향상 시키면 전반적으로 도움이 될 수 있지만 일반적으로 초점이 아닙니다.

즉, 물리 엔진은 종종 여러 스레드를 사용하며, 여러 논리 스레드 (예 : HOI3와 같은 Paradox RTS 게임)에서 도움이 된 여러 게임의 이름을 지정할 수 있습니다.

나는, 당신은 아마이 구체적인 예에서 고용 스레드에 대한 필요가 없습니다 것이라고 다른 게시물에 동의 할 경우에도 이 도움이 될 수 있습니다. 다른 방법으로 최적화 할 수없는 과도한 CPU로드가있는 경우 스레딩을 예약해야합니다. 그것은 큰 사업이며 엔진의 기본 구조에 영향을 미칩니다. 사실 후에는 해결할 수있는 것이 아닙니다.


2

나는 다른 답변이 질문의 스레드 부분에 너무 집중하여 질문의 중요한 부분을 놓치고 있다고 생각합니다.

컴퓨터는 게임의 모든 개체를 한 번에 처리하지 않습니다. 순서대로 처리합니다.

컴퓨터 게임은 별개의 시간 단계로 진행됩니다. 게임 및 PC 속도에 따라이 단계는 일반적으로 초당 30 또는 60 단계 또는 PC가 계산할 수있는 / 몇 단계입니다.

하나의 이러한 단계에서, 컴퓨터는 그 단계 동안 각각의 게임 객체가 무엇을하는지 계산하고 그에 따라 하나씩 업데이트한다. 스레드를 사용하여 더 빠르게 병렬 처리를 수행 할 수도 있지만 조만간 속도가 문제가되지 않습니다.

평균 CPU는 2GHz 이상이어야하며 이는 초당 10 9 클럭 사이클 을 의미 합니다. 우리는 초당 60 시간 단계, 그 잎 10 계산할 경우 (9) / 60 클럭 사이클 = 16666666 클럭 사이클 시간 당 단계. 70 개의 장치를 사용하더라도 여전히 장치 당 약 2,400,000 개의 클록 사이클이 남아 있습니다. 최적화해야한다면 게임 로직의 복잡성에 따라 최소 240 주기로 각 유닛을 업데이트 할 수 있습니다. 보시다시피, 우리 컴퓨터는이 작업에 필요한 것보다 약 10,000 배 빠릅니다.


0

면책 조항 : 내가 좋아하는 게임 유형은 텍스트 기반이며 오래된 MUD의 오랜 프로그래머로 작성합니다.

나는 당신이 스스로에게 물어봐야 할 중요한 질문은 이것이라고 생각합니다. 심지어 스레드가 필요합니까? 그래픽 게임이 MT를 더 많이 사용한다는 것을 이해하지만 게임의 메커니즘에도 달려 있다고 생각합니다. (GPU, CPU 및 오늘날 우리가 보유한 다른 모든 리소스를 사용하면 리소스에 대한 우려가 사용자에게 보이는 것처럼 문제가 될 수 있습니다. 실제로 100 개의 객체는 거의 제로입니다). 또한 '한 번에 모든 문자'를 정의하는 방법에 따라 다릅니다. 당신은 정확히 동시에 의미합니까? 베드로가 합리적으로 지적했듯이 한 번에 모든 것이 문자적인 의미와 관련이 없다는 것을 알 수 없습니다. 이 방법으로 만 나타납니다.

스레드와 함께 갈 것이라고 가정하면 : 100 개의 스레드를 고려해서는 안됩니다 (그리고 CPU에 너무 많은지 여부에 대해서는 다루지 않을 것입니다. 나는 합병증과 실용성 만 참조합니다).

그러나 이것을 기억하십시오 : 멀티 스레딩은 쉽지 않으며 (필립이 지적한 것처럼) 많은 문제가 있습니다. 다른 사람들은 MT보다 훨씬 더 많은 경험을 가지고 있지만, 그들도 같은 것을 제안 할 것이라고 말할 것입니다.

어떤 사람들은 스레드가 유익하지 않다고 동의하지 않으며 어떤 개체는 각 객체에 스레드가 있어야한다고 주장합니다. 그러나 필립은 게임이 목록을 반복하는 경향이 있다고 지적하면서 (이것은 모든 텍스트이지만 두 개 이상의 스레드를 고려하더라도 각 객체에 대해 고려할 필요는 없습니다.) 그러나 너무 적은 객체에 대해서만 (아마도 그가 너무 적은 객체의 매개 변수에만 응답하고 있음을 알 수 있지만) 아닙니다. MUD에서 나는 우리에게 다음과 같은 것을 가지고있는 프로그래머입니다 (그리고 이것은 실시간으로 일어나는 모든 활동이 아니기 때문에 그것을 명심하십시오).

(인스턴스 수는 물론 높고 낮음)

모바일 (NPC, 즉 비 플레이어 캐릭터) : 2614; 프로토 타입 : 1360 개체 : 4457; 프로토 타입 : 2281 실 : 7983; 프로토 타입 : 7983. 각 객실에는 일반적으로 자체 인스턴스가 있지만 객실 내에 방을 말하는 동적 방도 있습니다. 또는 이동체 내부의 방, 예를 들어 용의 위; 또는 물체의 방 (예 : 마법의 물체를 입력). 이 동적 룸은 실제로 정의 된 오브젝트 / 룸 / 모바일마다 존재합니다. 그렇습니다. 이것은 월드 오브 워크래프트와 매우 비슷합니다. (게임을하지는 않지만 친구가 Windows 머신을 가지고있을 때 한동안 친구가 게임을했던 경우) 월드 오브 워크래프트가 존재하기 훨씬 전에 인스턴스를 제외하고는 인스턴스에 대한 아이디어를 얻었습니다.

스크립트 : 868 (현재) (이상하게도 통계 명령은 프로토 타입이 몇 개인 지 보여주지 않기 때문에 추가 할 것입니다). 이들 모두는 지역 / 지역에서 개최되며 103 개가 있습니다. 우리는 또한 다른 시간에 처리하는 특별한 절차를 가지고 있습니다. 다른 행사도 있습니다. 그런 다음 소켓도 연결했습니다. 모바일은 움직이며 다른 활동 (전투 이외)을하고 플레이어와 상호 작용하는 등의 일을합니다. 다른 유형의 엔티티도 마찬가지입니다.

지체없이이 모든 것을 어떻게 처리합니까?

  • 소켓 : select (), 큐 (입력, 출력, 이벤트, 기타 사항), 버퍼 (입력, 출력, 기타 사항) 등 이들은 초당 10 번 폴링됩니다.

  • 캐릭터, 물체, 방, 전투, 모든 것 : 모두 다른 펄스의 중앙 루프에 있습니다.

또한 (창업자 / 다른 프로그래머와 본인 간의 토론을 기반으로 한 구현)에는 광범위한 링크 목록 추적 및 포인터 유효성 테스트가 있으며 실제로 필요한 경우 충분한 무료 리소스가 있습니다. 이 모든 것 (세계를 확장 한 것을 제외하고)은 몇 년 전에 RAM, CPU 전력, 하드 디스크 공간 등이 적었을 때 존재했습니다. 실제로도 우리는 아무런 문제가 없었습니다. 설명 된 루프에서 (스크립트는 다른 것들과 마찬가지로 영역 재설정 / 다시 채우기와 같이) 몬스터, 객체 (항목) 및 기타 것들이 생성되고 해제되는 등의 일을합니다. 연결도 수락, 폴링 및 기타 기대할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.