RosettaCodeData/Task/Animate-a-pendulum/Zig/animate-a-pendulum-2.zig
2023-07-01 13:44:08 -04:00

54 lines
1.7 KiB
Zig

pub fn main() void {
c.SetConfigFlags(c.FLAG_VSYNC_HINT);
c.InitWindow(640, 320, "Pendulum");
defer c.CloseWindow();
// Simulation constants.
const g = 9.81; // Gravity (should be positive).
const length = 5.0; // Pendulum length.
const theta0 = math.pi / 3.0; // Initial angle for which omega = 0.
const e = g * length * (1 - @cos(theta0)); // Total energy = potential energy when starting.
// Simulation variables.
var theta: f32 = theta0; // Current angle.
var omega: f32 = 0; // Angular velocity = derivative of theta.
var accel: f32 = -g / length * @sin(theta0); // Angular acceleration = derivative of omega.
c.SetTargetFPS(60);
while (!c.WindowShouldClose()) // Detect window close button or ESC key
{
const half_width = @as(f32, @floatFromInt(c.GetScreenWidth())) / 2;
const pivot = c.Vector2{ .x = half_width, .y = 0 };
// Compute the position of the mass.
const mass = c.Vector2{
.x = 300 * @sin(theta) + pivot.x,
.y = 300 * @cos(theta),
};
{
c.BeginDrawing();
defer c.EndDrawing();
c.ClearBackground(c.RAYWHITE);
c.DrawLineV(pivot, mass, c.GRAY);
c.DrawCircleV(mass, 20, c.GRAY);
}
// Update theta and omega.
const dt = c.GetFrameTime();
theta += (omega + dt * accel / 2) * dt;
omega += accel * dt;
// If, due to computation errors, potential energy is greater than total energy,
// reset theta to ±theta0 and omega to 0.
if (length * g * (1 - @cos(theta)) >= e) {
theta = math.sign(theta) * theta0;
omega = 0;
}
accel = -g / length * @sin(theta);
}
}