Прыгающий мяч на Яве - PullRequest
3 голосов
/ 04 марта 2009

Вероятно, это действительно основная проблема, но я не могу найти другие статьи по ней.

В любом случае, я написал небольшую программу для прыгающего мяча на Java, чтобы попытаться расширить свои базовые навыки. Программа представляет собой простой прыгающий шар, который упадет и , мы надеемся, подпрыгнет на некоторое время. Оригинальная программа работала нормально, но теперь я попытался добавить гравитации в программу. Некоторое время гравитация работает нормально, но затем, когда отскоки становятся очень маленькими, анимация очень ненадежная в течение очень короткого времени, тогда положение шара просто постоянно уменьшается. Я пытался выяснить проблему, но я просто не вижу ее. Любая помощь будет приветствоваться.

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 + = гравитации. Я просто не понимаю, как мне остановить движение.

Ответы [ 5 ]

3 голосов
/ 04 марта 2009

Когда вы делаете

yspeed += gravity;

вы предполагая , что у шара есть пространство, перемещающееся на расстояние dx = v_i * t + 1/2 (-g) t ^ 2. Когда вы очень близко к полу, это может быть не так. Сбой, если:

  • Вы достаточно близко к полу и двигаетесь вниз
  • Вы очень близко к полу и у вас низкая скорость (например, когда мяч потерял большую часть своей энергии)

Эта ошибка приводит к тому, что ваша симуляция прекращает экономить энергию , что приводит к ошибочному поведению, которое вы видите при низкой амплитуде.

Вы можете уменьшить эту проблему, используя меньшие временные шаги, и вы можете полностью избавиться от нее, если будете выполнять тестовые вычисления, чтобы заметить, когда вы выйдете из комнаты и выбрать безопасный временной шаг для , который итерация (т. е. всегда используйте значение по умолчанию, если нет проблем, затем рассчитайте лучший временной шаг).

Однако в используемом здесь базовом приближении есть и другие проблемы. В любом текстовом аналитическом тексте вы найдете обсуждение численного решения дифференциальных уравнений.

1 голос
/ 04 марта 2009

[РЕДАКТИРОВАТЬ: я думаю, что я неправильно понял, так что это, вероятно, не очень полезно :)]

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);
}
1 голос
/ 04 марта 2009

Проблема в том, что когда отскоки становятся очень маленькими,

yspeed *= -0.981;
Линия

будет вызвана в короткой последовательности. Мяч опустится ниже дна, начнет возвращаться вверх, но все равно будет ниже дна (потому что 0,981 <1,0) в конце концов, и будет вести себя эрадикально. Вот как это исправить: </p>

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

Фиксируя положение, вы не будете чередоваться между уменьшением и увеличением так же быстро и не будете застревать в ситуации, когда оно всегда уменьшается, потому что оно всегда ниже границ.

1 голос
/ 04 марта 2009

Перво-наперво: установка y-скорости на 1, когда вы подпрыгиваете в верхней части окна, неверна, вы должны установить yspeed на -yspeed (но если вы начинаете в пределах границ, она никогда не должна подпрыгивать до верха в любом случае).

Во-вторых, ваше умножение на -0,981, когда вы подпрыгиваете внизу, хорошо, но меня беспокоит постоянная сила тяжести 0,4, добавляемая к скорости yspeed на каждой итерации. Я думаю, это то, что заставляет вас покачиваться внизу, так как вы делаете движение перед проверкой, что может привести к падению шара ниже уровня земли.

Я бы попробовал убедиться, что значение y никогда не опустится ниже уровня земли, заменив движение на:

if (getY() + getHeight() + yspeed > 200) {
    move(xspeed, 200 - getY() - getHeight());
} else {
    move(xspeed, yspeed);
}
1 голос
/ 04 марта 2009

Я подозреваю, что это потому, что когда мяч подпрыгивает, он на самом деле будет немного ниже "земли", и на низких скоростях он не будет двигаться назад над землей за один тик - поэтому следующее обновление () увидит все еще под землей и снова подпрыгивают - но на этот раз вниз , поэтому цикл продолжается.

Вам нужно переместить мяч обратно на уровень земли, когда он отскакивает, что-то вроде этого:

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