Implement collinear case

This commit is contained in:
Lizard-13
2018-02-17 13:40:43 -03:00
parent c8eb13f18f
commit 458444ee7b
5 changed files with 93 additions and 15 deletions

View File

@@ -862,7 +862,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(gd:
extension.AddCondition("Raycast",
_("Raycast"),
_("Sends a ray from the given source position and angle, intersecting the closest object.\nThe instersected object will become the only one taken into account.\nIf the condition is inverted, the object to intrsect will be the farthest one within the radius."),
_("Sends a ray from the given source position and angle, intersecting the closest object.\nThe instersected object will become the only one taken into account.\nIf the condition is inverted, the object to be intersected will be the farthest one within the ray radius."),
_("Raycast _PARAM0_ from _PARAM1_;_PARAM2_, and save the result in _PARAM5_, _PARAM6_"),
_("Collision"),
"res/conditions/raycast24.png",

View File

@@ -7,6 +7,7 @@
#include "GDCpp/Runtime/Polygon2d.h"
#include <cmath>
#include <cfloat>
#include <algorithm>
namespace
{
@@ -150,7 +151,7 @@ RaycastResult GD_API PolygonRaycastTest(Polygon2d & poly, float startX, float st
sf::Vector2f p, q, r, s;
float minSqDist = FLT_MAX;
// ray segment: p + t*r, with p = start and r = end - start
// Ray segment: p + t*r, with p = start and r = end - start
p.x = startX;
p.y = startY;
r.x = endX - startX;
@@ -158,7 +159,7 @@ RaycastResult GD_API PolygonRaycastTest(Polygon2d & poly, float startX, float st
for( int i=0; i<poly.edges.size(); i++ )
{
// edge segment: q + u*s
// Edge segment: q + u*s
q = poly.vertices[i];
s = poly.edges[i];
sf::Vector2f deltaQP = q - p;
@@ -166,9 +167,38 @@ RaycastResult GD_API PolygonRaycastTest(Polygon2d & poly, float startX, float st
float t = crossProduct(deltaQP, s) / crossRS;
float u = crossProduct(deltaQP, r) / crossRS;
if ( crossRS == 0 && crossProduct(deltaQP, r) == 0 )
// Collinear
if ( abs(crossRS) <= 0.0001 && abs(crossProduct(deltaQP, r)) <= 0.0001 )
{
// TODO Collinear
// Project the ray and the edge to work on floats, keeping linearity through t
sf::Vector2f axis(r.x, r.y);
normalise(axis);
float rayA = 0.0f;
float rayB = dotProduct(axis, r);
float edgeA = dotProduct(axis, deltaQP);
float edgeB = dotProduct(axis, deltaQP + s);
// Get overlapping range
float minOverlap = std::max(std::min(rayA, rayB), std::min(edgeA, edgeB));
float maxOverlap = std::min(std::max(rayA, rayB), std::max(edgeA, edgeB));
if( minOverlap > maxOverlap ){
return result;
}
result.collision = true;
// Zero distance ray
if( rayB == 0.0f ){
result.closePoint = p;
result.closeSqDist = 0.0f;
result.farPoint = p;
result.farSqDist = 0.0f;
}
float t1 = minOverlap / abs(rayB);
float t2 = maxOverlap / abs(rayB);
result.closePoint = p + t1*r;
result.closeSqDist = t1*t1*(r.x*r.x + r.y*r.y);
result.farPoint = p + t2*r;
result.farSqDist = t2*t2*(r.x*r.x + r.y*r.y);
return result;
}
else if ( crossRS != 0 && 0<=t && t<=1 && 0<=u && u<=1 )
{

View File

@@ -250,7 +250,7 @@ gdjs.Polygon.raycastTest = function(poly, startX, startY, endX, endY)
var s = gdjs.Polygon.raycastTest._statics.s;
var minSqDist = Number.MAX_VALUE;
// ray segment: p + t*r, with p = start and r = end - start
// Ray segment: p + t*r, with p = start and r = end - start
p[0] = startX;
p[1] = startY;
r[0] = endX - startX;
@@ -258,20 +258,58 @@ gdjs.Polygon.raycastTest = function(poly, startX, startY, endX, endY)
for(var i=0; i<poly.edges.length; i++)
{
// edge segment: q + u*s
// Edge segment: q + u*s
q[0] = poly.vertices[i][0];
q[1] = poly.vertices[i][1];
s[0] = poly.edges[i][0];
s[1] = poly.edges[i][1];
var deltaQP = [q[0] - p[0], q[1] - p[1]];
var deltaQP = gdjs.Polygon.raycastTest._statics.deltaQP;
deltaQP[0] = q[0] - p[0];
deltaQP[1] = q[1] - p[1];
var crossRS = gdjs.Polygon.crossProduct(r, s);
var t = gdjs.Polygon.crossProduct(deltaQP, s) / crossRS;
var u = gdjs.Polygon.crossProduct(deltaQP, r) / crossRS;
if ( crossRS === 0 && gdjs.Polygon.crossProduct(deltaQP, r) === 0)
// Collinear
if ( Math.abs(crossRS) <= 0.0001 && Math.abs(gdjs.Polygon.crossProduct(deltaQP, r)) <= 0.0001 )
{
// TODO Collinear
// Project the ray and the edge to work on floats, keeping linearity through t
var axis = gdjs.Polygon.raycastTest._statics.axis;
axis[0] = r[0];
axis[1] = r[1];
gdjs.Polygon.normalise(axis);
var rayA = 0;
var rayB = gdjs.Polygon.dotProduct(axis, r);
var edgeA = gdjs.Polygon.dotProduct(axis, deltaQP);
var edgeB = gdjs.Polygon.dotProduct(axis, [deltaQP[0] + s[0], deltaQP[1] + s[1]]);
// Get overlapping range
var minOverlap = Math.max(Math.min(rayA, rayB), Math.min(edgeA, edgeB));
var maxOverlap = Math.min(Math.max(rayA, rayB), Math.max(edgeA, edgeB));
if( minOverlap > maxOverlap ){
return result;
}
result.collision = true;
// Zero distance ray
if( rayB === 0 ){
result.closeX = startX;
result.closeY = startY;
result.closeSqDist = 0;
result.farX = startX;
result.farY = startY;
result.farSqDist = 0;
}
var t1 = minOverlap / Math.abs(rayB);
var t2 = maxOverlap / Math.abs(rayB);
result.closeX = startX + t1*r[0];
result.closeY = startY + t1*r[1];
result.closeSqDist = t1*t1*(r[0]*r[0] + r[1]*r[1]);
result.farX = startX + t2*r[0];
result.farY = startY + t2*r[1];
result.farSqDist = t2*t2*(r[0]*r[0] + r[1]*r[1]);
return result;
}
// One point intersection
else if ( crossRS !== 0 && 0<=t && t<=1 && 0<=u && u<=1 )
{
var x = p[0] + t*r[0];
@@ -308,6 +346,8 @@ gdjs.Polygon.raycastTest._statics = {
q: [0,0],
r: [0,0],
s: [0,0],
deltaQP: [0,0],
axis: [0,0],
result: {
collision: false,
closeX: 0,

View File

@@ -1172,10 +1172,9 @@ gdjs.RuntimeObject.prototype.raycastTest = function(x, y, angle, dist, closest)
if ( Math.sqrt(diffX*diffX + diffY*diffY) > boundingRadius + dist )
return result;
var endX = x + dist*Math.cos(angle*3.14159/180.0);
var endY = y + dist*Math.sin(angle*3.14159/180.0);
var endX = x + dist*Math.cos(angle*Math.PI/180.0);
var endY = y + dist*Math.sin(angle*Math.PI/180.0);
var testSqDist = closest ? dist*dist : 0;
var hitBoxes = this.getHitBoxes();

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
<project firstLayout="">
<gdVersion build="96" major="4" minor="0" revision="137" />
<gdVersion build="96" major="4" minor="0" revision="140" />
<properties folderProject="false" linuxExecutableFilename="" macExecutableFilename="" packageName="com.example.gamename" projectFile="C:\Users\Maciel\Programacion\gits\GD\GDJS\tests\games\Raycast.gdg" useExternalSourceFiles="false" winExecutableFilename="" winExecutableIconFile="">
<name>Project</name>
<author></author>
@@ -384,6 +384,15 @@
</parameters>
<subInstructions />
</instruction>
<instruction>
<type inverted="false" value="ChangeScaleHeight" />
<parameters>
<parameter>Line</parameter>
<parameter>=</parameter>
<parameter>0.1</parameter>
</parameters>
<subInstructions />
</instruction>
</actions>
<events />
</event>