forked from enlightenment/efl
EPhysics: allow user to configure simulation
Required to fine tunning performance or avoid objects going throught others. SVN revision: 74659
This commit is contained in:
parent
6dd9396d6f
commit
ca3e40782a
|
@ -115,7 +115,7 @@ test_collision_speed(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *e
|
||||||
speed_data->bt = bt;
|
speed_data->bt = bt;
|
||||||
|
|
||||||
sp = elm_spinner_add(speed_data->base.win);
|
sp = elm_spinner_add(speed_data->base.win);
|
||||||
elm_spinner_min_max_set(sp, 0, 500);
|
elm_spinner_min_max_set(sp, 0, 300);
|
||||||
elm_spinner_step_set(sp, 5);
|
elm_spinner_step_set(sp, 5);
|
||||||
elm_spinner_value_set(sp, 100);
|
elm_spinner_value_set(sp, 100);
|
||||||
elm_object_style_set(sp, "ephysics-test");
|
elm_object_style_set(sp, "ephysics-test");
|
||||||
|
@ -124,6 +124,7 @@ test_collision_speed(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *e
|
||||||
|
|
||||||
world = ephysics_world_new();
|
world = ephysics_world_new();
|
||||||
ephysics_world_render_geometry_set(world, 50, 40, WIDTH - 100, FLOOR_Y - 40);
|
ephysics_world_render_geometry_set(world, 50, 40, WIDTH - 100, FLOOR_Y - 40);
|
||||||
|
ephysics_world_simulation_set(world, 1/260.f, 5);
|
||||||
speed_data->base.world = world;
|
speed_data->base.world = world;
|
||||||
|
|
||||||
boundary = ephysics_body_bottom_boundary_add(world);
|
boundary = ephysics_body_bottom_boundary_add(world);
|
||||||
|
|
|
@ -950,6 +950,86 @@ EAPI void ephysics_world_bodies_outside_left_autodel_set(EPhysics_World *world,
|
||||||
*/
|
*/
|
||||||
EAPI Eina_Bool ephysics_world_bodies_outside_left_autodel_get(const EPhysics_World *world);
|
EAPI Eina_Bool ephysics_world_bodies_outside_left_autodel_get(const EPhysics_World *world);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Set world simulation's fixed time step and max number of sub steps
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* It's important that time step is always less than
|
||||||
|
* @p max_sub_steps * @p fixed_time_step, otherwise you are losing time.
|
||||||
|
* Mathematically:
|
||||||
|
*
|
||||||
|
* time step < @p max_sub_steps * @p fixed_time_step;
|
||||||
|
*
|
||||||
|
* If you're a using a very large time step
|
||||||
|
* [say, five times the size of the fixed internal time step],
|
||||||
|
* then you must increase the number of max sub steps to compensate for this,
|
||||||
|
* otherwise your simulation is “losing” time.
|
||||||
|
*
|
||||||
|
* The time step may vary. Simulation ticks are called by an animator,
|
||||||
|
* so, by default, time step is @c 1/30 secs. If you're using elementary,
|
||||||
|
* default FPS configuration is 60 fps, i.e. time step is @c 1/60 secs.
|
||||||
|
* You can change that setting a
|
||||||
|
* different time with ecore_animator_frametime_set().
|
||||||
|
*
|
||||||
|
* Also, keep in mind
|
||||||
|
* that if you're using CPU intense calculations maybe this framerate won't
|
||||||
|
* be achieved, so the time step will be bigger. You need to define
|
||||||
|
* what range of frames per secons you need to support and configure
|
||||||
|
* @p max_sub_steps and @p fixed_time_step according to this.
|
||||||
|
*
|
||||||
|
* By decreasing the size of @p fixed_time_step, you are increasing the
|
||||||
|
* “resolution” of the simulation.
|
||||||
|
*
|
||||||
|
* If you are finding that your objects are moving very fast and escaping
|
||||||
|
* from your walls instead of colliding with them, then one way to help fix
|
||||||
|
* this problem is by decreasing @p fixed_time_step. If you do this,
|
||||||
|
* then you will need to increase @p max_sub_steps to ensure the equation
|
||||||
|
* listed above is still satisfied.
|
||||||
|
*
|
||||||
|
* The issue with this is that each internal “tick” takes an amount of
|
||||||
|
* computation. More of them means your CPU will be spending more time on
|
||||||
|
* physics and therefore less time on other stuff. Say you want twice the
|
||||||
|
* resolution, you'll need twice the @p max_sub_steps, which could chew up
|
||||||
|
* twice as much CPU for the same amount of simulation time.
|
||||||
|
*
|
||||||
|
* When you pass @p max_sub_steps > 1, it will interpolate movement for you.
|
||||||
|
* This means that if your @p fixed_time_step is 3 units, and you pass
|
||||||
|
* a timeStep of 4, then it will do exactly one tick, and estimate the
|
||||||
|
* remaining movement by 1/3. This saves you having to do interpolation
|
||||||
|
* yourself, but keep in mind that maxSubSteps needs to be greater than 1.
|
||||||
|
*
|
||||||
|
* By default @p fixed_time_step is 1/60 seconds and @p max_sub_steps is 3.
|
||||||
|
*
|
||||||
|
* @param world The physics world.
|
||||||
|
* @param fixed_time_step size of the internal simulation step, in seconds.
|
||||||
|
* @param max_sub_steps maximum number of steps that simulation is allowed
|
||||||
|
* to take at each simulation tick.
|
||||||
|
*
|
||||||
|
* @note The unit used for time is seconds.
|
||||||
|
*
|
||||||
|
* @see ephysics_world_simulation_get().
|
||||||
|
*
|
||||||
|
* @ingroup EPhysics_World
|
||||||
|
*/
|
||||||
|
EAPI void ephysics_world_simulation_set(EPhysics_World *world, double fixed_time_step, int max_sub_steps);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief
|
||||||
|
* Get world simulation's fixed time step and max number of sub steps
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* @param world The physics world.
|
||||||
|
* @param fixed_time_step size of the internal simulation step, in seconds.
|
||||||
|
* @param max_sub_steps maximum number of steps that simulation is allowed
|
||||||
|
* to take at each simulation tick.
|
||||||
|
*
|
||||||
|
* @see ephysics_world_simulation_set() for details.
|
||||||
|
*
|
||||||
|
* @ingroup EPhysics_World
|
||||||
|
*/
|
||||||
|
EAPI void ephysics_world_simulation_get(const EPhysics_World *world, double *fixed_time_step, int *max_sub_steps);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,8 +31,10 @@ struct _EPhysics_World {
|
||||||
Evas_Coord x, y, w, h;
|
Evas_Coord x, y, w, h;
|
||||||
Eina_Inlist *callbacks;
|
Eina_Inlist *callbacks;
|
||||||
Eina_List *bodies;
|
Eina_List *bodies;
|
||||||
|
int max_sub_steps;
|
||||||
double last_update;
|
double last_update;
|
||||||
double rate;
|
double rate;
|
||||||
|
double fixed_time_step;
|
||||||
Eina_Bool running:1;
|
Eina_Bool running:1;
|
||||||
Eina_Bool active:1;
|
Eina_Bool active:1;
|
||||||
Eina_Bool outside_autodel:1;
|
Eina_Bool outside_autodel:1;
|
||||||
|
@ -141,7 +143,8 @@ _simulate_worlds(void *data)
|
||||||
world->last_update = time_now;
|
world->last_update = time_now;
|
||||||
|
|
||||||
gDeactivationTime = world->max_sleeping_time;
|
gDeactivationTime = world->max_sleeping_time;
|
||||||
world->dynamics_world->stepSimulation(delta, 1, 1/40.f);
|
world->dynamics_world->stepSimulation(delta, world->max_sub_steps,
|
||||||
|
world->fixed_time_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
|
@ -342,6 +345,8 @@ ephysics_world_new(void)
|
||||||
world->dynamics_world->getPairCache()->setOverlapFilterCallback(filter_cb);
|
world->dynamics_world->getPairCache()->setOverlapFilterCallback(filter_cb);
|
||||||
|
|
||||||
world->rate = 30;
|
world->rate = 30;
|
||||||
|
world->max_sub_steps = 3;
|
||||||
|
world->fixed_time_step = 1/60.f;
|
||||||
world->dynamics_world->setInternalTickCallback(_ephysics_world_tick_cb,
|
world->dynamics_world->setInternalTickCallback(_ephysics_world_tick_cb,
|
||||||
(void *) world);
|
(void *) world);
|
||||||
|
|
||||||
|
@ -927,7 +932,7 @@ ephysics_world_bodies_outside_right_autodel_get(const EPhysics_World *world)
|
||||||
return world->outside_right;
|
return world->outside_right;
|
||||||
}
|
}
|
||||||
|
|
||||||
Eina_Bool
|
EAPI Eina_Bool
|
||||||
ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world)
|
ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world)
|
||||||
{
|
{
|
||||||
if (!world)
|
if (!world)
|
||||||
|
@ -939,6 +944,47 @@ ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world)
|
||||||
return world->outside_autodel;
|
return world->outside_autodel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ephysics_world_simulation_set(EPhysics_World *world, double fixed_time_step, int max_sub_steps)
|
||||||
|
{
|
||||||
|
if (!world)
|
||||||
|
{
|
||||||
|
ERR("Can't set simulation, no world provided.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_sub_steps < 1)
|
||||||
|
{
|
||||||
|
ERR("At least one sub step for simulation is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ecore_animator_frametime_get() >= max_sub_steps * fixed_time_step)
|
||||||
|
{
|
||||||
|
ERR("Assure frametime < max sub steps * fixed time step.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
world->max_sub_steps = max_sub_steps;
|
||||||
|
world->fixed_time_step = fixed_time_step;
|
||||||
|
|
||||||
|
DBG("World %p simulation set to fixed time step: %lf, max substeps:%i.",
|
||||||
|
world, fixed_time_step, max_sub_steps);
|
||||||
|
}
|
||||||
|
|
||||||
|
EAPI void
|
||||||
|
ephysics_world_simulation_get(const EPhysics_World *world, double *fixed_time_step, int *max_sub_steps)
|
||||||
|
{
|
||||||
|
if (!world)
|
||||||
|
{
|
||||||
|
ERR("No world, can't get simulation configuration.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fixed_time_step) *fixed_time_step = world->fixed_time_step;
|
||||||
|
if (max_sub_steps) *max_sub_steps = world->max_sub_steps;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue