Итак, в настоящее время я изобретаю колесо (и многому учусь), пробуя свои силы в создании простого физического движка для своего игрового движка. Я искал в Интернете, пытаясь (и безуспешно) исправить мою текущую проблему. На эту тему есть много ресурсов, но ни один из них, похоже, не применим к моему делу.
КРАТКАЯ ПРОБЛЕМА: разрешение столкновений не работает должным образом на некоторых углах, когда два прямоугольника сталкиваются. То, как это не удается, зависит от размеров прямоугольников. Я ищу разрешение «кратчайшего перекрытия» для столкновения или другое довольно простое решение (я открыт для предложений!). (Прокрутите вниз, чтобы найти лучшее объяснение и иллюстрации).
ВНИМАНИЕ! Следующий код, вероятно, не очень эффективен ...
Прежде всего, вот моя физическая петля. Он просто перебирает все игровые объекты и проверяет, не сталкиваются ли они с какими-либо другими игровыми объектами. Это неэффективно (n ^ 2 и все такое), но пока работает.
updatePhysics: function(step) {
// Loop through entities and update positions based on velocities
for (var entityID in Vroom.entityList) {
var entity = Vroom.entityList[entityID];
if (entity.physicsEnabled) {
switch (entity.entityType) {
case VroomEntity.KINEMATIC:
entity.pos.x += entity.vel.x * step;
entity.pos.y += entity.vel.y * step;
break;
case VroomEntity.DYNAMIC:
// Dynamic stuff
break;
}
}
}
// Loop through entities and detect collisions. Resolve collisions as they are detected.
for (var entityID in Vroom.entityList) {
var entity = Vroom.entityList[entityID];
if (entity.physicsEnabled && entity.entityType !== VroomEntity.STATIC) {
for (var targetID in Vroom.entityList) {
if (targetID !== entityID) {
var target = Vroom.entityList[targetID];
if (target.physicsEnabled) {
// Check if current entity and target is colliding
if (Vroom.collideEntity(entity, target)) {
switch (entity.collisionType) {
case VroomEntity.DISPLACE:
Vroom.resolveTestTest(entity, target);
break;
}
}
}
}
}
}
}
},
Вот код для фактического обнаружения столкновений. Кажется, это тоже работает нормально.
collideEntity: function(entity, target) {
if (entity.getBottom() < target.getTop() || entity.getTop() > target.getBottom() || entity.getRight() < target.getLeft() || entity.getLeft() > target.getRight()) {
return false;
}
return true;
},
Вот здесь и начинают появляться проблемы. Я хочу, чтобы сущность просто «выталкивалась» из целевой сущности, а скорость была установлена на 0. Это работает нормально, пока и сущность, и цель являются точными квадратами. Если предположить, что объект (фигура игрока на гифке) представляет собой прямоугольник, то столкновение будет "проскальзывать" при столкновении самых длинных сторон (ось X) с целью (квадратом). Если я поменяю местами размеры плеера так, чтобы он был коротким и широким, тогда та же проблема появится для оси Y.
resolveTestTest: function(entity, target) {
var normalizedX = (target.getMidX() - entity.getMidX());
var normalizedY = (target.getMidY() - entity.getMidY());
var absoluteNormalizedX = Math.abs(normalizedX);
var absoluteNormalizedY = Math.abs(normalizedY);
console.log(absoluteNormalizedX, absoluteNormalizedY);
// The collision is comming from the left or right
if (absoluteNormalizedX > absoluteNormalizedY) {
if (normalizedX < 0) {
entity.pos.x = target.getRight();
} else {
entity.pos.x = target.getLeft() - entity.dim.width;
}
// Set velocity to 0
entity.vel.x = 0;
// The collision is comming from the top or bottom
} else {
if (normalizedY < 0) {
entity.pos.y = target.getBottom();
} else {
entity.pos.y = target.getTop() - entity.dim.height;
}
// Set velocity to 0
entity.vel.y = 0;
}
},
Столкновение по оси Y работает с этими формами
Столкновение по оси X соскальзывает с этими формами
Что я могу сделать, чтобы решить эту проблему соскальзывания? Я бился об этом последние 5 дней, поэтому был бы безмерно благодарен, если бы кто-нибудь помог мне подтолкнуть меня в правильном направлении!
Спасибо :)
- РЕДАКТИРОВАТЬ: -
Проскальзывание также происходит, если двигаться только в одном направлении по левой или правой стороне.
- РЕДАКТИРОВАТЬ 2 РАБОЧИЙ КОД: - См. мой ответ ниже для примера рабочего кода!