123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- /** Example that fakes the momentum/energy conservation. We simply keep the
- record of total speed in the system (as an approximation of
- momentum/energy/whatever) and if it changes too much, we multiply them
- accordingly to get them back :) */
- #include "helper.h"
- #define SPHERE_R (7 * TPE_F)
- TPE_Vec3 environmentDistance(TPE_Vec3 p, TPE_Unit maxD)
- {
- TPE_ENV_START( TPE_envSphereInside(p,TPE_vec3(0,0,0),SPHERE_R),p )
- TPE_ENV_END
- }
- int main(void)
- {
- helper_init();
- tpe_world.environmentFunction = environmentDistance;
- s3l_scene.camera.transform.translation.z = -1 * SPHERE_R - 2 * TPE_F;
- for (int i = 0; i < 4; ++i) // add bodies
- {
- switch (i)
- {
- case 0: helper_addBox(5 * TPE_F / 4,5 * TPE_F / 4,5 * TPE_F / 4,TPE_F,2 * TPE_F); break;
- case 1: helper_addBall(TPE_F,TPE_F / 4); break;
- case 2: helper_addRect(5 * TPE_F / 4,5 * TPE_F / 4,TPE_F,2 * TPE_F); break;
- case 3: helper_add2Line(2 * TPE_F,TPE_F / 2,TPE_F); break;
- default: break;
- }
- TPE_bodyMoveBy(&helper_lastBody,TPE_vec3((i - 2) * TPE_F * 2,-1 * TPE_F * i,TPE_F / 2));
- /* We don't want any energy losses due to friction and non-elastic collision,
- so we'll turn them off. This alone won't be enough though as numeric errors
- will still change the total energy. */
- helper_lastBody.friction = 0;
- helper_lastBody.elasticity = TPE_FRACTIONS_PER_UNIT;
- helper_lastBody.flags |= TPE_BODY_FLAG_ALWAYS_ACTIVE;
- TPE_bodyAccelerate(&helper_lastBody, // give some initial velocity
- TPE_vec3Plus(TPE_vec3Times(TPE_bodyGetCenterOfMass(&helper_lastBody),TPE_F / 10),TPE_vec3(0,TPE_F / 100,0)));
- }
- TPE_Unit sTotal = TPE_worldGetNetSpeed(&tpe_world);
- // ^ keep the record of total speed
- while (helper_running)
- {
- helper_frameStart();
- helper_cameraFreeMovement();
- TPE_worldStep(&tpe_world);
- TPE_Unit s = TPE_worldGetNetSpeed(&tpe_world);
- TPE_Unit ratio = (sTotal * TPE_FRACTIONS_PER_UNIT) / TPE_nonZero(s);
- if (ratio < (4 * TPE_FRACTIONS_PER_UNIT) / 5 ||
- ratio > (6 * TPE_FRACTIONS_PER_UNIT) / 5)
- {
- // if total speed changed by more than 1/5, we adjust it
- printf("net speed is now %d but needs to be %d, correcting!\n",s,sTotal);
- for (int i = 0; i < tpe_world.bodyCount; ++i)
- TPE_bodyMultiplyNetSpeed(&tpe_world.bodies[i],ratio);
- }
- helper_set3DColor(200,10,10);
- for (int i = 0; i < tpe_world.bodyCount; ++i) // draw the bodies
- {
- TPE_Joint *joints = tpe_world.bodies[i].joints;
- TPE_Vec3 pos = TPE_bodyGetCenterOfMass(&tpe_world.bodies[i]);
- TPE_Vec3 right = TPE_vec3(TPE_F,0,0);
- TPE_Vec3 forw = TPE_vec3(0,0,TPE_F);
- if (i != 1) // ugly code to get the correct orientation :)
- {
- if (i != 3)
- {
- forw = TPE_vec3Minus(joints[2].position,joints[0].position);
- right = TPE_vec3Minus(joints[1].position,joints[0].position);
- }
- else
- forw = TPE_vec3Minus(joints[1].position,joints[0].position);
- }
- TPE_Vec3 orient = TPE_rotationFromVecs(forw,right);
- switch (i % 5) // and draw the correct shape
- {
- case 0: helper_draw3DBox(pos,TPE_vec3(1200,1200,1200),orient); break;
- case 1: helper_draw3DSphere(pos,TPE_vec3(500,500,500),orient); break;
- case 2: helper_draw3DBox(pos,TPE_vec3(1200,400,1200),orient); break;
- case 3: helper_draw3DBox(pos,TPE_vec3(200,200,1200),orient); break;
- default: break;
- }
- }
- helper_set3DColor(200,200,200);
- helper_draw3DSphereInside(TPE_vec3(0,0,0),
- TPE_vec3(SPHERE_R,SPHERE_R,SPHERE_R),TPE_vec3(0,0,0));
- if (helper_debugDrawOn)
- helper_debugDraw(1);
- helper_frameEnd();
- }
- helper_end();
- return 0;
- }
|