Browse Source

Physac redesign (3/3)

Finally, physics update is handled in main thread using steps to get
accuracy in collisions detection instead of moving it to a new thread.

Examples are finished as simple and clear as I could. Finally, physac
module is MORE simpler than in the first version, calculation everything
by the same way for both types of physic objects.

I tryed to add rotated physics a couple of times but I didn't get
anything good to get a base to improve it. Maybe for the next version...

No bugs or strange behaviours found during testing.
victorfisac 9 years ago
parent
commit
60223a358b

+ 6 - 3
examples/physics_basic_rigidbody.c

@@ -65,7 +65,7 @@ int main()
         if (IsKeyDown('A')) rectangle->rigidbody.velocity.x = -MOVE_VELOCITY;
         else if (IsKeyDown('D')) rectangle->rigidbody.velocity.x = MOVE_VELOCITY;
         
-        // Check player 2 movement inputs
+        // Check square movement inputs
         if (IsKeyDown(KEY_UP) && square->rigidbody.isGrounded) square->rigidbody.velocity.y = JUMP_VELOCITY;
         if (IsKeyDown(KEY_LEFT)) square->rigidbody.velocity.x = -MOVE_VELOCITY;
         else if (IsKeyDown(KEY_RIGHT)) square->rigidbody.velocity.x = MOVE_VELOCITY;
@@ -80,17 +80,20 @@ int main()
 
             ClearBackground(RAYWHITE);
 
-            // Convert transform values to rectangle data type variable
-            DrawRectangleRec(TransformToRectangle(floor->transform), DARKGRAY);
+            // Draw floor, roof and walls rectangles
+            DrawRectangleRec(TransformToRectangle(floor->transform), DARKGRAY);         // Convert transform values to rectangle data type variable
             DrawRectangleRec(TransformToRectangle(leftWall->transform), DARKGRAY);
             DrawRectangleRec(TransformToRectangle(rightWall->transform), DARKGRAY);
             DrawRectangleRec(TransformToRectangle(roof->transform), DARKGRAY);
             
+            // Draw middle platform rectangle
             DrawRectangleRec(TransformToRectangle(platform->transform), DARKGRAY);
             
+            // Draw physic objects
             DrawRectangleRec(TransformToRectangle(rectangle->transform), RED);
             DrawRectangleRec(TransformToRectangle(square->transform), BLUE);
             
+            // Draw collider lines if debug is enabled
             if (isDebug)
             {
                 DrawRectangleLines(floor->collider.bounds.x, floor->collider.bounds.y, floor->collider.bounds.width, floor->collider.bounds.height, GREEN);

BIN
examples/physics_basic_rigidbody.png


+ 31 - 9
examples/physics_forces.c

@@ -12,9 +12,12 @@
 #include "raylib.h"
 #include "math.h"
 
-#define FORCE_AMOUNT    5.0f
-#define FORCE_RADIUS    150
-#define LINE_LENGTH     100
+#define FORCE_AMOUNT        5.0f
+#define FORCE_RADIUS        150
+#define LINE_LENGTH         75
+#define TRIANGLE_LENGTH     12
+
+void DrawRigidbodyCircle(PhysicObject *obj, Color color);
 
 int main()
 {
@@ -42,6 +45,7 @@ int main()
     }
     
     // Create circles physic objects
+    // NOTE: when creating circle physic objects, transform.scale must be { 0, 0 } and object radius must be defined in collider.radius and use this value to draw the circle.
     PhysicObject *circles[3];
     for (int i = 0; i < 3; i++)
     {
@@ -111,14 +115,23 @@ int main()
                 // Draw force radius
                 DrawCircleLines(mousePosition.x, mousePosition.y, FORCE_RADIUS, BLACK);
                 
-                // Draw direction line
+                // Draw direction lines
                 if (CheckCollisionPointCircle((Vector2){ rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2, rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 }, mousePosition, FORCE_RADIUS))
                 {
                     Vector2 direction = { rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2 - mousePosition.x, rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 - mousePosition.y };
                     float angle = atan2l(direction.y, direction.x);
                     
-                    DrawLineV((Vector2){ rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2, rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 },
-                    (Vector2){ rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2 + (cos(angle)*LINE_LENGTH), rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 + (sin(angle)*LINE_LENGTH) }, BLACK);
+                    // Calculate arrow start and end positions
+                    Vector2 startPosition = { rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2, rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 };
+                    Vector2 endPosition = { rectangles[i]->transform.position.x + rectangles[i]->transform.scale.x/2 + (cos(angle)*LINE_LENGTH), rectangles[i]->transform.position.y + rectangles[i]->transform.scale.y/2 + (sin(angle)*LINE_LENGTH) };
+                    
+                    // Draw arrow line
+                    DrawLineV(startPosition, endPosition, BLACK);
+                    
+                    // Draw arrow triangle
+                    DrawTriangleLines((Vector2){ endPosition.x - cos(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH, endPosition.y - sin(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH },
+                                      (Vector2){ endPosition.x + cos(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH, endPosition.y + sin(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH },
+                                      (Vector2){ endPosition.x + cos(angle)*LINE_LENGTH/TRIANGLE_LENGTH*2, endPosition.y + sin(angle)*LINE_LENGTH/TRIANGLE_LENGTH*2 }, BLACK);
                 }
             }
             
@@ -131,14 +144,23 @@ int main()
                 // Draw force radius
                 DrawCircleLines(mousePosition.x, mousePosition.y, FORCE_RADIUS, BLACK);
                 
-                // Draw direction line
+                // Draw direction lines
                 if (CheckCollisionPointCircle((Vector2){ circles[i]->transform.position.x, circles[i]->transform.position.y }, mousePosition, FORCE_RADIUS))
                 {
                     Vector2 direction = { circles[i]->transform.position.x - mousePosition.x, circles[i]->transform.position.y - mousePosition.y };
                     float angle = atan2l(direction.y, direction.x);
                     
-                    DrawLineV((Vector2){ circles[i]->transform.position.x, circles[i]->transform.position.y },
-                    (Vector2){ circles[i]->transform.position.x + (cos(angle)*LINE_LENGTH), circles[i]->transform.position.y + (sin(angle)*LINE_LENGTH) }, BLACK);
+                    // Calculate arrow start and end positions
+                    Vector2 startPosition = { circles[i]->transform.position.x, circles[i]->transform.position.y };
+                    Vector2 endPosition = { circles[i]->transform.position.x + (cos(angle)*LINE_LENGTH), circles[i]->transform.position.y + (sin(angle)*LINE_LENGTH) };
+                    
+                    // Draw arrow line
+                    DrawLineV(startPosition, endPosition, BLACK);
+                    
+                    // Draw arrow triangle
+                    DrawTriangleLines((Vector2){ endPosition.x - cos(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH, endPosition.y - sin(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH },
+                                      (Vector2){ endPosition.x + cos(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH, endPosition.y + sin(angle + 90*DEG2RAD)*LINE_LENGTH/TRIANGLE_LENGTH },
+                                      (Vector2){ endPosition.x + cos(angle)*LINE_LENGTH/TRIANGLE_LENGTH*2, endPosition.y + sin(angle)*LINE_LENGTH/TRIANGLE_LENGTH*2 }, BLACK);
                 }
             }
             

BIN
examples/physics_forces.png


+ 26 - 23
src/physac.c

@@ -2,7 +2,7 @@
 *
 *   [physac] raylib physics module - Basic functions to apply physics to 2D objects
 *
-*   Copyright (c) 2015 Victor Fisac and Ramon Santamaria
+*   Copyright (c) 2016 Victor Fisac and Ramon Santamaria
 *
 *   This software is provided "as-is", without any express or implied warranty. In no event
 *   will the authors be held liable for any damages arising from the use of this software.
@@ -75,10 +75,7 @@ void InitPhysics(Vector2 gravity)
 void UpdatePhysics()
 {
     // Reset all physic objects is grounded state
-    for (int i = 0; i < physicObjectsCount; i++)
-    {
-        if (physicObjects[i]->rigidbody.enabled) physicObjects[i]->rigidbody.isGrounded = false;
-    }
+    for (int i = 0; i < physicObjectsCount; i++) physicObjects[i]->rigidbody.isGrounded = false;
     
     for (int steps = 0; steps < PHYSICS_STEPS; steps++)
     {
@@ -537,26 +534,32 @@ void ApplyForceAtPosition(Vector2 position, float force, float radius)
 {
     for(int i = 0; i < physicObjectsCount; i++)
     {
-        // Calculate direction and distance between force and physic object pposition
-        Vector2 distance = (Vector2){ physicObjects[i]->transform.position.x - position.x, physicObjects[i]->transform.position.y - position.y };
-
-        if(physicObjects[i]->collider.type == COLLIDER_RECTANGLE)
+        if(physicObjects[i]->rigidbody.enabled)
         {
-            distance.x += physicObjects[i]->transform.scale.x/2;
-            distance.y += physicObjects[i]->transform.scale.y/2;
-        }
-        
-        float distanceLength = Vector2Length(distance);
-        
-        // Check if physic object is in force range
-        if(distanceLength <= radius)
-        {
-            // Normalize force direction
-            distance.x /= distanceLength;
-            distance.y /= -distanceLength;
+            // Calculate direction and distance between force and physic object pposition
+            Vector2 distance = (Vector2){ physicObjects[i]->transform.position.x - position.x, physicObjects[i]->transform.position.y - position.y };
+
+            if(physicObjects[i]->collider.type == COLLIDER_RECTANGLE)
+            {
+                distance.x += physicObjects[i]->transform.scale.x/2;
+                distance.y += physicObjects[i]->transform.scale.y/2;
+            }
+            
+            float distanceLength = Vector2Length(distance);
             
-            // Apply force to the physic object
-            ApplyForce(physicObjects[i], (Vector2){ distance.x*force, distance.y*force });
+            // Check if physic object is in force range
+            if(distanceLength <= radius)
+            {
+                // Normalize force direction
+                distance.x /= distanceLength;
+                distance.y /= -distanceLength;
+                
+                // Calculate final force
+                Vector2 finalForce = { distance.x*force, distance.y*force };
+                
+                // Apply force to the physic object
+                ApplyForce(physicObjects[i], finalForce);
+            }
         }
     }
 }

+ 3 - 3
src/physac.h

@@ -2,7 +2,7 @@
 *
 *   [physac] raylib physics module - Basic functions to apply physics to 2D objects
 *
-*   Copyright (c) 2015 Victor Fisac and Ramon Santamaria
+*   Copyright (c) 2016 Victor Fisac and Ramon Santamaria
 *
 *   This software is provided "as-is", without any express or implied warranty. In no event
 *   will the authors be held liable for any damages arising from the use of this software.
@@ -44,8 +44,8 @@ typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE } ColliderType;
 
 typedef struct Transform {
     Vector2 position;
-    float rotation;
-    Vector2 scale;
+    float rotation;         // Radians (not used)
+    Vector2 scale;          // Just for rectangle physic objects, for circle physic objects use collider radius and keep scale as { 0, 0 }
 } Transform;
 
 typedef struct Rigidbody {

+ 2 - 2
src/raylib.h

@@ -498,8 +498,8 @@ typedef enum { COLLIDER_CIRCLE, COLLIDER_RECTANGLE } ColliderType;
 
 typedef struct Transform {
     Vector2 position;
-    float rotation;
-    Vector2 scale;
+    float rotation;         // Radians (not used)
+    Vector2 scale;          // Just for rectangle physic objects, for circle physic objects use collider radius and keep scale as { 0, 0 }
 } Transform;
 
 typedef struct Rigidbody {