Implement C++ version

And little fixes on the JS version
This commit is contained in:
Lizard-13
2017-12-16 10:13:03 -03:00
parent 3c3dc6ef6e
commit 6bbfa1d4a1
11 changed files with 370 additions and 101 deletions

View File

@@ -106,7 +106,7 @@ BaseObjectExtension::BaseObjectExtension()
GetAllConditions()["NbObjet"].SetFunctionName("PickedObjectsCount").SetManipulatedType("number").SetIncludeFile("GDCpp/Extensions/Builtin/ObjectTools.h");
GetAllConditions()["CollisionNP"].SetFunctionName("HitBoxesCollision").SetIncludeFile("GDCpp/Extensions/Builtin/ObjectTools.h");
GetAllConditions()["EstTourne"].SetFunctionName("ObjectsTurnedToward").SetIncludeFile("GDCpp/Extensions/Builtin/ObjectTools.h");
// GetAllConditions()["Raycast"].SetFunctionName("RaycastObject").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneTools.h");
GetAllConditions()["Raycast"].SetFunctionName("RaycastObject").SetIncludeFile("GDCpp/Extensions/Builtin/RuntimeSceneTools.h");
GetAllExpressions()["Count"].SetFunctionName("PickedObjectsCount").SetIncludeFile("GDCpp/Extensions/Builtin/ObjectTools.h");
#endif

View File

@@ -22,6 +22,9 @@
#include "GDCpp/Runtime/CommonTools.h"
#include "GDCpp/Runtime/Project/Variable.h"
#include "GDCpp/Extensions/CppPlatform.h"
#include "GDCpp/Runtime/PolygonCollision.h"
#include "GDCpp/Runtime/Polygon2d.h"
#include <iostream>
gd::String GD_API GetSceneName(RuntimeScene & scene)
{
@@ -208,34 +211,47 @@ bool GD_API PickNearestObject(std::map <gd::String, std::vector<RuntimeObject*>
return true;
}
// bool GD_API RaycastObject(std::map <gd::String, std::vector<RuntimeObject*> *> pickedObjectLists, double x, double y, double angle, double dist, const gd::Variable & resultX, const gd::Variable & resultY, bool inverted)
// {
// double minSqDist = 0;
// bool first = true;
// RuntimeObject * matchObject = NULL;
// for (auto it = pickedObjectLists.begin();it!=pickedObjectLists.end();++it)
// {
// if ( it->second == NULL ) continue;
// auto list = *it->second;
bool GD_API RaycastObject(std::map <gd::String, std::vector<RuntimeObject*> *> pickedObjectLists, float x, float y, float angle, float dist, gd::Variable & varX, gd::Variable & varY, bool inverted)
{
RuntimeObject * matchObject = NULL;
float testSqDist = inverted ? 0 : dist*dist;
float resultX = 0.0f;
float resultY = 0.0f;
for (auto it = pickedObjectLists.begin(); it != pickedObjectLists.end(); ++it)
{
if ( it->second == NULL ) continue;
auto list = *it->second;
// for (std::size_t i = 0;i<list.size();++i)
// {
// double value = list[i]->GetSqDistanceTo(x, y);
// if (first || ((value < best) ^ inverted)) {
// matchObject = list[i];
// best = value;
// }
for (std::size_t i = 0; i < list.size(); ++i)
{
// first = false;
// }
// }
RaycastResult result = list[i]->RaycastTest(x, y, angle, dist, !inverted);
// if (!matchObject)
// return false;
if( result.collision ) {
if ( !inverted && (result.closeSqDist <= testSqDist) ) {
testSqDist = result.closeSqDist;
matchObject = list[i];
resultX = result.closePoint.x;
resultY = result.closePoint.y;
}
else if ( inverted && (result.farSqDist >= testSqDist) ) {
testSqDist = result.farSqDist;
matchObject = list[i];
resultX = result.farPoint.x;
resultY = result.farPoint.y;
}
}
}
}
// PickOnly(pickedObjectLists, matchObject);
// return true;
// }
if ( !matchObject )
return false;
PickOnly(pickedObjectLists, matchObject);
varX.SetValue(resultX);
varY.SetValue(resultY);
return true;
}
bool GD_API SceneVariableExists(RuntimeScene & scene, const gd::String & variable)
{

View File

@@ -97,7 +97,7 @@ bool GD_API PickNearestObject(std::map <gd::String, std::vector<RuntimeObject*>
/**
* Only used internally by GD events generated code.
*/
// bool GD_API RaycastObject(std::map <gd::String, std::vector<RuntimeObject*> *> pickedObjectLists, double x, double y, double angle, double dist, const gd::Variable & resultX, const gd::Variable & resultY, bool inverted);
bool GD_API RaycastObject(std::map <gd::String, std::vector<RuntimeObject*> *> pickedObjectLists, float x, float y, float angle, float dist, gd::Variable & varX, gd::Variable & varY, bool inverted);
/**
* Only used internally by GD events generated code.

View File

@@ -7,6 +7,7 @@
#include "GDCpp/Runtime/Polygon2d.h"
#include <cmath>
#include <cfloat>
#include <iostream>
namespace
{
@@ -30,6 +31,13 @@ float dotProduct(const sf::Vector2f a, const sf::Vector2f b)
return dp;
}
float crossProduct(const sf::Vector2f a, const sf::Vector2f b)
{
float cp = a.x*b.y - a.y*b.x;
return cp;
}
void project(const sf::Vector2f axis, const Polygon2d & p, float& min, float& max)
{
float dp = dotProduct(axis, p.vertices[0]);
@@ -129,6 +137,132 @@ CollisionResult GD_API PolygonCollisionTest(Polygon2d & p1, Polygon2d & p2)
return result;
}
RaycastResult GD_API PolygonRaycastTest(Polygon2d & poly, float startX, float startY, float endX, float endY)
{
RaycastResult result;
result.collision = false;
if ( poly.vertices.size() < 2 )
{
return result;
}
if ( poly.vertices.size() == 2 )
{
float circleX = poly.vertices[0].x;
float circleY = poly.vertices[0].y;
float sqRadius = (circleX - poly.vertices[1].x)*(circleX - poly.vertices[1].x) +
(circleY - poly.vertices[1].y)*(circleY - poly.vertices[1].y);
float dx = endX - startX;
float dy = endY - startY;
float a = dx*dx + dy*dy;
float b = 2*(dx*(startX - circleX) + dy*(startY - circleY));
float c = (startX - circleX)*(startX - circleX) + (startY - circleY)*(startY - circleY) - sqRadius;
float det = b*b - 4*a*c;
if ( a == 0 || det < 0 ) return result;
if ( det == 0 )
{
float t = -b/(2*a);
if ( 0 <= t && t <= 1 ) {
result.closePoint.x = startX + t*dx;
result.closePoint.y = startY + t*dy;
result.closeSqDist = t*t*a;
result.farPoint = result.closePoint;
result.farSqDist = result.closeSqDist;
result.collision = true;
}
}
else
{
float sqDet = sqrt(det);
float t = (-b + sqDet)/(2*a);
if ( 0 <= t && t <= 1 ) {
result.closePoint.x = startX + t*dx;
result.closePoint.y = startY + t*dy;
result.closeSqDist = t*t*a;
result.farPoint = result.closePoint;
result.farSqDist = result.closeSqDist;
result.collision = true;
}
t = (-b - sqDet)/(2*a);
if ( 0 <= t && t <= 1 ){
result.closePoint.x = startX + t*dx;
result.closePoint.y = startY + t*dy;
result.closeSqDist = t*t*a;
if ( !result.collision ) {
result.farPoint = result.closePoint;
result.farSqDist = result.closeSqDist;
}
result.collision = true;
}
}
return result;
}
else
{
// Polygon raycasting
poly.ComputeEdges();
sf::Vector2f p, q, r, s;
float minSqDist = FLT_MAX;
// ray segment: p + t*r, with p = start and r = end - start
p.x = startX;
p.y = startY;
r.x = endX - startX;
r.y = endY - startY;
for(int i=0; i<poly.edges.size(); i++)
{
// edge segment: q + u*s
q = poly.vertices[i];
s = poly.edges[i];
sf::Vector2f deltaQP = q - p;
float crossRS = crossProduct(r, s);
float t = crossProduct(deltaQP, s) / crossRS;
float u = crossProduct(deltaQP, r) / crossRS;
if ( crossRS == 0 && crossProduct(deltaQP, r) == 0)
{
// TODO Collinear
}
else if ( crossRS != 0 && 0<=t && t<=1 && 0<=u && u<=1 )
{
sf::Vector2f point = p + t*r;
float sqDist = (point.x-startX)*(point.x-startX) + (point.y-startY)*(point.y-startY);
if ( sqDist < minSqDist )
{
if ( !result.collision ){
result.farPoint = point;
result.farSqDist = sqDist;
}
minSqDist = sqDist;
result.closePoint = point;
result.closeSqDist = sqDist;
result.collision = true;
}
else
{
result.farPoint = point;
result.farSqDist = sqDist;
}
}
}
return result;
}
}
bool GD_API IsPointInsidePolygon(Polygon2d & poly, float x, float y)
{
bool inside = false;

View File

@@ -19,6 +19,15 @@ struct CollisionResult
sf::Vector2f move_axis;
};
struct RaycastResult
{
bool collision;
sf::Vector2f closePoint;
float closeSqDist;
sf::Vector2f farPoint;
float farSqDist;
};
/**
* Do a collision test between the two polygons.
* \warning Polygons must convexes.
@@ -33,6 +42,16 @@ struct CollisionResult
*/
CollisionResult GD_API PolygonCollisionTest(Polygon2d & p1, Polygon2d & p2);
/**
* Do a raycast test.
* \warning Polygon must be convex.
*
* \return A raycast result with the contact points and distances
*
* \ingroup GameEngine
*/
RaycastResult GD_API PolygonRaycastTest(Polygon2d & poly, float startX, float startY, float endX, float endY);
/**
* Check if a point is inside a polygon.
*

View File

@@ -4,6 +4,8 @@
* This project is released under the MIT License.
*/
#include <cstring>
// #include <cfloat>
#include <cmath>
#include "GDCore/Tools/Localization.h"
#include "GDCpp/Extensions/Builtin/MathematicalTools.h"
#include "GDCpp/Runtime/RuntimeObject.h"
@@ -390,6 +392,43 @@ bool RuntimeObject::IsCollidingWithPoint(float pointX, float pointY){
return false;
}
RaycastResult RuntimeObject::RaycastTest(float x, float y, float angle, float dist, bool closest){
float objW = GetWidth();
float objH = GetHeight();
float diffX = GetDrawableX()+GetCenterX() - x;
float diffY = GetDrawableY()+GetCenterY() - y;
float boundingRadius = sqrt(objW*objW + objH*objH)/2.0;
RaycastResult result;
result.collision = false;
if ( sqrt(diffX*diffX + diffY*diffY) > boundingRadius + dist )
return result;
float endX = x + dist*cos(angle*3.14159/180.0);
float endY = y + dist*sin(angle*3.14159/180.0);
float testSqDist = closest ? dist*dist : 0.0f;
vector<Polygon2d> hitboxes = GetHitBoxes();
for (std::size_t i = 0; i < hitboxes.size(); ++i)
{
RaycastResult res = PolygonRaycastTest(hitboxes[i], x, y, endX, endY);
if ( res.collision ) {
if ( closest && (res.closeSqDist < testSqDist) ) {
testSqDist = res.closeSqDist;
result = res;
}
else if ( !closest && (res.farSqDist > testSqDist) && (res.farSqDist <= dist*dist) ) {
testSqDist = res.farSqDist;
result = res;
}
}
}
return result;
}
void RuntimeObject::SeparateObjectsWithoutForces( std::map <gd::String, std::vector<RuntimeObject*> *> pickedObjectLists)
{
vector<RuntimeObject*> objects2;

View File

@@ -20,6 +20,7 @@ namespace gd { class InitialInstance; }
namespace gd { class Object; }
namespace sf { class RenderTarget; }
class Polygon2d;
class RaycastResult;
class RuntimeScene;
/**
@@ -231,6 +232,17 @@ public:
*/
bool IsCollidingWithPoint(float pointX, float pointY);
/**
* \brief Check if a ray intersect any object hitbox.
* \param x The raycast source X
* \param y The raycast source Y
* \param angle The raycast angle
* \param dist The raycast max distance
* \param closest Get the closest or farthest collision mask result?
* \return A raycast result with the contact points and distances
*/
RaycastResult RaycastTest(float x, float y, float angle, float dist, bool closest);
/**
* \brief Check collision with each object of the list using their hitboxes, and move the object
* according to the sum of the move vector returned by each collision test.

View File

@@ -316,11 +316,11 @@ gdjs.evtTools.object.pickNearestObject = function(objectsLists, x, y, inverted)
return true;
};
gdjs.evtTools.object.raycastObject = function(objectsLists, x, y, angle, dist, resultX, resultY, inverted) {
gdjs.evtTools.object.raycastObject = function(objectsLists, x, y, angle, dist, varX, varY, inverted) {
var matchObject = null;
var testSqDist = inverted ? 0 : dist*dist;
var rx = 0;
var ry = 0;
var resultX = 0;
var resultY = 0;
var lists = gdjs.staticArray(gdjs.evtTools.object.raycastObject);
objectsLists.values(lists);
@@ -335,25 +335,25 @@ gdjs.evtTools.object.raycastObject = function(objectsLists, x, y, angle, dist, r
if ( !inverted && (result.closeSqDist <= testSqDist) ) {
testSqDist = result.closeSqDist;
matchObject = object;
rx = result.closeX;
ry = result.closeY;
resultX = result.closeX;
resultY = result.closeY;
}
else if ( inverted && (result.farSqDist >= testSqDist) && (result.farSqDist <= dist*dist) ) {
else if ( inverted && (result.farSqDist >= testSqDist) ) {
testSqDist = result.farSqDist;
matchObject = object;
rx = result.farX;
ry = result.farY;
resultX = result.farX;
resultY = result.farY;
}
}
}
}
if (!matchObject)
if ( !matchObject )
return false;
gdjs.evtTools.object.pickOnly(objectsLists, matchObject);
resultX.setNumber(rx);
resultY.setNumber(ry);
varX.setNumber(resultX);
varY.setNumber(resultY);
return true;
};

View File

@@ -221,7 +221,7 @@ gdjs.Polygon.collisionTest._statics = {
/**
* Do a raycast test.<br>
* Please note that polygons must be <b>convexes</b>!
* Please note that the polygon must be <b>convex</b>!
*
* @method raycastTest
* @static
@@ -230,7 +230,7 @@ gdjs.Polygon.collisionTest._statics = {
* @param startY {Number} The raycast start point Y
* @param endX {Number} The raycast end point X
* @param endY {Number} The raycast end point Y
* @return A raycast result with the collision points and distances
* @return A raycast result with the contact points and distances
*/
gdjs.Polygon.raycastTest = function(poly, startX, startY, endX, endY)
{
@@ -261,7 +261,7 @@ gdjs.Polygon.raycastTest = function(poly, startX, startY, endX, endY)
if ( det === 0 )
{
var t = -b/(2*a);
if ( 0 <= t && t <= 1 ) {
if ( 0 <= t && t <= 1 ) {
result.closeX = startX + t*dx;
result.closeY = startY + t*dy;
result.closeSqDist = t*t*a;
@@ -334,7 +334,11 @@ gdjs.Polygon.raycastTest = function(poly, startX, startY, endX, endY)
var u = gdjs.Polygon.crossProduct(deltaQP, r) / crossRS;
if ( crossRS !== 0 && 0<=t && t<=1 && 0<=u && u<=1 )
if ( crossRS === 0 && gdjs.Polygon.crossProduct(deltaQP, r) === 0)
{
// TODO Collinear
}
else if ( crossRS !== 0 && 0<=t && t<=1 && 0<=u && u<=1 )
{
var x = p[0] + t*r[0];
var y = p[1] + t*r[1];
@@ -342,16 +346,16 @@ gdjs.Polygon.raycastTest = function(poly, startX, startY, endX, endY)
var sqDist = (x-startX)*(x-startX) + (y-startY)*(y-startY);
if ( sqDist < minSqDist )
{
if ( result.collision === false ){
if ( !result.collision ){
result.farX = x;
result.farY = y;
result.farSqDist = sqDist;
}
minSqDist = sqDist;
result.collision = true;
result.closeX = x;
result.closeY = y;
result.closeSqDist = sqDist;
result.collision = true;
}
else
{
@@ -360,10 +364,6 @@ gdjs.Polygon.raycastTest = function(poly, startX, startY, endX, endY)
result.farSqDist = sqDist;
}
}
else if ( crossRS === 0 && gdjs.Polygon.crossProduct(deltaQP, r) === 0)
{
// TODO Collinear
}
}
return result;

View File

@@ -1157,8 +1157,8 @@ gdjs.RuntimeObject.collisionTest = function(obj1, obj2) {
* @param y {Number} The raycast source Y
* @param angle {Number} The raycast angle
* @param dist {Number} The raycast max distance
* @param closest {Boolean} Get the closest or farthest collision mask result
* @return A raycast result with the collision points and distances
* @param closest {Boolean} Get the closest or farthest collision mask result?
* @return A raycast result with the contact points and distances
*/
gdjs.RuntimeObject.prototype.raycastTest = function(x, y, angle, dist, closest) {
var objW = this.getWidth();
@@ -1166,25 +1166,28 @@ gdjs.RuntimeObject.prototype.raycastTest = function(x, y, angle, dist, closest)
var diffX = this.getDrawableX()+this.getCenterX() - x;
var diffY = this.getDrawableY()+this.getCenterY() - y;
var boundingRadius = Math.sqrt(objW*objW + objH*objH)/2.0;
if ( Math.sqrt(diffX*diffX + diffY*diffY) > boundingRadius + dist )
return false;
var result = gdjs.Polygon.raycastTest._statics.result;
result.collision = false;
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 testSqDist = closest ? 0 : Number.MAX_VALUE;
// var testSqDist = closest ? 0 : Number.MAX_VALUE;
var testSqDist = closest ? dist*dist : 0;
var hitBoxes = this.getHitBoxes();
for (var i=0; i<hitBoxes.length; i++) {
var res = gdjs.Polygon.raycastTest(hitBoxes[i], x, y, endX, endY);
if ( res.collision ) {
if ( closest && res.closeSqDist < testSqDist ) {
if ( closest && (res.closeSqDist < testSqDist) ) {
testSqDist = res.closeSqDist;
result = res;
}
else if ( !closest && res.farSqDist > testSqDist ) {
else if ( !closest && (res.farSqDist > testSqDist) && (res.farSqDist <= dist*dist) ) {
testSqDist = res.farSqDist;
result = res;
}
@@ -1194,15 +1197,6 @@ gdjs.RuntimeObject.prototype.raycastTest = function(x, y, angle, dist, closest)
return result;
};
/**
* Check the distance between two objects.
* @method distanceTest
* @static
*/
gdjs.RuntimeObject.distanceTest = function(obj1, obj2, distance) {
return obj1.getSqDistanceToObject(obj2) <= distance;
};
/**
* Return true if the specified position is inside object bounding box.
*
@@ -1218,6 +1212,15 @@ gdjs.RuntimeObject.prototype.insideObject = function(x, y) {
&& this.getDrawableY() + this.getHeight() >= y;
}
/**
* Check the distance between two objects.
* @method distanceTest
* @static
*/
gdjs.RuntimeObject.distanceTest = function(obj1, obj2, distance) {
return obj1.getSqDistanceToObject(obj2) <= distance;
};
/**
* Return true if the cursor, or any touch, is on the object.
*

View File

@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<project firstLayout="">
<gdVersion build="96" major="4" minor="0" revision="135" />
<gdVersion build="96" major="4" minor="0" revision="136" />
<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>
<windowWidth>400</windowWidth>
<windowHeight>300</windowHeight>
<windowWidth>800</windowWidth>
<windowHeight>600</windowHeight>
<latestCompilationDirectory></latestCompilationDirectory>
<maxFPS>60</maxFPS>
<minFPS>10</minFPS>
@@ -34,6 +34,7 @@
</extensions>
<platforms>
<platform name="GDevelop JS platform" />
<platform name="GDevelop C++ platform" />
</platforms>
<currentPlatform>GDevelop JS platform</currentPlatform>
</properties>
@@ -51,7 +52,7 @@
<variables />
<layouts>
<layout b="30" disableInputWhenNotFocused="true" mangledName="Scene" name="Scene" oglFOV="90.000000" oglZFar="500.000000" oglZNear="1.000000" r="30" standardSortMethod="false" stopSoundsOnStartup="true" title="" v="30">
<uiSettings grid="false" gridB="80" gridG="80" gridHeight="70" gridOffsetX="0" gridOffsetY="20" gridR="80" gridWidth="70" snap="true" windowMask="false" zoomFactor="1.391885" />
<uiSettings grid="false" gridB="80" gridG="80" gridHeight="70" gridOffsetX="0" gridOffsetY="20" gridR="80" gridWidth="70" snap="true" windowMask="false" zoomFactor="0.754867" />
<objectsGroups>
<group name="Colliders">
<objects>
@@ -64,132 +65,132 @@
</objectsGroups>
<variables />
<instances>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="Player" width="0.000000" x="199.063065" y="149.320938" zOrder="2">
<instance angle="0.000000" customSize="true" height="64.000000" layer="" locked="false" name="Player" width="64.000000" x="400.000000" y="300.000000" zOrder="2">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="80.000000" layer="" locked="false" name="Quad" width="80.000000" x="246.705933" y="212.292755" zOrder="1">
<instance angle="0.000000" customSize="true" height="160.000000" layer="" locked="false" name="Quad" width="160.000000" x="511.653046" y="426.899933" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="187.155807" y="37.701031" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="642.864868" y="20.479473" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="157.403275" y="263.996765" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="340.216797" y="524.969666" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="32.689121" y="48.477802" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="52.560143" y="106.766174" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="108.126335" y="17.584469" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="202.182587" y="29.507092" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="325.212219" y="106.484894" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="550.417358" y="268.102661" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="111.251595" y="232.307541" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="259.622040" y="466.785736" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="332.282593" y="22.613647" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="640.945984" y="188.205658" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="272.274597" y="147.940628" zOrder="1">
<instance angle="0.000000" customSize="true" height="80.000000" layer="" locked="false" name="Quad" width="80.000000" x="330.563049" y="69.781281" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="7.230614" y="272.390564" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="13.854311" y="547.935608" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="100.000000" layer="" locked="false" name="Circle" width="100.000000" x="18.591335" y="78.514206" zOrder="4">
<instance angle="0.000000" customSize="true" height="200.000000" layer="" locked="false" name="Circle" width="200.000000" x="30.513973" y="183.168365" zOrder="4">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="Circle" width="0.000000" x="5.659197" y="2.358517" zOrder="4">
<instance angle="0.000000" customSize="true" height="64.000000" layer="" locked="false" name="Circle" width="64.000000" x="22.880741" y="14.281113" zOrder="4">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="Circle" width="0.000000" x="349.078369" y="59.834511" zOrder="4">
<instance angle="0.000000" customSize="true" height="64.000000" layer="" locked="false" name="Circle" width="64.000000" x="694.834351" y="81.030281" zOrder="4">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="Circle" width="0.000000" x="155.815277" y="215.738190" zOrder="4">
<instance angle="0.000000" customSize="true" height="64.000000" layer="" locked="false" name="Circle" width="64.000000" x="321.407257" y="436.969086" zOrder="4">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="Drawer" width="0.000000" x="237.000183" y="107.970665" zOrder="5">
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="Drawer" width="0.000000" x="467.504181" y="221.897949" zOrder="5">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="20.000000" layer="" locked="false" name="Quad" width="20.000000" x="336.280762" y="243.652557" zOrder="1">
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Quad" width="40.000000" x="687.335632" y="495.352386" zOrder="1">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="false" height="0.000000" layer="" locked="false" name="Circle" width="0.000000" x="124.203461" y="57.679169" zOrder="4">
<instance angle="0.000000" customSize="true" height="64.000000" layer="" locked="false" name="Circle" width="64.000000" x="231.507050" y="134.513855" zOrder="4">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="30.000000" layer="" locked="false" name="Triangle" width="30.000000" x="195.330048" y="259.563660" zOrder="3">
<instance angle="0.000000" customSize="true" height="60.000000" layer="" locked="false" name="Triangle" width="60.000000" x="432.457794" y="17.137005" zOrder="3">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="30.000000" layer="" locked="false" name="Triangle" width="30.000000" x="63.853691" y="27.504265" zOrder="3">
<instance angle="0.000000" customSize="true" height="60.000000" layer="" locked="false" name="Triangle" width="60.000000" x="119.492599" y="63.272141" zOrder="3">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="30.000000" layer="" locked="false" name="Triangle" width="30.000000" x="305.971375" y="168.320496" zOrder="3">
<instance angle="0.000000" customSize="true" height="60.000000" layer="" locked="false" name="Triangle" width="60.000000" x="625.232666" y="333.912476" zOrder="3">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="30.000000" layer="" locked="false" name="Triangle" width="30.000000" x="229.097198" y="174.068100" zOrder="3">
<instance angle="0.000000" customSize="true" height="60.000000" layer="" locked="false" name="Triangle" width="60.000000" x="476.822723" y="355.556915" zOrder="3">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="30.000000" layer="" locked="false" name="Triangle" width="30.000000" x="240.592422" y="16.727512" zOrder="3">
<instance angle="0.000000" customSize="true" height="60.000000" layer="" locked="false" name="Triangle" width="60.000000" x="404.859680" y="522.776550" zOrder="3">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="40.000000" layer="" locked="false" name="Polygon" width="50.000000" x="11.406837" y="183.407883" zOrder="4">
<instance angle="0.000000" customSize="true" height="80.000000" layer="" locked="false" name="Polygon" width="100.000000" x="19.355259" y="383.442963" zOrder="4">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="27.728058" layer="" locked="false" name="Polygon" width="50.000000" x="356.262939" y="256.689789" zOrder="4">
<instance angle="0.000000" customSize="true" height="50.000000" layer="" locked="false" name="Polygon" width="100.000000" x="723.214783" y="536.209045" zOrder="4">
<numberProperties />
<stringProperties />
<initialVariables />
</instance>
<instance angle="0.000000" customSize="true" height="70.893356" layer="" locked="false" name="Polygon" width="29.883392" x="280.825653" y="23.193504" zOrder="4">
<instance angle="0.000000" customSize="true" height="140.000000" layer="" locked="false" name="Polygon" width="60.000000" x="517.953369" y="37.765617" zOrder="4">
<numberProperties />
<stringProperties />
<initialVariables />
@@ -343,6 +344,51 @@
</object>
</objects>
<events>
<event disabled="false" folded="false">
<type>BuiltinCommonInstructions::Standard</type>
<conditions>
<instruction>
<type inverted="false" value="DepartScene" />
<parameters>
<parameter></parameter>
</parameters>
<subInstructions />
</instruction>
</conditions>
<actions />
<events>
<event disabled="false" folded="false">
<type>BuiltinCommonInstructions::Repeat</type>
<repeatExpression>300</repeatExpression>
<conditions />
<actions>
<instruction>
<type inverted="false" value="Create" />
<parameters>
<parameter></parameter>
<parameter>Polygon</parameter>
<parameter>Random(200)</parameter>
<parameter>Random(200)</parameter>
<parameter></parameter>
</parameters>
<subInstructions />
</instruction>
<instruction>
<type inverted="false" value="Create" />
<parameters>
<parameter></parameter>
<parameter>Circle</parameter>
<parameter>500 + Random(300)</parameter>
<parameter>400 + Random(200)</parameter>
<parameter></parameter>
</parameters>
<subInstructions />
</instruction>
</actions>
<events />
</event>
</events>
</event>
<event disabled="false" folded="false">
<type>BuiltinCommonInstructions::Standard</type>
<conditions />
@@ -378,7 +424,7 @@
<parameter>Drawer</parameter>
<parameter>Player.X()</parameter>
<parameter>Player.Y()</parameter>
<parameter>200</parameter>
<parameter>400</parameter>
</parameters>
<subInstructions />
</instruction>
@@ -395,7 +441,7 @@
<parameter>Player.X()</parameter>
<parameter>Player.Y()</parameter>
<parameter>ToDeg(atan2(MouseY(&quot;&quot;,0)-Player.Y(), MouseX(&quot;&quot;,0)-Player.X()))</parameter>
<parameter>200</parameter>
<parameter>400</parameter>
<parameter>x</parameter>
<parameter>y</parameter>
<parameter></parameter>
@@ -409,7 +455,7 @@
<parameters>
<parameter>Colliders</parameter>
<parameter>+</parameter>
<parameter>90 * TimeDelta()</parameter>
<parameter>10 * TimeDelta()</parameter>
</parameters>
<subInstructions />
</instruction>
@@ -438,7 +484,7 @@
<parameter>Player.Y()</parameter>
<parameter>Variable(x)</parameter>
<parameter>Variable(y)</parameter>
<parameter>0.5</parameter>
<parameter>1</parameter>
</parameters>
<subInstructions />
</instruction>
@@ -448,7 +494,7 @@
<parameter>Drawer</parameter>
<parameter>Variable(x)</parameter>
<parameter>Variable(y)</parameter>
<parameter>2</parameter>
<parameter>3</parameter>
</parameters>
<subInstructions />
</instruction>
@@ -465,7 +511,7 @@
<parameter>Player.X()</parameter>
<parameter>Player.Y()</parameter>
<parameter>ToDeg(atan2(MouseY(&quot;&quot;,0)-Player.Y(), MouseX(&quot;&quot;,0)-Player.X()))</parameter>
<parameter>200</parameter>
<parameter>400</parameter>
<parameter>x</parameter>
<parameter>y</parameter>
<parameter></parameter>
@@ -507,7 +553,7 @@
<parameter>Player.Y()</parameter>
<parameter>Variable(x)</parameter>
<parameter>Variable(y)</parameter>
<parameter>0.5</parameter>
<parameter>1</parameter>
</parameters>
<subInstructions />
</instruction>
@@ -517,7 +563,7 @@
<parameter>Drawer</parameter>
<parameter>Variable(x)</parameter>
<parameter>Variable(y)</parameter>
<parameter>1</parameter>
<parameter>2</parameter>
</parameters>
<subInstructions />
</instruction>