Basit bir 2D fizik motoru yapmak

EmomaxD

Hectopat
Katılım
3 Ağustos 2018
Mesajlar
44
Daha fazla  
Cinsiyet
Erkek
C++'da kendimi geliştirmek için bu tarz ilgimi çeken bir şey yapmaya karar verdim.
Zor bir şey olduğunu biliyorum şimdilik sadece serbest düşme ve çarpışma gibi fiziksel olayları yapmayı düşündüm. Yeni bilgiler edindikçe daha çok geliştirmeyi planlıyorum.
Sıkıntı şu; bana genel proje tasarımı hakkında bilgi verebilir misiniz mesela şöyle classların olsun bu classlar şöyle değişkenlere sahip olsun, şöyle layerların olsun, şu şey şunu kontrol etsin tarzında öneri ve tavsiyeleriniz varsa alabilirim.
Eğer benim kullanacağım bir kaynak biliyorsanız ve paylaşırsanız çok mutlu olurum.
İlk aşamada Core kısmını herhangi bir grafiksel bir şey olmadan kodlayacağım Console üzerinden verilerin doğru bir şekilde değişip değişmediğini kontrol etmek istiyorum.
Son olarak serbest düşmeyi yapabilmem için fikriniz varsa alabilirim. 5-15-25 şeklinde mesafe kat edecek ama bunu koda dökemedim geçen zamana bağlı olarak tam 1 saniye sonrasında hızını 10m/s ye ulaştırsam ve grafiğin altında kalan olarak hesaplasam sanırım olabilir(yazarken aklıma geldi hala tavsiyelere açığım)
Biliyorum kuvvetli bir matematik ve fizik gerekli, sıkıntı yaşayacağımı düşünmüyorum bu konuda.
 
Son düzenleyen: Moderatör:
Konudan bağımsız olarak söyleyeceğim. Böyle konuların açıldığını görünce aşırı garibime gidiyor. Şaşırıp kalıyorum. Nasıl böyle seviyelere geliyorsunuz anlamıyorum.

Daha şurada bir trigonometri içeren hesaplamayı düzgün bir şekilde koda dökemiyorum, sizler motor yazıyorsunuz. 😄
 
2D fizik motorunda belki de en çok uğraştıran ve zor olan şey çarpma ve cisimlerin kütle, hızlarına ve yön vektörüne göre çarpma sonrasında hangi yöne ve hangi ivme ile hareket edeceğidir.

Cisimlerin şekli daire ve dörtgen ise bu işlemleri kolaylaştıran yöntemler mevcut (AABB collision gibi.)
Ancak konveks olmayan (konkav) cisimlerin birbiri ile etkileştirmek, akışkanlar, yumuşak gövde simulasyonları gibi şeyleri implement edebilmek için ciddi miktarda fizik ve matematik bilmeniz gerekli.

Düşme ivmesi konusuna gelirsek çok basit.

X konumunda olan bir cisim, V hızına sahipse bir sonraki T zamanında X + V konumunda olur. Bu sabit hızla ilerleyen cisimler için böyledir. Eğer cisim ivmeli bir hareket yapıyorsa her bir T zamanında V'nin değeri A hızlanma ivmesi ile toplanır sonrasında X'e dahil edilir.

Bu A ivmesi yer çekimi olabilir. Başka bir cisim ile çarpışma sonrasındaki momentum farkından oluşan çarpışma ivmesi de fark etmez.

Java:
update = new Timeline(new KeyFrame(Duration.millis(1000), e -> {
     // Remove Collisions
     vecCollidingPairs.clear();
     // Static Collision
     for (Ball ball : Ball.balls)
     {
         ball.update();
     }
     for (Ball ball : Ball.balls)
     {
         // Against Edges
         for (Capsule edge : Capsule.capsules)
         {
             double x1 = edge.getEndX() - edge.getStartX();
             double y1 = edge.getEndY() - edge.getStartY();

             double x2 = ball.getX() - edge.getStartX();
             double y2 = ball.getY() - edge.getStartY();

             double edgeLength = Math.pow(x1, 2) + Math.pow(y1, 2);

             double t = Math.max(0, Math.min(edgeLength, (x1 * x2 + y1 * y2))) / edgeLength;

             double closestPointX = edge.getStartX() + t * x1;
             double closestPointY = edge.getStartY() + t * y1;

             double distEdge = Math.sqrt((ball.getX() - closestPointX) * (ball.getX() - closestPointX) + (ball.getY() - closestPointY) * (ball.getY() - closestPointY));

             if (distEdge <= (ball.getRadius() + edge.getRadius()))
             {
                 // Static collision has occured
                 Ball fakeball = new Ball(false);
                 fakeball.setRadius(edge.getRadius());
                 fakeball.setMass(ball.getMass() * 1.0);
                 fakeball.setX(closestPointX);
                 fakeball.setY(closestPointY);
                 fakeball.setVel(-ball.getVelX(), -ball.getVelY());

                 vecFakeBalls.add(fakeball);
                 vecCollidingPairs.add(new BallPairs(ball, fakeball));

                 double overl = 1.0 * (distEdge - ball.getRadius() - fakeball.getRadius());

                 // Displace Current Ball away from collision
                 ball.setX(ball.getX() - (overl * (ball.getX() - fakeball.getX()) / distEdge));
                 ball.setY(ball.getY() - (overl * (ball.getY() - fakeball.getY()) / distEdge));
             }
         }

         // Against Other Balls
         for (Ball target : Ball.balls)
         {
             if (ball.getId() != target.getId())
             {
                 if (Utils.isHit(ball, target))
                 {
                     // Collision has occured
                     vecCollidingPairs.add(new BallPairs(ball, target));
                     // Distance between ball centers
                     double distance = Utils.distance(ball, target);
                     double overlap = 0.5 * (distance - ball.getRadius() - target.getRadius());

                     // Displace Current Ball
                     ball.setX(ball.getX() - ((overlap * (ball.getX() - target.getX()) / distance)));
                     ball.setY(ball.getY() - ((overlap * (ball.getY() - target.getY()) / distance)));

                     // Displace Targer Ball
                     target.setX(target.getX() + ((overlap * (ball.getX() - target.getX()) / distance)));
                     target.setY(target.getY() + ((overlap * (ball.getY() - target.getY()) / distance)));
                 }
             }
         }
     }
     // Now work out dynamic collisions
     for (BallPairs c : vecCollidingPairs)
     {
         Ball b1 = c.getB1();
         Ball b2 = c.getB2();

         // Distance between balls
         double dist = Utils.distance(b1, b2);

         // Normal
         double nx = (b2.getX() - b1.getX()) / dist;
         double ny = (b2.getY() - b1.getY()) / dist;

         // Tangent
         double tx = -ny;
         double ty = nx;

         // Dot Product Tangent
         double dpTan1 = b1.getVelX() * tx + b1.getVelY() * ty;
         double dpTan2 = b2.getVelX() * tx + b2.getVelY() * ty;

         // Dot Product Normal
         double dpNorm1 = b1.getVelX() * nx + b1.getVelY() * ny;
         double dpNorm2 = b2.getVelX() * nx + b2.getVelY() * ny;

         // Conservation of momentum in 1D
         double m1 = (dpNorm1 * (b1.getMass() - b2.getMass()) + 2.0 * b2.getMass() * dpNorm2) / (b1.getMass() + b2.getMass());
         double m2 = (dpNorm2 * (b2.getMass() - b1.getMass()) + 2.0 * b1.getMass() * dpNorm1) / (b1.getMass() + b2.getMass());

         // Update ball velocities

         b1.setVel(tx * dpTan1 + nx * m1, ty * dpTan1 + ny * m1);
         b2.setVel(tx * dpTan2 + nx * m2, ty * dpTan2 + ny * m2);
     }

     // Remove fake balls
     vecFakeBalls.clear();
}));

Zamanında ben de basit bir 2D fizik motoru yazmıştım. Bu sadece update kısmı.
 
İşin doğası gereği bu basit bir süreç değildir. Başlangıç için buralara bakabilirsin
Bu içeriği görüntülemek için üçüncü taraf çerezlerini yerleştirmek için izninize ihtiyacımız olacak.
Daha detaylı bilgi için, çerezler sayfamıza bakınız.
Bu içeriği görüntülemek için üçüncü taraf çerezlerini yerleştirmek için izninize ihtiyacımız olacak.
Daha detaylı bilgi için, çerezler sayfamıza bakınız.
 

Geri
Yukarı