Итак, у меня есть игровое тело + приспособление и т. Д., Это, по сути, шар, который отскакивает.
Я хочу определить, когда он «довольно много» закончил двигаться.
На данный момент я это делаю:
public Boolean isStopped() { return body.getLinearVelocity().x <= 0.3f && body.getLinearVelocity().y <= 0.3f; }
Это в основном работает, проблема заключается в том, что когда игрок что-то наткнулся, есть секунда, где его скорость равна 0, так что это возвращает true. Я действительно хотел просто вернуть true, когда он в основном закончен. Предпочтительно, в пределах диапазона, который я могу установить на все, что мне нравится, когда я настраиваю физику своего игрового мира.
Я не могу использовать чек о том, спит он или нет, потому что это происходит слишком поздно, но он не спит до тех пор, пока он не прекратит оказывать на него силы, мне нужно как раз перед этим.
Я мог бы просто хранить, как долго он был остановлен / количество остановленных шагов, но я надеялся, что будет хороший предыдущий метод, который я пропустил.
Есть идеи?
Вы можете следить за последним движением и обновлять его, слегка перемешивая текущую скорость каждый раз:
float speedNow = body.getLinearVelocity().len(); recentSpeed = 0.1 * speedNow + 0.9 * recentSpeed; if ( recentSpeed < someThreshold ) ... do something ...
Для recentSpeed
вам нужно установить значение recentSpeed
на подходящее значение, иначе оно может быть ниже порога на первом шаге.
Видя, как вы определили, что ваши ложные срабатывания вызваны взаимодействием тела с другим, почему бы не добавить пару строк в метод beginContact вашего ContactListener, сохранив текущую скорость тела в своих пользовательских данных? Затем вы можете проверить скорость в методе isStopped. Если есть сохраненная скорость, и текущая скорость не больше, это означает, что тело находится в процессе отскакивания от того, что он ударил: ignore. Если есть запасенная скорость и текущая скорость больше, шар отскочил и движется в каком-то новом направлении: очистите сохраненную скорость. Если нет сохраненной скорости, и текущая скорость ниже вашего порога, вы обнаружили найденную ситуацию.
В вашем ContactListener:
public void beginContact(Contact contact) { Body a = contact.getFixtureA().getBody(); Body b = contact.getFixtureB().getBody(); if (a == mBall) { a.setUserData(a.getLinearVelocity().len()); } else if (b == mBall) { b.setUserData(b.getLinearVelocity().len()); } }
И в вашей проверке isStopped:
public Boolean isStopped() { float storedSpd = (Float) body.getUserData(); float currentSpd = body.getLinearVelocity().len(); if ((storedSpd > Float.MIN_VALUE) && (currentSpd > storedSpd)) { body.setUserData(Float.MIN_VALUE); return false; } else { return (currentSpd < THRESHOLD); } }
Это непроверено, но вы получаете идею. Кроме того, не забудьте сначала установить данные пользователя в Float.MIN_VALUE.
В конце концов я просто передал дельта от каждого вызова рендеринга методу isStopped ().
public Boolean isStopped(float delta) { boolean isMoving = ( Math.abs(body.getLinearVelocity().x) >= 0.25f || Math.abs(body.getLinearVelocity().y) >= 0.25f); if(isMoving) { timeStopped = 0f; return false; } else { timeStopped += delta; return timeStopped >= 0.3f; } }
TimeStopped – это просто свойство класса, начинающееся с нуля. Это действительно верно для начала игры (до того, как пользователь сделал ход), но в моем приложении это абсолютно нормально. Кроме того, верно, что он остановился в этом обстоятельстве.
Мне все еще хотелось бы видеть способ сделать это, не сохранив лишнее дерьмо, так как я предполагаю, что box2d должен иметь эту информацию где-то, чтобы выяснить, не имеет ли сила тела с нулевой скоростью, или если она просто меняется Направление после удара.