سؤال

مع مساعدة من تجاوز سعة مكدس المجتمع لقد كتبت الأساسية جدا ولكن متعة الفيزياء محاكاة.

alt text

انقر واسحب الماوس لإطلاق الكرة.سوف ترتد حول تتوقف في نهاية المطاف على "الكلمة".

بلدي الكبير المقبل ميزة أريد أن أضيف في كرة الاصطدام.حركة الكرة هو كسر في x و y سرعة ناقلات.لدي الجاذبية (صغيرة تخفيض y ناقلات كل خطوة) لدي الاحتكاك (انخفاض صغير من كل من نواقل كل تصادم مع الجدار).الكرات بصراحة التحرك في واقعية بشكل مدهش الطريق.

اعتقد ان السؤال جزئين:

  1. ما هي أفضل طريقة للكشف عن الكرة إلى الكرة الاصطدام ؟
    هل لدي O(n^2) الحلقة أن تتكرر على كل كرة و يتحقق كل كرة أخرى لمعرفة ما اذا كان نصف قطر تتداخل ؟
  2. ما المعادلات هل يمكنني استخدام للتعامل مع الكرة إلى الكرة التصادم?فيزياء 101
    كيف هو تأثير اثنين من الكرات سرعة x/y النواقل ؟ ما هو الناتج اتجاه الكرات اثنين رأسك ؟ كيف ينطبق هذا على كل الكرة ؟

alt text

التعامل مع كشف التصادم من "الجدران" و الناتجة ناقلات التغييرات كانت سهلة ولكن أرى المزيد من المضاعفات مع الكرة الكرة التصادم.مع الجدران أنا ببساطة أن تأخذ السلبية المناسبة x أو y ناقلات وخارج أنها سوف تذهب في الاتجاه الصحيح.مع الكرات أنا لا أعتقد أنه من هذا الطريق.

بعض التوضيحات:البساطة أنا موافق تماما مع مرونة الاصطدام الآن أيضا كل الكرات لها نفس الكتلة الآن ولكن ربما يتغير ذلك في المستقبل.


تحرير:موارد لقد وجدت من المفيد

2d فيزياء الكرة مع المتجهات: 2-الأبعاد الاصطدامات من دون علم المثلثات.pdf
2d الكرة الكشف عن التصادم على سبيل المثال: مضيفا الكشف عن التصادم


النجاح!

لقد الكرة الكشف عن التصادم والاستجابة عمل عظيم!

كود ذات الصلة:

كشف التصادم:

for (int i = 0; i < ballCount; i++)  
{  
    for (int j = i + 1; j < ballCount; j++)  
    {  
        if (balls[i].colliding(balls[j]))  
        {
            balls[i].resolveCollision(balls[j]);
        }
    }
}

هذا وسوف تحقق التصادم بين كل الكرة ولكن تخطي زائدة الشيكات (إذا كان لديك للتحقق مما إذا الكرة 1 يصطدم مع الكرة 2 إذا كنت لا تحتاج إلى التحقق إذا الكرة 2 يصطدم مع الكرة 1.كما أنه يتخطى التحقق من التصادم مع نفسه).

ثم في الكرة الطبقة لدي الاصطدام() و resolveCollision() الأساليب:

public boolean colliding(Ball ball)
{
    float xd = position.getX() - ball.position.getX();
    float yd = position.getY() - ball.position.getY();

    float sumRadius = getRadius() + ball.getRadius();
    float sqrRadius = sumRadius * sumRadius;

    float distSqr = (xd * xd) + (yd * yd);

    if (distSqr <= sqrRadius)
    {
        return true;
    }

    return false;
}

public void resolveCollision(Ball ball)
{
    // get the mtd
    Vector2d delta = (position.subtract(ball.position));
    float d = delta.getLength();
    // minimum translation distance to push balls apart after intersecting
    Vector2d mtd = delta.multiply(((getRadius() + ball.getRadius())-d)/d); 


    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / getMass(); 
    float im2 = 1 / ball.getMass();

    // push-pull them apart based off their mass
    position = position.add(mtd.multiply(im1 / (im1 + im2)));
    ball.position = ball.position.subtract(mtd.multiply(im2 / (im1 + im2)));

    // impact speed
    Vector2d v = (this.velocity.subtract(ball.velocity));
    float vn = v.dot(mtd.normalize());

    // sphere intersecting but moving away from each other already
    if (vn > 0.0f) return;

    // collision impulse
    float i = (-(1.0f + Constants.restitution) * vn) / (im1 + im2);
    Vector2d impulse = mtd.normalize().multiply(i);

    // change in momentum
    this.velocity = this.velocity.add(impulse.multiply(im1));
    ball.velocity = ball.velocity.subtract(impulse.multiply(im2));

}

المصدر مدونة: المصدر الكامل على الكرة إلى الكرة مصادم.

إذا كان أي شخص لديه بعض الاقتراحات حول كيفية تحسين هذا الفيزياء الأساسية محاكاة اسمحوا لي أن أعرف!شيء واحد لم لإضافة هو الزخم الزاوي حتى الكرات سوف لفة أكثر واقعية.أي اقتراحات أخرى ؟ ترك تعليق!

هل كانت مفيدة؟

المحلول

لاكتشاف ما إذا كان اثنين من الكرات تصطدم, مجرد التحقق من ما إذا كانت المسافة بين مراكز أقل من مرتين في دائرة نصف قطرها.أن تفعل تماما مرنة تصادم بين الكرات ، تحتاج فقط إلى القلق حول عنصر السرعة في اتجاه التصادم.العنصر الآخر (الظل الى الاصطدام) سوف تبقى نفسها من أجل كل الكرات.يمكنك الحصول على الاصطدام المكونات من خلال إنشاء وحدة ناقلات مشيرا في الاتجاه من كرة واحدة إلى أخرى ، ثم أخذ المنتج نقطة مع سرعة النواقل من الكرات.ثم يمكنك توصيل هذه المكونات إلى 1D تماما مرنة الاصطدام المعادلة.

ويكيبيديا لديها جيدة ملخص العملية برمتها.عن كرات من أي كتلة جديدة السرعات يمكن حسابها باستخدام المعادلات (حيث v1 و v2 هي السرعات بعد الاصطدام ، u1, u2 من قبل):

v_{1} = \frac{u_{1}(m_{1}-m_{2})+2m_{2}u_{2}}{m_{1}+m_{2}}

v_{2} = \frac{u_{2}(m_{2}-m_{1})+2m_{1}u_{1}}{m_{1}+m_{2}}

إذا الكرات لها نفس كتلة ثم السرعات هي ببساطة تبديل.هنا بعض التعليمات البرمجية التي كتبت يفعل شيئا من هذا القبيل:

void Simulation::collide(Storage::Iterator a, Storage::Iterator b)
{
    // Check whether there actually was a collision
    if (a == b)
        return;

    Vector collision = a.position() - b.position();
    double distance = collision.length();
    if (distance == 0.0) {              // hack to avoid div by zero
        collision = Vector(1.0, 0.0);
        distance = 1.0;
    }
    if (distance > 1.0)
        return;

    // Get the components of the velocity vectors which are parallel to the collision.
    // The perpendicular component remains the same for both fish
    collision = collision / distance;
    double aci = a.velocity().dot(collision);
    double bci = b.velocity().dot(collision);

    // Solve for the new velocities using the 1-dimensional elastic collision equations.
    // Turns out it's really simple when the masses are the same.
    double acf = bci;
    double bcf = aci;

    // Replace the collision velocity components with the new ones
    a.velocity() += (acf - aci) * collision;
    b.velocity() += (bcf - bci) * collision;
}

كما الكفاءة ريان فوكس هو الحق ، يجب النظر في تقسيم المنطقة إلى أقسام ، ثم القيام الكشف عن التصادم داخل كل قسم.نضع في اعتبارنا أن الكرات يمكن أن تتصادم مع غيرها من الكرات على حدود القسم ، لذلك قد جعل التعليمات البرمجية الخاصة بك أكثر من ذلك بكثير تعقيدا.الكفاءة ربما لا يهم حتى يكون لديك عدة مئات من الكرات على الرغم من.للحصول على نقاط المكافأة ، يمكنك تشغيل كل قسم على مختلف الأساسية ، أو تقسيم معالجة التصادم داخل كل قسم.

نصائح أخرى

حسنا, منذ سنوات جعلت البرنامج مثلك المقدمة هنا.
هناك واحد مخفي المشكلة (أو كثير ، يعتمد على وجهة نظر):

  • إذا كانت سرعة الكرة أيضا عالية, يمكنك أن تفوت الاصطدام.

و أيضا, تقريبا في 100% من الحالات الجديدة سرعات سوف يكون من الخطأ.حسنا, لا سرعات, ولكن المواقف.لديك لحساب جديد سرعات بالضبط في المكان الصحيح.وإلا كنت مجرد نقل الكرات على بعض "خطأ" المبلغ المتوفر في السابق منفصلة الخطوة.

الحل واضح:لديك لتقسيم timestep حتى أن أول تحول لك إلى المكان الصحيح ، ثم تتصادم ، ثم تحول بقية من الوقت لديك.

يجب عليك استخدام الفضاء التقسيم لحل هذه المشكلة.

تقرأ على ثنائي تقسيم مساحة و Quadtrees

توضيح إلى اقتراح ريان فوكس تقسيم الشاشة إلى مناطق فقط التحقق من التصادم داخل المناطق...

على سبيل المثالتقسيم منطقة اللعب إلى شبكة من المربعات (والتي سوف تعسفا أقول هي من 1 وحدة طول كل جانب) ، تحقق التصادم داخل كل مربع الشبكة.

هذا هو بالتأكيد الحل الصحيح.المشكلة الوحيدة مع ذلك (كما ملصق آخر أشار) هو أن التصادم عبر الحدود هي المشكلة.

الحل هذا هو تراكب الشبكة الثانية في 0.5 وحدة الرأسي والأفقي تعويض لأول واحد.

ثم أي اصطدام ذلك سيكون عبر الحدود في أول شبكة (وبالتالي لم يتم الكشف) سيكون ضمن شبكة من المربعات في الشبكة الثانية.طالما كنت تتبع التصادم لقد سبق التعامل معها (كما أن هناك احتمالا أن يكون هناك بعض التداخل) كنت لا داعي للقلق حول التعامل مع الحالات الحافة.كل التصادم سيكون ضمن شبكة مربع على إحدى الشبكات.

وسيلة جيدة للحد من عدد من الاصطدام الشيكات هو تقسيم الشاشة إلى أقسام مختلفة.فقط قارن بين كل كرة من الكرات في نفس القسم.

شيء واحد أنا أرى هنا إلى تحسين.

بينما أنا لا أتفق أن الكرات ضرب عندما تكون المسافة مجموع أقطار ينبغي للمرء أبدا في الواقع حساب هذه المسافة!بل يحسب انها ساحة العمل معها بهذه الطريقة.ليس هناك سبب أن تكلفة الجذر التربيعي العملية.

أيضا, مرة واحدة كنت قد وجدت الاصطدام عليك أن تستمر في تقييم التصادم حتى لا تبقى.المشكلة هي أن الأولى قد يسبب الآخرين التي يجب حلها قبل أن يمكنك الحصول على صورة دقيقة.النظر في ما يحدث إذا كان يضرب الكرة الكرة على حافة الهاوية ؟ الكرة الثانية يضرب ايدج على الفور متابعات في الكرة الأولى.إذا كنت الانفجار في كومة من الكرات في الزاوية هل يمكن أن يكون عدد غير قليل من الاصطدامات التي يتعين حلها قبل أن تتمكن من تكرار الدورة القادمة.

أما بالنسبة O(n^2), كل ما عليك فعله هو تقليل تكلفة رفض تلك التي تفوت:

1) الكرة التي لا تتحرك لا تستطيع ضرب أي شيء.إذا كان هناك عدد معقول من الكرات ملقاة على الأرض هذا يمكن أن ينقذ الكثير من الاختبارات.(ملاحظة أنه يجب أن لا تزال تحقق إذا كان هناك شيء ضرب كرة ثابتة.)

2) شيء قد يكون من المفيد القيام:تقسيم الشاشة إلى عدد من المناطق ولكن يجب أن تكون خطوط غامض--الكرات على حافة المنطقة المذكورة كما يجري في كل ذات الصلة (يمكن أن يكون 4) مناطق.وأود أن استخدام شبكة 4x4, تخزين المناطق بت.إذا كان من مناطق اثنين من الكرات مناطق بإرجاع صفر في نهاية الاختبار.

3) كما ذكرت لا الجذر التربيعي.

وجدت صفحة ممتازة مع المعلومات على كشف التصادم والاستجابة في 2D.

http://www.metanetsoftware.com/technique.html

أنها محاولة لشرح كيف يتم ذلك من وجهة نظر أكاديمية.أنها تبدأ مع بسيطة كائن إلى كائن الكشف عن التصادم ، والانتقال إلى الاصطدام الاستجابة وكيفية نطاق عنه.

تحرير: تحديث الرابط

لديك اثنين من طرق سهلة للقيام بذلك.جاي وقد غطت طريقة دقيقة من التحقق من مركز الكرة.

أسهل طريقة هي استخدام مستطيل إحاطة مربع تعيين حجم مربع إلى 80% من حجم الكرة و سوف محاكاة التصادم بشكل جيد.

إضافة أسلوب الكرة الدرجة:

public Rectangle getBoundingRect()
{
   int ballHeight = (int)Ball.Height * 0.80f;
   int ballWidth = (int)Ball.Width * 0.80f;
   int x = Ball.X - ballWidth / 2;
   int y = Ball.Y - ballHeight / 2;

   return new Rectangle(x,y,ballHeight,ballWidth);
}

ثم في حلقة الخاص بك:

// Checks every ball against every other ball. 
// For best results, split it into quadrants like Ryan suggested. 
// I didn't do that for simplicity here.
for (int i = 0; i < balls.count; i++)
{
    Rectangle r1 = balls[i].getBoundingRect();

    for (int k = 0; k < balls.count; k++)
    {

        if (balls[i] != balls[k])
        {
            Rectangle r2 = balls[k].getBoundingRect();

            if (r1.Intersects(r2))
            {
                 // balls[i] collided with balls[k]
            }
        }
    }
}

أرى أنه ألمح هنا وهناك ، ولكن يمكنك أيضا أن تفعل أسرع الحساب أولا ، مثل مقارنة المربعات المحيطة التداخل ، ومن ثم القيام دائرة نصف قطرها القائم على التداخل إذا كان هذا أول اختبار يمر.

إضافة/الفرق الرياضيات هو أسرع بكثير عن المربع المحيط من كل علم حساب المثلثات عن دائرة نصف قطرها, و في معظم الأحيان المربع المحيط الاختبار سيتم استبعاد إمكانية حدوث تصادم.ولكن إذا كنت ثم إعادة الاختبار مع علم حساب المثلثات, كنت الحصول على دقة النتائج التي كنت تبحث عن.

نعم انها اختبارين ، ولكن سيكون أسرع بشكل عام.

هذا KineticModel هو تنفيذ استشهد النهج في جاوة.

لقد نفذت هذه التعليمات البرمجية في جافا سكريبت باستخدام HTML عنصر قماش, وأنتجت رائعة المحاكاة في 60 لقطة في الثانية.بدأت المحاكاة مع مجموعة من عشرات الكرات في المواقف العشوائية و السرعات.وجدت أن في سرعات أعلى ، نظرة عابرة تصادم بين الكرة الصغيرة و أحد أكبر بكثير تسبب في الكرة الصغيرة لتظهر عصا إلى حافة أكبر الكرة و نقل ما يصل إلى حوالي 90 درجة حول أكبر الكرة قبل أن يفصل.(وأتساءل عما إذا كان أي شخص آخر لاحظ هذا السلوك.)

بعض تسجيل الحسابات أظهرت أن الحد الأدنى الترجمة المسافة في هذه الحالات لم تكن كبيرة بما يكفي لمنع الكرات من الاصطدام في المرة القادمة خطوة.فعلت بعض التجارب وجدت أن أتمكن من حل هذه المشكلة عن طريق زيادة مليون دينار على أساس السرعات النسبية:

dot_velocity = ball_1.velocity.dot(ball_2.velocity);
mtd_factor = 1. + 0.5 * Math.abs(dot_velocity * Math.sin(collision_angle));
mtd.multplyScalar(mtd_factor);

وأنا التحقق من ذلك قبل وبعد هذا الإصلاح مجموع الطاقة الحركية كان الحفظ عن كل تصادم.0.5 قيمة في mtd_factor كان تقريبا minumum قيمة وجدت دائما يسبب كرات منفصلة بعد الاصطدام.

على الرغم من أن هذا الإصلاح يدخل كمية صغيرة من الخطأ في الدقيقة الفيزياء نظام المقايضة هو أن الآن سريع جدا الكرات يمكن محاكاة في المتصفح دون تقليل الوقت حجم الخطوة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top