EPhysics - Bouncing Ball

The purpose of this example is to show how to write an simple application - as the name suggests - with a small ball bouncing on the ground and responding to users events by making it jump - applying a central impulse on it.

We'll guide you on defining a EPhysics world, defining its render geometry and the physics limiting boundaries, you'll learn how to add EPhysics bodies and how to associate it to evas objects. We also explain how to change restitution and friction properties. We see how to apply central impulse on a EPhysics_Body by implementing an elementary input event callback and calling the proper function.

# A test struct

While in this example we'll be working with a struct to hold some objects in our code. For clarity sake we present you the struct declaration in the following block.

typedef struct _Test_Data Test_Data;
struct _Test_Data {
EPhysics_World *world;
Evas_Object *layout;
Evas_Object *win;
Eina_List *constraints;
Eina_List *evas_objs;
Eina_List *bodies;
void *data;
};
EPhysics_World
struct _EPhysics_World EPhysics_World
World handle, most basic type of EPhysics.
Definition: EPhysics.h:901
Evas_Object
Efl_Canvas_Object Evas_Object
An Evas Object handle.
Definition: Evas_Common.h:185
_Eina_List
Type for a generic double linked list.
Definition: eina_list.h:318

# World Initialization

Calling ephysics_world_new() will create a new physics world with its collision configuration, constraint solver, broadphase interface and dispatcher.

The default gravity is set to -9.81. It's possible to stop a running world but its default status is running. Take a look at ephysics_world_running_set() for further informations about world running status.

world = ephysics_world_new();
ephysics_world_new
EAPI EPhysics_World * ephysics_world_new(void)
Create a new physics world.

# Render geometry

By setting the render geometry you tell ephysics the dimensions of rendered area to be take on account by default updates.

By default it starts with null x, y, z, width, height and depth. Initially there's no physics limits but - as we'll see later in this example - boundaries can be added by issuing either ephysics_body_top_boundary_add(), ephysics_body_bottom_boundary_add(), ephysics_body_left_boundary_add() and ephysics_body_right_boundary_add().

While setting the worlds render geometry the first parameter is our just created world, the following parameters indicate the x, y, z, width, height and depth of our area of interest.

ephysics_world_render_geometry_set(world, 50, 40, -50,
WIDTH - 100, FLOOR_Y - 40, DEPTH);
ephysics_world_render_geometry_set
EAPI void ephysics_world_render_geometry_set(EPhysics_World *world, Evas_Coord x, Evas_Coord y, Evas_Coord z, Evas_Coord w, Evas_Coord h, Evas_Coord d)
Set dimensions of rendered area to be take on account by default updates.

# Adding boundaries

Boundaries are physics limits added by EPhysics which you can use to limit the area where your objects can move around. Bear in mind that those boundaries are created by EPhysics taking in account the render geometry you have previously defined by calling ephysics_world_render_geometry_set().

In our example we start by adding a bottom boundary. This EPhysics_Body represents a physics limit under the world render geometry.

The second line states the restitution factor for that bottom boundary, and the third line its friction. These changes will make our ball to bounce whenever it hits the ground.

boundary = ephysics_body_bottom_boundary_add(test_data->world);
ephysics_body_restitution_set(boundary, 0.65);
ephysics_body_friction_set(boundary, 4);
ephysics_body_restitution_set
EAPI void ephysics_body_restitution_set(EPhysics_Body *body, double restitution)
Set body's coefficient of restitution.
ephysics_body_friction_set
EAPI void ephysics_body_friction_set(EPhysics_Body *body, double friction)
Set body's friction.
ephysics_body_bottom_boundary_add
EAPI EPhysics_Body * ephysics_body_bottom_boundary_add(EPhysics_World *world)
Create a physic bottom boundary.

Then we add a right boundary limiting the physics world on the left side, we also change its restitution and friction factors but with a smaller value, we don't want to make it bounce as much as it is when hits the ground.

boundary = ephysics_body_right_boundary_add(test_data->world);
ephysics_body_restitution_set(boundary, 0.4);
ephysics_body_friction_set(boundary, 3);
ephysics_body_right_boundary_add
EAPI EPhysics_Body * ephysics_body_right_boundary_add(EPhysics_World *world)
Create a physic right boundary.

We also add a left boundary taking the same considerations for right boundary.

boundary = ephysics_body_left_boundary_add(test_data->world);
ephysics_body_restitution_set(boundary, 0.4);
ephysics_body_friction_set(boundary, 3);
ephysics_body_left_boundary_add
EAPI EPhysics_Body * ephysics_body_left_boundary_add(EPhysics_World *world)
Create a physic left boundary.

One of this examples requirements is to make the ball jump after a specific user event, so the ball can suffer an impulse for any direction.

With an upper impulse we don't want our ball to fly all over there, we want to limit its upper movements, it's intended to limit the ball movement within a box, it should not leave the render geometry area, for that purpose we must define a top boundary.

ephysics_body_top_boundary_add(test_data->world);
ephysics_body_top_boundary_add
EAPI EPhysics_Body * ephysics_body_top_boundary_add(EPhysics_World *world)
Create a physic top boundary.

# Adding a ball

Since we have defined the physics limits with our boundaries it's time to add some fun. Here we add a ball as an elementary image widget and tell ephysics about it.

After setting the file that will be used as the image's source of our elm image we move it to the center of render geometry and resize it to 70x70 pixels and show it.

sphere = elm_image_add(test_data->win);
elm_image_file_set(
sphere, PACKAGE_DATA_DIR "/" EPHYSICS_TEST_THEME ".edj", "big-blue-ball");
evas_object_move(sphere, WIDTH / 3, HEIGHT / 8);
evas_object_resize(sphere, 70, 70);
evas_object_show(sphere);
elm_image_add
Evas_Object * elm_image_add(Evas_Object *parent)
Add a new image to the parent.
Definition: efl_ui_image.c:2735
elm_image_file_set
Eina_Bool elm_image_file_set(Evas_Object *obj, const char *file, const char *group)
Set the file that will be used as the image's source.
Definition: efl_ui_image.c:2435
evas_object_show
EVAS_API void evas_object_show(Evas_Object *eo_obj)
Makes the given Evas object visible.
Definition: evas_object_main.c:1814
evas_object_move
EVAS_API void evas_object_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
Move the given Evas object to the given location inside its canvas' viewport.
Definition: evas_object_main.c:1171
evas_object_resize
EVAS_API void evas_object_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
Changes the size of the given Evas object.
Definition: evas_object_main.c:1236

The evas object is just set and we must tell EPhysics about it, creating the EPhysics_Body representing our ball and associating it to the just created evas object.

Once the ball has been moved to the center of render geometry it should start falling after associating it to the EPhysics_Body. By default its mass is initially set to 1 kilo, but it can be changed by calling ephysics_body_mass_set(). Bear in mind that if you change its mass to 0 kilos it becomes a static body and will not move at all, the body will remain fixed in the initial position.

In the following code the first line adds a circle body, then we associate the evas object to EPhysics_Body, EPhysics will map every changes on physics object simulation to its evas object. Some restitution and friction factors are added as well.

# Making it jump

The next step is to give us the ability to make our ball to jump - actually apply some impulse whenever a key has been pressed. Then we add a elementary input callback to the window widget.

The jumping callback implementation consists on handling only key up events and discarding any other input event we get. We're interested on keyboard events only. All the operations done in the following lines are done on sphere EPhysics_Body previously created.

We mainly use the ephysics_body_central_impulse_apply() function. This function applies an impulse on the center of a body.

Once pressed <Up> key it applies a central impulse of 0 kilos on X axis, 10 kilos on Y and 0 kilos on Z - so the ball is forced up.

If <Down> key has been pressed we apply an impulse of 0 kilos on X axis, -10 kilos on Y and 0 kilos on Z - here the ball is forced down.

In the case of <Right> key pressing it's applied an impulse of 10 kilos on X axis, 0 kilos on Y and 0 kilos on Z - which applies a force to the right side. But if the key being pressed is <Left> the opposite is done, and an impulse of -10 kilos is applied on X, 0 kilos on Y and 0 kilos on Z - and the ball is forced to the left.

_on_keydown(void *data, Evas_Object *obj __UNUSED__, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
{
Evas_Event_Key_Down *ev = event_info;
EPhysics_Body *body = data;
if (type != EVAS_CALLBACK_KEY_UP)
return EINA_FALSE;
if (strcmp(ev->key, "Up") == 0)
ephysics_body_central_impulse_apply(body, 0, -300, 0);
else if (strcmp(ev->key, "Down") == 0)
ephysics_body_central_impulse_apply(body, 0, 300, 0);
else if (strcmp(ev->key, "Right") == 0)
ephysics_body_central_impulse_apply(body, 300, 0, 0);
else if (strcmp(ev->key, "Left") == 0)
ephysics_body_central_impulse_apply(body, -300, 0, 0);
return EINA_TRUE;
}
Evas_Callback_Type
Evas_Callback_Type
Identifier of callbacks to be set for Evas canvases or Evas objects.
Definition: Evas_Common.h:419
EVAS_CALLBACK_KEY_UP
@ EVAS_CALLBACK_KEY_UP
Key Release Event.
Definition: Evas_Common.h:431
ephysics_body_central_impulse_apply
EAPI void ephysics_body_central_impulse_apply(EPhysics_Body *body, double x, double y, double z)
Apply an impulse on the center of a body.
EPhysics_Body
struct _EPhysics_Body EPhysics_Body
Body handle, represents an object on EPhysics world.
Definition: EPhysics.h:655
EINA_TRUE
#define EINA_TRUE
boolean value TRUE (numerical value 1)
Definition: eina_types.h:539
EINA_FALSE
#define EINA_FALSE
boolean value FALSE (numerical value 0)
Definition: eina_types.h:533
_Evas_Event_Key_Down
Key press event.
Definition: Evas_Legacy.h:314
_Evas_Event_Key_Down::key
const char * key
The logical key : (eg shift+1 == exclamation)
Definition: Evas_Legacy.h:320

Here we finish the very simple bouncing ball example. The full source code can be found at test_bouncing_ball.c.