Parcourir la source

Add a function

Miloslav Číž il y a 4 ans
Parent
commit
e9ea9e1241
3 fichiers modifiés avec 97 ajouts et 5 suppressions
  1. 4 0
      make.sh
  2. 22 0
      test.c
  3. 71 5
      tinyphysicsengine.h

+ 4 - 0
make.sh

@@ -0,0 +1,4 @@
+#!/bin/sh
+
+rm test
+g++ -x c -std=c99 -Wall -Wextra -pedantic -O3 -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -o test test.c && ./test

+ 22 - 0
test.c

@@ -0,0 +1,22 @@
+#include "tinyphysicsengine.h"
+#include <stdio.h>
+
+int main(void)
+{
+
+
+
+TPE_Unit 
+  v1 = 6000,
+  v2 = 0,
+  m1 = 2000,
+  m2 = 2000;
+
+
+TPE_getVelocitiesAfterCollision(&v1,&v2,m1,m2,512);
+
+printf("%d %d\n",v1,v2);
+
+
+  return 0;
+}

+ 71 - 5
tinyphysicsengine.h

@@ -7,17 +7,30 @@
            found at https://creativecommons.org/publicdomain/zero/1.0/
            + additional waiver of all IP
   version: 0.1d
-*/
 
 
-#include <stdint.h>
+  CONVENTIONS:
+
+  - No floating point is used, we instead use integers (effectively a fixed
+    point). TPE_FRACTIONS_PER_UNIT is an equivalent to 1.0 in floating point and
+    all numbers are normalized by this constant.
+
+  - Units: for any measure only an abstract mathematical unit is used. This unit
+    always has TPE_FRACTIONS_PER_UNIT parts. You can see assign any
+    correcpondence with real life units to these units. E.g. 1 spatial unit
+    (which you can see as e.g. 1 meter) is equal to TPE_FRACTIONS_PER_UNIT.
+    Same with temporatl (e.g. 1 second) and mass (e.g. 1 kilogram) units, and
+    also any derived units, e.g. a unit of velocity (e.g. 1 m/s) is also equal
+    to 1 TPE_FRACTIONS_PER_UNIT. A full angle is also split into
+    TPE_FRACTIONS_PER_UNIT parts (instead of 2 * PI or degrees).
+*/
 
+#include <stdint.h>
 
 typedef int32_t TPE_Unit;
 
-/** How many fractions a spatial or temporal unit is split into. This is NOT
-  SUPPOSED TO BE REDEFINED, so rather don't do it (otherwise things may
-  overflow etc.). */
+/** How many fractions a unit is split into. This is NOT SUPPOSED TO BE
+  REDEFINED, so rather don't do it (otherwise things may overflow etc.). */
 #define TPE_FRACTIONS_PER_UNIT 512
 
 #define TPE_INFINITY 2147483647
@@ -72,5 +85,58 @@ typedef struct
 
 } TPE_PhysicsWorld;
 
+//------------------------------------------------------------------------------
+
+static inline TPE_Unit TPE_nonZero(TPE_Unit x)
+{
+  return x + (x == 0);
+}
+
+void TPE_getVelocitiesAfterCollision(
+  TPE_Unit *v1,
+  TPE_Unit *v2,
+  TPE_Unit m1,
+  TPE_Unit m2,
+  TPE_Unit elasticity
+)
+{
+  /* in the following a lot of TPE_FRACTIONS_PER_UNIT cancel out, feel free to
+     check if confused */
+
+  #define ANTI_OVERFLOW 30000
+  #define ANTI_OVERFLOW_SCALE 128
+
+  uint8_t overflowDanger = m1 > ANTI_OVERFLOW || *v1 > ANTI_OVERFLOW ||
+    m2 > ANTI_OVERFLOW || *v2 > ANTI_OVERFLOW;
+
+  if (overflowDanger)
+  {
+    m1 = (m1 != 0) ? TPE_nonZero(m1 / ANTI_OVERFLOW_SCALE) : 0;
+    m2 = (m2 != 0) ? TPE_nonZero(m2 / ANTI_OVERFLOW_SCALE) : 0;
+    *v1 = (*v1 != 0) ? TPE_nonZero(*v1 / ANTI_OVERFLOW_SCALE) : 0;
+    *v2 = (*v2 != 0) ? TPE_nonZero(*v2 / ANTI_OVERFLOW_SCALE) : 0;
+  }
+
+  TPE_Unit m1Pm2 = m1 + m2;
+  TPE_Unit v2Mv1 = *v2 - *v1;
+
+  TPE_Unit m1v1Pm2v2 = ((m1 * *v1) + (m2 * *v2));
+
+  *v1 = (((elasticity * m2 / TPE_FRACTIONS_PER_UNIT) * v2Mv1)
+    + m1v1Pm2v2) / m1Pm2;
+
+  *v2 = (((elasticity * m1 / TPE_FRACTIONS_PER_UNIT) * -1 * v2Mv1)
+    + m1v1Pm2v2) / m1Pm2;
+
+  if (overflowDanger)
+  {
+    *v1 *= ANTI_OVERFLOW_SCALE;
+    *v2 *= ANTI_OVERFLOW_SCALE;
+  }
+
+  #undef ANTI_OVERFLOW
+  #undef ANTI_OVERFLOW_SCALE
+}
+
 
 #endif // guard