Làm thế nào tôi có thể xử lý sạch sẽ và thanh lịch dữ liệu và các phụ thuộc giữa các lớp


12

Tôi đang làm việc trên trò chơi topdown 2d trong SFML 2 và cần tìm một cách thanh lịch để mọi thứ sẽ hoạt động và khớp với nhau.

Cho phép tôi giải thích. Tôi có một số lớp kế thừa từ một cơ sở trừu tượng cung cấp phương thức vẽ và phương thức cập nhật cho tất cả các lớp.

Trong vòng lặp trò chơi, tôi gọi cập nhật và sau đó rút ra từng lớp, tôi tưởng tượng đây là một cách tiếp cận khá phổ biến. Tôi có các lớp cho gạch, va chạm, trình phát và trình quản lý tài nguyên có chứa tất cả các ô / hình ảnh / kết cấu. Do cách thức hoạt động của đầu vào trong SFML, tôi đã quyết định để mỗi lớp xử lý đầu vào (nếu cần) trong cuộc gọi cập nhật của nó.

Cho đến bây giờ tôi đã chuyển qua các phụ thuộc khi cần thiết, ví dụ, trong lớp người chơi khi nhấn phím di chuyển, tôi gọi một phương thức trên lớp va chạm để kiểm tra xem vị trí mà người chơi muốn di chuyển có bị va chạm không, và chỉ di chuyển người chơi nếu không có va chạm.

Điều này hoạt động tốt với hầu hết các phần, nhưng tôi tin rằng nó có thể được thực hiện tốt hơn, tôi chỉ không chắc làm thế nào.

Bây giờ tôi có những thứ phức tạp hơn mà tôi cần phải thực hiện, ví dụ: người chơi có thể đi tới một vật thể trên mặt đất, nhấn một phím để nhặt / cướp nó và sau đó nó sẽ hiển thị trong kho. Điều này có nghĩa là một vài điều cần phải xảy ra:

  • Kiểm tra xem người chơi có ở trong phạm vi của một vật phẩm có thể cướp được trên phím nhấn hay không, không thì tiếp tục.
  • Tìm vật phẩm.
  • Cập nhật kết cấu sprite trên vật phẩm từ kết cấu mặc định của nó thành kết cấu "bị cướp phá".
  • Cập nhật xung đột cho vật phẩm: nó có thể đã thay đổi hình dạng hoặc bị xóa hoàn toàn.
  • Hàng tồn kho cần được cập nhật với các mục được thêm vào.

Làm thế nào để tôi làm cho mọi thứ giao tiếp? Với hệ thống hiện tại của tôi, tôi sẽ kết thúc với các lớp học của mình vượt ra ngoài phạm vi và các cuộc gọi phương thức với nhau ở mọi nơi. Tôi có thể kết nối tất cả các lớp trong một trình quản lý lớn và cung cấp cho mỗi lớp một tham chiếu đến lớp trình quản lý cha mẹ, nhưng điều này có vẻ chỉ tốt hơn một chút.

Bất kỳ trợ giúp / lời khuyên sẽ được đánh giá rất cao! Nếu bất cứ điều gì không rõ ràng, tôi rất vui khi mở rộng mọi thứ.


1
Bạn có thể muốn xem xét thành phần ở đây, hơn là thừa kế. Có một cái nhìn xung quanh cho các ví dụ thành phần và nó có thể cung cấp cho bạn một số ý tưởng. Thành ngữ pimpl cũng có thể giúp sắp xếp mọi thứ.
OriginalDaemon

5
Một trong những bài viết kinh điển về thành phần: Phát triển thứ bậc của bạn
doppelgreener

Có vẻ quá cục bộ. Hãy thử đánh giá mã SE?
Anko

Câu trả lời:


5

Không chắc chắn nếu thành phần sẽ giải quyết tất cả các vấn đề. Có lẽ một phần có thể giúp đỡ. Nhưng nếu những gì bạn muốn là tách rời các lớp, tôi sẽ xem xét logic nhiều sự kiện hơn. Bằng cách này, ví dụ: bạn sẽ có chức năng OnLoot cần có vị trí người chơi và thông tin về các ổ có sẵn để tìm gần nhất. Sau đó, chức năng gửi sự kiện đến các mục bị cướp phá. Mục bị mất trong chu trình quy trình sự kiện của nó xử lý sự kiện này vì vậy mục chỉ cần biết cách tự cập nhật. Chức năng OnLoot cũng có thể cập nhật khoảng không quảng cáo của người chơi hoặc chính vật phẩm có thể gửi sự kiện updateInventory / * OnLootSucess * và trình phát / kho sẽ xử lý nó trong chu trình sự kiện quy trình của chính nó.

Ưu điểm: bạn đã tách một số lớp học của mình

Nhược điểm: thêm các lớp sự kiện, có thể không cần thiết mã trên không.

Đây là một trong những cách có thể trông như thế nào:

case LOOT_KEY:
   OnLoot(PLayer->getPos(), &inventoryItems);
....

// note onLoot do not needs to know anything about InvItem class (forward decl in enough)
int onLoot(vec3 pos, InvItems& pitems)
{
    InvItem* pitem = findInRange(pos, pitems, LOOT_RANGE);
    if(pitem)
     EventManager::Instance->post( Event::makeLootEvent(pitem));
}
....

// knows only about EventManager
InvItem::processEvents()
{
    while(!events.empty())
    {
        Event* pev = events.pop();
        ...
        case LOOT_EVENT:
            // in case you broadcasted it, but better is to sort all posted/sent events and add them only if they addressed to particular item 
            if(pev->item == this && handleLoot((LootEvent)pev))
            {
                EventManager::Instance->post(Event::makeLootSuccessEvent(this));
            }
    }
}

int handleLoot(LootEvent* plootev)
{
    InvItem* pi = plootev->item;
    if(pi->canLoot())
    {
        updateTexture(pi->icon, LOOTED_ICON_RES);
        return true;
    }
    return false; 
}


...
// knows only LootSuccessEvent and player
Inventory::processEvents()
{
    while(!events.empty())
    {
        Event* pev = events.pop();
        ...
        case LOOT_SUCCESS_EVENT:
             player->GetInventory()->add( ((LootSuccessEvent*)pev)->item );
        ...
}

Đây chỉ là một trong những cách có thể. Có lẽ bạn không cần quá nhiều sự kiện. Và tôi chắc chắn rằng bạn có thể làm tốt hơn khi biết dữ liệu của mình, đây chỉ là một trong nhiều cách.

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.