컴포넌트 기반 엔터티 시스템에서 스크립트 및 "네이티브"컴포넌트 처리


11

현재 구성 요소 기반 엔터티 시스템을 구현하려고합니다. 엔터티는 기본적으로 단지 ID이며 여러 구성 요소를 묶어 게임 객체를 형성하는 도우미 메서드입니다. 그 목표는 다음과 같습니다.

  1. 컴포넌트에는 상태 만 포함됩니다 (예 : 위치, 상태, 탄약 수) => 로직은 "시스템"으로 들어가고 이러한 컴포넌트와 해당 상태 (예 : PhysicsSystem, RenderSystem 등)를 처리합니다.
  2. 순수한 C #과 스크립팅 (Lua)을 통해 구성 요소와 시스템을 구현하고 싶습니다. 기본적으로 C # 소스를 다시 컴파일하지 않고도 Lua에서 완전히 새로운 구성 요소와 시스템을 직접 정의 할 수 있기를 원합니다.

이제 효율적이고 일관되게 처리하는 방법에 대한 아이디어를 찾고 있으므로 C # 구성 요소 또는 Lua 구성 요소에 액세스하기 위해 다른 구문을 사용할 필요가 없습니다.

현재 접근 방식은 일반 공개 속성을 사용하여 C # 구성 요소를 구현하는 것입니다. 아마도 편집기에 기본값과 내용을 알려주는 몇 가지 특성이 있습니다. 그런 다음 C # 클래스 "ScriptComponent"를 사용합니다.이 스크립트는 스크립트에 의해 생성되고 해당 특정 구성 요소 유형의 모든 상태를 유지하는이 테이블로 Lua 테이블을 내부적으로 래핑합니다. 컴파일 타임에 알 수 없으므로 C # 측면에서 그 상태에 많이 액세스하고 싶지 않습니다. 어떤 속성을 사용할 수있는 ScriptComponents가 있습니까? 그래도 에디터는 액세스해야하지만 다음과 같은 간단한 인터페이스로 충분합니다.

public ScriptComponent : IComponent
{
    public T GetProperty<T>(string propertyName) {..}
    public void SetProperty<T>(string propertyName, T value) {..}
}

Lua 테이블에 액세스하여 Lua에서 해당 속성을 설정 및 검색하면 순수 C # 구성 요소에도 쉽게 포함될 수 있습니다 (그러나 리플렉션 등을 통해 일반 C # 속성 사용). 일반 게임 코드가 아닌 에디터에서만 사용되므로 성능은 그다지 중요하지 않습니다. 특정 구성 요소 유형이 실제로 제공하는 특성을 문서화하는 일부 구성 요소 설명을 생성하거나 필기해야하지만 큰 문제는 아니며 충분히 자동화 될 수 있습니다.

그러나 Lua 쪽에서 구성 요소에 액세스하는 방법은 무엇입니까? 비슷한 getComponentsFromEntity(ENTITY_ID)것을 호출하면 아마도 "ScriptComponent"를 포함하여 많은 네이티브 C # 구성 요소를 userdata로 얻을 것입니다. 래핑 된 Lua 테이블에서 값 GetProperty<T>(..)에 액세스하면 다른 C # 구성 요소와 마찬가지로 속성에 직접 액세스하는 대신 메서드를 호출하게 됩니다.

getComponentsFromEntity()랩어 된 테이블을 대신 반환하는 "ScriptComponent"를 제외한 모든 네이티브 C # 구성 요소를 userdata로 반환하는 Lua에서만 호출 할 특수 메서드를 작성할 수도 있습니다. 그러나 다른 구성 요소 관련 메서드가있을 것이고 실제로 C # 코드 또는 Lua 스크립트에서 호출하기 위해 이러한 모든 메서드를 복제하고 싶지 않습니다.

궁극적 인 목표는 모든 유형의 구성 요소를 동일하게 처리하는 것입니다. 기본 구성 요소와 Lua 구성 요소, 특히 Lua 측면과 차별화되는 특별한 구문은 없습니다. 예를 들어 Lua 스크립트를 다음과 같이 작성할 수 있습니다.

entity = getEntity(1);
nativeComponent = getComponent(entity, "SomeNativeComponent")
scriptComponent = getComponent(entity, "SomeScriptComponent")

nativeComponent.NativeProperty = 5
scriptComponent.ScriptedProperty = 3

스크립트는 실제로 어떤 종류의 구성 요소를 가져도 상관 없으며 C # 측에서 사용하는 것과 동일한 방법을 사용하여 구성 요소를 검색, 추가 또는 제거하고 싶습니다.

스크립팅을 이와 같은 엔터티 시스템과 통합하는 샘플 구현이 있습니까?


1
루아를 계속 사용하고 있습니까? 런타임에 구문 분석되는 다른 CLR 언어로 C # 응용 프로그램을 스크립팅하는 비슷한 작업을 수행했습니다 (Boo, 내 경우). 이미 관리되는 환경에서 높은 수준의 코드를 실행하고 있으며 모든 것이 IL 아래에 있기 때문에 "스크립팅"측면에서 기존 클래스를 서브 클래 싱하고 해당 클래스의 인스턴스를 호스트 응용 프로그램으로 다시 전달하는 것은 쉽습니다. 필자의 경우 로딩 속도를 높이기 위해 컴파일 된 스크립트 어셈블리를 캐시하고 스크립트가 변경되면 다시 작성합니다.
저스틴

아니요, Lua를 사용하지 않습니다. 개인적으로 나는 그것의 단순성, 작은 크기, 속도 및 인기 때문에 사용하고 싶습니다.
마리오

C #과 스크립트 환경간에 동일한 정의 기능을 원하는 이유를 물어볼 수 있습니까? 일반적인 디자인은 C #에서 구성 요소를 정의한 다음 스크립팅 언어에서 '개체 어셈블리'입니다. 이것이 어떤 해결책으로 해결되었는지 궁금합니다.
제임스

1
목표는 구성 요소 시스템을 C # 소스 코드 외부에서 확장 할 수있게하는 것입니다. XML 또는 스크립트 파일에서 속성 값을 설정하는 것뿐만 아니라 완전히 새로운 속성과이를 처리하는 새로운 시스템으로 완전히 새로운 구성 요소를 정의합니다. 이것은 주로 그들이 잘 자체 스크립트 단지 래퍼 인 "GoSkritComponent"등으로 "기본"C ++ 구성 요소를 가지고 던전 시즈에있는 객체 시스템의 스콧 Bilas '설명에서 영감 : scottbilas.com/games/dungeon를 -siege
마리오

스크립팅 또는 플러그인 인터페이스를 너무 복잡하게 작성하여 원래 도구 (이 경우 C # 또는 Visual Studio)를 다시 작성하기에 너무 복잡합니다.
3Dave

답변:


6

FxIII의 답변에 대한 결론은 통합 로직이 실제로 모딩을 제공 할 수 있도록 스크립팅 언어로 모든 것을 (수정 가능할 것임) 먼저 디자인해야한다는 것 입니다. 스크립팅 통합이 다재다능하다고 확신 할 경우 C #에서 필요한 비트를 다시 작성하십시오.

나는 개인적 으로 C # 4.0 (정적 언어 중독자) 의 dynamic기능 을 싫어 하지만 이것은 반드시 사용해야하는 시나리오이며 실제로 빛나는 곳입니다. C # 구성 요소는 단순히 강력 / 확장 동작 객체 입니다.

public class Villian : ExpandoComponent
{
    public void Sound() { Console.WriteLine("Cackle!"); }
}

//...

dynamic villian = new Villian();
villian.Position = new Vector2(10, 10); // Add a property.
villian.Sound(); // Use a method that was defined in a strong context.

Lua 구성 요소는 완전히 동적입니다 (위의 동일한 기사에서이를 구현하는 방법에 대한 아이디어를 제공해야 함). 예를 들면 다음과 같습니다.

// LuaSharp is my weapon of choice.
public class LuaObject : DynamicObject
{
    private LuaTable _table;

    public LuaObject(LuaTable table)
    {
        _table = table;
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        var methodName = binder.Name;
        var function = (LuaFunction)_table[methodName];
        if (function == null)
        {
            return base.TryInvokeMember(binder, args, out result);
        }
        else
        {
            var resultArray = function.Call(args);
            if (resultArray == null)
                result = null;
            else if (resultArray.Length == 1)
                result = resultArray[0];
            else
                result = resultArray;
            return true;
        }
    }

    // Other methods for properties etc.
}

이제는 사용하기 때문에 dynamicC #에서 실제 클래스 인 것처럼 Lua 객체를 사용할 수 있습니다.

dynamic cSharpVillian = new Villian();
dynamic luaVillian = new LuaObject(_script["teh", "villian"]);
cSharpVillian.Sound();
luaVillian.Sound(); // This will call into the Lua function.

나는 첫 번째 단락에 전적으로 동의합니다. 나는 종종 이런 식으로 일을합니다. 저수준 언어로 다시 구현해야 할 수도있는 코드를 작성하는 것은이자를 지불해야한다는 대출을받는 것과 같습니다. IT 디자이너는 종종 대출을받습니다. 이는 그들이 해냈다는 사실을 알고 부채를 계속 통제 할 때 좋습니다.
FxIII

2

오히려 반대를하고 싶습니다. 동적 언어를 사용하여 모든 것을 작성한 다음 병이 있으면 추적하십시오 (있는 경우). 하나를 찾으면 C # 또는 (대신) C / C ++를 사용하여 관련된 기능을 선택적으로 다시 구현할 수 있습니다.

나는 주로 C # 부분에서 시스템의 유연성을 제한하기 위해 노력하고 있기 때문에 이것을 설명합니다. 시스템이 복잡해지면 C # "엔진"이 역동적 인 인터프리터처럼 보이기 시작합니다. 문제는 일반적인 C # 엔진을 작성하거나 게임을 확장하는 데 대부분의 시간을 투자 할 의향이 있습니까?

내가 믿는 것처럼 목표가 두 번째 목표라면 시간을 게임 역학에 가장 집중하여 노련한 통역사가 동적 코드를 실행할 수 있도록 할 것입니다.


그래도 스크립팅을 통해 모든 작업을 수행 할 경우 일부 핵심 시스템의 성능이 저하 될 우려가 여전히 모호합니다. 이 경우 해당 기능을 C # (또는 무엇이든)으로 다시 이동해야합니다. 그래서 어쨌든 C # 측에서 구성 요소 시스템과 인터페이스하는 좋은 방법이 필요합니다. 이것이 핵심 문제입니다. 컴포넌트 시스템 만들기 C #과 스크립트에서 동등하게 사용할 수 있습니다.
마리오

C # 은 C ++이나 C 같은 것들을위한 일종의 "가속화 된 스크립팅 같은"환경으로 사용 된다고 생각 했습니까? 어쨌든 어떤 언어로 끝날지 확실하지 않으면 Lua와 C #으로 논리를 작성하십시오. 결국 고급 편집기 툴링 및 디버깅 기능으로 인해 C #에서 더 빨리 끝날 것입니다.
Imi

4
+1 다른 이유로이 점에 동의합니다. 게임을 확장하려면 개밥을 먹어야합니다. 잠재적 인 모딩 커뮤니티가 실제로 아무것도 만들 수없는 것을 찾기 위해 스크립트 엔진을 통합 할 수도 있습니다. 그것.
Jonathan Dickinson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.