Bladeren bron

🐛 Fix Area2D mouse collision calculations

- Add Collisions singleton to deal with collision calculations with shapes,
- Fix globalScale calculations.
Pedro Schneider 2 jaren geleden
bovenliggende
commit
03d2fbbd0f

+ 1 - 0
build

@@ -6,6 +6,7 @@ rm pandora.min.js
 # Package singletons
 cat pandora/singletons/Enums.js > build.js
 cat pandora/singletons/Easings.js >> build.js
+cat pandora/singletons/Collisions.js >> build.js
 
 # Package handlers
 cat pandora/handlers/GameHandler.js >> build.js

File diff suppressed because it is too large
+ 1 - 1
pandora.min.js


+ 0 - 15
pandora/components/Ellipse.js

@@ -44,19 +44,4 @@ class Ellipse extends Shape
         this.rx = rx;
         this.ry = ry;
     }
-
-    /**
-     * Calculates if a point (x, y) lies iside the ellipse, assuming the
-     * ellipse is on the origin of the Cartesian plane.
-     * 
-     * @param {number} x    x-cooridnate of the point. 
-     * @param {number} y    y-coordinate of the point.
-     * 
-     * @returns {boolean}   true if the point lies within the bounds of the
-     *                      ellipse, false if not. 
-     */
-    isIn(x, y)
-    {
-        return (x * x) * (this.ry * this.ry) + (y * y) * (this.rx * this.rx) <= (this.rx * this.rx) * (this.ry * this.ry);
-    }
 }

+ 0 - 15
pandora/components/Rect.js

@@ -44,19 +44,4 @@ class Rect extends Shape
         this.w = w;
         this.h = h;
     }
-
-    /**
-     * Calculates if a point (x, y) lies iside the rect, assuming the
-     * rect is on the origin of the Cartesian plane.
-     * 
-     * @param {number} x    x-cooridnate of the point. 
-     * @param {number} y    y-coordinate of the point.
-     * 
-     * @returns {boolean}   true if the point lies within the bounds of the
-     *                      rect, false if not. 
-     */
-    isIn(x, y)
-    {
-        return abs(x) <= this.w / 2 && abs(y) <= this.h / 2;
-    }
 }

+ 2 - 2
pandora/game_objects/2d_objects/AnimatedSprite2D.js

@@ -213,8 +213,8 @@ class AnimatedSprite2D extends Sprite2D
             this.globalPosition.x = this.parent.globalPosition.x + this.position.x;
             this.globalPosition.y = this.parent.globalPosition.y + this.position.y;
             this.globalRotationDegrees = this.parent.globalRotationDegrees + this.rotationDegrees;
-            this.globalScale.x = this.parent.globalScale.x + this.scale.x;
-            this.globalScale.y = this.parent.globalScale.y + this.scale.y;
+            this.globalScale.x = this.parent.globalScale.x * this.scale.x;
+            this.globalScale.y = this.parent.globalScale.y * this.scale.y;
         }
 
         // Forwards the animation.

+ 13 - 3
pandora/game_objects/2d_objects/Area2D.js

@@ -50,6 +50,15 @@ class Area2D extends Object2D
         super(name);
 
         this.shapeType = shapeType;
+        switch (this.shapeType)
+        {
+            case SHAPES.RECT:
+                this.shapeName = "Rect";
+                break;
+            case SHAPES.ELLIPSE:
+                this.shapeName = "Ellipse";
+                break;
+        }
         this.shape = shape;
         this.listenToMouse = listenToMouse;
         this.drawDebug = drawDebug;
@@ -106,14 +115,15 @@ class Area2D extends Object2D
             this.globalPosition.x = this.parent.globalPosition.x + this.position.x;
             this.globalPosition.y = this.parent.globalPosition.y + this.position.y;
             this.globalRotationDegrees = this.parent.globalRotationDegrees + this.rotationDegrees;
-            this.globalScale.x = this.parent.globalScale.x + this.scale.x;
-            this.globalScale.y = this.parent.globalScale.y + this.scale.y;
+            this.globalScale.x = this.parent.globalScale.x * this.scale.x;
+            this.globalScale.y = this.parent.globalScale.y * this.scale.y;
         }
 
         // Checks collision with mouse
         if (this.listenToMouse)
         {
-            if (this.shape.isIn(GameHandler.mouseX - this.globalPosition.x, GameHandler.mouseY - this.globalPosition.y))
+            if (Collisions[this.shapeName].point(this.globalPosition.x, this.globalPosition.y, this.globalRotationDegrees, this.globalScale.x,
+                this.globalScale.y, this.shape, GameHandler.mouseX, GameHandler.mouseY))
             {
                 if (!this.mouseIn)
                     this.emitSignal("mouseEntered");

+ 3 - 3
pandora/game_objects/2d_objects/Object2D.js

@@ -138,15 +138,15 @@ class Object2D extends GameObject
         {
             this.globalPosition = this.position;
             this.globalRotationDegrees = this.rotationDegrees;
-            this.globalScale = this.globalScale;
+            this.globalScale = this.scale;
         }
         else
         {
             this.globalPosition.x = this.parent.globalPosition.x + this.position.x;
             this.globalPosition.y = this.parent.globalPosition.y + this.position.y;
             this.globalRotationDegrees = this.parent.globalRotationDegrees + this.rotationDegrees;
-            this.globalScale.x = this.parent.globalScale.x + this.scale.x;
-            this.globalScale.y = this.parent.globalScale.y + this.scale.y;
+            this.globalScale.x = this.parent.globalScale.x * this.scale.x;
+            this.globalScale.y = this.parent.globalScale.y * this.scale.y;
         }
 
         // Callbacks

+ 117 - 0
pandora/singletons/Collisions.js

@@ -0,0 +1,117 @@
+/************************************************************************
+ * Collisions.js
+ ************************************************************************
+ * Copyright (c) 2021 Pedro Tonini Rosenberg Schneider.
+ *
+ * This file is part of Pandora.
+ *
+ * Pandora is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pandora is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *     
+ * You should have received a copy of the GNU General Public License     
+ * along with Pandora.  If not, see <https://www.gnu.org/licenses/>.
+ *************************************************************************/
+
+/**
+ * This {@code Collisions} singleton provides an interface for the engine to calculate collisions
+ * with various differente shapes. They are used in the calculations of the Area2D GameObject,
+ * to check collisions with the mouse. They can be utilized by the user if it fits the need.
+ * 
+ * @author Pedro Schneider
+ * 
+ * @namespace
+ */
+const Collisions = {
+    /**
+     * Rotates the (x, y) vector by a degrees clockwise, around the origin.
+     * 
+     * @param {number} x    X coordinate of the vector to rotate.
+     * @param {number} y    Y coordinate of the vector to rotate.
+     * @param {number} a    angle in degrees to rotate the vector.
+     * 
+     * @returns {Array}     static array containing the tow coordinates of the rotated vector.
+     *                      Can be deconstructed. 
+     */
+    rotate(x, y, a)
+    {
+        var rotx = x,
+            roty = y;
+        if (a % 360 != 0)
+        {
+            rotx = x * cos(-radians(a)) - y * sin(-radians(a));
+            roty = x * sin(-radians(a)) + y * cos(-radians(a));
+        }
+
+        return Object.freeze([rotx, roty]);
+    },
+
+    /**
+     * Namespace to separate rectangle collision detection.
+     * 
+     * @namespace
+     */
+    Rect:
+    {
+        /**
+         * Calculates if a point is inside a rect.
+         * 
+         * @param {number} posx global X-axis position of the rect. 
+         * @param {number} posy global Y-axis position of the rect.
+         * @param {number} rot  global rotation in degrees of the rect.
+         * @param {number} sx   global X-axis scale of the rect.
+         * @param {number} sy   global Y-axis scale of the rect.
+         * @param {Rect} rect   Shape component with the rect data.
+         * @param {number} x    X-axis position of the point.
+         * @param {number} y    Y-axis position of the point.
+         * 
+         * @returns {boolean}   true if the point is inside the rect, false otherwise. 
+         */
+        point(posx, posy, rot, sx, sy, rect, x, y)
+        {
+            x -= posx;
+            y -= posy;
+
+            var [rotx, roty] = Collisions.rotate(x, y, rot);
+            return abs(rotx) <= rect.w / 2 * sx && abs(roty) <= rect.h / 2 * sy;
+        },
+    },
+
+    /**
+     * Namespace to separate ellipse collision detection.
+     * 
+     * @namespace
+     */
+    Ellipse:
+    {
+        /**
+         * Calculates if a point is inside a ellipse.
+         * 
+         * @param {number} posx global X-axis position of the ellipse. 
+         * @param {number} posy global Y-axis position of the ellipse.
+         * @param {number} rot  global rotation in degrees of the ellipse.
+         * @param {number} sx   global X-axis scale of the ellipse.
+         * @param {number} sy   global Y-axis scale of the ellipse.
+         * @param {Ellipse} e   Shape component with the ellipse data.
+         * @param {number} x    X-axis position of the point.
+         * @param {number} y    Y-axis position of the point.
+         * 
+         * @returns {boolean}   true if the point is inside the ellipse, false otherwise. 
+         */
+        point(posx, posy, rot, sx, sy, e, x, y)
+        {
+            x -= posx;
+            y -= posy;
+
+            var [rotx, roty] = Collisions.rotate(x, y, rot);
+            var srx = e.rx * sx, sry = e.ry * sy;
+            return (rotx * rotx) * (sry * sry) + (roty * roty) * (srx * srx) <= (srx * srx) * (sry * sry);
+        }
+    }
+}

+ 1 - 1
src/sketch.js

@@ -33,7 +33,7 @@ GameHandler._setup = function()
     GameHandler.drawDebugBufferBounds(true);
     textFont(AssetHandler.getP5FontByName("Lato"));
 
-    test = new Area2D("myTest", SHAPES.RECT, new Rect(200, 400), true, true);
+    test = new Area2D("myTest", SHAPES.ELLIPSE, new Ellipse(200, 400), true, true);
     test2 = new TestObj("myDummy");
     test2.setPosition(600, 600);
     test2.addChild(test);