Một thực hành thiết kế tốt để tránh yêu cầu một loại lớp con là gì?


11

Tôi đã đọc rằng khi chương trình của bạn cần biết một đối tượng là gì, thường chỉ ra một lỗi thiết kế vì vậy tôi muốn biết đâu là một thực tiễn tốt để xử lý việc này. Tôi đang triển khai một Hình dạng lớp với các lớp con khác nhau được kế thừa từ nó như Hình tròn, Đa giác hoặc Hình chữ nhật và tôi đã biết các thuật toán khác nhau để biết Hình tròn có va chạm với Đa giác hay Hình chữ nhật không. Sau đó, giả sử chúng ta có hai trường hợp của Shape và muốn biết liệu một trường hợp có va chạm với nhau không, trong phương thức đó tôi đã suy ra loại lớp con nào là đối tượng mà tôi đang va chạm để biết tôi nên gọi thuật toán nào, nhưng đây là thiết kế xấu hay thực hành? Đây là cách tôi giải quyết nó.

abstract class Shape {
  ShapeType getType();
  bool collide(Shape other);
}

class Circle : Shape {
  getType() { return Type.Circle; }

  bool collide(Shape other) {
    if(other.getType() == Type.Rect) {
      collideCircleRect(this, (Rect) other);     
    } else if(other.getType() == Type.Polygon) {
      collideCirclePolygon(this, (Polygon) other);
    }
  }
}

Đây là một mẫu thiết kế xấu? Làm thế nào tôi có thể giải quyết điều này mà không phải suy ra các loại lớp con?


1
Bạn kết thúc rằng mọi Instance, ví dụ Circle đều biết mọi loại hình dạng khác. Vì vậy, tất cả chúng được kết nối vững chắc bằng cách nào đó. Và ngay khi bạn thêm một hình dạng mới, như Tam giác, cuối cùng bạn sẽ thêm hỗ trợ Tam giác ở mọi nơi. Nó phụ thuộc vào những gì bạn muốn thay đổi thường xuyên hơn, bạn sẽ thêm Hình dạng mới, thiết kế này là xấu. Bởi vì bạn có giải pháp mở rộng - Hỗ trợ của bạn về hình tam giác phải được thêm ở mọi nơi. Thay vào đó, bạn nên trích xuất Collisiondetection của mình thành một Class riêng biệt, có thể hoạt động với tất cả các loại và ủy nhiệm.
đóng gói


IMO này đi xuống các yêu cầu hiệu suất. Mã càng cụ thể thì càng được tối ưu hóa và chạy nhanh hơn. Trong trường hợp đặc biệt này (thực hiện nó, quá), kiểm tra đối với loại là OK vì kiểm tra va chạm phù hợp có thể enourmously nhanh hơn so với một giải pháp chung. Nhưng khi hiệu năng thời gian chạy không quan trọng, tôi sẽ luôn đi theo cách tiếp cận chung / đa hình.
marstato

Cảm ơn tất cả, trong trường hợp hiệu năng của tôi rất quan trọng và tôi sẽ không thêm hình dạng mới, có thể tôi thực hiện phương pháp CollisionDetection, tuy nhiên tôi vẫn phải biết loại lớp con, tôi có nên giữ phương thức "Type getType ()" không Hình dạng hoặc thay vào đó thực hiện một số loại "ví dụ" với Shape trong lớp CollisionDetection?
Alejandro

1
Không có quy trình va chạm hiệu quả giữa Shapecác đối tượng trừu tượng. Logic của bạn phụ thuộc vào các phần bên trong của đối tượng khác trừ khi bạn kiểm tra xung đột cho các điểm giới hạn bool collide(x, y)(một tập hợp con các điểm kiểm soát có thể là một sự đánh đổi tốt). Mặt khác, bạn cần kiểm tra loại bằng cách nào đó - nếu thực sự cần trừu tượng thì việc tạo Collisionloại (cho các đối tượng trong khu vực của tác nhân hiện tại) sẽ là cách tiếp cận phù hợp.
rùng mình

Câu trả lời:


13

Đa hình

Miễn là bạn sử dụng getType()hoặc bất cứ thứ gì tương tự, bạn không sử dụng đa hình.

Tôi hiểu cảm giác như bạn cần biết bạn có loại gì. Nhưng bất kỳ công việc nào bạn muốn làm trong khi biết rằng thực sự nên được đẩy xuống lớp. Sau đó, bạn chỉ cần nói khi nào để làm điều đó.

Mã thủ tục nhận thông tin sau đó đưa ra quyết định. Mã hướng đối tượng cho các đối tượng làm việc.
- Alec sắc nét

Nguyên tắc này được gọi là nói, đừng hỏi . Làm theo nó giúp bạn không lan truyền các chi tiết như gõ xung quanh và tạo ra logic hoạt động trên chúng. Làm điều đó biến một lớp học từ trong ra ngoài. Tốt hơn là giữ hành vi đó bên trong lớp để nó có thể thay đổi khi lớp thay đổi.

Đóng gói

Bạn có thể nói với tôi rằng sẽ không cần hình dạng nào khác nhưng tôi không tin bạn và bạn cũng không nên.

Một hiệu ứng tuyệt vời của việc đóng gói sau là dễ dàng thêm các loại mới vì các chi tiết của chúng không lan truyền vào mã nơi chúng hiển thị ifswitchlogic. Mã cho một loại mới tất cả phải ở một nơi.

Một loại hệ thống phát hiện va chạm không biết gì

Hãy để tôi chỉ cho bạn cách tôi thiết kế một hệ thống phát hiện va chạm có hiệu suất và hoạt động với bất kỳ hình dạng 2D nào bằng cách không quan tâm đến loại.

nhập mô tả hình ảnh ở đây

Nói rằng bạn phải vẽ nó. Có vẻ đơn giản. Đó là tất cả các vòng tròn. Thật hấp dẫn khi tạo ra một lớp vòng tròn hiểu được sự va chạm. Vấn đề là điều này khiến chúng ta suy nghĩ về một dòng suy nghĩ sụp đổ khi chúng ta cần 1000 vòng tròn.

Chúng ta không nên nghĩ về vòng tròn. Chúng ta nên suy nghĩ về pixel.

Điều gì sẽ xảy ra nếu tôi nói với bạn rằng cùng một mã bạn sử dụng để vẽ những kẻ này là những gì bạn có thể sử dụng để phát hiện khi họ chạm vào hoặc ngay cả những mã mà người dùng đang nhấp vào.

nhập mô tả hình ảnh ở đây

Ở đây tôi đã vẽ mỗi vòng tròn bằng một màu duy nhất (nếu mắt bạn đủ tốt để nhìn đường viền màu đen, hãy bỏ qua điều đó). Điều này có nghĩa là mọi pixel trong ảnh ẩn này ánh xạ trở lại những gì đã vẽ nó. Một hashmap chăm sóc điều đó độc đáo. Bạn thực sự có thể làm đa hình theo cách này.

Hình ảnh này bạn không bao giờ phải hiển thị cho người dùng. Bạn tạo nó với cùng một mã đã vẽ cái đầu tiên. Chỉ với màu sắc khác nhau.

Khi người dùng nhấp vào vòng tròn tôi biết chính xác vòng tròn nào vì chỉ có một vòng tròn là màu đó.

Khi tôi vẽ một vòng tròn lên trên một vòng tròn khác, tôi có thể nhanh chóng đọc mọi pixel tôi sắp ghi đè bằng cách bỏ chúng vào một tập hợp. Khi tôi thực hiện xong các điểm được đặt cho mỗi vòng tròn mà nó va chạm và bây giờ tôi chỉ phải gọi cho mỗi người một lần để thông báo về vụ va chạm.

Một loại mới: Hình chữ nhật

Tất cả điều này được thực hiện với các vòng tròn nhưng tôi hỏi bạn: nó có hoạt động khác với hình chữ nhật không?

Không có kiến ​​thức vòng tròn đã bị rò rỉ vào hệ thống phát hiện. Nó không quan tâm đến bán kính, chu vi hoặc điểm trung tâm. Nó quan tâm đến pixel và màu sắc.

Phần duy nhất của hệ thống va chạm này cần được đẩy xuống thành các hình dạng riêng lẻ là một màu độc đáo. Khác hơn là các hình dạng chỉ có thể nghĩ về việc vẽ hình dạng của chúng. Dù sao thì đó cũng là những gì họ giỏi.

Bây giờ khi bạn viết logic va chạm, bạn không quan tâm bạn có loại phụ nào. Bạn bảo nó va chạm và nó cho bạn biết những gì nó tìm thấy dưới hình dạng nó giả vờ vẽ. Không cần biết loại. Và điều đó có nghĩa là bạn có thể thêm bao nhiêu loại phụ tùy thích mà không phải cập nhật mã trong các lớp khác.

Lựa chọn thực hiện

Thực sự, nó không cần phải là một màu độc đáo. Nó có thể là các tham chiếu đối tượng thực tế và lưu một mức độ gián tiếp. Nhưng những điều đó sẽ không đẹp khi được rút ra trong câu trả lời này.

Đây chỉ là một ví dụ thực hiện. Chắc chắn có những người khác. Điều này có nghĩa là cho thấy rằng bạn càng để các kiểu con hình dạng này gắn bó với trách nhiệm duy nhất của chúng thì toàn bộ hệ thống hoạt động càng tốt. Có thể có các giải pháp sử dụng nhiều bộ nhớ nhanh hơn và ít bộ nhớ hơn nhưng nếu chúng buộc tôi phải truyền bá kiến ​​thức về các kiểu con xung quanh thì tôi sẽ không thích sử dụng chúng ngay cả khi đạt được hiệu suất. Tôi sẽ không sử dụng chúng trừ khi tôi rõ ràng cần chúng.

Công văn đôi

Cho đến bây giờ tôi đã hoàn toàn bỏ qua công văn đôi . Tôi đã làm điều đó bởi vì tôi có thể. Chừng nào logic va chạm không quan tâm hai loại va chạm nào bạn không cần nó. Nếu bạn không cần nó, đừng sử dụng nó. Nếu bạn nghĩ rằng bạn có thể cần nó, hãy ngừng giao dịch với nó miễn là bạn có thể. Thái độ này được gọi là YAGNI .

Nếu bạn quyết định bạn thực sự cần các loại va chạm khác nhau thì hãy tự hỏi nếu các kiểu con hình n thực sự cần n 2 loại va chạm. Cho đến nay tôi đã làm việc rất chăm chỉ để dễ dàng thêm một kiểu con hình dạng khác. Tôi không muốn làm hỏng nó bằng cách thực hiện công văn kép buộc các vòng tròn phải biết rằng hình vuông tồn tại.

Có bao nhiêu loại va chạm có? Một chút suy đoán (một điều nguy hiểm) phát minh ra các va chạm đàn hồi (bouncy), không đàn hồi (dính), tràn đầy năng lượng (khám phá) và phá hoại (damagy). Có thể có nhiều hơn nhưng nếu điều này nhỏ hơn n 2 thì đừng cho phép thiết kế va chạm của chúng ta.

Điều này có nghĩa là khi ngư lôi của tôi chạm vào thứ gì đó chấp nhận thiệt hại, nó không phải BIẾT nó trúng tàu không gian. Nó chỉ phải nói với nó, "Ha ha! Bạn đã nhận 5 điểm sát thương."

Những thứ gây sát thương sẽ gửi thông điệp thiệt hại đến những thứ chấp nhận thông điệp thiệt hại. Thực hiện theo cách đó bạn có thể thêm hình dạng mới mà không cần nói với các hình dạng khác về hình dạng mới. Bạn chỉ kết thúc lan truyền xung quanh các loại va chạm mới.

Con tàu không gian có thể gửi lại cho ngư lôi "Ha ha! Bạn đã nhận 100 điểm thiệt hại." cũng như "Bây giờ bạn đang bị mắc kẹt vào thân tàu của tôi". Và sự đau khổ có thể gửi lại "Chà, tôi đã làm xong vì vậy hãy quên tôi đi".

Không có gì biết chính xác mỗi cái là gì. Họ chỉ biết nói chuyện với nhau thông qua giao diện va chạm.

Bây giờ chắc chắn, công văn kép cho phép bạn kiểm soát mọi thứ mật thiết hơn thế này nhưng bạn có thực sự muốn điều đó không?

Nếu bạn làm, ít nhất hãy nghĩ về việc thực hiện gửi hai lần thông qua sự trừu tượng về loại va chạm nào mà hình dạng chấp nhận và không phải trên hình thực hiện hình dạng thực tế. Ngoài ra, hành vi va chạm là thứ bạn có thể tiêm như một người phụ thuộc và ủy thác cho sự phụ thuộc đó.

Hiệu suất

Hiệu suất luôn luôn quan trọng. Nhưng điều đó không có nghĩa là nó luôn luôn là một vấn đề. Hiệu suất thử nghiệm. Đừng chỉ suy đoán. Hy sinh tất cả mọi thứ khác trong tên hiệu suất thường không dẫn đến mã đục lỗ.



+1 cho "Bạn có thể nói với tôi rằng sẽ không cần hình dạng nào khác nhưng tôi không tin bạn và bạn cũng không nên."
Tulains Córdova

Suy nghĩ về pixel sẽ không đưa bạn đến bất cứ nơi nào nếu chương trình này không phải là về vẽ hình mà là về các phép tính thuần túy toán học. Câu trả lời này ngụ ý rằng bạn nên hy sinh tất cả mọi thứ để nhận thấy sự thuần khiết hướng đối tượng. Nó cũng chứa một mâu thuẫn: trước tiên bạn nói rằng chúng ta nên dựa trên toàn bộ thiết kế của mình dựa trên ý tưởng rằng chúng ta có thể cần nhiều loại hình dạng hơn trong tương lai, sau đó bạn nói "YAGNI". Cuối cùng, bạn bỏ qua việc làm cho việc thêm các loại dễ dàng hơn thường có nghĩa là khó thêm các hoạt động, điều này thật tệ nếu hệ thống phân cấp loại tương đối ổn định nhưng các hoạt động thay đổi rất nhiều.
Christian Hackl

7

Mô tả vấn đề nghe có vẻ như bạn nên sử dụng Multimethods (còn gọi là Nhiều công văn), trong trường hợp cụ thể này - Công văn kép . Câu trả lời đầu tiên đã nói về cách đối phó một cách khái quát với các hình dạng va chạm trong kết xuất raster, nhưng tôi tin rằng OP muốn giải pháp "vectơ" hoặc có thể toàn bộ vấn đề đã được cải cách về hình dạng, đó là ví dụ cổ điển trong các giải thích OOP.

Ngay cả bài viết trên wikipedia được trích dẫn cũng sử dụng phép ẩn dụ va chạm, hãy để tôi chỉ trích dẫn (Python không có nhiều hình thức tích hợp như một số ngôn ngữ khác):

@multimethod(Asteroid, Asteroid)
def collide(a, b):
    """Behavior when asteroid hits asteroid"""
    # ...define new behavior...
@multimethod(Asteroid, Spaceship)
def collide(a, b):
    """Behavior when asteroid hits spaceship"""
    # ...define new behavior...
# ... define other multimethod rules ...

Vì vậy, câu hỏi tiếp theo là làm thế nào để có được sự hỗ trợ cho đa phương thức trong ngôn ngữ lập trình của bạn.



Có, trường hợp đặc biệt của nhiều công văn hay còn gọi là Multimethods, được thêm vào câu trả lời
Roman Susi

5

Vấn đề này yêu cầu thiết kế lại trên hai cấp độ.

Đầu tiên, bạn cần trích xuất logic để phát hiện sự va chạm giữa các hình dạng ra khỏi hình dạng. Điều này là để bạn không vi phạm OCP mỗi khi bạn cần thêm hình dạng mới vào mô hình. Hãy tưởng tượng bạn đã xác định Hình tròn, Hình vuông và Hình chữ nhật. Sau đó bạn có thể làm như thế này:

class ShapeCollisionDetector
{
    public void DetectCollisionCircleCircle(Circle firstCircle, Circle secondCircle)
    { 
        //Code that detects collision between two circles
    }

    public void DetectCollisionCircleSquare(Circle circle, Square square)
    {
        //Code that detects collision between circle and square
    }

    public void DetectCollisionCircleRectangle(Circle circle, Rectangle rectangle)
    {
        //Code that detects collision between circle and rectangle
    }

    public void DetectCollisionSquareSquare(Square firstSquare, Square secondSquare)
    {
        //Code that detects collision between two squares
    }

    public void DetectCollisionSquareRectangle(Square square, Rectangle rectangle)
    {
        //Code that detects collision between square and rectangle
    }

    public void DetectCollisionRectangleRectangle(Rectangle firstRectangle, Rectangle secondRectangle)
    { 
        //Code that detects collision between two rectangles
    }
}

Tiếp theo, bạn phải sắp xếp cho phương thức thích hợp được gọi tùy thuộc vào hình dạng mà nó gọi. Bạn có thể làm điều đó bằng cách sử dụng đa hình và mẫu khách truy cập . Để đạt được điều này, chúng ta phải có mô hình đối tượng phù hợp. Đầu tiên, tất cả các hình dạng phải tuân thủ cùng một giao diện:

    interface IShape
{
    void DetectCollision(IShape shape);
    void Accept (ShapeVisitor visitor);
}

Tiếp theo, chúng ta phải có một lớp khách truy cập cha mẹ:

    abstract class ShapeVisitor
{
    protected ShapeCollisionDetector collisionDetector = new ShapeCollisionDetector();

    abstract public void VisitCircle (Circle circle);

    abstract public void VisitSquare(Square square);

    abstract public void VisitRectangle(Rectangle rectangle);

}

Tôi đang sử dụng một lớp ở đây thay vì giao diện, vì tôi cần mỗi đối tượng khách truy cập phải có thuộc tính ShapeCollisionDetectorloại.

Mỗi lần thực hiện IShapegiao diện sẽ khởi tạo khách truy cập thích hợp và gọi Acceptphương thức thích hợp của đối tượng mà đối tượng gọi tương tác với, như sau:

    class Circle : IShape
{
    public void DetectCollision(IShape shape)
    {
        CircleVisitor visitor = new CircleVisitor(this);
        shape.Accept(visitor);
    }

    public void Accept(ShapeVisitor visitor)
    {
        visitor.VisitCircle(this);
    }
}

    class Rectangle : IShape
{
    public void DetectCollision(IShape shape)
    {
        RectangleVisitor visitor = new RectangleVisitor(this);
        shape.Accept(visitor);
    }

    public void Accept(ShapeVisitor visitor)
    {
        visitor.VisitRectangle(this);
    }
}

Và khách truy cập cụ thể sẽ trông như thế này:

    class CircleVisitor : ShapeVisitor
{
    private Circle Circle { get; set; }

    public CircleVisitor(Circle circle)
    {
        this.Circle = circle;
    }

    public override void VisitCircle(Circle circle)
    {
        collisionDetector.DetectCollisionCircleCircle(Circle, circle);
    }

    public override void VisitSquare(Square square)
    {
        collisionDetector.DetectCollisionCircleSquare(Circle, square);
    }

    public override void VisitRectangle(Rectangle rectangle)
    {
        collisionDetector.DetectCollisionCircleRectangle(Circle, rectangle);
    }
}

    class RectangleVisitor : ShapeVisitor
{
    private Rectangle Rectangle { get; set; }

    public RectangleVisitor(Rectangle rectangle)
    {
        this.Rectangle = rectangle;
    }

    public override void VisitCircle(Circle circle)
    {
        collisionDetector.DetectCollisionCircleRectangle(circle, Rectangle);
    }

    public override void VisitSquare(Square square)
    {
        collisionDetector.DetectCollisionSquareRectangle(square, Rectangle);
    }

    public override void VisitRectangle(Rectangle rectangle)
    {
        collisionDetector.DetectCollisionRectangleRectangle(Rectangle, rectangle);
    }
}

Theo cách này, bạn không cần thay đổi các lớp hình dạng mỗi khi bạn thêm hình dạng mới và bạn không cần kiểm tra loại hình để gọi phương thức phát hiện va chạm thích hợp.

Một nhược điểm của giải pháp này là nếu bạn thêm hình dạng mới, bạn phải mở rộng lớp ShapeVisitor bằng phương thức cho hình dạng đó (ví dụ VisitTriangle(Triangle triangle)), và do đó, bạn sẽ phải triển khai phương thức đó trong tất cả các khách truy cập khác. Tuy nhiên, vì đây là phần mở rộng, theo nghĩa là không có phương thức hiện tại nào được thay đổi, mà chỉ có phương thức mới được thêm vào, điều này không vi phạm OCP và chi phí mã là tối thiểu. Ngoài ra, bằng cách sử dụng lớp ShapeCollisionDetector, bạn tránh vi phạm SRP và bạn tránh dự phòng mã.


5

Vấn đề cơ bản của bạn là trong hầu hết các ngôn ngữ lập trình OO hiện đại, chức năng nạp chồng không hoạt động với liên kết động (tức là loại đối số hàm được xác định tại thời điểm biên dịch). Những gì bạn cần là một cuộc gọi phương thức ảo là ảo trên hai đối tượng chứ không phải chỉ một. Các phương pháp như vậy được gọi là đa phương pháp . Tuy nhiên, có nhiều cách để mô phỏng hành vi này trong các ngôn ngữ như Java, C ++, v.v ... Đây là nơi gửi công văn kép rất tiện dụng.

Ý tưởng cơ bản là bạn sử dụng đa hình hai lần. Khi hai hình dạng va chạm, bạn có thể gọi phương thức va chạm chính xác của một trong các đối tượng thông qua đa hình và truyền đối tượng khác của loại hình chung. Trong phương thức gọi anh em thì biết liệu này đối tượng là một vòng tròn, hình chữ nhật hoặc bất cứ điều gì. Sau đó, bạn gọi phương thức va chạm trên đối tượng hình đã qua và truyền cho đối tượng này . Cuộc gọi thứ hai này sau đó một lần nữa tìm thấy loại đối tượng chính xác thông qua đa hình.

abstract class Shape {
  bool collide(Shape other);
  bool collide(Rect other);
  bool collide(Circle other);
}

class Circle : Shape {

  bool collide(Shape other) {
    return other.collide(this);
  }

  bool collide(Rect other) {
    // algorithm to detect collision between Circle and Rect
  }

  // ...
}

class Rect : Shape {

  bool collide(Shape other) {
    return other.collide(this);
  }

  bool collide(Circle other) {
    // algorithm to detect collision between Circle and Rect
  }

  // ...
}

Tuy nhiên, một nhược điểm lớn của kỹ thuật này là mỗi lớp trong hệ thống phân cấp phải biết về tất cả các anh chị em. Điều này đặt một gánh nặng bảo trì cao nếu một hình dạng mới được thêm vào sau này.


2

Có lẽ đây không phải là cách tốt nhất để tiếp cận vấn đề này

Sự va chạm hình dạng toán học đặc biệt là sự kết hợp hình dạng. Có nghĩa là số lượng các thói quen phụ bạn sẽ cần là bình phương của số lượng hình dạng mà hệ thống của bạn hỗ trợ. Các va chạm hình dạng không thực sự hoạt động trên các hình dạng, mà là các hoạt động lấy hình dạng làm tham số.

Chiến lược quá tải toán tử

Nếu bạn không thể đơn giản hóa bài toán cơ bản, tôi sẽ đề xuất phương pháp quá tải toán tử. Cái gì đó như:

 public final class ShapeOp 
 {
     static { ... }

     public static boolean collision( Shape s1, Shape s2 )  { ... }
     public static boolean collision( Point p1, Point p2 ) { ... }
     public static boolean collision( Point p1, Square s1 ) { ... }
     public static boolean collision( Point p1, Circle c1 ) { ... }
     public static boolean collision( Point p1, Line l1 ) { ... }
     public static boolean collision( Square s1, Point p2 ) { ... }
     public static boolean collision( Square s1, Square s2 ) { ... }
     public static boolean collision( Square s1, Circle c1 ) { ... }
     public static boolean collision( Square s1, Line l1 ) { ... }
     (...)

Trên intializer tĩnh, tôi sẽ sử dụng sự phản chiếu để tạo ra một bản đồ của các phương thức để thực hiện một phân tán diocate trên phương thức va chạm chung (Shape s1, Shape s2). Intializer tĩnh cũng có thể có logic để phát hiện các hàm va chạm bị thiếu và báo cáo chúng, từ chối tải lớp.

Đây là loại tương tự như quá tải toán tử C ++. Trong C ++, quá tải toán tử rất khó hiểu vì bạn có một bộ ký hiệu cố định mà bạn có thể quá tải. Tuy nhiên, khái niệm này rất thú vị và có thể được nhân rộng với các hàm tĩnh.

Lý do tại sao tôi sẽ sử dụng phương pháp này là va chạm không phải là một hoạt động trên một đối tượng. Va chạm là một hoạt động bên ngoài cho biết một số quan hệ về hai đối tượng tùy ý. Ngoài ra, trình khởi tạo tĩnh sẽ có thể kiểm tra nếu tôi bỏ lỡ một số chức năng va chạm.

Đơn giản hóa bài toán của bạn nếu có thể

Như tôi đã đề cập, số lượng các hàm va chạm là bình phương của số loại hình dạng. Điều này có nghĩa là trong một hệ thống chỉ có 20 hình dạng, bạn sẽ cần 400 thói quen, với 21 hình dạng 441, v.v. Điều này không dễ dàng mở rộng.

Nhưng bạn có thể đơn giản hóa toán học của bạn . Thay vì mở rộng chức năng va chạm, bạn có thể rasterize hoặc tam giác mọi hình dạng. Bằng cách đó, động cơ va chạm không cần phải mở rộng. Va chạm, Khoảng cách, Giao lộ, Sáp nhập và một số chức năng khác sẽ là phổ quát.

Tam giác

Bạn có nhận thấy hầu hết các gói và trò chơi 3d sắp xếp mọi thứ không? Đó là một trong những hình thức đơn giản hóa toán học. Điều này áp dụng cho hình dạng 2d quá. Polys có thể được tam giác. Các vòng tròn và spline có thể được xấp xỉ với các poligons.

Một lần nữa ... bạn sẽ có một chức năng va chạm duy nhất. Lớp của bạn trở thành sau đó:

public class Shape 
{
    public Triangle[] triangulate();
}

Và hoạt động của bạn:

public final class ShapeOp
{
    public static boolean collision( Triangle[] shape1, Triangle[] shape2 )
}

Đơn giản hơn phải không?

Rasterize

Bạn có thể rasterize hình dạng của bạn để có một chức năng va chạm duy nhất.

Rasterization dường như là một giải pháp căn cơ, nhưng có thể phải chăng và nhanh chóng tùy thuộc vào mức độ chính xác của sự va chạm hình dạng của bạn. Nếu chúng không cần chính xác (như trong trò chơi), bạn có thể có bitmap độ phân giải thấp. Hầu hết các ứng dụng không cần độ chính xác tuyệt đối về toán học.

Xấp xỉ có thể là đủ tốt. Siêu máy tính ANTON cho mô phỏng sinh học là một ví dụ. Toán học của nó loại bỏ rất nhiều hiệu ứng lượng tử khó tính toán và cho đến nay các mô phỏng được thực hiện phù hợp với các thí nghiệm được thực hiện trong thế giới thực. Các mô hình đồ họa máy tính PBR được sử dụng trong các công cụ trò chơi và gói kết xuất giúp đơn giản hóa giúp giảm công suất máy tính cần thiết để hiển thị từng khung. Không thực sự chính xác về mặt ngữ pháp nhưng đủ gần để có thể thuyết phục bằng mắt thường.

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.