Implementing Realistic Physics in a Simple C/C++ Game Using EasyX: Ball Animation with Gravity and Bounce Effects
8. Enhancing Fall and Collision Behavior
The current ball movement uses constant velocity, lacking realistic deceleration during bounces. Introducing basic physics calculations improves the visual fidelity. While professional open-source physics angines like Box2D and PhysX offer advanced simulation capabilities, this section implements simplified physics manually.
1) Improved Display Function
A refined display function includes boundary checks to prevent the ball from moving outside screen limits. Multiple directional bounds can be added as needed.
void render_ball_animation(ball_object_t* ball)
{
// Clamp position within screen bounds
if (ball->state->y > SCREEN_HEIGHT - ball->state->radius)
ball->state->y = SCREEN_HEIGHT - ball->state->radius;
else if (ball->state->y < ball->state->radius)
ball->state->y = ball->state->radius;
else if (ball->state->x > SCREEN_WIDTH - ball->state->radius)
ball->state->x = SCREEN_WIDTH - ball->state->radius;
else if (ball->state->x < ball->state->radius)
ball->state->x = ball->state->radius;
cleardevice();
fillcircle((int)ball->state->x, (int)ball->state->y, (int)ball->state->radius);
Sleep(50);
}
2) Implementing Free-Fall Motion
Replace uniform downward motion with acceleration-based fall. Since mass is not modeled, a constant vertical acceleration simulates gravity.
Physics update logic:
- Velocity increases by acceleration per frame
- Position updates based on current velocity
ball->state->velocity_y += ball->state->gravity_accel;
ball->state->y += ball->state->velocity_y * 1; // 1 represents time delta (frame)
3) Adding Damped Bounce Effect
When the ball hits the bottom or top edge, apply energy loss via velocity scaling.
ball->state->velocity_y = -0.95f * ball->state->velocity_y;
4) Complete Falling and Bouncing Sequence
Combine physics update and collision response. Constants are now encapsulated within the animation structure for better maintainability.
void simulate_falling_ball(ball_object_t* ball)
{
const float ENERGY_LOSS_FACTOR = 0.95f;
ball->state->velocity_y += ball->state->gravity_accel;
ball->state->y += ball->state->velocity_y;
if (ball->state->y >= SCREEN_HEIGHT - ball->state->radius)
{
ball->state->velocity_y = -ENERGY_LOSS_FACTOR * ball->state->velocity_y;
}
render_ball_animation(ball);
}
9. Creating Parabolic Trajectory Animation
Now implement a more complex animation: parabolic motion.
1) Directional Velocity Components
Instead of using angles and trigonometry, define independent x and y velocity components directly in the state structure.
float velocity_x; // Horizontal speed
float velocity_y; // Vertical speed
2) Parabolic Motion Logic
The ball moves under simulated gravity and rebounds off walls with energy loss:
- Update position based on current velocities
- Apply gravity to vertical velocity
- Reverse direcsion and dampen speed upon wall collision
ball->state->x += ball->state->velocity_x;
ball->state->y += ball->state->velocity_y;
ball->state->velocity_y += GRAVITY; // Simulate gravitational pull
// Handle collisions
if (ball->state->x >= SCREEN_WIDTH - ball->state->radius || ball->state->x <= ball->state->radius)
ball->state->velocity_x = -K * ball->state->velocity_x;
if (ball->state->y >= SCREEN_HEIGHT - ball->state->radius || ball->state->y <= ball->state->radius)
ball->state->velocity_y = -K * ball->state->velocity_y;
3) Full Parabolic Animation Functon
void simulate_parabolic_motion(ball_object_t* ball)
{
const float GRAVITY = 0.8f;
const float K = 0.95f;
ball->state->x += ball->state->velocity_x;
ball->state->y += ball->state->velocity_y;
ball->state->velocity_y += GRAVITY;
// Wall collision detection and response
if (ball->state->x >= SCREEN_WIDTH - ball->state->radius || ball->state->x <= ball->state->radius)
ball->state->velocity_x = -K * ball->state->velocity_x;
if (ball->state->y >= SCREEN_HEIGHT - ball->state->radius || ball->state->y <= ball->state->radius)
ball->state->velocity_y = -K * ball->state->velocity_y;
render_ball_animation(ball);
}
4) Main Loop Integration
Initialize initial velocity and run animation loop:
ball->state->velocity_x = 10.0f;
ball->state->velocity_y = 0.0f;
while (true)
{
simulate_parabolic_motion(&ball);
// simulate_falling_ball(&ball); // Alternative: use simple fall
}
This completes the core graphical behavior of the animated ball. Future improvements include refactoring the object structure to support multiple shapes, replacing Sleep() with a non-blocking timer system, and introducing callback function pointers for event handling. A finalized version will be made available later.