سؤال

ربما تكون هذه مشكلة أساسية حقًا ، لكن لا يمكنني العثور على أي مقالات أخرى عليها.

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

public final class Ball extends Rectangle {
float xspeed = 1.0f; float yspeed = 1.0f; float gravity = 0.4f;


public Ball(float x, float y, float width, float height) {
    super(x, y, width, height);
}

public void update(){
    yspeed += gravity;

    move(xspeed, yspeed);

    if(getX() < 0){
        xspeed = 1;
    }
    if(getX() + getWidth() > 320){
        xspeed = -1;
    }
    if(getY() < 0){
        yspeed = 1;
    }
    if(getY() + getHeight() > 200 && yspeed > 0){
        yspeed *= -0.98f;
    }
    if(getY() + getHeight() > 200 && yspeed < 0){
        yspeed *= 0.98f;
    }

}

public void move(float x, float y){
    this.setX(getX()+x);
    this.setY(getY()+y);
}

}

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

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

المحلول

عندما تفعل

yspeed += gravity;

أنت على افتراض أن الكرة لديها مساحة تتحرك عبر مسافة dx = v_i * t + 1/2 (-g) t^2. عندما تكون بالقرب من الأرض ، قد لا يكون هذا صحيحًا. يفشل إذا:

  • أنت بالقرب من الأرض وتتحرك لأسفل
  • أنت بالقرب من الأرض ولديك سرعة منخفضة (مثل عندما فقدت الكرة معظم طاقتها)

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

يمكنك تقليل المشكلة باستخدام خطوات زمنية أصغر ، ويمكنك التخلص منها بشكل مباشر إذا قمت باختبار الحساب لتلاحظه عندما تكون خارج الغرفة وتحديد خطوة وقت آمنة لـ الذي - التي التكرار (أي دائمًا استخدم الافتراضي الخاص بك ما لم تكن هناك مشكلة ، ثم احسب أفضل خطوة زمنية).

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

نصائح أخرى

أول الأشياء أولاً: تعيين سرعة Y إلى 1 عندما ترتد في الجزء العلوي من النافذة غير صحيح ، يجب عليك تعيين yspeed على yspeed (ولكن إذا بدأت داخل الحدود ، فلن ترتد أبدًا إلى الأعلى على أي حال).

ثانياً ، تضاعفك بمقدار -0.981 عندما يكون الارتداد في القاع على ما يرام ، لكنني مهتم بالجاذبية الثابتة 0.4 التي يتم إضافتها إلى كل تكرار. أعتقد أن هذا هو ما يسبب لك تتشوه في الأسفل لأنك تقوم بهذه الخطوة قبل التحقق مما قد يؤدي إلى انخفاض الكرة إلى أسفل مستوى الأرض.

سأحاول التأكد من أن قيمة Y لا يمكن أن تنخفض أبدًا عن مستوى الأرض من خلال استبدال هذه الخطوة بـ:

if (getY() + getHeight() + yspeed > 200) {
    move(xspeed, 200 - getY() - getHeight());
} else {
    move(xspeed, yspeed);
}

المشكلة هي أنه عندما تصبح الارتداد صغيرة حقًا ،

yspeed *= -0.981;

سيتم استدعاء الخط في الخلافة القصيرة. ستذهب الكرة إلى أسفل القاع ، وتبدأ في العودة ، ولكن لا تزال تحت القاع (لأن 0.981 <1.0) في نهاية المطاف ، وسوف يتصرف بشكل مريح. إليك كيفية إصلاحه:

if(getY() + getHeight() > 200){
  yspeed *= -0.981;
  setY(400 - getY() - getHeight()); // I believe this is right.
}

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

تحرير: أعتقد أنني أسيء فهمه ، لذلك ربما لا يستخدم هذا كثيرًا :)

if(getY() + getHeight() > 200){
  yspeed *= -0.981;
}

أنت تنفي السرعة الرأسية في كل تحديث. من المحتمل أن أحاول التعامل مع الجاذبية في الشرائح بحجم التحديث. على افتراض أنك تقوم بـ 30 تحديثًا في الثانية (مقابل 30 إطارًا في الثانية) ، ربما شيء مثل

// Define some constants
SecondsPerUpdate = (1.0f / 30);
AccelDueToGravity = 0.981;

if(getY() + getHeight() > 200){
  yspeed -= (AccelDueToGravity * SecondsPerUpdate);
}

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

تحتاج إلى نقل الكرة مرة أخرى إلى مستوى الأرض عندما ترتد ، شيء من هذا القبيل:

    if(getY() + getHeight() > 200){
            yspeed *= -0.981;
            setY(200 - getHeight());
    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top