mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
223 lines
6 KiB
C++
223 lines
6 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* This code is based on the CRAB engine
|
|
*
|
|
* Copyright (c) Arvind Raja Yadav
|
|
*
|
|
* Licensed under MIT
|
|
*
|
|
*/
|
|
|
|
#include "crab/collision.h"
|
|
|
|
namespace Crab {
|
|
|
|
// Find if a line and a rectangle intersect
|
|
bool collideLineRect(int p0X, int p0Y, int p1X, int p1Y, const Rect &rect) {
|
|
int q0_x = rect.x;
|
|
int q0_y = rect.y;
|
|
int q1_x = rect.x + rect.w;
|
|
int q1_y = rect.y;
|
|
|
|
if (collideLine<int>(p0X, p0Y, p1X, p1Y, q0_x, q0_y, q1_x, q1_y))
|
|
return true;
|
|
|
|
q0_x = rect.x;
|
|
q0_y = rect.y;
|
|
q1_x = rect.x;
|
|
q1_y = rect.y + rect.h;
|
|
|
|
if (collideLine<int>(p0X, p0Y, p1X, p1Y, q0_x, q0_y, q1_x, q1_y))
|
|
return true;
|
|
|
|
q0_x = rect.x + rect.w;
|
|
q0_y = rect.y;
|
|
q1_x = rect.x + rect.w;
|
|
q1_y = rect.y + rect.h;
|
|
|
|
if (collideLine<int>(p0X, p0Y, p1X, p1Y, q0_x, q0_y, q1_x, q1_y))
|
|
return true;
|
|
|
|
q0_x = rect.x;
|
|
q0_y = rect.y + rect.h;
|
|
q1_x = rect.x + rect.w;
|
|
q1_y = rect.y + rect.h;
|
|
|
|
if (collideLine<int>(p0X, p0Y, p1X, p1Y, q0_x, q0_y, q1_x, q1_y))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
// Find if there is a clear line of sight between two rectangles
|
|
bool lineOfSight(const Rect &a, const Rect &b, const Rect &obstacle) {
|
|
int p0_x = a.x;
|
|
int p0_y = a.y;
|
|
int p1_x = b.x;
|
|
int p1_y = b.y;
|
|
|
|
if (collideLineRect(p0_x, p0_y, p1_x, p1_y, obstacle))
|
|
return false;
|
|
|
|
p0_x = a.x + a.w;
|
|
p0_y = a.y;
|
|
p1_x = b.x + b.w;
|
|
p1_y = b.y;
|
|
|
|
if (collideLineRect(p0_x, p0_y, p1_x, p1_y, obstacle))
|
|
return false;
|
|
|
|
p0_x = a.x;
|
|
p0_y = a.y + a.h;
|
|
p1_x = b.x;
|
|
p1_y = b.y + b.h;
|
|
|
|
if (collideLineRect(p0_x, p0_y, p1_x, p1_y, obstacle))
|
|
return false;
|
|
|
|
p0_x = a.x + a.w;
|
|
p0_y = a.y + a.h;
|
|
p1_x = b.x + b.w;
|
|
p1_y = b.y + b.h;
|
|
|
|
if (collideLineRect(p0_x, p0_y, p1_x, p1_y, obstacle))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// float IntervalDistance(float minA, float maxA, float minB, float maxB)
|
|
//{
|
|
// if (minA < minB)
|
|
// return minB - maxA;
|
|
//
|
|
// return minA - maxB;
|
|
// }
|
|
//
|
|
//// Calculate the projection of a polygon on an axis and returns it as a [min, max] interval
|
|
// void ProjectPolygon(const Vector2i &axis, const Polygon2D &poly, float &min, float &max)
|
|
//{
|
|
// // To project a point on an axis use the dot product
|
|
// float d = axis.DotProduct(poly.point[0]);
|
|
// min = d;
|
|
// max = d;
|
|
//
|
|
// for(auto i = poly.point.begin(); i != poly.point.end(); ++i)
|
|
// {
|
|
// d = i->DotProduct(axis);
|
|
//
|
|
// if (d < min) min = d;
|
|
// else if (d > max) max = d;
|
|
// }
|
|
// }
|
|
//
|
|
// PolygonCollisionResult Collide(const Polygon2D &polyA, const Polygon2D &polyB, const Vector2i &velocity)
|
|
//{
|
|
// PolygonCollisionResult result;
|
|
//
|
|
// int edgeCountA = polyA.edge.size();
|
|
// int edgeCountB = polyB.edge.size();
|
|
// float minIntervalDistance = std::numeric_limits<float>::max();
|
|
// Vector2i translationAxis;
|
|
// Vector2i edge;
|
|
//
|
|
// // Loop through all the edges of both polygons
|
|
// for(int edgeIndex = 0; edgeIndex < edgeCountA + edgeCountB; edgeIndex++)
|
|
// {
|
|
// if (edgeIndex < edgeCountA)
|
|
// edge = polyA.edge[edgeIndex];
|
|
// else
|
|
// edge = polyB.edge[edgeIndex - edgeCountA];
|
|
//
|
|
// // ===== 1. Find if the Polygon2Ds are currently intersecting =====
|
|
//
|
|
// // Find the axis perpendicular to the current edge
|
|
// Vector2i axis(-edge.y, edge.x);
|
|
// axis.Normalize();
|
|
//
|
|
// // Find the projection of the Polygon2D on the current axis
|
|
// float minA = 0; float minB = 0; float maxA = 0; float maxB = 0;
|
|
// ProjectPolygon(axis, polyA, minA, maxA);
|
|
// ProjectPolygon(axis, polyB, minB, maxB);
|
|
//
|
|
// // Check if the Polygon2D projections are currently intersecting
|
|
// if (IntervalDistance(minA, maxA, minB, maxB) > 0)
|
|
// result.intersect = false;
|
|
//
|
|
// // ===== 2. Now find if the Polygon2Ds *will* intersect =====
|
|
//
|
|
// // Project the velocity on the current axis
|
|
// float velocityProjection = axis.DotProduct(velocity);
|
|
//
|
|
// // Get the projection of Polygon2D A during the movement
|
|
// if (velocityProjection < 0)
|
|
// minA += velocityProjection;
|
|
// else
|
|
// maxA += velocityProjection;
|
|
//
|
|
// // Do the same test as above for the new projection
|
|
// float intervalDistance = IntervalDistance(minA, maxA, minB, maxB);
|
|
// if (intervalDistance > 0)
|
|
// result.will_intersect = false;
|
|
//
|
|
// // If the Polygon2Ds are not intersecting and won't intersect, exit the loop
|
|
// if (!result.intersect && !result.will_intersect)
|
|
// break;
|
|
//
|
|
// // Check if the current interval distance is the minimum one. If so store
|
|
// // the interval distance and the current distance.
|
|
// // This will be used to calculate the minimum translation vector
|
|
// intervalDistance = abs(intervalDistance);
|
|
// if (intervalDistance < minIntervalDistance)
|
|
// {
|
|
// minIntervalDistance = intervalDistance;
|
|
// translationAxis = axis;
|
|
//
|
|
// Vector2i d, ca, cb;
|
|
// ca = polyA.Center();
|
|
// cb = polyB.Center();
|
|
//
|
|
// d.x = ca.x - cb.x;
|
|
// d.y = ca.y - cb.y;
|
|
//
|
|
// if (d.DotProduct(translationAxis) < 0)
|
|
// {
|
|
// translationAxis.x = -translationAxis.x;
|
|
// translationAxis.y = -translationAxis.y;
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// // The minimum translation vector can be used to push the Polygon2Ds apart.
|
|
// // First moves the Polygon2Ds by their velocity
|
|
// // then move polyA by MinimumTranslationVector.
|
|
// if (result.will_intersect)
|
|
// {
|
|
// result.mtv.x = translationAxis.x * minIntervalDistance;
|
|
// result.mtv.y = translationAxis.y * minIntervalDistance;
|
|
// }
|
|
//
|
|
// return result;
|
|
// }
|
|
|
|
} // End of namespace Crab
|