#box2d
#box2d
Вопрос:
Итак, я поиграл с box2d на iOS (подумал, что этот вопрос на самом деле не ограничивается iOS), и у меня есть небольшая демонстрация, в которой персонаж игрока прыгает, когда пользователь нажимает на экран через ApplyLinearImpulse
.
По большей части это работает. За исключением того, что если я нажму, когда игрок находится в воздухе, ApplyLinearImpulse
вызывается снова, и игрок снова «прыгает», но уже в воздухе. Было бы неплохо сделать это в реальной жизни, но вы не можете, и я бы предпочел, чтобы мой игрок тоже не мог этого делать.
Итак, я пытался придумать достойный способ предотвратить прыжки, когда игрок уже прыгает, и я не уверен, куда идти дальше — моя лучшая мысль — попробовать что-то вроде этого:
- Прикрепите корпус, который является просто датчиком, к нижней части моего плеера с помощью фиксированного шарнира.
- Когда игрок прыгает, отключите прыжки до тех пор, пока вышеупомянутый датчик не обнаружит столкновение (т. е. когда игрок «приземляется» на что-то, что может быть землей, а может и не быть).
- Как только столкновение было обнаружено, снова включите прыжки.
Я не уверен, насколько мне нравится эта идея, например, я не уверен, что прикрепление датчика к нижней части моего плеера является «самым умным» способом обнаружения столкновений в нижней части моего плеера sprite. Я еще не пробовал это, я хотел вместо этого получить информацию от SO и посмотреть, может ли кто-нибудь предложить лучшую альтернативу. Есть идеи?
Редактировать: у mafutrct было хорошее предложение: попробуйте какой-нибудь тест на попадание вниз, используя луч, направленный прямо вниз от тела моего игрока, и посмотрите, пересекает ли этот луч другой объект на небольшом расстоянии (т. Е. прямо под моим игроком) — возможен ли такой тип теста на попадание луча с box2d?
Комментарии:
1. iforce2d.net/b2dtut/jumpability — iforce2d для меня — это универсальное хранилище знаний box2d.
Ответ №1:
Мой голос отдается методу «датчик у ног игрока». Вы могли бы сделать сенсорное крепление ребром, если вам действительно нужна проверка типа луча, но в целом я думаю, что более полезно иметь возможность указывать область, особенно если ваш персонаж сможет стоять на нескольких предметах одновременно, и если вы заинтересованы в поддержании актуального списка того, на чем стоит. Если вы создаете тело игрока в графическом редакторе, то также будет более интуитивно понятно размещать сенсор и смотреть на него вместо того, чтобы запускать все это программно с помощью raycasts. Я считаю, что метод датчика стопы также требует меньших затрат процессора в целом и меньше работы, чем самостоятельное выполнение проверок raycast. Я написал подробное руководство по этому поводу, надеюсь, оно полезно:http://www.iforce2d.net/b2dtut/jumpability
Комментарии:
1. Я воспользовался вашим руководством (хотя нашел ссылку в другом месте) и считаю, что этот подход кажется надежным и сработал для меня.
Ответ №2:
Вам нужно проверить, касаются ли ноги земли в момент прыжка.
В зависимости от вашей модели, измерьте расстояние между вашими ногами и землей. Либо примените вектор из центра модели и проверьте попадание в вершину, либо (более сложный способ) проверьте первое вертикальное попадание в многоугольник, описывающий область ваших ног с землей.
Простая проверка на любое столкновение завершается неудачей, поскольку вы можете упереться в стену, которая все равно считается воздушной (если вы не играете в Unreal Tournament, в котором это прыжок со стены).
Я не знаком с вашим программным обеспечением, так что это всего лишь идея — было бы здорово, если бы это действительно было полезно. Удачи 🙂
Комментарии:
1. Хм, проблема с проверкой только по земле заключается в том, что игрок вполне может приземлиться на что-то, что находится над землей, то есть на коробку, которая стоит на земле. Я не уверен, что этого будет достаточно.
2. Да, вам нужно выполнить тест попадания вниз. Если расстояние до удара небольшое, вы касаетесь земли. Если он большой, вы все еще в воздухе.
3. Вопрос, как описано в ответе выше, заключается в том, как выполнить тест попадания — вы хотите протестировать только одну точку, обычно луч, направленный прямо вниз от центра вашей модели, или вы хотите использовать более сложный тест (т. Е. полигон)? Я предполагаю, что первого достаточно, поскольку вы все еще можете расширить и улучшить его позже, если это необходимо.
4. Да — я думаю, это имеет гораздо больше смысла. Вы знаете, поддерживает ли box2d какой-либо тест попадания, подобный тому, что вы описываете? Похоже, это именно то, что мне нужно.
5. Извините, но я этого не знаю. Я надеюсь, вы сможете найти способ (возможно, в Google?) — или, может быть, создать другой вопрос по SO 🙂
Ответ №3:
Способ решить эту проблему — создать класс, который реализует ContactListener, а затем, когда вы создаете Мир, вы .setContactListener() присваиваете своему классу. Теперь ваш класс будет уведомляться обо всех столкновениях. Оттуда вы создаете флажок, показывающий, находится ли игрок в контакте с какими-либо наземными объектами.
Предположим, что вы установили пользовательские данные фигур в соответствующие GameObjects ( shapeDef.userData = this;
в конструкторе GameObject). Предположим, у вас есть перечисление, которое определяет типы GameObject в вашей игре, тогда у вас есть контактный прослушиватель в соответствии с этими строками:
импортируйте org.jbox2d.dynamics.ContactListener; импортируйте org.jbox2d.dynamics.contacts.Точка контакта; импортируйте org.jbox2d.dynamics.contacts.ContactResu< импортируйте android.util.Log; импортируйте GameObject.GAME_OBJECT_TYPE; открытый класс CollisionChecker реализует ContactListener { частное логическое столкновение с землей = false; @Переопределить добавить общедоступную пустоту (точка контакта arg0) { // Вызывается при добавлении точки контакта. Это включает в себя геометрию и силы. } @Переопределить сохраняется общедоступная пустота (точка контакта arg0) { // Вызывается, когда точка контакта сохраняется. Это включает в себя геометрию и силы. } @Переопределить удаление общедоступной пустоты (точка контакта arg0) { // Вызывается, когда точка контакта удалена. Это включает в себя последнюю вычисленную геометрию и силы. } @Переопределить результат public void (ContactResult arg0) { // Это вызывается после разрешения коллизии GAME_OBJECT_TYPE a = ((GameObject) arg0.shape1.getUserData()).GetType(); GAME_OBJECT_TYPE b = ((GameObject) arg0.shape2.getUserData()).GetType(); // проверьте наличие земли groundCollision = проверка(a, b, GAME_OBJECT_TYPE.ground); } частная логическая проверка (ТЕСТ GAME_OBJECT_TYPE a, ТЕСТ GAME_OBJECT_TYPE b, тест GAME_OBJECT_TYPE){ если (a == test amp;amp; b == GAME_OBJECT_TYPE.player){ верните true; } иначе, если (a == GAME_OBJECT_TYPE.player amp;amp; b == тест){ верните true; } возвращает false; } общедоступное логическое значение - groundcollision(){ вернуть столкновение с землей; } public void step() { /* если (столкновение с землей) Log.d("COLLSN", "У нас столкновение с землей");*/ //после логического завершения сбросьте переменные состояния сброс (); } сброс приватной пустоты (){ Столкновение с землей = false; } }
Теперь вы создаете логическое значение прыжка в вашем плеере. Когда он подпрыгнет, установите для него значение true. Он больше не может прыгать, когда флаг имеет значение true. Проверяйте каждый кадр на предмет столкновения с землей с помощью collisionChecker.isGroundCollision()’. При возникновении столкновения снова установите player.jump = false.
Проблема здесь в том, что если у вас вертикальная площадка, игрок сможет прыгать по стене. Если игрок ударится головой о землю, он также сможет прыгать больше. Чтобы решить эти проблемы, вы проверяете ‘arg0.position’, чтобы узнать, где находилась точка соприкосновения по отношению к объекту игрока. Если контакт находится не под игроком, то он ударяется головой или ударяется о стену.
Комментарии:
1. Я вижу здесь две проблемы. Во-первых, приспособления Box2D могут одновременно касаться нескольких других приспособлений, поэтому сохранения логического значения недостаточно — вам нужно увеличивать и уменьшать количество соприкасающихся в данный момент. Кроме того, remove () следует использовать для уменьшения количества — в приведенном выше коде кажется, что groundCollision никогда не будет возвращено значение false .
2. Это решение работает, и вам не нужно считать столкновения. Перед вызовом ‘world.step()’ предположим, что ‘groundCollision’ имеет значение false. ‘ContactListener’ должен проверить, не столкнется ли игрок в этом цикле. Я делаю это в методе ‘preSolve’, чтобы установить для ‘groundCollision’ значение true. Теперь вы можете отключить прыжки для этого цикла и начать все сначала.