mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-07 10:21:31 +00:00
TWP: Fix pathfinding
This commit is contained in:
parent
03dd90452d
commit
97c4353738
@ -204,7 +204,7 @@ static SQInteger actorDistanceTo(HSQUIRRELVM v) {
|
||||
return sq_throwerror(v, "failed to get object");
|
||||
else
|
||||
obj = g_engine->_actor;
|
||||
sqpush(v, distance(actor->_node->getPos(), obj->getUsePos()));
|
||||
sqpush(v, distance((Vector2i)actor->_node->getPos(), (Vector2i)obj->getUsePos()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -219,7 +219,7 @@ static SQInteger actorDistanceWithin(HSQUIRRELVM v) {
|
||||
if (!obj)
|
||||
return sq_throwerror(v, "failed to get spot");
|
||||
// not sure about this, needs to be check one day ;)
|
||||
sqpush(v, distance(actor1->_node->getAbsPos(), obj->getUsePos()) < distance(actor2->_node->getAbsPos(), obj->getUsePos()));
|
||||
sqpush(v, distance((Vector2i)actor1->_node->getAbsPos(), (Vector2i)obj->getUsePos()) < distance((Vector2i)actor2->_node->getAbsPos(), (Vector2i)obj->getUsePos()));
|
||||
return 1;
|
||||
} else if (nArgs == 4) {
|
||||
Object *actor = sqactor(v, 2);
|
||||
@ -231,7 +231,7 @@ static SQInteger actorDistanceWithin(HSQUIRRELVM v) {
|
||||
int dist;
|
||||
if (SQ_FAILED(sqget(v, 4, dist)))
|
||||
return sq_throwerror(v, "failed to get distance");
|
||||
sqpush(v, distance(actor->_node->getAbsPos(), obj->getUsePos()) < dist);
|
||||
sqpush(v, distance((Vector2i)actor->_node->getAbsPos(), (Vector2i)obj->getUsePos()) < dist);
|
||||
return 1;
|
||||
} else {
|
||||
return sq_throwerror(v, "actorDistanceWithin not implemented");
|
||||
@ -336,7 +336,7 @@ static SQInteger actorInWalkbox(HSQUIRRELVM v) {
|
||||
for (size_t i = 0; i < g_engine->_room->_walkboxes.size(); i++) {
|
||||
const Walkbox &walkbox = g_engine->_room->_walkboxes[i];
|
||||
if (walkbox._name == name) {
|
||||
if (walkbox.contains(actor->_node->getAbsPos())) {
|
||||
if (walkbox.contains((Vector2i)actor->_node->getAbsPos())) {
|
||||
sqpush(v, true);
|
||||
return 1;
|
||||
}
|
||||
@ -689,7 +689,7 @@ static SQInteger actorWalkForward(HSQUIRRELVM v) {
|
||||
dir = Math::Vector2d(dist, 0);
|
||||
break;
|
||||
}
|
||||
actor->walk(actor->_node->getAbsPos() + dir);
|
||||
actor->walk((Vector2i)(actor->_node->getAbsPos() + dir));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -760,7 +760,7 @@ static SQInteger actorWalkTo(HSQUIRRELVM v) {
|
||||
return sq_throwerror(v, "failed to get dir");
|
||||
facing = (Facing *)&dir;
|
||||
}
|
||||
actor->walk(Math::Vector2d(x, y), facing ? *facing : 0);
|
||||
actor->walk(Vector2i(x, y), facing ? *facing : 0);
|
||||
} else {
|
||||
return sq_throwerror(v, "invalid number of arguments in actorWalkTo");
|
||||
}
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
|
||||
//improve performance but coordinate values are limited to the range +/- 46340
|
||||
//#define use_int32
|
||||
#define use_int32
|
||||
|
||||
//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
|
||||
//#define use_xyz
|
||||
@ -47,7 +47,7 @@
|
||||
#define use_lines
|
||||
|
||||
//use_deprecated: Enables temporary support for the obsolete functions
|
||||
//#define use_deprecated
|
||||
//#define use_deprecated
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
@ -302,7 +302,7 @@ private:
|
||||
bool m_UsingPolyTree;
|
||||
bool m_StrictSimple;
|
||||
#ifdef use_xyz
|
||||
ZFillCallback m_ZFill; //custom callback
|
||||
ZFillCallback m_ZFill; //custom callback
|
||||
#endif
|
||||
void SetWindingCount(TEdge &edge);
|
||||
bool IsEvenOddFillType(const TEdge &edge) const;
|
||||
|
@ -19,49 +19,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define FORBIDDEN_SYMBOL_ALLOW_ALL
|
||||
|
||||
#include "twp/graph.h"
|
||||
#include "twp/util.h"
|
||||
|
||||
#define EPSILON 1e-9
|
||||
#include "twp/clipper/clipper.hpp"
|
||||
|
||||
namespace Twp {
|
||||
|
||||
struct Segment {
|
||||
Segment(Math::Vector2d s, Math::Vector2d t);
|
||||
void normalize();
|
||||
float distance(Math::Vector2d p);
|
||||
|
||||
Math::Vector2d start, to;
|
||||
float left, right, top, bottom;
|
||||
float a, b, c;
|
||||
};
|
||||
|
||||
Segment::Segment(Math::Vector2d s, Math::Vector2d t) {
|
||||
start = s;
|
||||
to = t;
|
||||
left = MIN(s.getX(), t.getX());
|
||||
right = MAX(s.getX(), t.getX());
|
||||
top = MIN(s.getY(), t.getY());
|
||||
bottom = MAX(s.getY(), t.getY());
|
||||
a = s.getY() - t.getY();
|
||||
b = t.getX() - s.getX();
|
||||
c = -a * s.getX() - b * s.getY();
|
||||
normalize();
|
||||
}
|
||||
|
||||
void Segment::normalize() {
|
||||
float z = sqrt(a * a + b * b);
|
||||
if (abs(z) > EPSILON) {
|
||||
a /= z;
|
||||
b /= z;
|
||||
c /= z;
|
||||
}
|
||||
}
|
||||
|
||||
float Segment::distance(Math::Vector2d p) {
|
||||
return a * p.getX() + b * p.getY() + c;
|
||||
}
|
||||
|
||||
IndexedPriorityQueue::IndexedPriorityQueue(Common::Array<float> &keys)
|
||||
: _keys(keys) {
|
||||
}
|
||||
@ -111,25 +76,11 @@ bool IndexedPriorityQueue::isEmpty() {
|
||||
|
||||
Graph::Graph() {}
|
||||
|
||||
Graph::Graph(const Graph &graph) {
|
||||
_nodes = graph._nodes;
|
||||
_concaveVertices = graph._concaveVertices;
|
||||
for (size_t i = 0; i < graph._edges.size(); i++) {
|
||||
const Common::Array<GraphEdge> &e = graph._edges[i];
|
||||
Common::Array<GraphEdge> sEdges;
|
||||
for (size_t j = 0; j < e.size(); j++) {
|
||||
const GraphEdge &se = e[j];
|
||||
sEdges.push_back(GraphEdge(se.start, se.to, se.cost));
|
||||
}
|
||||
_edges.push_back(sEdges);
|
||||
}
|
||||
}
|
||||
|
||||
GraphEdge::GraphEdge(int s, int t, float c)
|
||||
: start(s), to(t), cost(c) {
|
||||
}
|
||||
|
||||
void Graph::addNode(Math::Vector2d node) {
|
||||
void Graph::addNode(Vector2i node) {
|
||||
_nodes.push_back(node);
|
||||
_edges.push_back(Common::Array<GraphEdge>());
|
||||
}
|
||||
@ -139,16 +90,11 @@ AStar::AStar(Graph *graph)
|
||||
_graph = graph;
|
||||
}
|
||||
|
||||
// TODO this really should have some simd optimization
|
||||
// matrix multiplication is based on this
|
||||
static float dot(Math::Vector2d u, Math::Vector2d v) {
|
||||
float result = 0.f;
|
||||
result += u.getX() * v.getX();
|
||||
result += u.getY() * v.getY();
|
||||
return result;
|
||||
static float dot(Vector2i u, Vector2i v) {
|
||||
return (u.x * v.x) + (u.y * v.y);
|
||||
}
|
||||
|
||||
static float length(Math::Vector2d v) { return sqrt(dot(v, v)); }
|
||||
static float length(Vector2i v) { return sqrt(dot(v, v)); }
|
||||
|
||||
void AStar::search(int source, int target) {
|
||||
IndexedPriorityQueue pq(_fCost);
|
||||
@ -157,7 +103,6 @@ void AStar::search(int source, int target) {
|
||||
int NCN = pq.pop();
|
||||
_spt[NCN] = _sf[NCN];
|
||||
if (NCN != target) {
|
||||
// for (edge in _graph->edges[NCN]) {
|
||||
for (size_t i = 0; i < _graph->_edges[NCN].size(); i++) {
|
||||
GraphEdge &edge = _graph->_edges[NCN][i];
|
||||
float Hcost = length(_graph->_nodes[edge.to] - _graph->_nodes[target]);
|
||||
@ -227,54 +172,18 @@ void PathFinder::setWalkboxes(const Common::Array<Walkbox> &walkboxes) {
|
||||
_graph = nullptr;
|
||||
}
|
||||
|
||||
// Indicates whether or not the specified position is inside this walkbox.
|
||||
static bool inside(const Walkbox &self, Math::Vector2d position, bool toleranceOnOutside = true) {
|
||||
bool result = false;
|
||||
Math::Vector2d point = position;
|
||||
const float epsilon = 1.0f;
|
||||
|
||||
// Must have 3 or more edges
|
||||
const Common::Array<Math::Vector2d> &polygon = self.getPoints();
|
||||
if (polygon.size() < 3)
|
||||
return false;
|
||||
|
||||
Math::Vector2d oldPoint(polygon[polygon.size() - 1]);
|
||||
float oldSqDist = distanceSquared(oldPoint, point);
|
||||
|
||||
for (size_t i = 0; i < polygon.size(); i++) {
|
||||
Math::Vector2d newPoint = polygon[i];
|
||||
float newSqDist = distanceSquared(newPoint, point);
|
||||
|
||||
if (oldSqDist + newSqDist + 2.0f * sqrt(oldSqDist * newSqDist) - distanceSquared(newPoint, oldPoint) < epsilon)
|
||||
return toleranceOnOutside;
|
||||
|
||||
Math::Vector2d left;
|
||||
Math::Vector2d right;
|
||||
if (newPoint.getX() > oldPoint.getX()) {
|
||||
left = oldPoint;
|
||||
right = newPoint;
|
||||
} else {
|
||||
left = newPoint;
|
||||
right = oldPoint;
|
||||
}
|
||||
|
||||
if ((left.getX() < point.getX()) && (point.getX() <= right.getX()) && ((point.getY() - left.getY()) * (right.getX() - left.getX()) < (right.getY() - left.getY()) * (point.getX() - left.getX())))
|
||||
result = !result;
|
||||
|
||||
oldPoint = newPoint;
|
||||
oldSqDist = newSqDist;
|
||||
}
|
||||
return result;
|
||||
static Vector2i toVector2i(float x, float y) {
|
||||
return Vector2i(round(x), round(y));
|
||||
}
|
||||
|
||||
Math::Vector2d Walkbox::getClosestPointOnEdge(Math::Vector2d p3) const {
|
||||
Vector2i Walkbox::getClosestPointOnEdge(Vector2i p) const {
|
||||
int vi1 = -1;
|
||||
int vi2 = -1;
|
||||
float minDist = 100000.0f;
|
||||
|
||||
const Common::Array<Math::Vector2d> &polygon = getPoints();
|
||||
const Common::Array<Vector2i> &polygon = getPoints();
|
||||
for (size_t i = 0; i < polygon.size(); i++) {
|
||||
float dist = distanceToSegment(p3, polygon[i], polygon[(i + 1) % polygon.size()]);
|
||||
float dist = distanceToSegment(p, polygon[i], polygon[(i + 1) % polygon.size()]);
|
||||
if (dist < minDist) {
|
||||
minDist = dist;
|
||||
vi1 = i;
|
||||
@ -282,15 +191,15 @@ Math::Vector2d Walkbox::getClosestPointOnEdge(Math::Vector2d p3) const {
|
||||
}
|
||||
}
|
||||
|
||||
Math::Vector2d p1 = polygon[vi1];
|
||||
Math::Vector2d p2 = polygon[vi2];
|
||||
Vector2i p1 = polygon[vi1];
|
||||
Vector2i p2 = polygon[vi2];
|
||||
|
||||
float x1 = p1.getX();
|
||||
float y1 = p1.getY();
|
||||
float x2 = p2.getX();
|
||||
float y2 = p2.getY();
|
||||
float x3 = p3.getX();
|
||||
float y3 = p3.getY();
|
||||
float x1 = p1.x;
|
||||
float y1 = p1.y;
|
||||
float x2 = p2.x;
|
||||
float y2 = p2.y;
|
||||
float x3 = p.x;
|
||||
float y3 = p.y;
|
||||
|
||||
float u = (((x3 - x1) * (x2 - x1)) + ((y3 - y1) * (y2 - y1))) / (((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
|
||||
|
||||
@ -298,67 +207,31 @@ Math::Vector2d Walkbox::getClosestPointOnEdge(Math::Vector2d p3) const {
|
||||
float yu = y1 + u * (y2 - y1);
|
||||
|
||||
if (u < 0)
|
||||
return Math::Vector2d(x1, y1);
|
||||
return toVector2i(x1, y1);
|
||||
if (u > 1)
|
||||
return Math::Vector2d(x2, y2);
|
||||
return Math::Vector2d(xu, yu);
|
||||
return toVector2i(x2, y2);
|
||||
return toVector2i(xu, yu);
|
||||
}
|
||||
|
||||
static bool less(Math::Vector2d p1, Math::Vector2d p2) {
|
||||
return (((p1.getX() < p2.getX() - EPSILON) ||
|
||||
(abs(p1.getX() - p2.getX()) < EPSILON)) &&
|
||||
(p1.getY() < p2.getY() - EPSILON));
|
||||
}
|
||||
|
||||
static float det(float a, float b, float c, float d) {
|
||||
return a * d - b * c;
|
||||
}
|
||||
|
||||
static bool betw(float l, float r, float x) {
|
||||
return (MIN(l, r) <= x + EPSILON) && (x <= MAX(l, r) + EPSILON);
|
||||
}
|
||||
|
||||
static bool intersect_1d(float a, float b, float c, float d) {
|
||||
float a2 = a;
|
||||
float b2 = b;
|
||||
float c2 = c;
|
||||
float d2 = d;
|
||||
if (a2 > b2)
|
||||
SWAP(a2, b2);
|
||||
if (c2 > d2)
|
||||
SWAP(c2, d2);
|
||||
return MAX(a2, c2) <= MIN(b2, d2) + EPSILON;
|
||||
}
|
||||
|
||||
static bool lineSegmentsCross(Math::Vector2d a1, Math::Vector2d b1, Math::Vector2d c1, Math::Vector2d d1) {
|
||||
Math::Vector2d a = a1;
|
||||
Math::Vector2d b = b1;
|
||||
Math::Vector2d c = c1;
|
||||
Math::Vector2d d = d1;
|
||||
if ((!intersect_1d(a.getX(), b.getX(), c.getX(), d.getX())) || (!intersect_1d(a.getY(), b.getY(), c.getY(), d.getY())))
|
||||
static bool lineSegmentsCross(Vector2i a, Vector2i b, Vector2i c, Vector2i d) {
|
||||
const float EPSILON = 4.f;
|
||||
const float denominator = ((b.x - a.x) * (d.y - c.y)) - ((b.y - a.y) * (d.x - c.x));
|
||||
if (abs(denominator) < EPSILON) {
|
||||
return false;
|
||||
|
||||
Segment m(a, b);
|
||||
Segment n(c, d);
|
||||
float zn = det(m.a, m.b, n.a, n.b);
|
||||
|
||||
if (abs(zn) < EPSILON) {
|
||||
if ((abs(m.distance(c)) > EPSILON) || (abs(n.distance(a)) > EPSILON))
|
||||
return false;
|
||||
|
||||
if (less(b, a))
|
||||
SWAP(a, b);
|
||||
if (less(d, c))
|
||||
SWAP(c, d);
|
||||
return true;
|
||||
}
|
||||
|
||||
float lx = -det(m.c, m.b, n.c, n.b) / zn;
|
||||
float ly = -det(m.a, m.c, n.a, n.c) / zn;
|
||||
return betw(a.getX(), b.getX(), lx) && betw(a.getY(), b.getY(), ly) && betw(c.getX(), d.getX(), lx) && betw(c.getY(), d.getY(), ly);
|
||||
const float numerator1 = ((a.y - c.y) * (d.x - c.x)) - ((a.x - c.x) * (d.y - c.y));
|
||||
const float numerator2 = ((a.y - c.y) * (b.x - a.x)) - ((a.x - c.x) * (b.y - a.y));
|
||||
if ((abs(numerator1) < EPSILON) || (abs(numerator2) < EPSILON)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const float r = numerator1 / denominator;
|
||||
const float s = numerator2 / denominator;
|
||||
return ((r > 0.f) && (r < 1.f)) && ((s > 0.f) && (s < 1.f));
|
||||
}
|
||||
|
||||
bool PathFinder::inLineOfSight(Math::Vector2d start, Math::Vector2d to) {
|
||||
bool PathFinder::inLineOfSight(Vector2i start, Vector2i to) {
|
||||
const float epsilon = 0.5f;
|
||||
|
||||
// Not in LOS if any of the ends is outside the polygon
|
||||
@ -370,13 +243,13 @@ bool PathFinder::inLineOfSight(Math::Vector2d start, Math::Vector2d to) {
|
||||
return true;
|
||||
|
||||
// Not in LOS if any edge is intersected by the start-end line segment
|
||||
for (size_t i = 0; i < _walkboxes.size(); i++) {
|
||||
Walkbox &walkbox = _walkboxes[i];
|
||||
const Common::Array<Math::Vector2d> &polygon = walkbox.getPoints();
|
||||
int size = polygon.size();
|
||||
for (int j = 0; j < size; j++) {
|
||||
Math::Vector2d v1 = polygon[j];
|
||||
Math::Vector2d v2 = polygon[(j + 1) % size];
|
||||
for (uint i = 0; i < _walkboxes.size(); i++) {
|
||||
const Walkbox &walkbox = _walkboxes[i];
|
||||
const Common::Array<Vector2i> &polygon = walkbox.getPoints();
|
||||
const uint size = polygon.size();
|
||||
for (uint j = 0; j < size; j++) {
|
||||
Vector2i v1 = polygon[j];
|
||||
Vector2i v2 = polygon[(j + 1) % size];
|
||||
if (!lineSegmentsCross(start, to, v1, v2))
|
||||
continue;
|
||||
|
||||
@ -387,19 +260,20 @@ bool PathFinder::inLineOfSight(Math::Vector2d start, Math::Vector2d to) {
|
||||
}
|
||||
|
||||
// Finally the middle point in the segment determines if in LOS or not
|
||||
Math::Vector2d v2 = (start + to) / 2.0f;
|
||||
bool result = _walkboxes[0].contains(v2);
|
||||
for (size_t i = 1; i < _walkboxes.size(); i++) {
|
||||
const Vector2i v2 = (start + to) / 2.0f;
|
||||
if (!_walkboxes[0].contains(v2))
|
||||
return false;
|
||||
for (uint i = 1; i < _walkboxes.size(); i++) {
|
||||
if (_walkboxes[i].contains(v2, false))
|
||||
result = false;
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int minIndex(const Common::Array<float> values) {
|
||||
static uint minIndex(const Common::Array<float> &values) {
|
||||
float min = values[0];
|
||||
int index = 0;
|
||||
for (size_t i = 1; i < values.size(); i++) {
|
||||
uint index = 0;
|
||||
for (uint i = 1; i < values.size(); i++) {
|
||||
if (values[i] < min) {
|
||||
index = i;
|
||||
min = values[i];
|
||||
@ -410,13 +284,15 @@ static int minIndex(const Common::Array<float> values) {
|
||||
|
||||
Graph *PathFinder::createGraph() {
|
||||
Graph *result = new Graph();
|
||||
for (size_t i = 0; i < _walkboxes.size(); i++) {
|
||||
Walkbox &walkbox = _walkboxes[i];
|
||||
for (uint i = 0; i < _walkboxes.size(); i++) {
|
||||
const Walkbox &walkbox = _walkboxes[i];
|
||||
if (walkbox.getPoints().size() > 2) {
|
||||
bool visible = walkbox.isVisible();
|
||||
for (size_t j = 0; j < walkbox.getPoints().size(); j++) {
|
||||
if (walkbox.concave(j) == visible) {
|
||||
Math::Vector2d vertex = walkbox.getPoints()[j];
|
||||
bool firstWalkbox = (i == 0);
|
||||
if (!walkbox.isVisible())
|
||||
firstWalkbox = true;
|
||||
for (uint j = 0; j < walkbox.getPoints().size(); j++) {
|
||||
if (walkbox.concave(j) == firstWalkbox) {
|
||||
const Vector2i &vertex = walkbox.getPoints()[j];
|
||||
result->_concaveVertices.push_back(vertex);
|
||||
result->addNode(vertex);
|
||||
}
|
||||
@ -424,12 +300,12 @@ Graph *PathFinder::createGraph() {
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < result->_concaveVertices.size(); i++) {
|
||||
for (size_t j = 0; j < result->_concaveVertices.size(); j++) {
|
||||
Math::Vector2d c1(result->_concaveVertices[i]);
|
||||
Math::Vector2d c2(result->_concaveVertices[j]);
|
||||
for (uint i = 0; i < result->_concaveVertices.size(); i++) {
|
||||
for (uint j = 0; j < result->_concaveVertices.size(); j++) {
|
||||
const Vector2i c1(result->_concaveVertices[i]);
|
||||
const Vector2i c2(result->_concaveVertices[j]);
|
||||
if (inLineOfSight(c1, c2)) {
|
||||
float d = distance(c1, c2);
|
||||
const float d = distance(c1, c2);
|
||||
result->addEdge(GraphEdge(i, j, d));
|
||||
}
|
||||
}
|
||||
@ -437,27 +313,27 @@ Graph *PathFinder::createGraph() {
|
||||
return result;
|
||||
}
|
||||
|
||||
Common::Array<Math::Vector2d> PathFinder::calculatePath(Math::Vector2d start, Math::Vector2d to) {
|
||||
Common::Array<Math::Vector2d> result;
|
||||
Common::Array<Vector2i> PathFinder::calculatePath(Vector2i start, Vector2i to) {
|
||||
Common::Array<Vector2i> result;
|
||||
if (_walkboxes.size() > 0) {
|
||||
// find the walkbox where the actor is and put it first
|
||||
for (size_t i = 0; i < _walkboxes.size(); i++) {
|
||||
for (uint i = 0; i < _walkboxes.size(); i++) {
|
||||
const Walkbox &wb = _walkboxes[i];
|
||||
if (inside(wb, start) && (i != 0)) {
|
||||
if (wb.contains(start) && (i != 0)) {
|
||||
SWAP(_walkboxes[0], _walkboxes[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if no walkbox has been found => find the nearest walkbox
|
||||
if (!inside(_walkboxes[0], start)) {
|
||||
if (!_walkboxes[0].contains(start)) {
|
||||
Common::Array<float> dists(_walkboxes.size());
|
||||
for (size_t i = 0; i < _walkboxes.size(); i++) {
|
||||
Walkbox wb = _walkboxes[i];
|
||||
for (uint i = 0; i < _walkboxes.size(); i++) {
|
||||
const Walkbox &wb = _walkboxes[i];
|
||||
dists[i] = distance(wb.getClosestPointOnEdge(start), start);
|
||||
}
|
||||
|
||||
int index = minIndex(dists);
|
||||
const uint index = minIndex(dists);
|
||||
if (index != 0)
|
||||
SWAP(_walkboxes[0], _walkboxes[index]);
|
||||
}
|
||||
@ -466,39 +342,51 @@ Common::Array<Math::Vector2d> PathFinder::calculatePath(Math::Vector2d start, Ma
|
||||
_graph = createGraph();
|
||||
|
||||
// create new node on start position
|
||||
Graph *walkgraph = new Graph(*_graph);
|
||||
int startNodeIndex = walkgraph->_nodes.size();
|
||||
_walkgraph = *_graph;
|
||||
const uint startNodeIndex = _walkgraph._nodes.size();
|
||||
|
||||
// if destination is not inside current walkable area, then get the closest point
|
||||
const Walkbox &wb = _walkboxes[0];
|
||||
if (wb.isVisible() && !wb.contains(to))
|
||||
if (wb.isVisible() && !wb.contains(start)) {
|
||||
start = wb.getClosestPointOnEdge(start);
|
||||
}
|
||||
if (wb.isVisible() && !wb.contains(to)) {
|
||||
to = wb.getClosestPointOnEdge(to);
|
||||
}
|
||||
// we don't want the actor to walk in a different walkbox
|
||||
// then check if endpoint is inside one of the other walkboxes and find closest point on edge
|
||||
for (uint i = 1; i < _walkboxes.size(); i++) {
|
||||
if (_walkboxes[i].contains(to)) {
|
||||
to = _walkboxes[i].getClosestPointOnEdge(to);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
walkgraph->addNode(start);
|
||||
_walkgraph.addNode(start);
|
||||
|
||||
for (size_t i = 0; i < walkgraph->_concaveVertices.size(); i++) {
|
||||
Math::Vector2d c = walkgraph->_concaveVertices[i];
|
||||
for (uint i = 0; i < _walkgraph._concaveVertices.size(); i++) {
|
||||
const Vector2i c = _walkgraph._concaveVertices[i];
|
||||
if (inLineOfSight(start, c))
|
||||
walkgraph->addEdge(GraphEdge(startNodeIndex, i, distance(start, c)));
|
||||
_walkgraph.addEdge(GraphEdge(startNodeIndex, i, distance(start, c)));
|
||||
}
|
||||
|
||||
// create new node on end position
|
||||
int endNodeIndex = walkgraph->_nodes.size();
|
||||
walkgraph->addNode(to);
|
||||
const uint endNodeIndex = _walkgraph._nodes.size();
|
||||
_walkgraph.addNode(to);
|
||||
|
||||
for (size_t i = 0; i < walkgraph->_concaveVertices.size(); i++) {
|
||||
Math::Vector2d c = walkgraph->_concaveVertices[i];
|
||||
for (uint i = 0; i < _walkgraph._concaveVertices.size(); i++) {
|
||||
const Vector2i c = _walkgraph._concaveVertices[i];
|
||||
if (inLineOfSight(to, c))
|
||||
walkgraph->addEdge(GraphEdge(i, endNodeIndex, distance(to, c)));
|
||||
_walkgraph.addEdge(GraphEdge(i, endNodeIndex, distance(to, c)));
|
||||
}
|
||||
|
||||
if (inLineOfSight(start, to))
|
||||
walkgraph->addEdge(GraphEdge(startNodeIndex, endNodeIndex, distance(start, to)));
|
||||
_walkgraph.addEdge(GraphEdge(startNodeIndex, endNodeIndex, distance(start, to)));
|
||||
|
||||
Common::Array<int> indices = walkgraph->getPath(startNodeIndex, endNodeIndex);
|
||||
for (size_t i = 0; i < indices.size(); i++) {
|
||||
int index = indices[i];
|
||||
result.push_back(walkgraph->_nodes[index]);
|
||||
const Common::Array<int> indices = _walkgraph.getPath(startNodeIndex, endNodeIndex);
|
||||
for (uint i = 0; i < indices.size(); i++) {
|
||||
const int index = indices[i];
|
||||
result.push_back(_walkgraph._nodes[index]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "common/array.h"
|
||||
#include "math/vector2d.h"
|
||||
#include "twp/util.h"
|
||||
|
||||
namespace Twp {
|
||||
|
||||
@ -62,16 +63,15 @@ struct GraphEdge {
|
||||
class Graph {
|
||||
public:
|
||||
Graph();
|
||||
Graph(const Graph &graph);
|
||||
void addNode(Math::Vector2d node);
|
||||
void addNode(Vector2i node);
|
||||
void addEdge(GraphEdge edge);
|
||||
// Gets the edge from 'from' index to 'to' index.
|
||||
GraphEdge *edge(int start, int to);
|
||||
Common::Array<int> getPath(int source, int target);
|
||||
|
||||
Common::Array<Math::Vector2d> _nodes;
|
||||
Common::Array<Vector2i> _nodes;
|
||||
Common::Array<Common::Array<GraphEdge> > _edges;
|
||||
Common::Array<Math::Vector2d> _concaveVertices;
|
||||
Common::Array<Vector2i> _concaveVertices;
|
||||
};
|
||||
|
||||
class AStar {
|
||||
@ -83,27 +83,27 @@ public:
|
||||
Common::Array<GraphEdge *> _spt; // The Shortest Path Tree
|
||||
Common::Array<float> _gCost; // This array will store the G cost of each node
|
||||
Common::Array<float> _fCost; // This array will store the F cost of each node
|
||||
Common::Array<GraphEdge*> _sf; // The Search Frontier
|
||||
Common::Array<GraphEdge *> _sf; // The Search Frontier
|
||||
};
|
||||
|
||||
// Represents an area where an actor can or cannot walk
|
||||
class Walkbox {
|
||||
public:
|
||||
Walkbox(const Common::Array<Math::Vector2d> &polygon, bool visible = true);
|
||||
Walkbox(const Common::Array<Vector2i> &polygon, bool visible = true);
|
||||
|
||||
// Indicates whether or not the specified position is inside this walkbox.
|
||||
bool contains(Math::Vector2d position, bool toleranceOnOutside = true) const;
|
||||
// Indicates whether or not the specified position is inside this walkbox.
|
||||
bool contains(Vector2i position, bool toleranceOnOutside = true) const;
|
||||
bool concave(int vertex) const;
|
||||
void setVisible(bool visible) { _visible = visible; }
|
||||
bool isVisible() const { return _visible; }
|
||||
const Common::Array<Math::Vector2d>& getPoints() const { return _polygon; }
|
||||
Math::Vector2d getClosestPointOnEdge(Math::Vector2d p3) const;
|
||||
const Common::Array<Vector2i> &getPoints() const { return _polygon; }
|
||||
Vector2i getClosestPointOnEdge(Vector2i p) const;
|
||||
|
||||
public:
|
||||
Common::String _name;
|
||||
|
||||
private:
|
||||
Common::Array<Math::Vector2d> _polygon;
|
||||
Common::Array<Vector2i> _polygon;
|
||||
bool _visible;
|
||||
};
|
||||
|
||||
@ -111,18 +111,20 @@ private:
|
||||
class PathFinder {
|
||||
public:
|
||||
void setWalkboxes(const Common::Array<Walkbox> &walkboxes);
|
||||
Common::Array<Math::Vector2d> calculatePath(Math::Vector2d start, Math::Vector2d to);
|
||||
Common::Array<Walkbox> getWalkboxes() const { return _walkboxes; }
|
||||
Common::Array<Vector2i> calculatePath(Vector2i start, Vector2i to);
|
||||
void setDirty(bool dirty) { _isDirty = dirty; }
|
||||
bool isDirty() const { return _isDirty; }
|
||||
const Graph* getGraph() const { return _graph; }
|
||||
const Graph &getGraph() const { return _walkgraph; }
|
||||
|
||||
private:
|
||||
Graph *createGraph();
|
||||
bool inLineOfSight(Math::Vector2d start, Math::Vector2d to);
|
||||
bool inLineOfSight(Vector2i start, Vector2i to);
|
||||
|
||||
private:
|
||||
Common::Array<Walkbox> _walkboxes;
|
||||
Graph *_graph = nullptr;
|
||||
Graph _walkgraph;
|
||||
bool _isDirty = true;
|
||||
};
|
||||
|
||||
|
@ -164,13 +164,14 @@ void ReachAnim::update(float elapsed) {
|
||||
}
|
||||
}
|
||||
|
||||
WalkTo::WalkTo(Object *obj, Math::Vector2d dest, int facing)
|
||||
WalkTo::WalkTo(Object *obj, Vector2i dest, int facing)
|
||||
: _obj(obj), _facing(facing) {
|
||||
if (obj->_useWalkboxes) {
|
||||
_path = obj->_room->calculatePath(obj->_node->getAbsPos(), dest);
|
||||
_path = obj->_room->calculatePath((Vector2i)obj->_node->getAbsPos(), dest);
|
||||
} else {
|
||||
_path = {obj->_node->getAbsPos(), dest};
|
||||
_path = {(Vector2i)obj->_node->getAbsPos(), dest};
|
||||
}
|
||||
|
||||
_wsd = sqrt(obj->_walkSpeed.getX() * obj->_walkSpeed.getX() + obj->_walkSpeed.getY() * obj->_walkSpeed.getY());
|
||||
if (sqrawexists(obj->_table, "preWalking"))
|
||||
sqcall(obj->_table, "preWalking");
|
||||
@ -234,18 +235,18 @@ void WalkTo::actorArrived() {
|
||||
|
||||
void WalkTo::update(float elapsed) {
|
||||
if (_path.size() != 0) {
|
||||
Math::Vector2d dest = _path[0];
|
||||
float d = distance(dest, _obj->_node->getAbsPos());
|
||||
Vector2i dest = _path[0];
|
||||
float d = distance(dest, (Vector2i)_obj->_node->getAbsPos());
|
||||
|
||||
// arrived at destination ?
|
||||
if (d < 1.0) {
|
||||
_obj->_node->setPos(_path[0]);
|
||||
_obj->_node->setPos((Math::Vector2d)_path[0]);
|
||||
_path.remove_at(0);
|
||||
if (_path.size() == 0) {
|
||||
actorArrived();
|
||||
}
|
||||
} else {
|
||||
Math::Vector2d delta = dest - _obj->_node->getAbsPos();
|
||||
Math::Vector2d delta = (Math::Vector2d)dest - _obj->_node->getAbsPos();
|
||||
float duration = d / _wsd;
|
||||
float factor = Twp::clamp(elapsed / duration, 0.f, 1.f);
|
||||
|
||||
@ -337,7 +338,8 @@ int Talking::loadActorSpeech(const Common::String &name) {
|
||||
}
|
||||
|
||||
void Talking::say(const Common::String &text) {
|
||||
if(text.empty()) return;
|
||||
if (text.empty())
|
||||
return;
|
||||
|
||||
Common::String txt(text);
|
||||
if (text[0] == '@') {
|
||||
|
@ -205,10 +205,10 @@ private:
|
||||
|
||||
class WalkTo : public Motor {
|
||||
public:
|
||||
WalkTo(Object *obj, Math::Vector2d dest, int facing = 0);
|
||||
WalkTo(Object *obj, Vector2i dest, int facing = 0);
|
||||
virtual void disable() override;
|
||||
|
||||
const Common::Array<Math::Vector2d> &getPath() const { return _path; }
|
||||
const Common::Array<Vector2i> &getPath() const { return _path; }
|
||||
|
||||
private:
|
||||
void actorArrived();
|
||||
@ -216,7 +216,7 @@ private:
|
||||
|
||||
private:
|
||||
Object *_obj = nullptr;
|
||||
Common::Array<Math::Vector2d> _path;
|
||||
Common::Array<Vector2i> _path;
|
||||
int _facing = 0;
|
||||
float _wsd;
|
||||
};
|
||||
|
@ -665,10 +665,9 @@ static bool verbNotClose(VerbId id) {
|
||||
}
|
||||
|
||||
static void cantReach(Object *self, Object *noun2) {
|
||||
// TODO: check if we need to use sqrawexists or sqexists
|
||||
if (sqrawexists(self->_table, "verbCantReach")) {
|
||||
int nParams = sqparamCount(g_engine->getVm(), self->_table, "verbCantReach");
|
||||
debug("verbCantReach found in obj '{self.key}' with {nParams} params");
|
||||
debug("verbCantReach found in obj '%s' with %d params", self->_key.c_str(), nParams);
|
||||
if (nParams == 1) {
|
||||
sqcall(self->_table, "verbCantReach");
|
||||
} else {
|
||||
@ -676,12 +675,13 @@ static void cantReach(Object *self, Object *noun2) {
|
||||
sq_resetobject(&table);
|
||||
if (noun2)
|
||||
table = noun2->_table;
|
||||
sqcall(self->_table, "verbCantReach", self->_table, table);
|
||||
sqcall(self->_table, "verbCantReach", table);
|
||||
}
|
||||
} else if (!noun2) {
|
||||
} else if (noun2) {
|
||||
cantReach(noun2, nullptr);
|
||||
} else {
|
||||
HSQOBJECT nilTbl;
|
||||
sq_resetobject(&nilTbl);
|
||||
sqcall(g_engine->_defaultObj, "verbCantReach", self->_table, !noun2 ? nilTbl : noun2->_table);
|
||||
}
|
||||
}
|
||||
@ -701,11 +701,11 @@ void Object::execVerb() {
|
||||
return;
|
||||
}
|
||||
// Did we get close enough?
|
||||
float dist = distance(getUsePos(), noun1->getUsePos());
|
||||
float dist = distance((Vector2i)getUsePos(), (Vector2i)noun1->getUsePos());
|
||||
float min_dist = verb.id == VERB_TALKTO ? MIN_TALK_DIST : MIN_USE_DIST;
|
||||
debug("actorArrived: noun1 min_dist: %f > %f (actor: {self.getUsePos}, obj: {noun1.getUsePos}) ?", dist, min_dist);
|
||||
if (!verbNotClose(verb) && (dist > min_dist)) {
|
||||
cantReach(this, noun1);
|
||||
cantReach(noun1, noun2);
|
||||
return;
|
||||
}
|
||||
if (noun1->_useDir != dNone) {
|
||||
@ -719,11 +719,11 @@ void Object::execVerb() {
|
||||
_exec.enabled = false;
|
||||
return;
|
||||
}
|
||||
float dist = distance(getUsePos(), noun2->getUsePos());
|
||||
float dist = distance((Vector2i)getUsePos(), (Vector2i)noun2->getUsePos());
|
||||
float min_dist = verb.id == VERB_TALKTO ? MIN_TALK_DIST : MIN_USE_DIST;
|
||||
debug("actorArrived: noun2 min_dist: {dist} > {min_dist} ?");
|
||||
if (dist > min_dist) {
|
||||
cantReach(this, noun2);
|
||||
cantReach(noun1, noun2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -735,8 +735,8 @@ void Object::execVerb() {
|
||||
}
|
||||
|
||||
// Walks an actor to the `pos` or actor `obj` and then faces `dir`.
|
||||
void Object::walk(Math::Vector2d pos, int facing) {
|
||||
debug("walk to obj %s: %f,%f, %d", _key.c_str(), pos.getX(), pos.getY(), facing);
|
||||
void Object::walk(Vector2i pos, int facing) {
|
||||
debug("walk to obj %s: %d,%d, %d", _key.c_str(), pos.x, pos.y, facing);
|
||||
if (!_walkTo || (!_walkTo->isEnabled())) {
|
||||
play(getAnimName(WALK_ANIMNAME), true);
|
||||
}
|
||||
@ -747,7 +747,7 @@ void Object::walk(Math::Vector2d pos, int facing) {
|
||||
void Object::walk(Object *obj) {
|
||||
debug("walk to obj %s: (%f,%f)", obj->_key.c_str(), obj->getUsePos().getX(), obj->getUsePos().getY());
|
||||
Facing facing = (Facing)obj->_useDir;
|
||||
walk(obj->getUsePos(), facing);
|
||||
walk((Vector2i)obj->getUsePos(), facing);
|
||||
}
|
||||
|
||||
void Object::turn(Facing facing) {
|
||||
|
@ -187,7 +187,7 @@ public:
|
||||
void setReach(Motor *reach);
|
||||
Motor *getWalkTo() const { return _walkTo; }
|
||||
Motor *getReach() const { return _reach; }
|
||||
void walk(Math::Vector2d pos, int facing = 0);
|
||||
void walk(Vector2i pos, int facing = 0);
|
||||
void walk(Object* obj);
|
||||
|
||||
void setTalking(Motor *talking);
|
||||
|
@ -71,16 +71,16 @@ static Math::Vector2d parseParallax(const Common::JSONValue &v) {
|
||||
}
|
||||
|
||||
static Walkbox parseWalkbox(const Common::String &text) {
|
||||
Common::Array<Math::Vector2d> points;
|
||||
Common::Array<Vector2i> points;
|
||||
size_t i = 1;
|
||||
size_t endPos;
|
||||
do {
|
||||
uint32 commaPos = text.find(',', i);
|
||||
long x = strtol(text.substr(i, commaPos - i).c_str(), nullptr, 10);
|
||||
int x = (int)strtol(text.substr(i, commaPos - i).c_str(), nullptr, 10);
|
||||
endPos = text.find('}', commaPos + 1);
|
||||
long y = strtol(text.substr(commaPos + 1, endPos - commaPos - 1).c_str(), nullptr, 10);
|
||||
int y = (int)strtol(text.substr(commaPos + 1, endPos - commaPos - 1).c_str(), nullptr, 10);
|
||||
i = endPos + 3;
|
||||
points.push_back({(float)x, (float)y});
|
||||
points.push_back({x, y});
|
||||
} while ((text.size() - 1) != endPos);
|
||||
return Walkbox(points);
|
||||
}
|
||||
@ -99,18 +99,18 @@ static Scaling parseScaling(const Common::JSONArray &jScalings) {
|
||||
|
||||
static ClipperLib::Path toPolygon(const Walkbox &walkbox) {
|
||||
ClipperLib::Path path;
|
||||
const Common::Array<Math::Vector2d> &points = walkbox.getPoints();
|
||||
const Common::Array<Vector2i> &points = walkbox.getPoints();
|
||||
for (size_t i = 0; i < points.size(); i++) {
|
||||
path.push_back(ClipperLib::IntPoint(points[i].getX(), points[i].getY()));
|
||||
path.push_back(ClipperLib::IntPoint(points[i].x, points[i].y));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
static Walkbox toWalkbox(const ClipperLib::Path &path) {
|
||||
Common::Array<Math::Vector2d> pts;
|
||||
Common::Array<Vector2i> pts;
|
||||
for (size_t i = 0; i < path.size(); i++) {
|
||||
const ClipperLib::IntPoint &pt = path[i];
|
||||
pts.push_back(Math::Vector2d(pt.X, pt.Y));
|
||||
pts.push_back(Vector2i{pt.X, pt.Y});
|
||||
}
|
||||
return Walkbox(pts, ClipperLib::Orientation(path));
|
||||
}
|
||||
@ -131,11 +131,16 @@ static Common::Array<Walkbox> merge(const Common::Array<Walkbox> &walkboxes) {
|
||||
ClipperLib::Paths solutions;
|
||||
ClipperLib::Clipper c;
|
||||
c.AddPaths(subjects, ClipperLib::ptSubject, true);
|
||||
c.AddPaths(clips, ClipperLib::ptClip, true);
|
||||
c.Execute(ClipperLib::ClipType::ctDifference, solutions, ClipperLib::pftEvenOdd);
|
||||
c.Execute(ClipperLib::ClipType::ctUnion, solutions, ClipperLib::pftEvenOdd);
|
||||
|
||||
for (size_t i = 0; i < solutions.size(); i++) {
|
||||
result.push_back(toWalkbox(solutions[i]));
|
||||
ClipperLib::Paths solutions2;
|
||||
ClipperLib::Clipper c2;
|
||||
c2.AddPaths(solutions, ClipperLib::ptSubject, true);
|
||||
c2.AddPaths(clips, ClipperLib::ptClip, true);
|
||||
c2.Execute(ClipperLib::ClipType::ctDifference, solutions2, ClipperLib::pftEvenOdd);
|
||||
|
||||
for (size_t i = 0; i < solutions2.size(); i++) {
|
||||
result.push_back(toWalkbox(solutions2[i]));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -472,16 +477,16 @@ void Room::walkboxHidden(const Common::String &name, bool hidden) {
|
||||
if (wb._name == name) {
|
||||
wb.setVisible(!hidden);
|
||||
// 1 walkbox has change so update merged polygon
|
||||
_mergedPolygon = merge(_walkboxes);
|
||||
_pathFinder.setDirty(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Array<Math::Vector2d> Room::calculatePath(Math::Vector2d frm, Math::Vector2d to) {
|
||||
Common::Array<Vector2i> Room::calculatePath(Vector2i frm, Vector2i to) {
|
||||
if (_mergedPolygon.size() > 0) {
|
||||
if (_pathFinder.isDirty()) {
|
||||
_mergedPolygon = merge(_walkboxes);
|
||||
_pathFinder.setWalkboxes(_mergedPolygon);
|
||||
_pathFinder.setDirty(false);
|
||||
}
|
||||
@ -502,44 +507,44 @@ Layer::Layer(const Common::StringArray &name, Math::Vector2d parallax, int zsort
|
||||
_zsort = zsort;
|
||||
}
|
||||
|
||||
Walkbox::Walkbox(const Common::Array<Math::Vector2d> &polygon, bool visible)
|
||||
Walkbox::Walkbox(const Common::Array<Vector2i> &polygon, bool visible)
|
||||
: _polygon(polygon), _visible(visible) {
|
||||
}
|
||||
|
||||
bool Walkbox::concave(int vertex) const {
|
||||
Math::Vector2d current = _polygon[vertex];
|
||||
Math::Vector2d next = _polygon[(vertex + 1) % _polygon.size()];
|
||||
Math::Vector2d previous = _polygon[vertex == 0 ? _polygon.size() - 1 : vertex - 1];
|
||||
Vector2i current = _polygon[vertex];
|
||||
Vector2i next = _polygon[(vertex + 1) % _polygon.size()];
|
||||
Vector2i previous = _polygon[vertex == 0 ? _polygon.size() - 1 : vertex - 1];
|
||||
|
||||
Math::Vector2d left(current.getX() - previous.getX(), current.getY() - previous.getY());
|
||||
Math::Vector2d right(next.getX() - current.getX(), next.getY() - current.getY());
|
||||
Vector2i left{current.x - previous.x, current.y - previous.y};
|
||||
Vector2i right{next.x - current.x, next.y - current.y};
|
||||
|
||||
float cross = (left.getX() * right.getY()) - (left.getY() * right.getX());
|
||||
return _visible ? cross < 0 : cross >= 0;
|
||||
float cross = (left.x * right.y) - (left.y * right.x);
|
||||
return cross < 0;
|
||||
}
|
||||
|
||||
bool Walkbox::contains(Math::Vector2d position, bool toleranceOnOutside) const {
|
||||
Math::Vector2d point = position;
|
||||
const float epsilon = 1.0f;
|
||||
bool Walkbox::contains(Vector2i position, bool toleranceOnOutside) const {
|
||||
Vector2i point = position;
|
||||
const float epsilon = 2.0f;
|
||||
bool result = false;
|
||||
|
||||
// Must have 3 or more edges
|
||||
if (_polygon.size() < 3)
|
||||
return false;
|
||||
|
||||
Math::Vector2d oldPoint(_polygon[_polygon.size() - 1]);
|
||||
Vector2i oldPoint(_polygon[_polygon.size() - 1]);
|
||||
float oldSqDist = distanceSquared(oldPoint, point);
|
||||
|
||||
for (size_t i = 0; i < _polygon.size(); i++) {
|
||||
Math::Vector2d newPoint = _polygon[i];
|
||||
Vector2i newPoint = _polygon[i];
|
||||
float newSqDist = distanceSquared(newPoint, point);
|
||||
|
||||
if (oldSqDist + newSqDist + 2.0f * sqrt(oldSqDist * newSqDist) - distanceSquared(newPoint, oldPoint) < epsilon)
|
||||
return toleranceOnOutside;
|
||||
|
||||
Math::Vector2d left;
|
||||
Math::Vector2d right;
|
||||
if (newPoint.getX() > oldPoint.getX()) {
|
||||
Vector2i left;
|
||||
Vector2i right;
|
||||
if (newPoint.x > oldPoint.x) {
|
||||
left = oldPoint;
|
||||
right = newPoint;
|
||||
} else {
|
||||
@ -547,7 +552,7 @@ bool Walkbox::contains(Math::Vector2d position, bool toleranceOnOutside) const {
|
||||
right = oldPoint;
|
||||
}
|
||||
|
||||
if ((left.getX() < point.getX()) && (point.getX() <= right.getX()) && ((point.getY() - left.getY()) * (right.getX() - left.getX())) < ((right.getY() - left.getY()) * (point.getX() - left.getX())))
|
||||
if ((left.x < point.x) && (point.x <= right.x) && ((point.y - left.y) * (right.x - left.x)) < ((right.y - left.y) * (point.x - left.x)))
|
||||
result = !result;
|
||||
|
||||
oldPoint = newPoint;
|
||||
|
@ -126,7 +126,7 @@ public:
|
||||
Color getOverlay() const;
|
||||
|
||||
void walkboxHidden(const Common::String &name, bool hidden);
|
||||
Common::Array<Math::Vector2d> calculatePath(Math::Vector2d frm, Math::Vector2d to);
|
||||
Common::Array<Vector2i> calculatePath(Vector2i frm, Vector2i to);
|
||||
|
||||
public:
|
||||
Common::String _name; // Name of the room
|
||||
|
@ -49,7 +49,7 @@ static SQInteger addTrigger(HSQUIRRELVM v) {
|
||||
|
||||
static SQInteger clampInWalkbox(HSQUIRRELVM v) {
|
||||
SQInteger numArgs = sq_gettop(v);
|
||||
Math::Vector2d pos1, pos2;
|
||||
Vector2i pos1, pos2;
|
||||
if (numArgs == 3) {
|
||||
int x = 0;
|
||||
if (SQ_FAILED(sqget(v, 2, x)))
|
||||
@ -57,7 +57,7 @@ static SQInteger clampInWalkbox(HSQUIRRELVM v) {
|
||||
int y = 0;
|
||||
if (SQ_FAILED(sqget(v, 3, y)))
|
||||
return sq_throwerror(v, "failed to get y");
|
||||
pos1 = Math::Vector2d(x, y);
|
||||
pos1 = Vector2i(x, y);
|
||||
pos2 = pos1;
|
||||
} else if (numArgs == 5) {
|
||||
int x1 = 0;
|
||||
@ -66,14 +66,14 @@ static SQInteger clampInWalkbox(HSQUIRRELVM v) {
|
||||
int y1 = 0;
|
||||
if (SQ_FAILED(sqget(v, 3, y1)))
|
||||
return sq_throwerror(v, "failed to get y1");
|
||||
pos1 = Math::Vector2d(x1, y1);
|
||||
pos1 = Vector2i(x1, y1);
|
||||
int x2 = 0;
|
||||
if (SQ_FAILED(sqget(v, 4, x2)))
|
||||
return sq_throwerror(v, "failed to get x2");
|
||||
int y2 = 0;
|
||||
if (SQ_FAILED(sqget(v, 5, y1)))
|
||||
return sq_throwerror(v, "failed to get y2");
|
||||
pos2 = Math::Vector2d(x2, y2);
|
||||
pos2 = Vector2i(x2, y2);
|
||||
} else {
|
||||
return sq_throwerror(v, "Invalid argument number in clampInWalkbox");
|
||||
}
|
||||
@ -85,7 +85,7 @@ static SQInteger clampInWalkbox(HSQUIRRELVM v) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
Math::Vector2d pos = walkboxes[0].getClosestPointOnEdge(pos2);
|
||||
Vector2i pos = walkboxes[0].getClosestPointOnEdge(pos2);
|
||||
sqpush(v, pos);
|
||||
return 1;
|
||||
}
|
||||
|
@ -87,17 +87,22 @@ SQInteger sqpush(HSQUIRRELVM v, HSQOBJECT value) {
|
||||
}
|
||||
|
||||
template<>
|
||||
SQInteger sqpush(HSQUIRRELVM v, Math::Vector2d value) {
|
||||
SQInteger sqpush(HSQUIRRELVM v, Vector2i value) {
|
||||
sq_newtable(v);
|
||||
sq_pushstring(v, "x", -1);
|
||||
sq_pushinteger(v, value.getX());
|
||||
sq_pushinteger(v, value.x);
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
sq_pushstring(v, "y", -1);
|
||||
sq_pushinteger(v, value.getY());
|
||||
sq_pushinteger(v, value.y);
|
||||
sq_newslot(v, -3, SQFalse);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<>
|
||||
SQInteger sqpush(HSQUIRRELVM v, Math::Vector2d value) {
|
||||
return sqpush(v, (Vector2i)value);
|
||||
}
|
||||
|
||||
template<>
|
||||
SQInteger sqpush(HSQUIRRELVM v, Rectf value) {
|
||||
sq_newtable(v);
|
||||
|
@ -230,7 +230,7 @@ void TwpEngine::clickedAt(Math::Vector2d scrPos) {
|
||||
// Just clicking on the ground
|
||||
cancelSentence(_actor);
|
||||
if (_actor->_room == _room)
|
||||
_actor->walk(roomPos);
|
||||
_actor->walk((Vector2i)roomPos);
|
||||
_hud._verb = _hud.actorSlot(_actor)->verbs[0];
|
||||
_holdToMove = true;
|
||||
}
|
||||
@ -454,8 +454,8 @@ void TwpEngine::update(float elapsed) {
|
||||
if (_holdToMove && (_time > _nextHoldToMoveTime)) {
|
||||
walkFast();
|
||||
cancelSentence(_actor);
|
||||
if (_actor->_room == _room && (distance(_actor->_node->getAbsPos(), roomPos) > 5)) {
|
||||
_actor->walk(roomPos);
|
||||
if (_actor->_room == _room && (distance((Vector2i)_actor->_node->getAbsPos(), (Vector2i)roomPos) > 5)) {
|
||||
_actor->walk((Vector2i)roomPos);
|
||||
}
|
||||
_nextHoldToMoveTime = _time + 0.250f;
|
||||
}
|
||||
|
@ -130,29 +130,29 @@ void parseObjectAnimations(const Common::JSONArray &jAnims, Common::Array<Object
|
||||
}
|
||||
}
|
||||
|
||||
float distanceSquared(Math::Vector2d p1, Math::Vector2d p2) {
|
||||
float dx = p1.getX() - p2.getX();
|
||||
float dy = p1.getY() - p2.getY();
|
||||
float distanceSquared(Vector2i p1, Vector2i p2) {
|
||||
const float dx = p1.x - p2.x;
|
||||
const float dy = p1.y - p2.y;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
float distanceToSegmentSquared(Math::Vector2d p, Math::Vector2d v, Math::Vector2d w) {
|
||||
float l2 = distanceSquared(v, w);
|
||||
float distanceToSegmentSquared(Vector2i p, Vector2i v, Vector2i w) {
|
||||
const float l2 = distanceSquared(v, w);
|
||||
if (l2 == 0)
|
||||
return distanceSquared(p, v);
|
||||
float t = ((p.getX() - v.getX()) * (w.getX() - v.getX()) + (p.getY() - v.getY()) * (w.getY() - v.getY())) / l2;
|
||||
const float t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
|
||||
if (t < 0)
|
||||
return distanceSquared(p, v);
|
||||
if (t > 1)
|
||||
return distanceSquared(p, w);
|
||||
return distanceSquared(p, Math::Vector2d(v.getX() + t * (w.getX() - v.getX()), v.getY() + t * (w.getY() - v.getY())));
|
||||
return distanceSquared(p, Vector2i(v.x + t * (w.x - v.x), v.y + t * (w.y - v.y)));
|
||||
}
|
||||
|
||||
float distanceToSegment(Math::Vector2d p, Math::Vector2d v, Math::Vector2d w) {
|
||||
float distanceToSegment(Vector2i p, Vector2i v, Vector2i w) {
|
||||
return sqrt(distanceToSegmentSquared(p, v, w));
|
||||
}
|
||||
|
||||
float distance(Math::Vector2d p1, Math::Vector2d p2) {
|
||||
float distance(Vector2i p1, Vector2i p2) {
|
||||
return sqrt(distanceSquared(p1, p2));
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ Common::String join(const Common::Array<Common::String> &array, const Common::St
|
||||
Common::String result;
|
||||
if (array.size() > 0) {
|
||||
result += array[0];
|
||||
for (size_t i = 1; i < array.size(); i++) {
|
||||
for (uint i = 1; i < array.size(); i++) {
|
||||
result += (sep + array[i]);
|
||||
}
|
||||
}
|
||||
@ -170,7 +170,7 @@ Common::String join(const Common::Array<Common::String> &array, const Common::St
|
||||
Common::String replace(const Common::String &s, const Common::String &what, const Common::String &by) {
|
||||
Common::String result;
|
||||
uint i = 0;
|
||||
size_t whatSize = what.size();
|
||||
uint whatSize = what.size();
|
||||
while (true) {
|
||||
uint j = s.find(what, i);
|
||||
if (j == Common::String::npos)
|
||||
|
@ -33,6 +33,35 @@ namespace Twp {
|
||||
|
||||
class Object;
|
||||
|
||||
struct Vector2i {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
Vector2i() {}
|
||||
Vector2i(int x_, int y_) : x(x_), y(y_) {}
|
||||
Vector2i(float x_, float y_) : x(round(x_)), y(round(y_)) {}
|
||||
explicit Vector2i(const Math::Vector2d &p) : x(round(p.getX())), y(round(p.getY())) {}
|
||||
explicit operator Math::Vector2d() const {
|
||||
return Math::Vector2d(x, y);
|
||||
}
|
||||
|
||||
Vector2i operator-(const Vector2i &v) const {
|
||||
return Vector2i(x - v.x, y - v.y);
|
||||
}
|
||||
|
||||
Vector2i operator+(const Vector2i &v) const {
|
||||
return Vector2i(x + v.x, y + v.y);
|
||||
}
|
||||
|
||||
Vector2i operator*(float f) const {
|
||||
return Vector2i(x * f, y * f);
|
||||
}
|
||||
|
||||
Vector2i operator/(float f) const {
|
||||
return Vector2i(x / f, y / f);
|
||||
}
|
||||
};
|
||||
|
||||
// general util
|
||||
template<typename T, class DL = Common::DefaultDeleter<T> >
|
||||
using unique_ptr = Common::ScopedPtr<T, DL>;
|
||||
@ -59,7 +88,7 @@ void parseObjectAnimations(const Common::JSONArray &jAnims, Common::Array<Object
|
||||
|
||||
// array util
|
||||
template<typename T>
|
||||
size_t find(const Common::Array<T>& array, const T& o) {
|
||||
size_t find(const Common::Array<T> &array, const T &o) {
|
||||
for (size_t i = 0; i < array.size(); i++) {
|
||||
if (array[i] == o) {
|
||||
return i;
|
||||
@ -69,16 +98,16 @@ size_t find(const Common::Array<T>& array, const T& o) {
|
||||
}
|
||||
|
||||
// string util
|
||||
Common::String join(const Common::Array<Common::String>& array, const Common::String& sep);
|
||||
Common::String replace(const Common::String& s, const Common::String& what, const Common::String& by);
|
||||
Common::String join(const Common::Array<Common::String> &array, const Common::String &sep);
|
||||
Common::String replace(const Common::String &s, const Common::String &what, const Common::String &by);
|
||||
Common::String remove(const Common::String &txt, char startC, char endC);
|
||||
|
||||
// math util
|
||||
void scale(Math::Matrix4 &m, const Math::Vector2d &v);
|
||||
Math::Vector2d operator*(Math::Vector2d v, float f);
|
||||
float distance(Math::Vector2d p1, Math::Vector2d p2);
|
||||
float distanceSquared(Math::Vector2d p1, Math::Vector2d p2);
|
||||
float distanceToSegment(Math::Vector2d p, Math::Vector2d v, Math::Vector2d w);
|
||||
float distance(Vector2i p1, Vector2i p2);
|
||||
float distanceSquared(Vector2i p1, Vector2i p2);
|
||||
float distanceToSegment(Vector2i p, Vector2i v, Vector2i w);
|
||||
|
||||
} // namespace Twp
|
||||
|
||||
|
@ -35,25 +35,27 @@ void WalkboxNode::drawCore(Math::Matrix4 trsf) {
|
||||
Color red(1.f, 0.f, 0.f);
|
||||
Color green(0.f, 1.f, 0.f);
|
||||
Color yellow(1.f, 1.f, 0.f);
|
||||
Common::Array<Walkbox> walkboxes = g_engine->_room ? g_engine->_room->_pathFinder.getWalkboxes() : Common::Array<Walkbox>();
|
||||
|
||||
switch (_mode) {
|
||||
case WalkboxMode::All: {
|
||||
Math::Matrix4 transf;
|
||||
// cancel camera pos
|
||||
Math::Vector2d pos = g_engine->getGfx().cameraPos();
|
||||
transf.translate(Math::Vector3d(-pos.getX(), pos.getY(), 0.f));
|
||||
for (uint i = 0; i < g_engine->_room->_walkboxes.size(); i++) {
|
||||
Walkbox &wb = g_engine->_room->_walkboxes[i];
|
||||
Color color = wb.isVisible() ? green : red;
|
||||
transf.translate(Math::Vector3d(-pos.getX(), -pos.getY(), 0.f));
|
||||
for (uint i = 0; i < walkboxes.size(); i++) {
|
||||
const Walkbox &wb = walkboxes[i];
|
||||
const Color color = wb.isVisible() ? green : red;
|
||||
Common::Array<Vertex> vertices;
|
||||
for (uint j = 0; j < wb.getPoints().size(); j++) {
|
||||
Math::Vector2d p = wb.getPoints()[j];
|
||||
vertices.push_back(Vertex(p, color));
|
||||
const Common::Array<Vector2i>& points = wb.getPoints();
|
||||
for (uint j = 0; j < points.size(); j++) {
|
||||
Vector2i pInt = points[j];
|
||||
Math::Vector2d p = (Math::Vector2d)pInt;
|
||||
vertices.push_back(Vertex((Math::Vector2d)p, color));
|
||||
|
||||
Color vertexColor = wb.concave(j) ? white : yellow;
|
||||
Math::Matrix4 t(transf);
|
||||
p -= Math::Vector2d(2.f, 2.f);
|
||||
p -= Math::Vector2d(1.f, 1.f);
|
||||
t.translate(Math::Vector3d(p.getX(), p.getY(), 0.f));
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(4.f, 4.f), vertexColor, t);
|
||||
}
|
||||
g_engine->getGfx().drawLinesLoop(vertices.data(), vertices.size(), transf);
|
||||
}
|
||||
@ -62,20 +64,22 @@ void WalkboxNode::drawCore(Math::Matrix4 trsf) {
|
||||
Math::Matrix4 transf;
|
||||
Math::Vector2d pos = g_engine->getGfx().cameraPos();
|
||||
// cancel camera pos
|
||||
transf.translate(Math::Vector3d(-pos.getX(), pos.getY(), 0.f));
|
||||
for (uint i = 0; i < g_engine->_room->_mergedPolygon.size(); i++) {
|
||||
Walkbox &wb = g_engine->_room->_mergedPolygon[i];
|
||||
Color color = wb.isVisible() ? green : red;
|
||||
transf.translate(Math::Vector3d(-pos.getX(), -pos.getY(), 0.f));
|
||||
for (uint i = 0; i < walkboxes.size(); i++) {
|
||||
const Walkbox &wb = walkboxes[i];
|
||||
const Color color = i == 0 ? green : red;
|
||||
Common::Array<Vertex> vertices;
|
||||
for (uint j = 0; j < wb.getPoints().size(); j++) {
|
||||
Math::Vector2d p = wb.getPoints()[j];
|
||||
const Common::Array<Vector2i>& points = wb.getPoints();
|
||||
for (uint j = 0; j < points.size(); j++) {
|
||||
Vector2i pInt = points[j];
|
||||
Math::Vector2d p = (Math::Vector2d)pInt;
|
||||
vertices.push_back(Vertex(p, color));
|
||||
|
||||
Color vertexColor = wb.concave(j) ? white : yellow;
|
||||
Math::Matrix4 t(transf);
|
||||
p -= Math::Vector2d(2.f, 2.f);
|
||||
p -= Math::Vector2d(1.f, 1.f);
|
||||
t.translate(Math::Vector3d(p.getX(), p.getY(), 0.f));
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(4.f, 4.f), vertexColor, t);
|
||||
// if (wb.concave(j) == (i == 0))
|
||||
// g_engine->getGfx().drawQuad(Math::Vector2d(3.f, 3.f), yellow, t);
|
||||
}
|
||||
g_engine->getGfx().drawLinesLoop(vertices.data(), vertices.size(), transf);
|
||||
}
|
||||
@ -90,11 +94,11 @@ PathNode::PathNode() : Node("Path") {
|
||||
_zOrder = -1000;
|
||||
}
|
||||
|
||||
Math::Vector2d PathNode::fixPos(Math::Vector2d pos) {
|
||||
Vector2i PathNode::fixPos(Vector2i pos) {
|
||||
for (size_t i = 0; i < g_engine->_room->_mergedPolygon.size(); i++) {
|
||||
Walkbox &wb = g_engine->_room->_mergedPolygon[i];
|
||||
if (!wb.isVisible() && wb.contains(pos)) {
|
||||
return wb.getClosestPointOnEdge(pos);
|
||||
return wb.getClosestPointOnEdge((Vector2i)pos);
|
||||
}
|
||||
}
|
||||
// for wb in gEngine.room.mergedPolygon:
|
||||
@ -104,21 +108,24 @@ Math::Vector2d PathNode::fixPos(Math::Vector2d pos) {
|
||||
}
|
||||
|
||||
void PathNode::drawCore(Math::Matrix4 trsf) {
|
||||
if(!g_engine->_room) return;
|
||||
if (!g_engine->_room)
|
||||
return;
|
||||
|
||||
const Color green(0.f, 1.f, 0.f);
|
||||
const Color red(1.f, 0.f, 0.f);
|
||||
const Color yellow(1.f, 1.f, 0.f);
|
||||
const Color blue(0.f, 0.f, 1.f);
|
||||
const Object *actor = g_engine->_actor;
|
||||
|
||||
Color red(1.f, 0.f, 0.f);
|
||||
Color yellow(1.f, 1.f, 0.f);
|
||||
Color blue(0.f, 0.f, 1.f);
|
||||
Object *actor = g_engine->_actor;
|
||||
// draw actor path
|
||||
if (((_mode == PathMode::GraphMode) || (_mode == PathMode::All)) && actor && actor->getWalkTo()) {
|
||||
WalkTo *walkTo = (WalkTo *)actor->getWalkTo();
|
||||
const Common::Array<Math::Vector2d> &path = walkTo->getPath();
|
||||
const WalkTo *walkTo = (WalkTo *)actor->getWalkTo();
|
||||
const Common::Array<Vector2i> &path = walkTo->getPath();
|
||||
if (path.size() > 0) {
|
||||
Common::Array<Vertex> vertices;
|
||||
vertices.push_back(Vertex(g_engine->roomToScreen(actor->_node->getPos()), yellow));
|
||||
for (uint i = 0; i < path.size(); i++) {
|
||||
Math::Vector2d p = g_engine->roomToScreen(path[i]);
|
||||
Math::Vector2d p = g_engine->roomToScreen((Math::Vector2d)path[i]);
|
||||
vertices.push_back(Vertex(p, yellow));
|
||||
|
||||
Math::Matrix4 t;
|
||||
@ -131,23 +138,22 @@ void PathNode::drawCore(Math::Matrix4 trsf) {
|
||||
}
|
||||
|
||||
// draw graph nodes
|
||||
const Twp::Graph *graph = g_engine->_room->_pathFinder.getGraph();
|
||||
if (((_mode == PathMode::GraphMode) || (_mode == PathMode::All)) && graph) {
|
||||
for (uint i = 0; i < graph->_concaveVertices.size(); i++) {
|
||||
Math::Vector2d v = graph->_concaveVertices[i];
|
||||
const Twp::Graph& graph = g_engine->_room->_pathFinder.getGraph();
|
||||
if (((_mode == PathMode::GraphMode) || (_mode == PathMode::All))) {
|
||||
for (uint i = 0; i < graph._concaveVertices.size(); i++) {
|
||||
const Math::Vector2d p = g_engine->roomToScreen((Math::Vector2d)graph._concaveVertices[i]) - Math::Vector2d(2.f, 2.f);
|
||||
Math::Matrix4 t;
|
||||
Math::Vector2d p = g_engine->roomToScreen(v) - Math::Vector2d(2.f, 2.f);
|
||||
t.translate(Math::Vector3d(p.getX(), p.getY(), 0.f));
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(4.f, 4.f), yellow);
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(4.f, 4.f), yellow, t);
|
||||
}
|
||||
|
||||
if (_mode == PathMode::All) {
|
||||
for (uint i = 0; i < graph->_edges.size(); i++) {
|
||||
const Common::Array<GraphEdge> &edges = graph->_edges[i];
|
||||
for (uint i = 0; i < graph._edges.size(); i++) {
|
||||
const Common::Array<GraphEdge> &edges = graph._edges[i];
|
||||
for (uint j = 0; j < edges.size(); j++) {
|
||||
const GraphEdge &edge = edges[j];
|
||||
Math::Vector2d p1 = g_engine->roomToScreen(graph->_nodes[edge.start]);
|
||||
Math::Vector2d p2 = g_engine->roomToScreen(graph->_nodes[edge.to]);
|
||||
const Math::Vector2d p1 = g_engine->roomToScreen((Math::Vector2d)graph._nodes[edge.start]);
|
||||
const Math::Vector2d p2 = g_engine->roomToScreen((Math::Vector2d)graph._nodes[edge.to]);
|
||||
Vertex vertices[] = {Vertex(p1), Vertex(p2)};
|
||||
g_engine->getGfx().drawLines(&vertices[0], 2);
|
||||
}
|
||||
@ -162,30 +168,47 @@ void PathNode::drawCore(Math::Matrix4 trsf) {
|
||||
t.translate(Math::Vector3d(pos.getX(), pos.getY(), 0.f));
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(4.f, 4.f), yellow, t);
|
||||
|
||||
Math::Vector2d scrPos = g_engine->winToScreen(g_engine->_cursor.pos);
|
||||
Math::Vector2d roomPos = g_engine->screenToRoom(scrPos);
|
||||
Math::Vector2d p = fixPos(roomPos);
|
||||
const Math::Vector2d scrPos = g_engine->winToScreen(g_engine->_cursor.pos);
|
||||
const Math::Vector2d roomPos = g_engine->screenToRoom(scrPos);
|
||||
Vector2i p = fixPos((Vector2i)roomPos);
|
||||
t = Math::Matrix4();
|
||||
pos = g_engine->roomToScreen(p) - Math::Vector2d(4.f, 4.f);
|
||||
pos = g_engine->roomToScreen((Math::Vector2d)p) - Math::Vector2d(4.f, 4.f);
|
||||
t.translate(Math::Vector3d(pos.getX(), pos.getY(), 0.f));
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(8.f, 8.f), yellow, t);
|
||||
|
||||
Object* obj = g_engine->objAt(roomPos);
|
||||
if(obj) {
|
||||
Object *obj = g_engine->objAt(roomPos);
|
||||
if (obj) {
|
||||
t = Math::Matrix4();
|
||||
pos = g_engine->roomToScreen(obj->getUsePos()) - Math::Vector2d(4.f, 4.f);
|
||||
t.translate(Math::Vector3d(pos.getX(), pos.getY(), 0.f));
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(8.f, 8.f), red, t);
|
||||
}
|
||||
|
||||
Common::Array<Math::Vector2d> path = g_engine->_room->calculatePath(fixPos(actor->_node->getPos()), p);
|
||||
const Common::Array<Vector2i> path = g_engine->_room->calculatePath(fixPos((Vector2i)actor->_node->getPos()), p);
|
||||
Common::Array<Vertex> vertices;
|
||||
for (uint i = 0; i < path.size(); i++) {
|
||||
vertices.push_back(Vertex(g_engine->roomToScreen(path[i]), yellow));
|
||||
vertices.push_back(Vertex(g_engine->roomToScreen((Math::Vector2d)path[i]), yellow));
|
||||
}
|
||||
if (vertices.size() > 0) {
|
||||
g_engine->getGfx().drawLines(vertices.data(), vertices.size());
|
||||
}
|
||||
|
||||
// draw a green square if inside walkbox, red if not
|
||||
Common::Array<Walkbox> walkboxes = g_engine->_room ? g_engine->_room->_pathFinder.getWalkboxes() : Common::Array<Walkbox>();
|
||||
if(walkboxes.empty())
|
||||
return;
|
||||
|
||||
const bool inside = (walkboxes.size() > 0) && walkboxes[0].contains((Vector2i)roomPos);
|
||||
pos = scrPos - Math::Vector2d(4.f, 4.f);
|
||||
t = Math::Matrix4();
|
||||
t.translate(Math::Vector3d(pos.getX(), pos.getY(), 0.f));
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(8.f, 8.f), inside ? green : red, t);
|
||||
|
||||
// draw a blue square on the closest point
|
||||
pos = g_engine->roomToScreen((Math::Vector2d)walkboxes[0].getClosestPointOnEdge((Vector2i)roomPos));
|
||||
t = Math::Matrix4();
|
||||
t.translate(Math::Vector3d(pos.getX()-2.f, pos.getY()-2.f, 0.f));
|
||||
g_engine->getGfx().drawQuad(Math::Vector2d(4.f, 4.f), blue, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
PathMode getMode() const { return _mode; }
|
||||
|
||||
private:
|
||||
Math::Vector2d fixPos(Math::Vector2d pos);
|
||||
Vector2i fixPos(Vector2i pos);
|
||||
virtual void drawCore(Math::Matrix4 trsf) override;
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user