Разрешить персонажу ходить по стенам и потолку в Box2D?
Я хочу сделать игру, которая происходит в космосе, используя Box2D для физики. Одна из вещей, которую я хочу, чтобы главный герой, которого вы контролируете, была в состоянии сделать, это ходить вверх ногами по потолку или боком по стенам. Я хочу, чтобы стены и / или потолки могли быть под любым углом, поэтому, независимо от формы комнаты, он всегда сможет придерживаться ее.
Хотя я хочу, чтобы персонаж мог ходить по всей местности, я все же хочу, чтобы у всех врагов, предметов, объектов и т. Д. К ним была применена нормальная гравитация, толкающая их вниз к земле.
Будет ли это возможно в Box2D? Если это так, что будет лучшим способом заставить это работать?
2 ответа
Это вполне возможно в Box2d, но требует некоторой работы, чтобы все заработало.
Игра, над которой я работаю, под названием "Космические пауки должны умереть!", Требовала, чтобы "космические пауки" могли ходить по астроидам и прыгать между ними.
Первое, что вам нужно, это путевые точки. Это те точки, на теле, которые вы хотите передвигать, или в вашем случае, прямо возле ваших стен, по которым вы хотите, чтобы ваш персонаж двигался вперед. Наличие "неподвижности" точек (не на движущемся теле) значительно сокращает объем работы.
Предположим, вы хотите перемещаться между двумя точками p0 и p1 во времени T. Ваш временной шаг dT (фиксированный). Соблазнительно использовать SetTransform(...) для тела, делая что-то вроде:
// Initialize for new points
int steps = T/dT;
Vec2 toTarget = p1-p0;
toTarget.Normalize();
int stepsTaken = 0;
float32 bodyAngle = atan2f(toTarget.y,toTarget.x)
// Each time step
stepsTaken++;
Vec2 pos = p0 + stepsTaken*dT*toTarget;
body.SetTransform(pos,bodyAngle);
if(stepsTaken >= steps)
{
// Set up next set of points.
}
ОДНАКО, если вы сделаете это, я верю, что вы обнаружите, что физический движок больше не взаимодействует с вашим телом при столкновениях. Я считаю, что это потому, что SetTransform(...) заставляет двигатель "пропустить удар" в отношении обнаружения столкновений.
Итак, решение, которое я нашел, состояло в том, чтобы создать b2PrismaticJoint в p0, прикрепленный к телу и указывающий в направлении p1. Максимальная длина сустава была установлена на расстояние между точками.
Это код из проекта, в котором я сделал это:
void CreateNextMovingJoint(float32 motorStrength = 1.0f)
{
b2PrismaticJointDef jointDef;
// We need to figure out some geometry here.
_pathIter = _pathDataList.begin();
PATH_DATA_T& pd = *_pathIter;
_pathIter++;
// Anchor
Vec2 pAnchor = pd.point;
// End point of the anchor, used for the axis.
Vec2 pEnd = pd.point + pd.distToNext[_direction]*pd.normalAlongPath[_direction];
jointDef.bodyA = _bodyMovingOn;
jointDef.bodyB = _bodyMoving;
jointDef.localAnchorA = pAnchor;
jointDef.localAnchorB = Vec2(0.0,0.0);
jointDef.localAxisA = pEnd-pAnchor;
jointDef.referenceAngle = 0;
jointDef.enableMotor = true;
jointDef.enableLimit = true;
jointDef.motorSpeed = _maxSpeed;
jointDef.maxMotorForce = motorStrength*(_maxSpeed/4)*_bodyMoving->GetMass();
jointDef.lowerTranslation = -0.1*pd.distToNext[_direction];
jointDef.upperTranslation = 1.1*pd.distToNext[_direction];
jointDef.collideConnected = true;
_bodyMoving->GetWorld()->CreateJoint(&jointDef);
}
После каждого обновления физического движка вам нужно проверять, насколько близко движущееся тело находится к следующей точке. Когда он подойдет достаточно близко, уничтожьте существующее призматическое соединение и создайте новое до следующей точки.
Это часть большей кодовой базы, но идея должна быть хорошо представлена здесь. В моем случае я сохранил все данные для каждого сегмента точка-точка в структуре под названием PATH_DATA_T. Был список из них, который я повторил. Когда паук приближается к следующей точке, итератор переходит к следующему элементу и обрабатывает его. Это сработало ОЧЕНЬ хорошо ( смотрите видео здесь).
это было полезно?
Гравитация - это просто постоянная сила, прикладываемая к телу игрока в определенном направлении, обычно вниз. Все, что вам нужно сделать, это управлять этим самостоятельно, отменив гравитацию по умолчанию на игроке и добавив свою собственную вручную, если это необходимо.
Отменить гравитацию для одного тела очень легко, подробности смотрите здесь: http://www.iforce2d.net/b2dtut/custom-gravity
Более важный вопрос - как вы решите, в какую сторону должна идти новая гравитация... вы могли бы найти ближайшую стену, или, возможно, ваш игрок сам может контролировать направление гравитации, я не знаю. В любом случае, после того, как вы определились, в каком направлении это будет, просто примените ту же силу, которая использовалась для отмены гравитации по умолчанию, но в текущем направлении гравитации. Возможно, вам захочется перевернуть тело игрока, чтобы он не попал в стены и не уперся головой в потолок:)