mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-03 09:23:37 +00:00
FREESCAPE: refactor and improve triggering of collision conditions
This commit is contained in:
parent
7f21ad3cb5
commit
5eff8d6f4d
@ -248,7 +248,7 @@ void Area::drawGroup(Freescape::Renderer *gfx, Group* group, bool runAnimation)
|
||||
group->draw(gfx);
|
||||
}
|
||||
|
||||
Object *Area::shootRay(const Math::Ray &ray) {
|
||||
Object *Area::checkCollisionRay(const Math::Ray &ray, int raySize) {
|
||||
float distance = 1.0;
|
||||
float size = 16.0 * 8192.0; // TODO: check if this is the max size
|
||||
Math::AABB boundingBox(ray.getOrigin(), ray.getOrigin());
|
||||
@ -257,7 +257,7 @@ Object *Area::shootRay(const Math::Ray &ray) {
|
||||
if (!obj->isDestroyed() && !obj->isInvisible()) {
|
||||
GeometricObject *gobj = (GeometricObject *)obj;
|
||||
Math::Vector3d collidedNormal;
|
||||
float collidedDistance = sweepAABB(boundingBox, gobj->_boundingBox, 8192 * ray.getDirection(), collidedNormal);
|
||||
float collidedDistance = sweepAABB(boundingBox, gobj->_boundingBox, raySize * ray.getDirection(), collidedNormal);
|
||||
debugC(1, kFreescapeDebugMove, "shot obj id: %d with distance %f", obj->getObjectID(), collidedDistance);
|
||||
if (collidedDistance >= 1.0)
|
||||
continue;
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
void drawGroup(Renderer *gfx, Group *group, bool runAnimation);
|
||||
void show();
|
||||
|
||||
Object *shootRay(const Math::Ray &ray);
|
||||
Object *checkCollisionRay(const Math::Ray &ray, int raySize);
|
||||
bool checkInSight(const Math::Ray &ray, float maxDistance);
|
||||
ObjectArray checkCollisions(const Math::AABB &boundingBox);
|
||||
Math::Vector3d resolveCollisions(Math::Vector3d const &lastPosition, Math::Vector3d const &newPosition, int playerHeight);
|
||||
|
@ -169,7 +169,7 @@ void FreescapeEngine::activate() {
|
||||
|
||||
Math::Vector3d direction = directionToVector(_pitch - yoffset, _yaw - xoffset);
|
||||
Math::Ray ray(_position, direction);
|
||||
Object *interacted = _currentArea->shootRay(ray);
|
||||
Object *interacted = _currentArea->checkCollisionRay(ray, 8192);
|
||||
if (interacted) {
|
||||
GeometricObject *gobj = (GeometricObject *)interacted;
|
||||
debugC(1, kFreescapeDebugMove, "Interact with object %d with flags %x", gobj->getObjectID(), gobj->getObjectFlags());
|
||||
@ -196,7 +196,7 @@ void FreescapeEngine::shoot() {
|
||||
|
||||
Math::Vector3d direction = directionToVector(_pitch - yoffset, _yaw - xoffset);
|
||||
Math::Ray ray(_position, direction);
|
||||
Object *shot = _currentArea->shootRay(ray);
|
||||
Object *shot = _currentArea->checkCollisionRay(ray, 8192);
|
||||
if (shot) {
|
||||
GeometricObject *gobj = (GeometricObject *)shot;
|
||||
debugC(1, kFreescapeDebugMove, "Shot object %d with flags %x", gobj->getObjectID(), gobj->getObjectFlags());
|
||||
@ -399,43 +399,31 @@ void FreescapeEngine::resolveCollisions(Math::Vector3d const position) {
|
||||
|
||||
bool FreescapeEngine::runCollisionConditions(Math::Vector3d const lastPosition, Math::Vector3d const newPosition) {
|
||||
bool executed = false;
|
||||
// We need to make sure the bounding box touches the floor so we will expand it and run the collision checking
|
||||
uint tolerance = isCastle() ? 1 : 3;
|
||||
|
||||
int yDifference = _flyMode ? tolerance : -_playerHeight - tolerance;
|
||||
Math::Vector3d v(newPosition.x() - 1, newPosition.y() + yDifference, newPosition.z() - 1);
|
||||
Math::AABB boundingBox(lastPosition, lastPosition);
|
||||
boundingBox.expand(v);
|
||||
|
||||
ObjectArray objs = _currentArea->checkCollisions(boundingBox);
|
||||
|
||||
// sort so the condition from those objects that are larger are executed last
|
||||
struct {
|
||||
bool operator()(Object *object1, Object *object2) {
|
||||
return object1->getSize().length() < object2->getSize().length();
|
||||
};
|
||||
} compareObjectsSizes;
|
||||
|
||||
Common::sort(objs.begin(), objs.end(), compareObjectsSizes);
|
||||
uint16 areaID = _currentArea->getAreaID();
|
||||
GeometricObject *gobj = nullptr;
|
||||
Object *collided = nullptr;
|
||||
|
||||
bool largeObjectWasBlocking = false;
|
||||
for (auto &obj : objs) {
|
||||
GeometricObject *gobj = (GeometricObject *)obj;
|
||||
debugC(1, kFreescapeDebugMove, "Collided with object id %d of size %f %f %f", gobj->getObjectID(), gobj->getSize().x(), gobj->getSize().y(), gobj->getSize().z());
|
||||
// The following check stops the player from going through big solid objects such as walls
|
||||
// FIXME: find a better workaround of this
|
||||
if (gobj->getSize().length() > 3000) {
|
||||
if (largeObjectWasBlocking && !(isDriller() && _currentArea->getAreaID() == 14))
|
||||
continue;
|
||||
largeObjectWasBlocking = true;
|
||||
}
|
||||
|
||||
Math::Ray ray(newPosition, -_upVector);
|
||||
collided = _currentArea->checkCollisionRay(ray, _playerHeight + 3);
|
||||
if (collided) {
|
||||
gobj = (GeometricObject *)collided;
|
||||
debugC(1, kFreescapeDebugMove, "Collided down with object id %d of size %f %f %f", gobj->getObjectID(), gobj->getSize().x(), gobj->getSize().y(), gobj->getSize().z());
|
||||
executed |= executeObjectConditions(gobj, false, true, false);
|
||||
}
|
||||
|
||||
if (areaID != _currentArea->getAreaID())
|
||||
break;
|
||||
return collided;
|
||||
|
||||
Math::Vector3d direction = newPosition - lastPosition;
|
||||
direction.normalize();
|
||||
ray = Math::Ray(newPosition, direction);
|
||||
collided = _currentArea->checkCollisionRay(ray, 45);
|
||||
if (collided) {
|
||||
gobj = (GeometricObject *)collided;
|
||||
debugC(1, kFreescapeDebugMove, "Collided with object id %d of size %f %f %f", gobj->getObjectID(), gobj->getSize().x(), gobj->getSize().y(), gobj->getSize().z());
|
||||
executed |= executeObjectConditions(gobj, false, true, false);
|
||||
}
|
||||
|
||||
return executed;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user