mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Implement collinear case
This commit is contained in:
@@ -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",
|
||||
|
@@ -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 )
|
||||
{
|
||||
|
@@ -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,
|
||||
|
@@ -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();
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user