ZeroEpsilon/spec/engine/physics_spec.cr

112 lines
4.1 KiB
Crystal

require "spec"
require "../../src/engine/physics"
describe Physics do
it "test basic tick usage" do
time = Time.utc
one_second = Time::Span.new(seconds: 1)
t1 = Physics::Tick.new(n: 0, time: time, last: nil)
t2 = Physics::Tick.new(n: 1, time: time + one_second, last: t1)
t2.timelaps.should eq(one_second)
end
it "test basic timer" do
timer = Physics::Tick::Timer.new
start_time = timer.tick.time
timer.tick.n.should eq(0)
12.times { timer.timeskip!(seconds: 1) }
timer.tick.n.should eq(12)
timer.tick.time.should eq(start_time + Time::Span.new(seconds: 12))
end
it "accelerate an object" do
a_ball_movement = Vector[0.0, 0.0, 0.0]
a_engine_accelerate = Vector[20.0, 0.0, 0.0]
timer = Physics::Tick::Timer.new
timer.timeskip!(seconds: 1)
Physics.accelerate_by_one_tick!(timer.tick, a_ball_movement, a_engine_accelerate)
a_ball_movement[0].should eq(20.0)
a_ball_movement[1].should eq(0.0)
timer.timeskip!(milliseconds: 500)
Physics.accelerate_by_one_tick!(timer.tick, a_ball_movement, a_engine_accelerate)
a_ball_movement[0].should eq(30.0)
a_ball_movement[1].should eq(0.0)
timer.timeskip!(milliseconds: 500)
Physics.accelerate_by_one_tick!(timer.tick, a_ball_movement, a_engine_accelerate)
a_ball_movement[0].should eq(40.0)
a_ball_movement[1].should eq(0.0)
a_engine_stopped = Vector[0.0, 0.0, 0.0]
timer.timeskip!(milliseconds: 500)
Physics.accelerate_by_one_tick!(timer.tick, a_ball_movement, a_engine_stopped)
a_ball_movement[0].should eq(40.0)
a_ball_movement[1].should eq(0.0)
a_retro_pulse = Vector[0.0, 0.1, 0.0]
timer.timeskip!(milliseconds: 500)
Physics.accelerate_by_one_tick!(timer.tick, a_ball_movement, a_retro_pulse)
a_ball_movement[0].should eq(40.0)
a_ball_movement[1].should eq(0.05)
end
it "move and accelerate an object" do
a_ball_position = Vector[0.0, 0.0, 0.0]
a_ball_movement = Vector[0.0, 0.0, 0.0]
a_engine_accelerate = Vector[20.0, 0.0, 0.0]
timer = Physics::Tick::Timer.new
timer.timeskip!(seconds: 1)
Physics.move_by_one_tick!(timer.tick, a_ball_position, a_ball_movement, a_engine_accelerate)
a_ball_position[0].should eq(10.0)
a_ball_position[1].should eq(0.0)
a_ball_movement[0].should eq(20.0)
a_ball_movement[1].should eq(0.0)
timer.timeskip!(seconds: 1)
Physics.move_by_one_tick!(timer.tick, a_ball_position, a_ball_movement, a_engine_accelerate)
a_ball_position[0].should eq(40.0)
a_ball_position[1].should eq(0.0)
a_ball_movement[0].should eq(40.0)
a_ball_movement[1].should eq(0.0)
# cut a second in 2 computations gives the same result as one second
timer.timeskip!(milliseconds: 500)
Physics.move_by_one_tick!(timer.tick, a_ball_position, a_ball_movement, a_engine_accelerate)
a_ball_position[0].should eq(62.5)
a_ball_position[1].should eq(0.0)
a_ball_movement[0].should eq(50.0)
a_ball_movement[1].should eq(0.0)
timer.timeskip!(milliseconds: 500)
Physics.move_by_one_tick!(timer.tick, a_ball_position, a_ball_movement, a_engine_accelerate)
a_ball_position[0].should eq(90.0)
a_ball_position[1].should eq(0.0)
a_ball_movement[0].should eq(60.0)
a_ball_movement[1].should eq(0.0)
a_gravity_generator = Vector[0.0, 0.0, 0.0]
a_retro_pulse = Vector[0.0, 0.1, 0.0]
star_gravity = Vector[-0.01, 0.02, 0.01]
total_forces = a_gravity_generator + a_retro_pulse + star_gravity
timer.timeskip!(seconds: 1)
Physics.move_by_one_tick!(timer.tick, a_ball_position, a_ball_movement, total_forces)
a_ball_position[0].round(3).should eq(149.995)
a_ball_position[1].round(3).should eq(0.06)
a_ball_position[2].round(3).should eq(0.005)
a_ball_movement[0].round(3).should eq(59.99)
a_ball_movement[1].round(3).should eq(0.12)
a_ball_movement[2].round(3).should eq(0.01)
end
end
# v0 = 40 m/s
# a = 20 m/s²
# t1 = 0.5 s
# v1 = v0 + a * t1 = 40 + 20 * 0.6 = 50 m/s (m/s + m/s^2*s = m/s)
# [v] = (v0 + v1) / 2 = (40 + 50) / 2 = 45 (m/s + m/s)
# d = [v] * (t1 - t0) = 45 * 0.5 = 22.5 (m/s * s)