2010-03-03 2 views
3

제목에 대해 죄송합니다. 문제를 설명하는 더 좋은 방법을 생각할 수 없었습니다. 기본적으로 게임에서 충돌 시스템을 구현하려고합니다. 특정 유형으로 형변환 될 수있는 두 객체 (임의의 순서로 주어진)의 충돌을 처리하는 "충돌 처리기"를 등록 할 수 있기를 원합니다. 따라서 Player : Ship : Entity과 및 (Ship, Particle)(Laser, Entity)의 핸들러가 (Laser, Player)의 충돌보다 등록되어 있으면 두 핸들러에 올바른 순서로 인수를 알리고 (Laser, Laser)의 충돌로 인해 두 번째 처리기에만 알릴 수 있습니다.C#에서 다중 발송 통지 알고리즘 최적화?

는 코드는 그래서 여기에 내가 (naieve 방법) 지금 잘하고있어 무엇을, 천 단어를 말한다 :

public IObservable<Collision<T1, T2>> onCollisionsOf<T1, T2>() 
     where T1 : Entity 
     where T2 : Entity 
    { 
     Type t1 = typeof(T1); 
     Type t2 = typeof(T2); 
     Subject<Collision<T1, T2>> obs = new Subject<Collision<T1, T2>>(); 
     _onCollisionInternal += delegate(Entity obj1, Entity obj2) 
     { 
      if (t1.IsAssignableFrom(obj1.GetType()) && t2.IsAssignableFrom(obj2.GetType())) 
       obs.OnNext(new Collision<T1, T2>((T1) obj1, (T2) obj2)); 
      else if (t1.IsAssignableFrom(obj2.GetType()) && t2.IsAssignableFrom(obj1.GetType())) 
       obs.OnNext(new Collision<T1, T2>((T1) obj2, (T2) obj1)); 
     }; 
     return obs; 
    } 

그러나,이 방법은 (측정 매우 느린, 나는 실행 후 ~ 2 FPS를 잃었다 이), 그래서 나는 몇 사이클/할당을 면도하는 방법을 찾고 있어요.

나는 해시 코드에 기초한 형식으로 유형을 넣은 다음 사전에 넣는 방식으로 생각하고 (그런 다음 구현하는 데 시간을 들여 바보 같은 벽에 내 머리를 찔렀다.), 각 엔트리는 핸들러가 인수의 순서를 바꿔야하는지 여부를 부울 (boolean) 표시와 함께 유형의 쌍에 대한 핸들러의 링크 된 목록입니다. 유감스럽게도 파생 된 유형이 전달 된 경우 구독자에게 기본 유형을 알리지 않으므로 파생 된 유형에 대해서는 작동하지 않습니다. 누구든지 모든 유형 쌍 (두 번)을 확인하는 것보다 더 나은 방법을 생각해 볼 수 있습니까?

감사합니다, 로버트

+1

'당신이 두 핸들러 알림을 원하는 경우 모두 핸들러가 올바른 order'의 인수를 통지해야한다, 당신은 모두 핸들러를 확인해야 그래서 다른 것들을 바꾸지 않고 "두배"의 요구 사항을 제거 할 수는 없습니다. 어쨌든 코드가이 요구 사항을 만족시키는 것 같지 않습니다 ...? – Tanzelax

+0

@Tanzelax - 각 처리기에 대해 OnCollisionsOf 메서드를 한 번 호출하면 실제로 (이 시스템에서) 각 처리기에 알림이 전송됩니다 (두 명의 대리자가 추가되므로). –

답변

3

모든 반사가 빠르지 않을 것입니다. 충돌이 발생할 때마다 어떻게 반사되는지 확인하십시오. 그것이 문제이다.

몇 가지 생각.

생각 번호 1 : 방문자 패턴.

OO 언어에서 합리적으로 빠른 이중 가상 디스패치를 ​​구현하는 표준 방법은 방문자 패턴을 구현하는 것입니다.

vistior의 각 수락자가 "이 상황에서 할 일"의 목록을 유지하는 방문자 패턴을 구현할 수 있습니까? 그런 다음 adder 메서드는 새로운 "할 일"을 작성할 올바른 위치를 식별 한 다음 위임을 추가합니다. 충돌이 발생하면 방문객이 이중 발송을하고, 수행 할 위임자를 찾아 호출합니다.

두 번 이상 발송해야합니까? 효율적인 다중 가상 디스패치는 가능하지만 정확하지는 않습니다.

사상 번호 2 : 다이나믹 디스패치

C# 4는 동적 디스패치있다. 그것이 작동하는 방식은 콜 사이트를 처음으로 분석하여 콜 사이트를 분석 할 때 반영을 사용하는 것입니다. 그런 다음 새로운 IL을 동적으로 생성하여 호출을 실행하고 IL을 캐시합니다. 두 번째 호출에서는 이전과 완전히 동일한 유형인지 여부를 확인합니다. 그럴 경우 기존 IL을 다시 사용하고 호출합니다. 그렇지 않은 경우 분석을 다시 수행합니다. 인수가 일반적으로 몇 가지 유형 만있는 경우 캐시는 매우 빠르게 히트 및 누락이 시작되고 성능은 실제로 모든 것이 고려되는 좋은 것입니다. 매번 많은 성찰보다 빠릅니다. 매번 우리가하는 유일한 반영은 인수의 런타임 유형 분석입니다.

생각 세 번째 : 구현 자신의 동적 파견 DLR에가하고있는 일에 대해 마법 거기에 아무것도

. 그것은 한 번 분석을하고, 일리노이를 뿌리고 결과를 캐시합니다. 나는 매번 분석을 다시하고 있기 때문에 당신의 고통이 일어나고 있다고 생각합니다.

+0

동적 인 디스패치 같은 시스템을 롤업하기로 결정했습니다 (런타임 IL은 생성되지 않지만 어쨌든 훨씬 빠릅니다). 감사! –

1

Entity는 엔티티 유형을 식별하고 방금 그 속성 값을 가져 속성을 가지고있는 경우, 즉 빨리되지 않을 것? 레이저 항상 등, 플레이어 전에 될 수 있도록 당신이 당신의 처리기에서 개체의 순서에 대한 규칙이 있다면 다음

귀하의 개체 유형은 및 열거하고 열거 순서는 일 수 있었다 당신의 핸들러 객체 순서.

public IObservable<Collision<T1, T2>> onCollisionsOf<T1, T2>() 
    where T1 : Entity 
    where T2 : Entity 
{ 
    EntityTypeEnum t1 = T1.EntityType; 
    EntityTypeEnum t2 = T2.EntityType; 

    Subject<Collision<T1, T2>> obs = new Subject<Collision<T1, T2>>(); 
    _onCollisionInternal += delegate(Entity obj1, Entity obj2) 
    { 
     if (t1 < t2) 
      obs.OnNext(new Collision<T1, T2>((T1) obj1, (T2) obj2)); 
     else 
      obs.OnNext(new Collision<T1, T2>((T1) obj2, (T2) obj1)); 
    }; 
    return obs; 
} 
+0

이것은 디스패치 문제를 전혀 해결하지 못하는 것 같습니다. 형식에 대한 엄격한 순서 지정 만 제공하십시오 (이미 obj.GetType(). GetHashCode() 사용). 또한 기본 유형 객체의 충돌에 대한 등록을 허용하지 않습니다. –

0

나는 레이저/플레이어와 레이저/레이저의 충돌이 2 세트 있다고 가정하고 있습니다. 당신이 기꺼이 IOCservable < Collision < T1, T2 >>를 그 두 가지 경우와 일치 시키려면, 위임을 단 한 번만 줄이고 비교를 위해 모든 것을 강하게 입력 할 수 있습니다. (당신이 어떤 전혀 어쨌든 확인하고있는 경우)

_onCollisionInternal += delegate(T1 obj1, T2 obj2) { 
    obs.OnNext(new Collision<T1, T2>(obj1, obj2)); 
}; 


public IObservable<Collision<T1, T2>> onCollisionsOf<T1, T2>() 
     where T1 : Entity 
     where T2 : Entity 
    { 
     Subject<Collision<T1, T2>> obs = new Subject<Collision<T1, T2>>(); 
     _onCollisionInternal += delegate(T1 obj1, T2 obj2) { 
      obs.OnNext(new Collision<T1, T2>(obj1, obj2)); 
     }; 
     return obs; 
    } 

Observable<Collision<Laser, Player>> lp = onCollisionsOf<Laser, Player>(); 
Observable<Collision<Laser, Laser>> ll = onCollisionsOf<Laser, Laser>(); 
+0

아니요, 더 많은 충돌 유형이 있습니다. 나는 일반화 된 것을 찾고 있는데 AFAICT는 주문 독립 적이 지 않지만 충돌 시스템은 주문 보증을하지 않는다. –