Xử lý các thành phần mã nguồn gốc và mã nguồn gốc trong hệ thống thực thể dựa trên thành phần


11

Tôi hiện đang cố gắng thực hiện một hệ thống thực thể dựa trên thành phần, trong đó một thực thể về cơ bản chỉ là một ID và một số phương thức trợ giúp buộc một loạt các thành phần lại với nhau để tạo thành một đối tượng trò chơi. Một số mục tiêu bao gồm:

  1. Các thành phần chỉ chứa trạng thái (ví dụ: vị trí, sức khỏe, số lượng đạn) => logic đi vào "các hệ thống", xử lý các thành phần này và trạng thái của chúng (ví dụ: PhysSystem, RenderSystem, v.v.)
  2. Tôi muốn triển khai các thành phần và hệ thống cả trong C # thuần túy và thông qua kịch bản (Lua). Về cơ bản tôi muốn có thể định nghĩa các thành phần và hệ thống hoàn toàn mới trực tiếp trong Lua mà không phải biên dịch lại nguồn C # của tôi.

Bây giờ tôi đang tìm ý tưởng về cách xử lý vấn đề này một cách hiệu quả một cách nhất quán, vì vậy tôi không cần sử dụng các cú pháp khác nhau để truy cập các thành phần C # hoặc các thành phần Lua chẳng hạn.

Cách tiếp cận hiện tại của tôi sẽ là triển khai các thành phần C # bằng cách sử dụng các thuộc tính công khai, thông thường, có thể được trang trí bằng một số thuộc tính cho trình soạn thảo biết về các giá trị và công cụ mặc định. Sau đó, tôi có một lớp "ScriptComponent" lớp C #, nó chỉ bao bọc một bảng Lua bên trong với bảng này được tạo bởi một tập lệnh và giữ tất cả trạng thái của loại thành phần cụ thể đó. Tôi thực sự không muốn truy cập vào trạng thái đó nhiều từ phía C #, vì tôi không biết vào thời gian biên dịch, ScriptComponents với những thuộc tính nào sẽ có sẵn cho tôi. Tuy nhiên, trình chỉnh sửa sẽ cần truy cập vào đó, nhưng một giao diện đơn giản như sau sẽ đủ:

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

Điều này chỉ đơn giản là truy cập vào bảng Lua và thiết lập và truy xuất các thuộc tính đó từ Lua và nó cũng có thể dễ dàng được bao gồm trong các thành phần C # thuần túy (nhưng sau đó sử dụng các thuộc tính C # thông thường, thông qua sự phản chiếu hoặc một cái gì đó). Điều này sẽ chỉ được sử dụng trong trình chỉnh sửa, không phải bởi mã trò chơi thông thường, vì vậy hiệu suất không quan trọng ở đây. Nó sẽ khiến bạn cần phải tạo hoặc viết tay một số mô tả thành phần ghi lại các thuộc tính mà một loại thành phần nhất định thực sự cung cấp, nhưng đó sẽ không phải là một vấn đề lớn và có thể được tự động hóa hoàn toàn.

Tuy nhiên, làm thế nào để truy cập các thành phần từ phía Lua? Nếu tôi thực hiện một cuộc gọi đến một cái gì đó như getComponentsFromEntity(ENTITY_ID)có lẽ tôi sẽ nhận được một loạt các thành phần C # bản địa, bao gồm cả "ScriptComponent", dưới dạng userdata. Truy cập các giá trị từ bảng Lua được bao bọc sẽ dẫn đến việc tôi gọi GetProperty<T>(..)phương thức thay vì truy cập trực tiếp các thuộc tính, như với các thành phần C # khác.

Có thể viết một getComponentsFromEntity()phương thức đặc biệt chỉ được gọi từ Lua, trả về tất cả các thành phần C # gốc là userdata, ngoại trừ "ScriptComponent", thay vào đó, nó sẽ trả về bảng được bọc. Nhưng sẽ có các phương thức liên quan đến thành phần khác và tôi thực sự không muốn sao chép tất cả các phương thức này để được gọi từ mã C # hoặc từ tập lệnh Lua.

Mục tiêu cuối cùng sẽ là xử lý tất cả các loại thành phần giống nhau, không có cú pháp trường hợp đặc biệt nào khác biệt giữa các thành phần gốc và các thành phần Lua - đặc biệt là từ phía Lua. Ví dụ: tôi muốn có thể viết một kịch bản Lua như thế:

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

nativeComponent.NativeProperty = 5
scriptComponent.ScriptedProperty = 3

Kịch bản không nên quan tâm loại thành phần nào thực sự có và tôi muốn sử dụng các phương thức tương tự mà tôi sử dụng từ phía C # để truy xuất, thêm hoặc xóa thành phần.

Có lẽ có một số triển khai mẫu tích hợp kịch bản với các hệ thống thực thể như vậy?


1
Bạn đang bị mắc kẹt khi sử dụng Lua? Tôi đã thực hiện những điều tương tự kịch bản một ứng dụng C # với các ngôn ngữ CLR khác được phân tích cú pháp khi chạy (Boo, trong trường hợp của tôi). Vì bạn đang chạy mã cấp cao trong môi trường được quản lý và tất cả đều là IL, nên dễ dàng phân lớp các lớp hiện có từ phía "tập lệnh" và chuyển các thể hiện của các lớp đó trở lại ứng dụng máy chủ. Trong trường hợp của tôi, tôi thậm chí sẽ lưu trữ một tập hợp các tập lệnh được biên dịch để tăng tốc độ tải và chỉ xây dựng lại khi tập lệnh thay đổi.
justinian

Không, tôi không bị mắc kẹt khi sử dụng Lua. Cá nhân tôi rất thích sử dụng nó vì tính đơn giản, kích thước nhỏ, tốc độ và mức độ phổ biến của nó (vì vậy khả năng mọi người đã quen thuộc với nó có vẻ cao hơn), nhưng tôi mở cho các lựa chọn thay thế.
Mario

Tôi có thể hỏi tại sao bạn muốn có khả năng định nghĩa bằng nhau giữa C # và môi trường tập lệnh của bạn không? Thiết kế bình thường là định nghĩa thành phần trong C # và sau đó là 'lắp ráp đối tượng' bằng ngôn ngữ kịch bản. Tôi đang tự hỏi vấn đề gì đã phát sinh rằng đây là giải pháp cho?
James

1
Mục tiêu là làm cho hệ thống thành phần có thể mở rộng từ bên ngoài mã nguồn C #. Không chỉ thông qua việc thiết lập các giá trị thuộc tính trong các tệp XML hoặc tập lệnh, mà bằng cách xác định toàn bộ các thành phần mới với toàn bộ các thuộc tính mới và các hệ thống mới xử lý chúng. Điều này phần lớn lấy cảm hứng từ các mô tả của Scott Bilas về hệ thống đối tượng trong Dungeon Siege, nơi họ có các thành phần C ++ "bản địa" cũng như "GoSkritComponent", bản thân nó chỉ là một trình bao bọc cho một kịch bản: scottbilas.com/games/dungeon -Siege
Mario

Coi chừng rơi vào bẫy xây dựng giao diện tập lệnh hoặc plugin phức tạp đến mức nó tiếp cận việc viết lại công cụ gốc (C # hoặc Visual Studio trong trường hợp này).
3Dave

Câu trả lời:


6

Một hệ quả của câu trả lời của FxIII là bạn nên thiết kế mọi thứ (có thể sửa đổi được) bằng ngôn ngữ kịch bản trước (hoặc ít nhất là một phần rất hợp lý của nó) để đảm bảo rằng logic tích hợp của bạn thực sự cung cấp cho việc sửa đổi. Khi bạn chắc chắn rằng tích hợp kịch bản của bạn đủ linh hoạt, hãy viết lại các bit cần thiết trong C #.

Cá nhân tôi ghét dynamictính năng này trong C # 4.0 (tôi là một người nghiện ngôn ngữ tĩnh) - nhưng đây chắc chắn là một kịch bản nên sử dụng nó và là nơi nó thực sự tỏa sáng. Các thành phần C # của bạn chỉ đơn giản là các đối tượng hành vi mạnh / mở rộng .

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.

Các thành phần Lua của bạn sẽ hoàn toàn năng động (chính bài viết trên sẽ cung cấp cho bạn ý tưởng về cách thực hiện việc này). Ví dụ:

// 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.
}

Bây giờ vì bạn đang sử dụng dynamicnên bạn có thể sử dụng các đối tượng Lua như thể chúng là các lớp thực trong C #.

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

Tôi hoàn toàn đồng ý với đoạn đầu tiên, tôi thường làm công việc của mình theo cách này. Viết mã bạn biết bạn có thể phải thực hiện lại bằng ngôn ngữ cấp thấp hơn, giống như vay tiền BIẾT rằng bạn sẽ phải trả tiền lãi. Các nhà thiết kế CNTT thường nhận các khoản vay: điều này tốt khi họ biết rằng họ đã làm điều đó và họ kiểm soát các khoản nợ của mình.
FxIII

2

Tôi muốn làm điều ngược lại: viết tất cả bằng cách sử dụng một ngôn ngữ động và sau đó theo dõi các nút thắt (nếu có). Khi bạn tìm thấy một thứ bạn có thể chọn lọc lại các chức năng liên quan bằng cách sử dụng C # hoặc (đúng hơn) C / C ++.

Tôi nói với bạn điều này chủ yếu bởi vì những gì đang cố gắng làm là giới hạn tính linh hoạt của hệ thống của bạn trong phần C #; khi hệ thống trở nên phức tạp, "công cụ" C # của bạn sẽ bắt đầu trông giống như một trình thông dịch động, có thể không phải là trình thông dịch tốt nhất. Câu hỏi là: bạn có sẵn sàng đầu tư hầu hết thời gian của mình vào việc viết một công cụ C # chung chung hoặc để mở rộng trò chơi của bạn không?

Nếu mục tiêu của bạn là mục tiêu thứ hai, như tôi tin, có lẽ bạn sẽ sử dụng thời gian tập trung tốt nhất vào cơ chế trò chơi của mình, để cho một trình thông dịch dày dạn chạy mã động.


Vâng, vẫn còn nỗi sợ mơ hồ về hiệu suất kém đối với một số hệ thống cốt lõi, nếu tôi sẽ làm mọi thứ thông qua kịch bản. Trong trường hợp đó, tôi phải chuyển chức năng đó trở lại C # (hoặc bất cứ điều gì) ... vì vậy dù sao tôi cũng cần một cách tốt để giao tiếp với hệ thống thành phần từ phía C #. Đó là vấn đề cốt lõi ở đây: tạo ra một hệ thống thành phần tôi có thể sử dụng tốt như nhau từ cả C # và tập lệnh.
Mario

Tôi nghĩ rằng C # được sử dụng như một loại môi trường "tăng tốc giống như kịch bản" cho những thứ như C ++ hoặc C? Dù sao, nếu bạn không chắc chắn ngôn ngữ nào bạn sẽ kết thúc, hãy bắt đầu thử viết một số logic bằng Lua và C #. Tôi cá là cuối cùng bạn sẽ nhanh hơn trong C #, vì các tính năng sửa lỗi và công cụ chỉnh sửa nâng cao.
Imi

4
+1 Tôi đồng ý với điều này vì một lý do khác - nếu bạn muốn trò chơi của mình có thể mở rộng, bạn nên ăn thức ăn cho chó của riêng mình: bạn có thể chỉ tích hợp một công cụ kịch bản để tìm cộng đồng mod tiềm năng của mình thực sự không thể làm gì với nó
Jonathan Dickinson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.