Apa praktik desain yang baik untuk menghindari bertanya jenis subkelas?

11

Saya telah membaca bahwa ketika program Anda perlu tahu kelas apa objek itu, biasanya menunjukkan cacat desain jadi saya ingin tahu apa praktik yang baik untuk menangani ini. Saya menerapkan Bentuk kelas dengan subclass yang berbeda diwarisi darinya seperti Circle, Polygon atau Rectangle dan saya memiliki algoritma yang berbeda untuk mengetahui apakah sebuah Circle bertabrakan dengan Polygon atau Rectangle. Lalu anggaplah kita punya dua contoh Shape dan ingin tahu jika satu bertabrakan dengan yang lain, dalam metode itu saya harus menyimpulkan apa jenis subclass adalah objek yang saya tabrak untuk mengetahui algoritma apa yang harus saya panggil tetapi, ini adalah desain atau praktik yang buruk? Ini adalah cara saya menyelesaikannya.

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);
    }
  }
}

Ini adalah pola desain yang buruk? Bagaimana saya bisa menyelesaikan ini tanpa harus menyimpulkan jenis subkelas?

Alejandro
sumber
1
Anda akhirnya mengetahui bahwa setiap Mesin Virtual misalnya Circle mengetahui setiap Bentuk-Jenis lainnya. Jadi mereka semua terhubung entah bagaimana solid. Dan segera setelah Anda menambahkan bentuk baru, seperti Segitiga, Anda akhirnya menambahkan dukungan Segitiga di mana-mana. Tergantung pada apa yang ingin Anda ubah lebih sering, apakah Anda akan menambahkan Bentuk baru, desain ini buruk. Karena Anda memiliki solusi sprawl - Dukungan Anda untuk segitiga harus ditambahkan di mana-mana. Alih-alih, Anda harus mengekstrak Collisiondetection Anda ke dalam Kelas terpisah, yang dapat bekerja dengan semua jenis dan mendelegasikan.
kemasan
IMO ini turun ke persyaratan kinerja. Semakin spesifik kode, semakin optimal dapat dan semakin cepat dijalankan. Dalam kasus ini (diimplementasikan, juga), memeriksa jenis adalah OK karena disesuaikan cek tabrakan bisa enourmously lebih cepat dari solusi generik. Tetapi ketika kinerja runtime tidak kritis, saya akan selalu pergi dengan pendekatan umum / polimorfik.
marstato
Terima kasih untuk semua, dalam hal ini kinerja saya sangat penting dan saya tidak akan menambahkan bentuk baru, mungkin saya melakukan pendekatan CollisionDetection, Namun saya masih harus tahu jenis subclass, haruskah saya menyimpan metode "Type getType ()" di Shape atau malah melakukan semacam "instance" dengan Shape di kelas CollisionDetection?
Alejandro
1
Tidak ada prosedur tabrakan yang efektif antara Shapeobjek abstrak . Logika Anda bergantung pada objek internal lain kecuali Anda memeriksa tabrakan untuk titik batas bool collide(x, y)(subset titik kontrol mungkin merupakan tradeoff yang baik). Kalau tidak, Anda perlu memeriksa jenisnya entah bagaimana - jika benar-benar diperlukan untuk abstraksi maka menghasilkan Collisionjenis (untuk objek dalam area aktor saat ini) harus menjadi pendekatan yang tepat.
gemetaran

Jawaban:

13

Polimorfisme

Selama Anda menggunakan getType()atau apa pun seperti itu, Anda tidak menggunakan polimorfisme.

Saya mengerti perasaan seperti Anda perlu tahu jenis apa yang Anda miliki. Tetapi pekerjaan apa pun yang ingin Anda lakukan sambil tahu itu harus benar-benar didorong ke dalam kelas. Maka Anda hanya memberi tahu kapan harus melakukannya.

Kode prosedural mendapat informasi kemudian mengambil keputusan. Kode berorientasi objek memberi tahu objek untuk melakukan sesuatu.
- Alec Sharp

Prinsip ini disebut tell, jangan tanya . Mengikutinya membantu Anda tidak menyebarkan detail seperti mengetik di sekitar dan membuat logika yang bekerja pada mereka. Melakukan itu mengubah kelas menjadi luar. Lebih baik menjaga perilaku itu di dalam kelas sehingga bisa berubah ketika kelas berubah.

Enkapsulasi

Anda bisa memberi tahu saya bahwa tidak ada bentuk lain yang akan dibutuhkan, tetapi saya tidak percaya Anda dan begitu juga Anda.

Efek bagus mengikuti enkapsulasi adalah mudah untuk menambahkan tipe baru karena detailnya tidak menyebar ke kode tempat mereka muncul ifdan masuk switchakal. Kode untuk tipe baru semua harus di satu tempat.

Jenis sistem deteksi tabrakan bodoh

Mari saya tunjukkan bagaimana saya merancang sistem pendeteksian tabrakan yang berkinerja dan bekerja dengan bentuk 2D apa pun dengan tidak peduli dengan jenisnya.

masukkan deskripsi gambar di sini

Katakanlah Anda seharusnya menggambar itu. Tampak sederhana. Semuanya lingkaran. Sangat menggoda untuk membuat kelas lingkaran yang memahami tumbukan. Masalahnya adalah ini mengirim kita ke garis pemikiran yang berantakan ketika kita membutuhkan 1000 lingkaran.

Kita seharusnya tidak memikirkan lingkaran. Kita harus memikirkan piksel.

Bagaimana jika saya katakan bahwa kode yang sama yang Anda gunakan untuk menggambar orang-orang ini adalah apa yang dapat Anda gunakan untuk mendeteksi ketika mereka menyentuh atau bahkan yang mana yang diklik pengguna.

masukkan deskripsi gambar di sini

Di sini saya telah menggambar setiap lingkaran dengan warna yang unik (jika mata Anda cukup bagus untuk melihat garis hitam, abaikan saja). Ini berarti setiap piksel dalam gambar tersembunyi ini memetakan kembali ke apa yang menariknya. Hashmap menangani hal itu dengan baik. Anda sebenarnya dapat melakukan polimorfisme dengan cara ini.

Gambar ini tidak harus Anda perlihatkan kepada pengguna. Anda membuatnya dengan kode yang sama dengan yang pertama. Hanya dengan warna berbeda.

Ketika pengguna mengklik pada lingkaran saya tahu persis lingkaran mana karena hanya satu lingkaran adalah warna itu.

Ketika saya menggambar lingkaran di atas yang lain saya dapat dengan cepat membaca setiap piksel yang akan saya timpa dengan membuangnya dalam satu set. Ketika saya selesai mengatur poin ke setiap lingkaran yang bertabrakan dan sekarang saya hanya perlu memanggil masing-masing satu kali untuk memberitahukannya tentang tabrakan.

Tipe baru: Persegi panjang

Ini semua dilakukan dengan lingkaran tetapi saya bertanya: apakah akan bekerja berbeda dengan persegi panjang?

Tidak ada pengetahuan lingkaran yang bocor ke sistem deteksi. Itu tidak peduli tentang jari-jari, keliling, atau titik pusat. Itu peduli tentang piksel dan warna.

Satu-satunya bagian dari sistem tabrakan ini yang perlu didorong ke dalam bentuk individual adalah warna yang unik. Selain itu bentuknya bisa saja memikirkan menggambar bentuknya. Itu yang mereka kuasai.

Sekarang ketika Anda menulis logika tabrakan, Anda tidak peduli subtipe apa yang Anda miliki. Anda menyuruhnya bertabrakan dan memberi tahu Anda apa yang ditemukan di bawah bentuk yang berpura-pura menggambar. Tidak perlu tahu tipe. Dan itu berarti Anda dapat menambahkan sub tipe sebanyak yang Anda suka tanpa harus memperbarui kode di kelas lain.

Pilihan implementasi

Sungguh, itu tidak perlu menjadi warna yang unik. Ini bisa menjadi referensi objek aktual dan menyimpan tingkat tipuan. Tapi itu tidak akan terlihat bagus ketika ditarik dalam jawaban ini.

Ini hanyalah satu contoh implementasi. Tentu ada yang lain. Apa yang ingin ditunjukkan ini adalah bahwa semakin dekat Anda membiarkan subtipe bentuk ini tetap dengan tanggung jawab tunggal mereka, semakin baik keseluruhan sistem bekerja. Kemungkinan ada solusi yang lebih cepat dan lebih sedikit memori tetapi jika mereka memaksa saya untuk menyebarkan pengetahuan tentang subtipe di sekitar saya akan enggan menggunakannya bahkan dengan keuntungan kinerja. Saya tidak akan menggunakannya kecuali saya jelas membutuhkannya.

Pengiriman ganda

Sampai sekarang saya benar-benar mengabaikan pengiriman ganda . Saya melakukan itu karena saya bisa. Selama logika bertabrakan tidak peduli dua jenis yang bertabrakan Anda tidak membutuhkannya. Jika Anda tidak membutuhkannya, jangan gunakan itu. Jika Anda merasa mungkin membutuhkannya, tunda berurusan dengannya selama mungkin. Sikap ini disebut YAGNI .

Jika Anda memutuskan Anda benar-benar membutuhkan berbagai jenis tabrakan maka tanyakan pada diri Anda apakah n subtipe benar-benar membutuhkan 2 jenis tabrakan. Sejauh ini saya telah bekerja sangat keras untuk memudahkan menambahkan subtipe bentuk lain. Saya tidak ingin merusaknya dengan implementasi pengiriman ganda yang memaksa lingkaran mengetahui kotak ada.

Berapa banyak jenis tabrakan di sana? Sedikit berspekulasi (hal yang berbahaya) menciptakan tumbukan elastis (goyang), tidak elastis (lengket), energik (meledak), dan destruktif (rusak). Mungkin ada lebih banyak tetapi jika ini kurang dari n 2 mari kita tidak merancang tabrakan kita.

Ini berarti ketika torpedo saya mengenai sesuatu yang menerima kerusakan, ia tidak harus TAHU itu mengenai kapal ruang angkasa. Hanya harus mengatakannya, "Ha ha! Kamu mengambil 5 poin kerusakan."

Hal-hal yang menangani kerusakan mengirimkan pesan kerusakan ke hal-hal yang menerima pesan kerusakan. Dengan cara itu Anda bisa menambahkan bentuk baru tanpa memberi tahu bentuk lain tentang bentuk baru. Anda hanya akan menyebar di sekitar jenis tabrakan baru.

Kapal luar angkasa dapat mengirim kembali ke torp "Ha ha! Kau mengambil 100 poin kerusakan." dan juga "Anda sekarang terjebak di lambung kapal saya". Dan torp dapat mengirim kembali "Yah, aku sudah selesai untuk jadi lupakan aku".

Tidak ada yang tahu persis apa masing-masing. Mereka hanya tahu bagaimana berbicara satu sama lain melalui antarmuka tabrakan.

Sekarang yakin, pengiriman ganda memungkinkan Anda mengontrol hal-hal lebih intim dari ini, tetapi apakah Anda benar-benar menginginkannya ?

Jika Anda melakukannya, setidaknya pikirkan tentang melakukan pengiriman ganda melalui abstraksi jenis tabrakan apa yang diterima bentuk dan bukan pada implementasi bentuk yang sebenarnya. Juga, perilaku tabrakan adalah sesuatu yang Anda dapat menyuntikkan sebagai ketergantungan dan mendelegasikan ketergantungan itu.

Performa

Kinerja selalu penting. Tapi itu tidak berarti itu selalu menjadi masalah. Tes kinerja. Jangan hanya berspekulasi. Mengorbankan segala sesuatu atas nama kinerja biasanya tidak mengarah pada kode performen.

candied_orange
sumber
Mari kita lanjutkan diskusi ini dalam obrolan .
candied_orange
+1 untuk "Anda dapat memberi tahu saya bahwa tidak ada bentuk lain yang akan diperlukan, tetapi saya tidak percaya Anda dan Anda juga tidak."
Tulains Córdova
Memikirkan piksel tidak akan membawa Anda ke mana pun jika program ini bukan tentang menggambar bentuk tetapi tentang perhitungan matematika murni. Jawaban ini menyiratkan bahwa Anda harus mengorbankan segalanya untuk kemurnian berorientasi objek yang dirasakan. Ini juga mengandung kontradiksi: Anda pertama kali mengatakan bahwa kami harus mendasarkan seluruh desain kami pada gagasan bahwa kami mungkin membutuhkan lebih banyak jenis bentuk di masa depan, kemudian Anda berkata "YAGNI". Akhirnya, Anda lalai yang membuatnya lebih mudah untuk menambahkan jenis sering berarti lebih sulit untuk menambahkan operasi, yang buruk jika hirarki jenis relatif stabil tetapi operasi banyak berubah.
Christian Hackl
7

Deskripsi masalah terdengar seperti Anda harus menggunakan Multimethods (alias Pengiriman ganda), dalam kasus khusus ini - Pengiriman ganda . Jawaban pertama panjang lebar tentang bagaimana menangani secara umum dengan bentuk bertabrakan dalam raster render, tapi saya percaya OP ingin solusi "vektor" atau mungkin seluruh masalah telah dirumuskan kembali dalam bentuk Bentuk, yang merupakan contoh klasik dalam penjelasan OOP.

Bahkan artikel wikipedia yang dikutip menggunakan metafora tabrakan yang sama, izinkan saya mengutip (Python tidak memiliki multimethod built-in seperti beberapa bahasa lain):

@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 ...

Jadi, pertanyaan selanjutnya adalah bagaimana mendapatkan dukungan untuk metode multimetode dalam bahasa pemrograman Anda.

Roman Susi
sumber
Ya, kasus khusus pengiriman Ganda alias Multimethods, ditambahkan ke jawaban
Roman Susi
5

Masalah ini membutuhkan desain ulang pada dua level.

Pertama, Anda perlu mengekstrak logika untuk mendeteksi tabrakan antara bentuk dari bentuk. Ini agar Anda tidak akan melanggar OCP setiap kali Anda perlu menambahkan bentuk baru ke model. Bayangkan Anda sudah memiliki Circle, Square, dan Rectangle. Anda kemudian dapat melakukannya seperti ini:

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

Selanjutnya, Anda harus mengatur metode yang tepat untuk dipanggil tergantung pada bentuk yang memanggilnya. Anda dapat melakukannya menggunakan polimorfisme dan Pola Pengunjung . Untuk mencapai ini, kita harus memiliki model objek yang sesuai. Pertama, semua bentuk harus mematuhi antarmuka yang sama:

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

Selanjutnya, kita harus memiliki kelas pengunjung orang tua:

    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);

}

Saya menggunakan kelas di sini bukan antarmuka, karena saya membutuhkan setiap objek pengunjung untuk memiliki atribut ShapeCollisionDetectortipe.

Setiap implementasi IShapeantarmuka akan memberi contoh pengunjung yang sesuai dan memanggil Acceptmetode yang sesuai dari objek yang berinteraksi dengan objek panggilan, seperti ini:

    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);
    }
}

Dan pengunjung spesifik akan terlihat seperti ini:

    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);
    }
}

Dengan cara ini, Anda tidak perlu mengubah kelas bentuk setiap kali Anda menambahkan bentuk baru, dan Anda tidak perlu memeriksa jenis bentuk untuk memanggil metode deteksi tabrakan yang tepat.

Kelemahan dari solusi ini adalah bahwa jika Anda menambahkan bentuk baru, Anda harus memperluas kelas ShapeVisitor dengan metode untuk bentuk itu (misalnya VisitTriangle(Triangle triangle)), dan akibatnya, Anda harus menerapkan metode itu di semua pengunjung lain. Namun, karena ini adalah ekstensi, dalam arti bahwa tidak ada metode yang ada diubah, tetapi hanya yang baru ditambahkan, ini tidak melanggar OCP , dan overhead kode minimal. Selain itu, dengan menggunakan kelas ShapeCollisionDetector, Anda menghindari pelanggaran SRP dan Anda menghindari redundansi kode.

Vladimir Stokic
sumber
5

Masalah dasar Anda adalah bahwa dalam kebanyakan bahasa pemrograman OO modern kelebihan fungsi tidak berfungsi dengan ikatan dinamis (yaitu jenis argumen fungsi ditentukan pada waktu kompilasi). Yang Anda perlukan adalah pemanggilan metode virtual yang virtual pada dua objek, bukan hanya satu. Metode seperti ini disebut multi-metode . Namun, ada cara untuk meniru perilaku ini dalam bahasa seperti Java, C ++, dll. Di sinilah pengiriman ganda sangat berguna.

Ide dasarnya adalah Anda memanfaatkan polimorfisme dua kali. Ketika dua bentuk bertabrakan, Anda dapat memanggil metode tumbukan yang benar dari salah satu objek melalui polimorfisme dan melewati objek lain dari jenis bentuk umum. Dalam metode yang disebut Anda kemudian tahu apakah objek ini adalah lingkaran, persegi panjang atau apa pun. Anda kemudian memanggil metode tumbukan pada objek bentuk berlalu dan meneruskannya objek ini . Panggilan kedua ini sekali lagi menemukan jenis objek yang benar melalui polimorfisme.

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
  }

  // ...
}

Namun, kelemahan besar dari teknik ini adalah bahwa setiap kelas dalam hierarki harus tahu tentang semua saudara kandung. Ini menempatkan beban perawatan yang tinggi jika bentuk baru ditambahkan kemudian.

sigy
sumber
2

Mungkin ini bukan cara terbaik untuk mendekati masalah ini

Tabrakan bentuk behing matematika khusus untuk kombinasi bentuk. Berarti jumlah sub-rutin yang Anda perlukan adalah kuadrat dari jumlah bentuk yang Anda dukung sistem. Tabrakan bentuk sebenarnya bukan operasi pada bentuk, tetapi operasi yang mengambil bentuk sebagai parameter.

Strategi Kelebihan Operator

Jika Anda tidak dapat menyederhanakan masalah matematika yang mendasarinya, saya akan merekomendasikan pendekatan kelebihan operator. Sesuatu seperti:

 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 ) { ... }
     (...)

Pada intializer statis saya akan menggunakan refleksi untuk membuat peta metode untuk menerapkan diynamic dispather pada metode tabrakan generik (Shape s1, Shape s2). Intializer statis juga dapat memiliki logika untuk mendeteksi fungsi tabrakan yang hilang dan melaporkannya, menolak untuk memuat kelas.

Ini mirip dengan kelebihan operator C ++. Dalam C ++ operator overload sangat membingungkan karena Anda memiliki satu set simbol yang dapat Anda overload. Namun, konsepnya sangat menarik dan dapat direplikasi dengan fungsi statis.

Alasan mengapa saya akan menggunakan pendekatan ini adalah bahwa tabrakan bukanlah operasi atas suatu objek. Tabrakan adalah operasi eksternal yang mengatakan beberapa hubungan tentang dua objek yang berubah-ubah. Juga, penginisialisasi statis akan dapat memeriksa apakah saya melewatkan beberapa fungsi tabrakan.

Sederhanakan masalah matematika Anda jika memungkinkan

Seperti yang saya sebutkan, jumlah fungsi tabrakan adalah kuadrat dari jumlah jenis bentuk. Ini berarti bahwa dalam sistem dengan hanya 20 bentuk Anda akan membutuhkan 400 rutin, dengan 21 bentuk 441 dan seterusnya. Ini tidak mudah diperluas.

Tetapi Anda dapat menyederhanakan matematika Anda . Alih-alih memperluas fungsi tabrakan Anda dapat merasterisasi atau melakukan triangulasi setiap bentuk. Dengan begitu mesin tabrakan tidak perlu diperpanjang. Tabrakan, Jarak, Persimpangan, Penggabungan dan beberapa fungsi lainnya akan bersifat universal.

Triangulasi

Apakah Anda memperhatikan sebagian besar paket dan permainan 3d melakukan triangulasi segalanya? Itu adalah salah satu bentuk penyederhanaan matematika. Ini berlaku untuk bentuk 2d juga. Polys dapat triangulasi. Lingkaran dan spline dapat didekati dengan poligon.

Sekali lagi ... Anda akan memiliki fungsi tabrakan tunggal. Kelas Anda menjadi:

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

Dan operasi Anda:

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

Lebih sederhana bukan?

Rasterisasi

Anda dapat meraster bentuk Anda untuk memiliki fungsi tumbukan tunggal.

Rasterisasi mungkin terlihat sebagai solusi radikal, tetapi mungkin terjangkau dan cepat tergantung pada seberapa tepat benturan bentuk Anda. Jika mereka tidak perlu tepat (seperti dalam game), Anda mungkin memiliki bitmap resolusi rendah. Sebagian besar aplikasi tidak membutuhkan ketepatan mutlak pada matematika.

Perkiraan mungkin cukup baik. Superkomputer ANTON untuk simulasi biologi adalah contohnya. Matematikanya membuang banyak efek kuantum yang sulit dihitung dan sejauh ini simulasi yang dibuat konsisten dengan eksperimen yang dibuat di dunia nyata. Model grafis komputer PBR yang digunakan dalam mesin gim dan paket render membuat penyederhanaan yang mengurangi daya komputer yang diperlukan untuk membuat setiap frame. Sebenarnya tidak akurat secara fisik tetapi cukup dekat untuk meyakinkan dengan mata telanjang.

Lucas
sumber