Cập nhật đối tượng, nội bộ vs bên ngoài?


8

Tiêu đề hơi khó hiểu, nhưng tôi không nghĩ cách giải thích câu hỏi của mình bằng một cụm từ ngắn. Vì vậy, đây là:

Bất cứ khi nào tôi viết công cụ trò chơi, dù nó là vật lý / chế độ, v.v., tôi luôn đi đến điểm mà tôi không chắc mình nên quản lý mọi thứ như thế nào. Các thực thể trên thế giới nên tự xử lý, hay nên có một số hệ thống toàn cầu quản lý chúng?

Đây là một ví dụ dễ dàng: Di chuyển mọi thứ. Mỗi đối tượng nên nhìn thế giới xung quanh mình (kiểm tra va chạm) và di chuyển dựa trên đó.

[lưu ý, đây là trò chơi dựa trên ô xếp nơi đối tượng di chuyển trên mỗi ô, vì vậy tôi không sử dụng vật lý để chuyển từ ô này sang ô khác]

public class Actor : GameObject
    {
        private void MoveTo(Vector2 location)
        {
            if (world.getTile(location) != solid && world.objAtTile(location) == null)
            {
                Tweener.addTween(this, location);
            }
          }
        }

Hay sự chuyển động của từng đối tượng nên được xử lý trong thế giới, nơi thế giới kiểm tra mọi thứ?

public class Actor : GameObject
    {
        private void MoveTo(Vector2 location)
        {
            world.moveTo(location);
          }
        }

public class World
{

    public void moveObject(GameObject obj, Vector2 location)
    {
      //called from object

      if (getTile(location) != solid && objAtTile(location) == null)
         {
                Tweener.addTween(obj, location);
         }
    }
}

Tôi cho rằng điều này thực sự không quan trọng lắm đối với ví dụ này, nhưng tôi có thể thấy mình gặp rắc rối sau này. Cảm ơn trước.


1
Thêm vào câu hỏi, nên Actorbiết về worldtất cả?
giảm tốc

1
Tôi nghĩ rằng bạn đang kết hợp các Đối tượng với các Thành phần và điều đó gây nhầm lẫn cho vấn đề ai đang làm gì. Nó có thể là vấn đề ngữ nghĩa vì Thành phần là một thuật ngữ quá tải. Tôi nghĩ rằng nếu bạn làm rõ Đối tượng là gì, Thành phần của bạn là gì và cách bạn tổ chức các công cụ nhỏ thực sự hoàn thành công việc thì bạn có thể trả lời câu hỏi của chính mình.
Patrick Hughes

1
Tôi phải đồng ý với những người khác rằng bạn đang yêu cầu đối tượng trò chơi tự di chuyển hay thế giới di chuyển đối tượng trò chơi. Đoạn mã trên không khiến tôi tin rằng bạn thực sự có nghĩa là một hệ thống loại thành phần và do đó có thể gây hiểu lầm trong tiêu đề câu hỏi của bạn.
James

Tôi đã sử dụng một số thuật ngữ gây hiểu lầm bây giờ mà các bạn đề cập đến nó. Đi để điều chỉnh nó ngay bây giờ! Chỉnh sửa: Xem nó đã được thay đổi, cảm ơn!
omgnoseat

@daniel Các diễn viên rõ ràng cần phải hiểu biết về thế giới xung quanh để di chuyển hiệu quả, mặc dù tôi thường sẽ thiết kế xung quanh một container chứa cả hai nhưng không biết gì. ví dụ. Thế giới chứa cả Diễn viên và Cấp độ; Diễn viên biết về Cấp độ (hay đúng hơn là được nói về Cấp độ khi cần, nhưng không phải là tài liệu tham khảo vĩnh viễn) nhưng không phải về Thế giới.
jhocking

Câu trả lời:


2

Tôi thấy các ví dụ của bạn bằng Java, nhưng các thẻ của bạn không chỉ định bất kỳ ngôn ngữ nào. Trong C ++, câu trả lời là không - bạn không nên sử dụng hàm thành viên cho việc này!

void move_to(actor *a, world *w, vec2 location);

4
Phải nói fan hâm mộ lớn của những cuốn sách mà tác giả của bài báo đã viết. Tuy nhiên, lý do của bài viết là, theo như tôi có thể nói, lý thuyết tốt nhưng không phải là mã thực tế. Bằng cách di chuyển các phương thức như thế này ra khỏi các đối tượng mà chúng liên quan đến bạn, bạn sẽ thêm nhiều vị trí hơn để tìm kiếm chức năng liên quan đến chúng, điều này chỉ gây nhầm lẫn và mức độ bảo trì cần thiết cao hơn. Chỉ là quan điểm của tôi về nó, vì vậy không + hoặc -. Chỉ hai xu.
James

1
Ngoài ra, phải nói rằng trông giống như C # với sự kế thừa bằng cách sử dụng: ClassName thay vì mở rộng ClassName.
James

Đó là mã giả dựa trên C #, nhưng điều đó không liên quan đến câu hỏi của tôi :)
omgnoseat

1
@omgnoseat: Điều đó có liên quan vì lời khuyên là không thể trong một ngôn ngữ mà không có chức năng trần và tính hữu dụng của nó bị giảm trong bất kỳ ngôn ngữ nào mà không có ADL. Kiến trúc tốt không độc lập với sự lựa chọn ngôn ngữ.

2
@James: Không có gì ngoài OO về các hàm trần, nếu các hàm tự gọi các phương thức tuân theo các nguyên tắc thiết kế OO. Đó là điểm của bài viết. (OO cũng không đồng nghĩa với thiết kế tốt. Nếu một thiết kế rõ ràng hoặc đơn giản yêu cầu bạn không sử dụng OO, hãy bỏ qua OO, không phải thiết kế.)

1

Không có câu trả lời đơn giản.

Như với hầu hết mọi thứ trong lập trình, đó là một sự đánh đổi. Cung cấp nhiều năng lượng hơn cho các đối tượng riêng lẻ làm cho chúng lớn hơn - và do đó chậm hơn - nhưng làm cho động cơ dễ hiểu và mở rộng hơn. Có một siêu hạng có thể xử lý mọi thứ cùng nhau có thể nhanh hơn, nhưng với chi phí để có một siêu hạng; đó là, nó thường được coi là hình thức xấu để tạo ra các lớp học siêu lớn.

Tôi đã đọc một số bài viết về thiết kế hướng thành phần và dữ liệu, trong đó bạn có một lớp duy nhất đại diện cho tất cả các đối tượng thuộc một loại nhất định, lưu trữ dữ liệu của chúng trong danh sách và chỉ truyền xung quanh các chỉ mục để lấy các thuộc tính của một đối tượng riêng lẻ. Mặc dù tôi có thể xem đây là một loại kiến ​​trúc khả thi, tôi cảm thấy nó khá khó khăn với toàn bộ hướng của đối tượng, điều này cũng đã nhận được sự chỉ trích công bằng của nó.

Cá nhân tôi khuyên bạn nên cung cấp thêm sức mạnh cho các đối tượng. Nó có ý nghĩa hơn trong một ngôn ngữ hướng đối tượng, và (tôi sẽ tưởng tượng) dễ hiểu và duy trì hơn theo thời gian.


Bạn phần nào nhấn mạnh mọi thứ bằng cách nói rằng phong cách của thiết kế dựa trên dữ liệu và thành phần mà bạn mô tả là "ốc vít với toàn bộ quan điểm của OO" - hoàn toàn không phải là OO . Ít nhất như được mô tả trong "Hệ thống thực thể là tương lai của sự phát triển MMOG" (được liên kết trong câu trả lời của pek), hệ thống thực thể là một mô hình lập trình hoàn toàn khác và nếu bạn thấy mình đang cố gắng làm cho các thành phần hoặc thực thể của mình vượt quá sự tiện lợi của việc đóng gói đơn giản, Bạn ' Đang làm sai.
Dave Sherohman

6
Họ hoàn toàn hướng đối tượng. Đó không chỉ là OO mà hầu hết mọi người đã quen, nhưng điều đó tốt. Hướng đối tượng là về trạng thái ghép với các phương thức hoạt động trên trạng thái đó, chỉ vậy thôi. Nó không yêu cầu mỗi đối tượng phải là một đối tượng trong đời thực hoặc bất cứ điều gì tương tự.
Kylotan

@Kylotan: Một lần nữa, tôi đang nói cụ thể về các mô hình như được mô tả trong "Hệ thống thực thể là tương lai của sự phát triển MMOG", trong đó các thành phần là dữ liệu câm được vận hành bởi các "hệ thống" bên ngoài. Chúng không phải là đối tượng vì chúng không có hành vi / phương pháp; chúng là các mối quan hệ (nghĩ các hàng cơ sở dữ liệu hoặc các cấu trúc C). Một sự tương đương nhầm giữa OOP và việc sử dụng "đối tượng" hàng ngày không liên quan gì đến nó. Từ Phần 3: "Tôi mạnh mẽ chống lại việc sử dụng OOP ở bất cứ đâu trong quá trình triển khai ES; thật dễ dàng để lén một số OOP trở lại nơi không phù hợp và tự lừa dối bản thân rằng đây là một ý tưởng hay."
Dave Sherohman

Tôi biết về bài viết này, nhưng đó chỉ là ý kiến ​​của một người về cách thực hiện những điều này - đó không phải là cách tiêu chuẩn, hoặc nhất thiết là cách tốt nhất, vì vậy không đúng khi nói rằng thiết kế hướng thành phần là hoàn toàn khác mô hình lập trình. Hoàn toàn có thể - và phổ biến hơn nhiều - để triển khai kiến ​​trúc dựa trên thành phần với mã OO và sử dụng mã OO không làm tổn hại đến "tính thành phần" của nó hơn bất kỳ việc sử dụng các thủ tục được lưu trữ làm hỏng khía cạnh quan hệ của cơ sở dữ liệu .
Kylotan

@Dave, câu hỏi này không có nghĩa là về các hệ thống thành phần thực thể. Cả ES và thiết kế không dựa trên dữ liệu không phải là OO, đó là một lỗi phổ biến, nhưng sai lầm lớn khi cho rằng như vậy. Nếu bạn google cho nó, bạn sẽ tìm thấy một số bài viết hay khám phá huyền thoại này. Tuy nhiên, đây câu hỏi là về nguyên tắc OO chung của cách thiết kế đối tượng của bạn, các mẫu thiết kế trình độ cao hơn không trả lời câu hỏi đó cả.
Maik

0

Tôi đang cập nhật câu trả lời của mình vì rất nhiều điều không rõ ràng trước các bình luận. Hãy trần với tôi trong khi tôi giải thích suy nghĩ của tôi.

Nói chung, hai khía cạnh quan trọng cần xem xét trong bất kỳ thiết kế nào là sự gắn kếtkhớp nối . Chúng ta đều biết rằng chúng ta cần sự gắn kết cao và khớp nối thấp để có thể tạo ra một thiết kế có thể tái sử dụng và mở rộng hơn.

Vì vậy, nếu thế giới phải quản lý mọi thứ, điều đó có nghĩa là nó có độ gắn kết thấp và khớp nối chặt chẽ (bởi vì nó cần phải biết và làm mọi thứ). Tuy nhiên, đây cũng là trường hợp khi một thực thể trò chơi phải làm mọi thứ. Cập nhật vị trí của anh ấy, kết xuất kết cấu của anh ấy, v.v.

Điều bạn thực sự quan tâm là tạo ra các hệ thống tập trung vào một khía cạnh của thực thể. Ví dụ: một thực thể trò chơi có thể có Texture, nhưng Trình kết xuất sẽ chịu trách nhiệm hiển thị kết cấu đó trên màn hình. Trình kết xuất không quan tâm các thuộc tính khác mà thực thể có.

Nói xa hơn một chút, một thực thể trò chơi chỉ đơn giản là một túi tài sản. Các thuộc tính này được thao tác bởi các hệ thống tập trung vào các thuộc tính cụ thể. Và đây là nơi các Hệ thống thực thể dựa trên thành phần (CBES) xuất hiện, nơi các thuộc tính = thành phần.

Cụ thể, CBES với Hệ thống (hoặc Hệ thống con). Thiết kế này có xu hướng có một vài Hệ thống tập trung vào các thành phần cụ thể của một thực thể trong khi không quan tâm đến những thành phần khác mà thực thể đó có. Ngoài ra, các Hệ thống chỉ được kết hợp với thông tin họ cần để xử lý các thành phần này.

Hãy lấy ví dụ của bạn. Vì đầu vào của nơi để di chuyển thực thể dựa trên bộ điều khiển của trình phát, nên bạn có thể sẽ có PlayerControllSystem. Hệ thống này, sẽ kiểm soát, ngoài nhiều thứ khác, PositionComponent của thực thể. Trong trường hợp này, PlayerControllSystem sẽ cần biết về Cấp độ và PositionComponent. Nếu sau này bạn quyết định thêm phát hiện va chạm, bạn sẽ tạo một CollisionSystem sẽ sử dụng lại vị trí của các thực thể, nhưng lần này để tính các hộp giới hạn (hoặc bạn có thể có BoundingBoxComponent, cuộc gọi của bạn). Thực tế là, bạn có thể dễ dàng bật hoặc tắt hành vi (ngay cả khi đang di chuyển) bằng cách thêm / xóa các thành phần. Vì vậy, nhiều hành vi hơn có nghĩa là nhiều hệ thống đang thao túng các thành phần của một thực thể, nhưng tất cả chúng đều nằm trong một lớp được xác định rõ ràng với độ khớp thấp. Muốn viết kịch bản? Thêm một ScriptComponent. BAM! Bạn chỉ cần thêm khả năng kịch bản với 2 lớp. Vật lý? Âm thanh? Lại như vậy.

Vì vậy, lý do tôi ủng hộ CBES với SubSystems là nó hoàn toàn OO và một hệ thống có thể bảo trì / mở rộng dễ dàng. Thêm một hành vi vào một thực thể cũng đơn giản như quyết định dữ liệu nào hành vi đó cần và thực thể nào cần nó.

Để biết thêm thông tin về Hệ thống thực thể dựa trên thành phần với Hệ thống con, có một loạt bài đăng blog tuyệt vời của T = Machine tại Hệ thống thực thể là tương lai của sự phát triển MMOG . Tác giả thậm chí đã đi xa đến mức tạo ra một wiki để thu thập các triển khai khác nhau có tên Dự án Hệ thống Thực thể

Một bài đăng chung (và nổi tiếng) về Hệ thống thực thể dựa trên thành phần nói chung là Phát triển hệ thống phân cấp của bạn , người đã tạo ra hệ thống cho Tony Hawk Pro.

Cuối cùng, nếu bạn đang tìm kiếm một thư viện có mã ví dụ, đừng đi xa hơn thư viện Artemis . Artemis chủ yếu ở Java nhưng đây là một cổng trong C # (mà tôi hiện đang sử dụng trong dự án XNA của mình).


2
-1, vì điều này không giải quyết được vấn đề, chỉ cần di chuyển nó. Anh ta vẫn sẽ không có câu trả lời rõ ràng về việc đối tượng nào đưa ra quyết định, cho dù nó bao gồm các thành phần hay không.
Kylotan

1
Liên kết thứ hai cung cấp một hướng dẫn mở rộng về lý do tại sao hành vi của các thực thể trò chơi nên được đưa ra ngoài vào Hệ thống thực thể. Artemis theo cùng một kiến ​​trúc.
pek

Liên kết thứ hai là một ý kiến. Các thành phần được nhiều người ưa thích nhưng chúng không phải là giải pháp cho tất cả các vấn đề và chúng chắc chắn không có giải pháp nội tại cho vấn đề này.
Kylotan

Câu trả lời được bình chọn nhiều nhất trong câu hỏi này bắt đầu "Không có câu trả lời đơn giản. Như với hầu hết mọi thứ trong lập trình, đó là một sự đánh đổi." Liên kết thứ hai cung cấp một trong nhiều giải pháp. Trong thực tế, nó ủng hộ chính xác ngược lại với câu trả lời đó. Có lẽ tôi nên chỉnh sửa câu trả lời của mình để làm cho nó rõ ràng hơn. Nhưng một lần nữa, có lẽ điều này sẽ không thay đổi số phiếu tiêu cực: P
pek

@pek: Downvote của tôi là vì "sử dụng các thành phần" không phải là câu trả lời cho câu hỏi này. Tôi sử dụng các thành phần và tôi khuyên dùng mẫu thành phần, nhưng "sử dụng hệ thống thực thể dựa trên thành phần" không phải là câu trả lời cho mọi vấn đề trong phát triển trò chơi, hoặc thậm chí trong kiến ​​trúc phần mềm trò chơi - câu hỏi này phát sinh giống với các thành phần hoặc kế thừa hệ thống phân cấp hoặc các loại thực thể tĩnh hoàn toàn không liên quan!

0

Tôi thường đi với một thiết kế nơi các đối tượng tự xử lý (rốt cuộc đó là phương thức nào) nhưng Thế giới cơ sở có danh sách tất cả các đối tượng và nó sử dụng các danh sách đó để phối hợp chúng. Vì vậy, một cái gì đó như:

class World {
  var walls = [];
  var actors = [];
  function update() {
    for each (actor in actors) {
      actor.update(walls);
    }
  }
}

class Actor {
  function update(walls) {
    this.move();
    for each (wall in walls) {
      this.collide(wall);
    }
  }
}

0

Giữ nó KHÔ, ngại ngùng và nói với anh chàng kia.

Tốt hơn là yêu cầu thế giới di chuyển diễn viên của bạn hơn là hỏi thế giới nếu bạn có thể di chuyển đến nơi bạn muốn. Bằng cách này, bạn có thể thay đổi thuật toán tìm đường dễ dàng trong lớp thế giới và như vậy. Tất nhiên, bạn chỉ có thể để điều này lên một lớp cơ sở cho diễn viên, nhưng đó là hướng tôi sẽ đi và lý do tại sao.


-1

EDIT: Viết lại do phản hồi cho biết tôi đã không vẽ dòng đủ rõ ràng cho câu trả lời này cho câu hỏi ban đầu.

Tôi muốn làm rõ câu hỏi hơn một chút nếu có thể. Nên logic tác động lên một đối tượng là bên trong hoặc bên ngoài đối tượng đó. Phần cuối của bài viết đặc biệt đề cập đến tuổi thọ của thiết kế làm cơ sở để đặt câu hỏi, để tránh rắc rối về sau.

Câu trả lời cấp cao đơn giản của tôi là giữ tất cả logic tác động lên một đối tượng trong đối tượng đó.

Bạn không cần thế giới để di chuyển một đối tượng, tất cả những gì bạn cần là đối tượng được di chuyển và vectơ đại diện cho vị trí để di chuyển đến đối tượng đó. Thế giới có thể đi vào hoạt động khi một điểm đến đang được chọn hoặc khi cần phải có phản ứng với môi trường do va chạm, nhưng những điều đó nằm ngoài ví dụ được đưa ra để làm việc.

Để giải quyết phần cơ bản của câu hỏi và đạt được tuổi thọ của thiết kế, tôi sẽ đề xuất một kiến ​​trúc hướng thành phần. Các kiến ​​trúc thành phần chia một đối tượng thành các tập hợp dữ liệu và chức năng riêng biệt (giả sử bạn đi với câu trả lời của tôi ở trên trạng thái nào để giữ logic với dữ liệu). Nếu cấu trúc của bạn trông giống như CEntity-> CHuman-> CSoldier-> CPlayerCharacter thì bạn sẽ luôn gặp phải các vấn đề khi bạn cần thay đổi một số logic và tùy thuộc vào vị trí của nó trong cây đó (ví dụ có bao nhiêu loại người khác?) nó có thể có ảnh hưởng quét trên nhiều loại đối tượng.

Thay vào đó, một hệ thống thành phần sẽ có một bộ giao diện xác định đối tượng CEntity được tạo thành như ICompRenderable, ICompMovizable, ICompHealth, ICompInventory, v.v. Nơi bạn sẽ có CCompMovizableHuman và có thể là CCompMovizableSoldier và CCompMovizablePlayer để tách các mẫu chuyển động riêng lẻ của chúng. Vì vậy, nói rằng Người lính được thay đổi để chạy trong đội hình. Thay đổi này sẽ chỉ ảnh hưởng đến các thực thể được xây dựng bằng thành phần đó.

Vì vậy, để tóm tắt, tôi khuyên bạn nên chứa logic với dữ liệu mà logic áp dụng. Tôi cũng khuyên bạn nên chia nhỏ các đối tượng thành các thành phần riêng biệt để cắt giảm 'Tôi phải đặt cái này ở đâu?' câu hỏi và cung cấp sự ổn định trong tương lai dễ dàng bảo trì và mở rộng của nó.

Hi vọng điêu nay co ich.


Tôi đã xem xét mô hình thành phần trong vài giờ qua. (các liên kết của pek rất hay). Nhưng vẫn chưa rõ "hành vi" thực sự sẽ diễn ra ở đâu. Rõ ràng là một thực thể có các thành phần khác nhau cho đầu vào, kết xuất, vật lý. Nhưng nếu tôi hiểu chính xác, các thành phần chỉ chứa dữ liệu cần thiết để có thể hoạt động, nhưng thực tế không chứa triển khai. Chúng ta hãy quay trở lại việc di chuyển một lần nữa; Tôi nên làm thế nào để thực thể di chuyển bằng cách sử dụng các thành phần? Tôi có nên mở rộng thành phần đầu vào và mã hóa việc thực hiện ở đó không? Hoặc điều gì khác quản lý việc thực hiện?
omgnoseat

Đối với tôi, tôi giữ logic trong các đối tượng, nhưng tôi thực sự đang thực hiện một hệ thống thành phần trên Thiết kế hướng dữ liệu, có nghĩa là hầu hết các đối tượng của tôi thực sự chỉ là logic dù được ánh xạ tới các vị trí bên trong dữ liệu để xử lý nhanh ... Và vào cuối ngày, hãy học một mẫu thiết kế tại một thời điểm: D Đối với -1, sẽ đánh giá cao việc biết tại sao nó được gắn thẻ như vậy, ngay cả khi nó chỉ là 'Tôi thích câu trả lời của tôi hơn' Tôi vẫn muốn biết tại sao.
James

1
@James, đủ công bằng. Tôi đánh giá thấp vì các hệ thống thành phần thực thể không trả lời câu hỏi ban đầu. Một thành phần vị trí vẫn có thể tự di chuyển hoặc thế giới có thể lặp lại trên tất cả các thành phần vị trí và di chuyển chúng. Lý do tương tự Kylotan đã bỏ phiếu cho câu trả lời của pek, vì vậy tôi nghĩ lý do -1 là rõ ràng. Và ngay cả khi hệ thống thành phần bắt buộc phải tự di chuyển (không phải là trường hợp) thì nó vẫn không phải là một câu trả lời, chỉ là trường hợp sử dụng cho 1 trong các tùy chọn. Nhưng câu hỏi là về lý do sử dụng cái này hay cái khác, ưu và nhược điểm của chúng. Câu trả lời không bao gồm điều đó.
Maik

@Maik Học kỳ. Cảm ơn vì bạn đã phản hồi. Tôi đã viết lại câu trả lời để thử và vẽ các dòng rõ ràng hơn cho câu hỏi ban đầu và ổ đĩa chung cho nó ở vị trí đầu tiên như được đưa ra ở cuối câu hỏi.
James

@James, cảm ơn vì đã dành thời gian để chỉnh sửa câu trả lời để phản hồi bình luận của tôi, rất cảm kích. Câu trả lời được đề xuất để "giữ tất cả logic tác động lên một đối tượng trong đối tượng đó" đánh bại một tính năng cốt lõi của OO, cụ thể là đóng gói. Như liên kết của Joe cho thấy, sử dụng các hàm không phải là thành viên không kết bạn sẽ làm tăng mức độ đóng gói của một đối tượng. Hơn nữa, nó giới thiệu một phương pháp rõ ràng là làm thế nào để thực sự đo lường sự đóng gói. Việc đưa chức năng di chuyển vào một trong hai thế giới hoặc tác nhân sẽ làm giảm sự đóng gói của thiết kế, dẫn đến việc kém linh hoạt và khó duy trì mã hơn.
Maik

-1

Tôi khuyên bạn nên cố gắng đọc lên các kiến ​​trúc dựa trên thành phần. Có khá nhiều bài viết trên blog, bài thuyết trình và viết lên đó về chúng có thể làm tốt hơn bao giờ hết.

AltDevBlogADay có khá nhiều bài viết về nó, một bài rất hay là loạt bài này về các thực thể trò chơi: http://altdevblogaday.com/2011/07/10/the-game-entity- nhiều phần tập trung vào vấn đề bạn đang cố gắng giải quyết.

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.