Tôi nên sử dụng kỹ thuật nào để tạo điều kiện giao tiếp giữa XNA GameComponents (hoặc giữa các thành phần thuộc bất kỳ loại nào trong trò chơi)?


9

Tôi đang bắt đầu dự án trò chơi 'phù hợp' đầu tiên của mình và chắc chắn tôi đã gặp phải một khối cố gắng quyết định cách các thành phần trò chơi trong XNA nên giao tiếp.

Từ các sự kiện lập trình GUI (Java) trước đây, trình xử lý và trình nghe dường như là con đường phía trước. Vì vậy, tôi có một số loại xe buýt sự kiện chấp nhận đăng ký sự kiện và các lớp đã đăng ký vào các sự kiện đó, với các trình xử lý để đối phó với chúng. Ví dụ (mã giả):

class SpriteManager
    Update(){
        if(player.collidesWith(enemy)
             // create new 'PlayerCollisionEvent'
    }

class HUDManager
    onPlayerCollisionEvent(){
        // Update the HUD (reduce lives etc)
    }

Tuy nhiên, tôi không chắc chắn về thiết lập mã (trong C #) sẽ được yêu cầu để thực hiện đầy đủ điều này. Điều gì theo dõi các sự kiện (một số loại xe buýt?), Và nó được cấu trúc như thế nào?

Dường như cũng có rất nhiều đề cập về Dịch vụ trò chơi, theo đó bạn có thể đăng ký GameComponent trong lớp Game.cs chính của mình, sau đó tìm nạp nó từ bất kỳ đâu trong mã của bạn có tham chiếu đến đối tượng 'Trò chơi' chính. Tôi đã thử điều này với đối tượng SpriteBatch của tôi và nó có vẻ rất dễ dàng .. tuy nhiên, tôi không thể thấy điều này linh hoạt như một mô hình sự kiện.

Lấy ví dụ khi kẻ thù chết. Chúng tôi muốn cập nhật điểm số trò chơi. Sử dụng các dịch vụ tôi có thể có được một tham chiếu đến đối tượng StateManager của mình được tạo trong Game1 và được thêm dưới dạng dịch vụ, sau đó đặt 'điểm' thành giá trị mới. Tôi nghĩ rằng một sự kiện 'onEnemyDeath', có thể được xử lý khác nhau bởi vô số các lớp, nhưng được khởi tạo bởi 1 dòng mã trong phần 'phát hiện tử vong kẻ thù' có liên quan, sẽ tốt hơn so với việc chọn từng GameComponent được yêu cầu phương pháp được yêu cầu.

Hay là những chiến lược thấp kém hơn một cái gì khác?

Tôi nhận ra đây là một phần kiến ​​thức C # kém của tôi cũng giống như mô hình giao tiếp trò chơi, nhưng tôi thực sự muốn có được điều cơ bản này ngay.

Cập nhật

Nhìn vào Dịch vụ chi tiết hơn tôi thấy ít thuyết phục hơn - về cơ bản nó đang chuyển một biến toàn cầu (từ những gì tôi hiểu).

Cập nhật 2

Đã xem hướng dẫn cơ bản này về xử lý sự kiện và kiểm tra mã mẫu, có vẻ như các sự kiện sẽ là một lựa chọn hợp lý cho những gì tôi đang thảo luận. Nhưng tôi không thể sử dụng nó nhiều trong các mẫu tôi đã thấy. Có một số lý do rõ ràng tại sao một người không nên?


Tôi khuyên bạn nên thử FlatRedBall trước. Nó nằm trên XNA và làm cho cuộc sống thực sự dễ dàng.
tro999

3
Tôi muốn thực sự hiểu những điều cơ bản của những gì đang diễn ra trước khi nhảy vào một động cơ.
mã hóa

Tôi nghĩ rằng thất bại của bạn ở đây thực sự là thiếu thông tin về C #. C # sử dụng các sự kiện để tạo điều kiện giao tiếp giữa các lớp thường. Bạn thực sự tùy thuộc vào cách thực hiện - XNA cung cấp lớp SpriteBatch và hầu hết các công việc đều tùy thuộc vào bạn để viết. Một động cơ sẽ cho bạn một ý tưởng vững chắc về cách mọi thứ hoạt động ở mức cao hơn trước khi đi sâu vào chi tiết.
tro999

1
Tôi đồng ý ở một mức độ nào đó, nhưng từ tôi đã đọc hầu hết các giao tiếp giữa các lớp giữa GameComponents có thể được thực hiện bằng Dịch vụ. Tôi đã quen sử dụng các sự kiện. Tôi không chắc chắn cách nào là tốt nhất hoặc nếu có các lựa chọn thay thế hợp lệ (singletons, các lớp tĩnh giả dạng toàn cầu như 2 phương thức khác tôi đã bỏ qua)
mã hóa vào

Câu trả lời:


4

Từ các sự kiện lập trình GUI (Java) trước đây, trình xử lý và trình nghe dường như là con đường phía trước. Vì vậy, tôi có một số loại xe buýt sự kiện chấp nhận đăng ký sự kiện và các lớp đã đăng ký vào các sự kiện đó, với các trình xử lý để đối phó với chúng.

Lý do bạn sẽ không tìm thấy nhiều về xe buýt sự kiện trong C # là vì tôi không nghĩ bất kỳ ai ngoài Java gọi đó là "xe buýt", theo kinh nghiệm của tôi. Các thuật ngữ phổ biến hơn có thể là hàng đợi tin nhắn, trình quản lý sự kiện, tín hiệu / vị trí, xuất bản / đăng ký, v.v.

Bạn không cần bất kỳ thứ gì để tạo ra một trò chơi hoạt động, nhưng nếu đó là loại hệ thống mà bạn cảm thấy thoải mái, thì nó cũng sẽ phục vụ bạn tốt ở đây. Thật không may, không ai có thể cho bạn biết chính xác làm thế nào để tạo ra một vì mọi người cuộn chúng một chút khác nhau, nếu họ thậm chí sử dụng chúng. (Tôi không, ví dụ.) Bạn có thể bắt đầu với một System.Collections.Generic.List<Event>hàng đợi đơn giản , với các sự kiện khác nhau của bạn là các lớp sự kiện và danh sách người đăng ký cho từng loại sự kiện. Đối với mỗi sự kiện trong hàng đợi, hãy lấy danh sách người đăng ký và đối với mỗi người đăng ký, hãy gọi handle(this_event)cho nó. Sau đó loại bỏ nó khỏi hàng đợi. Nói lại.

Dường như cũng có rất nhiều đề cập về Dịch vụ trò chơi, theo đó bạn có thể đăng ký GameComponent trong lớp Game.cs chính của mình, sau đó tìm nạp nó từ bất kỳ đâu trong mã của bạn có tham chiếu đến đối tượng 'Trò chơi' chính. Tôi đã thử điều này với đối tượng SpriteBatch của tôi và nó có vẻ rất dễ dàng .. tuy nhiên, tôi không thể thấy điều này linh hoạt như một mô hình sự kiện.

Nó có thể không linh hoạt, nhưng dễ gỡ lỗi hơn. Các sự kiện và tin nhắn rất phức tạp vì chúng tách rời chức năng gọi khỏi chức năng được gọi, điều đó có nghĩa là ngăn xếp cuộc gọi của bạn không hữu ích lắm khi gỡ lỗi, các hành động trung gian có thể khiến một cái gì đó bị hỏng, thông thường có thể thất bại khi không kết nối đúng cách , và như thế. Phương pháp rõ ràng là "lấy một thành phần và gọi những gì bạn cần trên nó" hoạt động tốt khi bắt lỗi sớm và có mã rõ ràng và rõ ràng. Nó chỉ có xu hướng dẫn đến mã được liên kết chặt chẽ và rất nhiều phụ thuộc phức tạp.

Tôi nhận ra đây là một phần kiến ​​thức C # kém của tôi cũng giống như mô hình giao tiếp trò chơi, nhưng tôi thực sự muốn có được điều cơ bản này ngay.

C # là ngôn ngữ giống hệt với Java. Bất cứ điều gì bạn đã làm trong Java đều có thể được thực hiện bằng C #, chỉ với cú pháp khác nhau. Nếu bạn gặp khó khăn trong việc dịch một khái niệm, có lẽ chỉ vì bạn chỉ biết một tên cụ thể của Java cho nó.


Cảm ơn bạn @Kylotan. Vì tò mò, bản thân bạn sử dụng hệ thống nào để liên lạc giữa các lớp - phương pháp Dịch vụ hay cái gì khác?
mã hóa

AFAIK, xe buýt sự kiện tương tự như công cụ xếp hàng nhắn tin, nhưng dành cho các sự kiện.
tro999

2
@codinghands, tôi thường không sử dụng bất kỳ phương thức giao tiếp giữa các lớp chính thức nào. Tôi chỉ giữ mọi thứ đơn giản - nếu một lớp cần gọi một lớp khác, thì nó thường có một tham chiếu đến lớp thứ hai với tư cách là thành viên hoặc có lớp thứ hai được truyền vào làm đối số. Tuy nhiên, đôi khi khi tôi làm việc với công cụ Unity, có cách tiếp cận tương tự như cách bạn gọi là phương pháp 'dịch vụ', trong đó tôi sẽ tìm kiếm một đối tượng theo tên có thành phần tôi yêu cầu, tìm kiếm thành phần trên đối tượng, sau đó gọi các phương thức trên thành phần đó.
Kylotan

@ as999999 - Tin nhắn và sự kiện khá giống nhau trong bối cảnh này. Nếu bạn đặt một sự kiện lên hàng đợi, hoặc xe buýt, hoặc bất cứ điều gì, những gì bạn thực sự lưu trữ là một thông báo biểu thị rằng một sự kiện đã diễn ra. Tương tự như vậy, đặt một tin nhắn trên hàng đợi ngụ ý rằng một sự kiện đã xảy ra để tạo ra tin nhắn đó. Chỉ là những cách khác nhau để xem một cuộc gọi chức năng không đồng bộ.
Kylotan

Xin lỗi, tôi chưa đánh dấu câu này là 'đã trả lời', nhưng tôi nghĩ sẽ có nhiều quan điểm hơn cho rằng mọi trò chơi cần giao tiếp giữa các thành phần bằng cách nào đó, bất kể ngôn ngữ ... Chúng ta đã bao quát các khả năng chính chưa?
mã hóa

1

Bạn đã thử chỉ sử dụng các sự kiện tĩnh đơn giản? Ví dụ, nếu bạn muốn lớp điểm của mình biết khi nào kẻ thù chết, bạn sẽ làm một cái gì đó như thế này:

Điểm.cs

class Score
{
    public int PlayerScore { get; set; }

    public Score()
    {
        EnemySpaceship.Death += new EventHandler<SpaceshipDeathEventArgs>(Spaceship_Death);
    }

    private void Spaceship_Death(object sender, SpaceshipDeathEventArgs e)
    {
        PlayerScore += e.Points;
    }
}

EnemySpaceship.cs

class EnemySpaceship
{
    public static event EventHandler<SpaceshipDeathEventArgs> Death;

    public void Kill()
    {
        OnDeath();
    }

    protected virtual void OnDeath()
    {
        if (Death != null)
        {
            Death(this, new SpaceshipDeathEventArgs(50));
        }
    }
}

SpaceshipDeathEventArss.cs

class SpaceshipDeathEventArgs : EventArgs
{
    public int Points { get; private set; }

    internal SpaceshipDeathEventArgs(int points)
    {
        Points = points;
    }
}


0

hãy thử sử dụng trình tổng hợp sự kiện như thế này


4
Câu trả lời này sẽ tốt hơn nếu bạn xây dựng thêm về đề xuất của mình, thay vì chỉ cung cấp liên kết.
MichaelHouse
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.