Compare commits

..

No commits in common. "c0445364da752f016f824c4ad960e656bdf357d9" and "7cc9ae15a9f1d2c19ef8540ab444de833640e9e0" have entirely different histories.

6 changed files with 400 additions and 552 deletions

View File

@ -27,19 +27,19 @@ class Projectable(N)
@gravity_body.speed @gravity_body.speed
end end
def sf_shape(offset : Vector(Float64, N) = Vector(Float64, N).zero) def sf_shape(coef : Float64 = 1.0, offset : Vector(Float64, N) = Vector(Float64, N).zero)
shape = SF::CircleShape.new(@size) shape = SF::CircleShape.new(@size)
shape.fill_color = SF.color(@color[0], @color[1], @color[2]) shape.fill_color = SF.color(@color[0], @color[1], @color[2])
shape.outline_thickness = @outline_size shape.outline_thickness = @outline_size
shape.outline_color = SF.color(@outline_color[0], @outline_color[1], @outline_color[2]) shape.outline_color = SF.color(@outline_color[0], @outline_color[1], @outline_color[2])
shape.position = sf_position(offset) shape.position = sf_position(coef, offset)
shape shape
end end
# the sf_position is the projected position of the gravity_body on the graphic plan # the sf_position is the projected position of the gravity_body on the graphic plan
def sf_position(offset : Vector(Float64, N) = Vector(Float64, N).zero) def sf_position(coef : Float64 = 1.0, offset : Vector(Float64, N) = Vector(Float64, N).zero)
zoomed_position = @gravity_body.position + offset zoomed_position = @gravity_body.position * coef + offset
SF.vector2(zoomed_position[0], zoomed_position[1]) SF.vector2(zoomed_position[0], zoomed_position[1])
end end
end end

View File

@ -186,25 +186,13 @@ class Vessel(N)
end end
class Navigation(N) < Station(N) class Navigation(N) < Station(N)
class Cadran
property radius : Array(Float64)
def initialize(default_radius : Float64 = 1000.0)
@radius = [] of Float64
@radius << default_radius if !default_radius.nil?
end
end
property zoom_select : Int32 property zoom_select : Int32
property zoom_position : Vector(Float64, N) property zoom_position : Vector(Float64, N)
property cadran : Cadran
property zoom_ratio : Float64
def initialize(*p, **o) def initialize(*p, **o)
super super
@zoom_ratio = 1.0
@zoom_select = 0 @zoom_select = 0
@zoom_position = Vector(Float64, N).zero @zoom_position = Vector(Float64, N).zero
@cadran = Cadran.new
end end
end end
end end

View File

@ -7,8 +7,6 @@ require "crsfml"
require "imgui" require "imgui"
require "imgui-sfml" require "imgui-sfml"
require "./physics_sandbox/*"
require "log" require "log"
Log.setup(:debug) Log.setup(:debug)
@ -22,58 +20,26 @@ class Game
@window : SF::RenderWindow @window : SF::RenderWindow
@delta_clock : SF::Clock @delta_clock : SF::Clock
@screen_center_position : Vector(Float64, 2) @screen_center_position : Vector(Float64, 2)
@center_position : Vector(Float64, 2)
@joystick_moved : Vector(Float64, 2) @joystick_moved : Vector(Float64, 2)
ZOOM = 1/4
SECOND_IN_NANO = 1_000_000_000 SECOND_IN_NANO = 1_000_000_000
DEFAULT_ZOOM = 5/16
def accuracy_frequency_nano_rate def accuracy_frequency_nano_rate
((SECOND_IN_NANO * @timescale) // @framerate).to_u64 ((SECOND_IN_NANO * @timescale) // @framerate).to_u64
end end
def draw(item : SF::VertexBuffer, transform : SF::Transform? = nil)
states = SF::RenderStates.new
if transform
states.transform = transform
end
@window.draw(item, states)
end
def draw(item : SF::Shape, transform : SF::Transform? = nil)
states = SF::RenderStates.new
if transform
states.transform = transform
end
@window.draw(item, states)
end
def default_viewport
SF.float_rect(0.0, 0.0, 1.0, @width / @height)
end
def initialize(@framerate : Int32 = 60, @width : Int32 = 800, @height : Int32 = 600) def initialize(@framerate : Int32 = 60, @width : Int32 = 800, @height : Int32 = 600)
@window = SF::RenderWindow.new( @window = SF::RenderWindow.new(
SF::VideoMode.new(width, height), SF::VideoMode.new(width, height),
"Sandbox", "Sandbox",
) )
@zoom = 1.0
@joystick_moved = Vector[0.0, 0.0] @joystick_moved = Vector[0.0, 0.0]
@screen_center_position = Vector[width / 2, height / 2] @screen_center_position = Vector[width / 2, height / 2]
@center_position = Vector[0.0, 0.0]
@delta_clock = SF::Clock.new @delta_clock = SF::Clock.new
@time_passed = Time::Span.zero
@timescale = 1.0
@window_frequency = Time::Span.new(nanoseconds: SECOND_IN_NANO // @framerate)
ImGui::SFML.init(@window) ImGui::SFML.init(@window)
@window.framerate_limit = @framerate @window.framerate_limit = @framerate
@time_passed = Time::Span.zero
@view = SF::View.new
@view.viewport = default_viewport # SF.float_rect(0.0, 0.0, 1.0, @width / @height)
@view.center = {@center_position[0], @center_position[1]}
@window.view = @view
# connected = SF::Joystick.connected?(0) # connected = SF::Joystick.connected?(0)
# # How many buttons does joystick #0 support? # # How many buttons does joystick #0 support?
@ -85,6 +51,9 @@ class Game
# # What's the current position of the Y axis on joystick #0? # # What's the current position of the Y axis on joystick #0?
# position = SF::Joystick.get_axis_position(0, SF::Joystick::Y) # position = SF::Joystick.get_axis_position(0, SF::Joystick::Y)
@timescale = 1.0
@window_frequency = Time::Span.new(nanoseconds: SECOND_IN_NANO // @framerate)
sun_offset = Vector[3*10.0**11, 3*10.0**11] sun_offset = Vector[3*10.0**11, 3*10.0**11]
@bodies = { @bodies = {
vessel: Gravity::MovingBody(2).new(mass: 1.0, g: 0.1, position: Vector[10.0, 10.0]), vessel: Gravity::MovingBody(2).new(mass: 1.0, g: 0.1, position: Vector[10.0, 10.0]),
@ -102,34 +71,33 @@ class Game
@vessel_p = Projectable(2).new( @vessel_p = Projectable(2).new(
gravity_body: @bodies[:vessel], gravity_body: @bodies[:vessel],
color: {255, 0, 250}, color: {255, 0, 250},
size: 5, size: 3,
) )
@star = Projectable(2).new( @star = Projectable(2).new(
gravity_body: @bodies[:star], gravity_body: @bodies[:star],
color: {200, 200, 50}, color: {200, 200, 50},
size: 20, size: 10,
) )
@pla1 = Projectable(2).new( @pla1 = Projectable(2).new(
gravity_body: @bodies[:pla1], gravity_body: @bodies[:pla1],
color: {150, 50, 50}, color: {150, 50, 50},
size: 10, size: 5,
) )
@pla2 = Projectable(2).new( @pla2 = Projectable(2).new(
gravity_body: @bodies[:pla2], gravity_body: @bodies[:pla2],
color: {50, 50, 150}, color: {50, 50, 150},
size: 10, size: 5,
) )
@pla3 = Projectable(2).new( @pla3 = Projectable(2).new(
gravity_body: @bodies[:pla3], gravity_body: @bodies[:pla3],
color: {50, 150, 50}, color: {50, 150, 50},
size: 10, size: 5,
) )
@projectables = { @projectables = {
@star, @pla1, @pla2, @pla3, @star, @vessel_p, @star, @pla1, @pla2, @pla3, @star, @vessel_p,
} }
@g = Gravity::Field(2).new(@gravited) @g = Gravity::Field(2).new(@gravited)
@vessel = Vessel(2).new(name: "Starbird", gravity_body: @bodies[:vessel], gravity_field: @g) @vessel = Vessel(2).new(name: "Starbird", gravity_body: @bodies[:vessel], gravity_field: @g)
@vessel.navigation.zoom_ratio = DEFAULT_ZOOM
@timer = Physics::Tick::Timer.new @timer = Physics::Tick::Timer.new
@ui_events_handler = UI::EventHandler.new @ui_events_handler = UI::EventHandler.new
end end
@ -145,10 +113,10 @@ class Game
@window.close @window.close
exit exit
when SF::Event::KeyPressed when SF::Event::KeyPressed
Log.debug "KeyPressed #{event}" puts "KeyPressed #{event}"
when SF::Event::MouseMoved when SF::Event::MouseMoved
when SF::Event::MouseButtonEvent when SF::Event::MouseButtonEvent
Log.debug "MouseButtonEvent #{event}" puts "MouseButtonEvent #{event}"
when SF::Event::JoystickButtonPressed when SF::Event::JoystickButtonPressed
@joystick_moved.zero! # reset 0 @joystick_moved.zero! # reset 0
joystick_moved_modified = :vector # force exact set joystick_moved_modified = :vector # force exact set
@ -178,11 +146,11 @@ class Game
@vessel.pilot.set_exact_acceleration_axis!(@joystick_moved) @vessel.pilot.set_exact_acceleration_axis!(@joystick_moved)
elsif joystick_moved_modified == :accelerate elsif joystick_moved_modified == :accelerate
# can double the vector each second # can double the vector each second
Log.debug "accelerate #{@joystick_moved}" puts "accelerate #{@joystick_moved}"
@vessel.pilot.accelerate_current_vector!(1.0 + (@joystick_moved[0] + 100) / 2 * 0.01) @vessel.pilot.accelerate_current_vector!(1.0 + (@joystick_moved[0] + 100) / 2 * 0.01)
elsif joystick_moved_modified == :slow elsif joystick_moved_modified == :slow
# can slow # can slow
Log.debug "slow down #{@joystick_moved}" puts "slow down #{@joystick_moved}"
@vessel.pilot.accelerate_current_vector!(-1.0 - (@joystick_moved[0] + 100) / 2 * 0.01) @vessel.pilot.accelerate_current_vector!(-1.0 - (@joystick_moved[0] + 100) / 2 * 0.01)
end end
end end
@ -200,15 +168,250 @@ class Game
end end
end end
include ImGui::Helper
# will yield the value
def draw_slider(label : String, data : Float64, max : Float64 = 100.0, min : Float64 = -100.0, flags : ImGui::ImGuiSliderFlags = ImGui::ImGuiSliderFlags::NoRoundToFormat, &)
ptr = pointerof(data)
if ImGui.slider_scalar(
label: label,
p_data: ptr,
p_min: min,
p_max: max,
flags: flags,
)
yield data
end
end
# will yield the value
def draw_input(label : String, data : Float64, max : Float64 = 100.0, min : Float64 = -100.0, flags : ImGui::ImGuiInputTextFlags = ImGui::ImGuiInputTextFlags::EnterReturnsTrue, &)
ptr = pointerof(data)
if ImGui.input_scalar(
label: label,
p_data: ptr,
flags: flags,
)
data = max if data > max
data = min if data < min
yield data
end
end
def accelerate_by_tick(movable_body : Gravity::MovingBody) def accelerate_by_tick(movable_body : Gravity::MovingBody)
gravity_field = @g.acceleration(movable_body.position) gravity_field = @g.acceleration(movable_body.position)
acceleration = movable_body.acceleration + gravity_field acceleration = movable_body.acceleration + gravity_field
Physics.move_by_one_tick!(@timer.tick, movable_body.position, movable_body.speed, acceleration) Physics.move_by_one_tick!(@timer.tick, movable_body.position, movable_body.speed, acceleration)
end end
include PhysicsSandboxDraw def draw_captain
include PhysicsSandboxGrid ImGui.text "Time passed: #{@time_passed}"
include PhysicsSandboxCadran draw_slider(
label: "Set timescale###set_timescale",
data: @timescale,
min: 0.1,
max: 3600 * 24 * 7,
flags: (
ImGui::ImGuiSliderFlags::Logarithmic
),
) do |value|
@timescale = value
end
end
def draw_pilot
draw_table(title: "Trusters", headers: {"Name", "X", "Y", "unit"}) do
draw_table_line(
"Analogic acceleration",
->{
draw_slider(
label: "###acceleration_analogue_x",
data: @vessel.gravity_body.acceleration[0],
flags: (
ImGui::ImGuiSliderFlags::Logarithmic
),
) do |value|
@vessel.pilot.order(priority: 10, group: :acceleration_x) do
@vessel.pilot.set_exact_acceleration_axis!(0, value)
@vessel.pilot.permanent_mode = :constant
@vessel.pilot.low_thrust_pressed = false
@vessel.pilot.low_thrust_save = value
end
end
},
->{
draw_slider(
label: "###acceleration_analogue_y",
data: @vessel.gravity_body.acceleration[1],
flags: (
ImGui::ImGuiSliderFlags::Logarithmic
),
) do |value|
@vessel.pilot.order(priority: 10, group: :acceleration_y) do
@vessel.pilot.set_exact_acceleration_axis!(1, value)
@vessel.pilot.permanent_mode = :constant
@vessel.pilot.low_thrust_pressed = false
@vessel.pilot.low_thrust_save = value
end
end
},
"m/s²",
)
# automatically reset acceleration to 0, used for maneuvers
draw_table_line(
"Low thrust",
->{
draw_slider(
label: "###acceleration_low_analogic_x",
data: @vessel.gravity_body.acceleration[0],
) do |value|
@vessel.pilot.order(priority: 10, group: :maneuvers) do
@vessel.pilot.temporary_mode = :pulse
if !@vessel.pilot.low_thrust_pressed
@vessel.pilot.low_thrust_save = @vessel.gravity_body.acceleration[0]
end
@vessel.pilot.low_thrust_pressed = true
@vessel.pilot.set_exact_acceleration_axis!(0, value)
lock_callback = @ui_events_handler.add(SF::Event::KeyPressed) do |callback, event|
if event.as(SF::Event::KeyPressed).code == SF::Keyboard::Key::L
@vessel.pilot.low_thrust_save = value
end
end
@ui_events_handler.add(SF::Event::MouseButtonReleased) do |callback|
@ui_events_handler.remove(SF::Event::MouseButtonReleased, callback)
@ui_events_handler.remove(SF::Event::MouseButtonReleased, lock_callback)
@vessel.pilot.low_thrust_pressed = false
@vessel.pilot.set_exact_acceleration_axis!(0, @vessel.pilot.low_thrust_save)
end
end
end
},
->{
draw_slider(
label: "###acceleration_low_analogic_y",
data: @vessel.gravity_body.acceleration[1],
) do |value|
@vessel.pilot.order(priority: 10, group: :maneuvers) do
@vessel.pilot.temporary_mode = :pulse
if !@vessel.pilot.low_thrust_pressed
@vessel.pilot.low_thrust_save = @vessel.gravity_body.acceleration[1]
end
@vessel.pilot.low_thrust_pressed = true
@vessel.pilot.set_exact_acceleration_axis!(1, value)
lock_callback = @ui_events_handler.add(SF::Event::KeyPressed) do |callback, event|
if event.as(SF::Event::KeyPressed).code == SF::Keyboard::Key::L
@vessel.pilot.low_thrust_save = value
end
end
@ui_events_handler.add(SF::Event::MouseButtonReleased) do |callback|
@ui_events_handler.remove(SF::Event::MouseButtonReleased, callback)
@ui_events_handler.remove(SF::Event::MouseButtonReleased, lock_callback)
@vessel.pilot.low_thrust_pressed = false
@vessel.pilot.set_exact_acceleration_axis!(1, @vessel.pilot.low_thrust_save)
end
end
end
},
"m/s²",
)
draw_table_line(
"Computer acceleration",
->{
draw_input(
label: "###acceleration_digit_x",
data: @vessel.pilot.computer_input_thurst[0],
) do |value|
@vessel.pilot.order(priority: 9, group: :maneuvers) do
@vessel.pilot.computer_input_thurst[0] = value
end
end
},
->{
draw_input(
label: "###acceleration_digit_y",
data: @vessel.pilot.computer_input_thurst[1],
) do |value|
@vessel.pilot.order(priority: 9, group: :maneuvers) do
@vessel.pilot.computer_input_thurst[1] = value
end
end
},
"m/s²",
)
draw_table_line(
"",
->{
if ImGui.button("Comfirm")
@vessel.pilot.order(priority: 100, group: :maneuvers) do
@vessel.pilot.permanent_mode = :constant
@vessel.pilot.set_exact_acceleration_axis!(@vessel.pilot.computer_input_thurst)
# @vessel.pilot.set_exact_acceleration_axis!(0, @vessel.pilot.computer_input_thurst[0])
# @vessel.pilot.set_exact_acceleration_axis!(1, @vessel.pilot.computer_input_thurst[1])
end
end
if ImGui.button("Reset")
@vessel.pilot.order(priority: 100, group: :prepare) do
@vessel.pilot.set_exact_acceleration_axis!(@vessel.pilot.computer_input_thurst)
# @vessel.pilot.computer_input_thurst[0] = @vessel.gravity_body.acceleration[0]
# @vessel.pilot.computer_input_thurst[1] = @vessel.gravity_body.acceleration[1]
end
end
},
->{
if ImGui.button("Zero")
@vessel.pilot.order(priority: 10, group: :prepare) do
@vessel.pilot.computer_input_thurst[0] = 0.0
@vessel.pilot.computer_input_thurst[1] = 0.0
end
end
},
->{
if @vessel.pilot.permanent_mode != :antigrav
if ImGui.button("Anti-grav")
@vessel.pilot.order(priority: 10, group: :fly_mode) do
@vessel.pilot.permanent_mode = :antigrav
@vessel.gravity_body.acceleration[0] = @vessel.gravity[0]
@vessel.gravity_body.acceleration[1] = @vessel.gravity[1]
end
end
else
if ImGui.button("Disable anti-grav")
@vessel.pilot.order(priority: 11, group: :fly_mode) do
if @vessel.pilot.permanent_mode == :antigrav
@vessel.pilot.permanent_mode = nil
end
end
end
end
},
)
end
end
def draw_navigation(gravity_field)
# ImGui.text "Total Accele is : [#{acceleration[0].round(4)}, #{acceleration[1].round(4)}] m/s²"
ImGui.text "Pulse Accele is : [#{@vessel.gravity_body.acceleration[0].round(4)}, #{@vessel.gravity_body.acceleration[1].round(4)}] m/s²"
ImGui.text "GraviticBody is : [#{gravity_field[0].round(4)}, #{gravity_field[1].round(4)}] m/s²"
ImGui.text "Current speed is : #{@vessel.gravity_body.speed.magnitude.round(4)} m/s"
draw_table(title: "Actual vectors", headers: {"Name", "X", "Y", "unit"}) do
draw_table_line "Position", @vessel.gravity_body.position[0].round(3).to_s, @vessel.gravity_body.position[1].round(3).to_s, "m"
draw_table_line "Speed", @vessel.gravity_body.speed[0].round(3).to_s, @vessel.gravity_body.speed[1].round(3).to_s, "m/s"
draw_table_line "Acceleration", @vessel.gravity_body.acceleration[0].round(3).to_s, @vessel.gravity_body.acceleration[1].round(3).to_s, "m/s²"
end
ImGui.text "Zoom on"
ImGui.radio_button("vessel##navigation_zoom", pointerof(@vessel.navigation.zoom_select), 0)
ImGui.same_line
ImGui.radio_button("star##navigation_zoom", pointerof(@vessel.navigation.zoom_select), 1)
ImGui.same_line
ImGui.radio_button("fixed##navigation_zoom", pointerof(@vessel.navigation.zoom_select), 2)
ImGui.same_line
ImGui.radio_button("zero##navigation_zoom", pointerof(@vessel.navigation.zoom_select), 3)
end
def execute(tick : Int) def execute(tick : Int)
@vessel.execute_orders! @vessel.execute_orders!
@ -219,68 +422,180 @@ class Game
gravity_field = @g.acceleration(@bodies[:vessel].position) gravity_field = @g.acceleration(@bodies[:vessel].position)
@graviting.each { |graviting| accelerate_by_tick(graviting) } @graviting.each { |graviting| accelerate_by_tick(graviting) }
draw_bridge(gravity_field) if ImGui.begin("Bridge")
if ImGui.tree_node_ex("Captain", ImGui::ImGuiTreeNodeFlags.new(ImGui::ImGuiTreeNodeFlags::DefaultOpen))
draw_captain
ImGui.tree_pop
end
object_position = if ImGui.tree_node_ex("Navigation", ImGui::ImGuiTreeNodeFlags.new(ImGui::ImGuiTreeNodeFlags::DefaultOpen))
draw_navigation(gravity_field)
ImGui.tree_pop
end
if ImGui.tree_node_ex("Pilot", ImGui::ImGuiTreeNodeFlags.new(ImGui::ImGuiTreeNodeFlags::DefaultOpen))
draw_pilot
ImGui.tree_pop
end
ImGui.end
end
zoom_object_position =
if @vessel.navigation.zoom_select == 0 if @vessel.navigation.zoom_select == 0
@vessel.navigation.zoom_position = @vessel.gravity_body.position @vessel.navigation.zoom_position = @vessel.gravity_body.position * ZOOM
elsif @vessel.navigation.zoom_select == 1 elsif @vessel.navigation.zoom_select == 1
@vessel.navigation.zoom_position = @star.gravity_body.position @vessel.navigation.zoom_position = @star.gravity_body.position * ZOOM
elsif @vessel.navigation.zoom_select == 2 elsif @vessel.navigation.zoom_select == 2
@vessel.navigation.zoom_position @vessel.navigation.zoom_position
else else
@vessel.navigation.zoom_position = @screen_center_position @vessel.navigation.zoom_position = @screen_center_position
end end
@center_position = object_position zoom_offset = @screen_center_position - zoom_object_position
@view.set_center( @projectables.each { |projectable| @window.draw(projectable.sf_shape(ZOOM, zoom_offset)) }
@center_position[0], draw_all_trajectories(ZOOM, zoom_offset)
@center_position[1],
)
if @zoom != @vessel.navigation.zoom_ratio
@view.zoom @zoom / @vessel.navigation.zoom_ratio
@zoom = @vessel.navigation.zoom_ratio
if @zoom == 1.0
@view.viewport = default_viewport
end
end
@window.view = @view
@projectables.each { |projectable| draw(projectable.sf_shape) } draw_grid(ZOOM, zoom_object_position)
draw_all_trajectories # draw_grid(ZOOM, Vector[0.0, 0.0])
# draw_grid
@vessel.navigation.cadran.radius.each do |radius|
draw_cadran(center: @vessel.gravity_body.position, radius: radius)
end
end end
def draw_all_trajectories def draw_all_trajectories(coef, offset)
t = Trajectory.new(body: @vessel_p.gravity_body, gravity_field: @g) t = Trajectory.new(body: @vessel_p.gravity_body, gravity_field: @g)
t_with_gravity = t.compute(steps: 1000, accuracy: 500.millisecond * @timescale) t_with_gravity = t.compute(steps: 1000, accuracy: 500.millisecond * @timescale)
draw_trajectory({255, 0, 0}, t_with_gravity) draw_trajectory({255, 0, 0}, t_with_gravity, coef, offset)
t = Trajectory.new(body: @vessel_p.gravity_body, gravity_field: Gravity::Field(2).zero) t = Trajectory.new(body: @vessel_p.gravity_body, gravity_field: Gravity::Field(2).zero)
t_without_gravity = t.compute(steps: 20, accuracy: 5.second * @timescale) t_without_gravity = t.compute(steps: 20, accuracy: 5.second * @timescale)
draw_trajectory({255, 255, 0}, t_without_gravity) draw_trajectory({255, 255, 0}, t_without_gravity, coef, offset)
t = Trajectory.new(body: @pla1.gravity_body, gravity_field: @g) t = Trajectory.new(body: @pla1.gravity_body, gravity_field: @g)
t_without_gravity = t.compute(steps: 100, accuracy: 10.second * @timescale) t_without_gravity = t.compute(steps: 100, accuracy: 10.second * @timescale)
draw_trajectory({255, 0, 0}, t_without_gravity) draw_trajectory({255, 0, 0}, t_without_gravity, coef, offset)
t = Trajectory.new(body: @pla2.gravity_body, gravity_field: @g) t = Trajectory.new(body: @pla2.gravity_body, gravity_field: @g)
t_without_gravity = t.compute(steps: 100, accuracy: 10.second * @timescale) t_without_gravity = t.compute(steps: 100, accuracy: 10.second * @timescale)
draw_trajectory({0, 0, 255}, t_without_gravity) draw_trajectory({0, 0, 255}, t_without_gravity, coef, offset)
t = Trajectory.new(body: @pla3.gravity_body, gravity_field: @g) t = Trajectory.new(body: @pla3.gravity_body, gravity_field: @g)
t_without_gravity = t.compute(steps: 100, accuracy: 10.second * @timescale) t_without_gravity = t.compute(steps: 100, accuracy: 10.second * @timescale)
draw_trajectory({0, 255, 0}, t_without_gravity) draw_trajectory({0, 255, 0}, t_without_gravity, coef, offset)
end end
def draw_trajectory(color : Tuple(Int32, Int32, Int32), trajectory) def draw_trajectory(color : Tuple(Int32, Int32, Int32), trajectory, coef = 1.0, offset = Vector(Float64, 2).zero)
trajectory.each do |point| trajectory.each do |point|
sf_point = SF::CircleShape.new(2) sf_point = SF::CircleShape.new(1)
sf_point.fill_color = SF.color(*color) sf_point.fill_color = SF.color(*color)
point = point * coef + offset
sf_point.position = SF.vector2(point[0], point[1]) sf_point.position = SF.vector2(point[0], point[1])
draw(sf_point) @window.draw(sf_point)
end
end
def absolute_coordinates(x, y, coef, offset)
v = SF.vector2f(
(x - (offset[0] % MAIN_LINES_REAL_SPACE)) * coef,
(y - (offset[1] % MAIN_LINES_REAL_SPACE)) * coef,
)
# pp v
# v
end
def relative_coordinates(x, y, coef, offset)
SF.vector2f(x * coef, y * coef)
end
MAIN_LINES_REAL_SPACE = 1000
SECONDARY_LINES_AMOUNT = 3
SECONDARY_LINES_SPACE = MAIN_LINES_REAL_SPACE / SECONDARY_LINES_AMOUNT
SECONDARY_LINES_COLOR = SF::Color.new(255, 255, 255, 20)
# this one will be dynamic to evaluate distances
def draw_grid(coef, zoom_offset)
main_lines = Array(SF::VertexBuffer).new
secondary_lines = Array(SF::VertexBuffer).new
max_size = {@width, @height}.max
# puts "------------------"
main_lines_amount = (MAIN_LINES_REAL_SPACE / max_size / coef).ceil.to_i32 + 2
main_lines_amount.times do |index|
main_line_v = SF::VertexBuffer.new(SF::LineStrip)
main_line_h = SF::VertexBuffer.new(SF::LineStrip)
main_lines << main_line_v
main_lines << main_line_h
main_line_v.create(2)
main_line_h.create(2)
v_start = MAIN_LINES_REAL_SPACE * index
v_end = @width / coef + zoom_offset[0] % MAIN_LINES_REAL_SPACE
h_start = MAIN_LINES_REAL_SPACE * index
h_end = @height / coef + zoom_offset[1] % MAIN_LINES_REAL_SPACE
# pp({
# index: index,
# v_start: v_start,
# v_end: v_end,
# h_start: h_start,
# h_end: h_end,
# offset: zoom_offset,
# coef: coef,
# })
main_line_v_buffer_0 = SF::Vertex.new(
absolute_coordinates(v_start, 0, coef, zoom_offset),
)
main_line_v_buffer_1 = SF::Vertex.new(
absolute_coordinates(v_start, h_end, coef, zoom_offset),
)
main_line_h_buffer_0 = SF::Vertex.new(
absolute_coordinates(0, h_start, coef, zoom_offset),
)
main_line_h_buffer_1 = SF::Vertex.new(
absolute_coordinates(v_end, h_start, coef, zoom_offset),
)
main_line_v_buffer = Slice[main_line_v_buffer_0, main_line_v_buffer_1]
main_line_h_buffer = Slice[main_line_h_buffer_0, main_line_h_buffer_1]
main_line_v.update(main_line_v_buffer, 0)
main_line_h.update(main_line_h_buffer, 0)
SECONDARY_LINES_AMOUNT.times do |subindex|
secondary_line_v = SF::VertexBuffer.new(SF::LineStrip)
secondary_line_h = SF::VertexBuffer.new(SF::LineStrip)
secondary_lines << secondary_line_v
secondary_lines << secondary_line_h
secondary_line_v.create(2)
secondary_line_h.create(2)
secondary_v_start = SECONDARY_LINES_SPACE * subindex
secondary_h_start = SECONDARY_LINES_SPACE * subindex
secondary_line_v_buffer_0 = SF::Vertex.new(
absolute_coordinates(v_start + secondary_v_start, 0, coef, zoom_offset),
color: SECONDARY_LINES_COLOR,
)
secondary_line_v_buffer_1 = SF::Vertex.new(
absolute_coordinates(v_start + secondary_v_start, h_end, coef, zoom_offset),
color: SECONDARY_LINES_COLOR,
)
secondary_line_h_buffer_0 = SF::Vertex.new(
absolute_coordinates(0, h_start + secondary_h_start, coef, zoom_offset),
color: SECONDARY_LINES_COLOR,
)
secondary_line_h_buffer_1 = SF::Vertex.new(
absolute_coordinates(v_end, h_start + secondary_h_start, coef, zoom_offset),
color: SECONDARY_LINES_COLOR,
)
secondary_line_v_buffer = Slice[secondary_line_v_buffer_0, secondary_line_v_buffer_1]
secondary_line_h_buffer = Slice[secondary_line_h_buffer_0, secondary_line_h_buffer_1]
secondary_line_v.update(secondary_line_v_buffer, 0)
secondary_line_h.update(secondary_line_h_buffer, 0)
end
end
main_lines.each do |line|
# line[0].color = SF::Color.new(255, 255, 255)
# line[1].color = SF::Color.new(255, 255, 255)
@window.draw(line)
end
secondary_lines.each do |line|
# line[0].color = SF::Color.new(255, 255, 255)
# line[1].color = SF::Color.new(255, 255, 255)
@window.draw(line)
end end
end end
end end

View File

@ -1,56 +0,0 @@
module PhysicsSandboxCadran
def add_line(lines, p1 : SF::Vector2f, p2 : SF::Vector2f, color : SF::Color = SF::Color::White)
line1 = SF::VertexBuffer.new(SF::LineStrip)
line1.create(2)
line1.update(
Slice[
SF::Vertex.new(position: p1, color: color),
SF::Vertex.new(position: p2, color: color),
], 0)
lines << line1
end
CADRAN_COLOR = SF::Color.new(230, 230, 230, 120)
def draw_cadran(center : Vector(Float64, 2), radius : Number)
circle = SF::CircleShape.new(radius: radius, point_count: 100)
circle.outline_color = CADRAN_COLOR
circle.outline_thickness = 1
center_position_offset = {
center[0] - radius,
center[1] - radius,
}
circle.position = center_position_offset
circle.fill_color = SF::Color::Transparent
draw(circle)
lines = Array(SF::VertexBuffer).new
add_line(
lines: lines,
p1: SF.vector2f(center[0] - 2**(1/2)/2 * radius, center[1] - 2**(1/2)/2 * radius),
p2: SF.vector2f(center[0] + 2**(1/2)/2 * radius, center[1] + 2**(1/2)/2 * radius),
color: CADRAN_COLOR,
)
add_line(
lines: lines,
p1: SF.vector2f(center[0] + 2**(1/2)/2 * radius, center[1] - 2**(1/2)/2 * radius),
p2: SF.vector2f(center[0] - 2**(1/2)/2 * radius, center[1] + 2**(1/2)/2 * radius),
color: CADRAN_COLOR,
)
add_line(
lines: lines,
p1: SF.vector2f(center[0] + radius, center[1]),
p2: SF.vector2f(center[0] - radius, center[1]),
color: CADRAN_COLOR,
)
add_line(
lines: lines,
p1: SF.vector2f(center[0], center[1] - radius),
p2: SF.vector2f(center[0], center[1] + radius),
color: CADRAN_COLOR,
)
lines.each { |line| draw(line) }
end
end

View File

@ -1,284 +0,0 @@
module PhysicsSandboxDraw
include ImGui::Helper
# will yield the value
def draw_slider(label : String, data : Float64, max : Float64 = 100.0, min : Float64 = -100.0, flags : ImGui::ImGuiSliderFlags = ImGui::ImGuiSliderFlags::NoRoundToFormat, &)
ptr = pointerof(data)
if ImGui.slider_scalar(
label: label,
p_data: ptr,
p_min: min,
p_max: max,
flags: flags,
)
yield data
end
end
# will yield the value
def draw_input(label : String, data : Float64, max : Float64 = 100.0, min : Float64 = -100.0, flags : ImGui::ImGuiInputTextFlags = ImGui::ImGuiInputTextFlags::EnterReturnsTrue, &)
ptr = pointerof(data)
if ImGui.input_scalar(
label: label,
p_data: ptr,
flags: flags,
)
data = max if data > max
data = min if data < min
yield data
end
end
def draw_captain
ImGui.text "Time passed: #{@time_passed}"
draw_slider(
label: "Set timescale###set_timescale",
data: @timescale,
min: 0.1,
max: 3600 * 24 * 7,
flags: (
ImGui::ImGuiSliderFlags::Logarithmic
),
) do |value|
@timescale = value
end
end
def draw_pilot
draw_table(title: "Trusters", headers: {"Name", "X", "Y", "unit"}) do
draw_table_line(
"Analogic acceleration",
->{
draw_slider(
label: "###acceleration_analogue_x",
data: @vessel.gravity_body.acceleration[0],
flags: (
ImGui::ImGuiSliderFlags::Logarithmic
),
) do |value|
@vessel.pilot.order(priority: 10, group: :acceleration_x) do
@vessel.pilot.set_exact_acceleration_axis!(0, value)
@vessel.pilot.permanent_mode = :constant
@vessel.pilot.low_thrust_pressed = false
@vessel.pilot.low_thrust_save = value
end
end
},
->{
draw_slider(
label: "###acceleration_analogue_y",
data: @vessel.gravity_body.acceleration[1],
flags: (
ImGui::ImGuiSliderFlags::Logarithmic
),
) do |value|
@vessel.pilot.order(priority: 10, group: :acceleration_y) do
@vessel.pilot.set_exact_acceleration_axis!(1, value)
@vessel.pilot.permanent_mode = :constant
@vessel.pilot.low_thrust_pressed = false
@vessel.pilot.low_thrust_save = value
end
end
},
"m/s²",
)
# automatically reset acceleration to 0, used for maneuvers
draw_table_line(
"Low thrust",
->{
draw_slider(
label: "###acceleration_low_analogic_x",
data: @vessel.gravity_body.acceleration[0],
) do |value|
@vessel.pilot.order(priority: 10, group: :maneuvers) do
@vessel.pilot.temporary_mode = :pulse
if !@vessel.pilot.low_thrust_pressed
@vessel.pilot.low_thrust_save = @vessel.gravity_body.acceleration[0]
end
@vessel.pilot.low_thrust_pressed = true
@vessel.pilot.set_exact_acceleration_axis!(0, value)
lock_callback = @ui_events_handler.add(SF::Event::KeyPressed) do |callback, event|
if event.as(SF::Event::KeyPressed).code == SF::Keyboard::Key::L
@vessel.pilot.low_thrust_save = value
end
end
@ui_events_handler.add(SF::Event::MouseButtonReleased) do |callback|
@ui_events_handler.remove(SF::Event::MouseButtonReleased, callback)
@ui_events_handler.remove(SF::Event::MouseButtonReleased, lock_callback)
@vessel.pilot.low_thrust_pressed = false
@vessel.pilot.set_exact_acceleration_axis!(0, @vessel.pilot.low_thrust_save)
end
end
end
},
->{
draw_slider(
label: "###acceleration_low_analogic_y",
data: @vessel.gravity_body.acceleration[1],
) do |value|
@vessel.pilot.order(priority: 10, group: :maneuvers) do
@vessel.pilot.temporary_mode = :pulse
if !@vessel.pilot.low_thrust_pressed
@vessel.pilot.low_thrust_save = @vessel.gravity_body.acceleration[1]
end
@vessel.pilot.low_thrust_pressed = true
@vessel.pilot.set_exact_acceleration_axis!(1, value)
lock_callback = @ui_events_handler.add(SF::Event::KeyPressed) do |callback, event|
if event.as(SF::Event::KeyPressed).code == SF::Keyboard::Key::L
@vessel.pilot.low_thrust_save = value
end
end
@ui_events_handler.add(SF::Event::MouseButtonReleased) do |callback|
@ui_events_handler.remove(SF::Event::MouseButtonReleased, callback)
@ui_events_handler.remove(SF::Event::MouseButtonReleased, lock_callback)
@vessel.pilot.low_thrust_pressed = false
@vessel.pilot.set_exact_acceleration_axis!(1, @vessel.pilot.low_thrust_save)
end
end
end
},
"m/s²",
)
draw_table_line(
"Computer acceleration",
->{
draw_input(
label: "###acceleration_digit_x",
data: @vessel.pilot.computer_input_thurst[0],
) do |value|
@vessel.pilot.order(priority: 9, group: :maneuvers) do
@vessel.pilot.computer_input_thurst[0] = value
end
end
},
->{
draw_input(
label: "###acceleration_digit_y",
data: @vessel.pilot.computer_input_thurst[1],
) do |value|
@vessel.pilot.order(priority: 9, group: :maneuvers) do
@vessel.pilot.computer_input_thurst[1] = value
end
end
},
"m/s²",
)
draw_table_line(
"",
->{
if ImGui.button("Comfirm")
@vessel.pilot.order(priority: 100, group: :maneuvers) do
@vessel.pilot.permanent_mode = :constant
@vessel.pilot.set_exact_acceleration_axis!(@vessel.pilot.computer_input_thurst)
# @vessel.pilot.set_exact_acceleration_axis!(0, @vessel.pilot.computer_input_thurst[0])
# @vessel.pilot.set_exact_acceleration_axis!(1, @vessel.pilot.computer_input_thurst[1])
end
end
if ImGui.button("Reset")
@vessel.pilot.order(priority: 100, group: :prepare) do
@vessel.pilot.set_exact_acceleration_axis!(@vessel.pilot.computer_input_thurst)
# @vessel.pilot.computer_input_thurst[0] = @vessel.gravity_body.acceleration[0]
# @vessel.pilot.computer_input_thurst[1] = @vessel.gravity_body.acceleration[1]
end
end
},
->{
if ImGui.button("Zero")
@vessel.pilot.order(priority: 10, group: :prepare) do
@vessel.pilot.computer_input_thurst[0] = 0.0
@vessel.pilot.computer_input_thurst[1] = 0.0
end
end
},
->{
if @vessel.pilot.permanent_mode != :antigrav
if ImGui.button("Anti-grav")
@vessel.pilot.order(priority: 10, group: :fly_mode) do
@vessel.pilot.permanent_mode = :antigrav
@vessel.gravity_body.acceleration[0] = @vessel.gravity[0]
@vessel.gravity_body.acceleration[1] = @vessel.gravity[1]
end
end
else
if ImGui.button("Disable anti-grav")
@vessel.pilot.order(priority: 11, group: :fly_mode) do
if @vessel.pilot.permanent_mode == :antigrav
@vessel.pilot.permanent_mode = nil
end
end
end
end
},
)
end
end
def draw_navigation(gravity_field)
# ImGui.text "Total Accele is : [#{acceleration[0].round(4)}, #{acceleration[1].round(4)}] m/s²"
ImGui.text "Pulse Accele is : [#{@vessel.gravity_body.acceleration[0].round(4)}, #{@vessel.gravity_body.acceleration[1].round(4)}] m/s²"
ImGui.text "GraviticBody is : [#{gravity_field[0].round(4)}, #{gravity_field[1].round(4)}] m/s²"
ImGui.text "Current speed is : #{@vessel.gravity_body.speed.magnitude.round(4)} m/s"
draw_table(title: "Actual vectors", headers: {"Name", "X", "Y", "unit"}) do
draw_table_line "Position", @vessel.gravity_body.position[0].round(3).to_s, @vessel.gravity_body.position[1].round(3).to_s, "m"
draw_table_line "Speed", @vessel.gravity_body.speed[0].round(3).to_s, @vessel.gravity_body.speed[1].round(3).to_s, "m/s"
draw_table_line "Acceleration", @vessel.gravity_body.acceleration[0].round(3).to_s, @vessel.gravity_body.acceleration[1].round(3).to_s, "m/s²"
end
ImGui.text "Zoom on"
ImGui.radio_button("vessel##navigation_zoom", pointerof(@vessel.navigation.zoom_select), 0)
ImGui.same_line
ImGui.radio_button("star##navigation_zoom", pointerof(@vessel.navigation.zoom_select), 1)
ImGui.same_line
ImGui.radio_button("fixed##navigation_zoom", pointerof(@vessel.navigation.zoom_select), 2)
ImGui.same_line
ImGui.radio_button("zero##navigation_zoom", pointerof(@vessel.navigation.zoom_select), 3)
draw_slider(
label: "###cadran_slide_zoom_ratio",
data: @vessel.navigation.zoom_ratio,
max: 10,
min: 0.001,
flags: ImGui::ImGuiSliderFlags::Logarithmic,
) do |value|
@vessel.navigation.zoom_ratio = value
end
ImGui.text "Cadran"
draw_slider(
label: "###cadran_slide_radius",
data: @vessel.navigation.cadran.radius[0],
max: 10.0**10,
min: 0.0,
flags: ImGui::ImGuiSliderFlags::Logarithmic,
) do |value|
@vessel.navigation.cadran.radius[0] = value
end
end
def draw_bridge(gravity_field)
if ImGui.begin("Bridge")
if ImGui.tree_node_ex("Captain", ImGui::ImGuiTreeNodeFlags.new(ImGui::ImGuiTreeNodeFlags::DefaultOpen))
draw_captain
ImGui.tree_pop
end
if ImGui.tree_node_ex("Navigation", ImGui::ImGuiTreeNodeFlags.new(ImGui::ImGuiTreeNodeFlags::DefaultOpen))
draw_navigation(gravity_field)
ImGui.tree_pop
end
if ImGui.tree_node_ex("Pilot", ImGui::ImGuiTreeNodeFlags.new(ImGui::ImGuiTreeNodeFlags::DefaultOpen))
draw_pilot
ImGui.tree_pop
end
ImGui.end
end
end
end

View File

@ -1,115 +0,0 @@
module PhysicsSandboxGrid
MAIN_LINES_REAL_SPACE = 1000
SECONDARY_LINES_AMOUNT = 3
SECONDARY_LINES_SPACE = MAIN_LINES_REAL_SPACE / SECONDARY_LINES_AMOUNT
SECONDARY_LINES_COLOR = SF::Color.new(255, 255, 255, 30)
def absolute_coordinates(pos, offset)
SF.vector2f(pos[0] + offset[0], pos[1] + offset[1])
end
# this one will be dynamic to evaluate distances
def draw_grid
main_lines = Array(SF::VertexBuffer).new
secondary_lines = Array(SF::VertexBuffer).new
width = @width
height = @height
max_size = {width, height}.max
offset = {
-@center_position[0] + (@center_position[0] // MAIN_LINES_REAL_SPACE) * MAIN_LINES_REAL_SPACE,
-@center_position[1] + (@center_position[1] // MAIN_LINES_REAL_SPACE) * MAIN_LINES_REAL_SPACE,
}
main_lines_amount = (max_size / MAIN_LINES_REAL_SPACE).ceil.to_i32 + 1
start = -main_lines_amount // 2
stop = start + main_lines_amount
pp({
center_position: @center_position,
offset: offset,
max_size: max_size,
start: start,
stop: stop,
main_lines_amount: main_lines_amount,
})
(start..stop).each do |index|
main_line_v = SF::VertexBuffer.new(SF::LineStrip)
main_line_h = SF::VertexBuffer.new(SF::LineStrip)
main_lines << main_line_v
main_lines << main_line_h
main_line_v.create(2)
main_line_h.create(2)
x_start = MAIN_LINES_REAL_SPACE * index
x_end = width
y_start = MAIN_LINES_REAL_SPACE * index
y_end = height
# pp({
# center_position: @center_position,
# index: index,
# v_start: v_start,
# x_end: x_end,
# y_start: y_start,
# h_end: h_end,
# x_start: x_start,
# y_start: y_start,
# })
main_line_v_buffer_0 = SF::Vertex.new(
absolute_coordinates({x_start, start * MAIN_LINES_REAL_SPACE}, offset),
)
main_line_v_buffer_1 = SF::Vertex.new(
absolute_coordinates({x_start, y_end}, offset),
)
main_line_h_buffer_0 = SF::Vertex.new(
absolute_coordinates({start * MAIN_LINES_REAL_SPACE, y_start}, offset),
)
main_line_h_buffer_1 = SF::Vertex.new(
absolute_coordinates({x_end, y_start}, offset),
)
main_line_v_buffer = Slice[main_line_v_buffer_0, main_line_v_buffer_1]
main_line_h_buffer = Slice[main_line_h_buffer_0, main_line_h_buffer_1]
main_line_v.update(main_line_v_buffer, 0)
main_line_h.update(main_line_h_buffer, 0)
SECONDARY_LINES_AMOUNT.times do |subindex|
secondary_line_v = SF::VertexBuffer.new(SF::LineStrip)
secondary_line_h = SF::VertexBuffer.new(SF::LineStrip)
secondary_lines << secondary_line_v
secondary_lines << secondary_line_h
secondary_line_v.create(2)
secondary_line_h.create(2)
secondary_x_start = SECONDARY_LINES_SPACE * subindex
secondary_y_start = SECONDARY_LINES_SPACE * subindex
secondary_line_v_buffer_0 = SF::Vertex.new(
absolute_coordinates({x_start + secondary_x_start, start * MAIN_LINES_REAL_SPACE}, offset),
color: SECONDARY_LINES_COLOR,
)
secondary_line_v_buffer_1 = SF::Vertex.new(
absolute_coordinates({x_start + secondary_x_start, y_end}, offset),
color: SECONDARY_LINES_COLOR,
)
secondary_line_h_buffer_0 = SF::Vertex.new(
absolute_coordinates({start * MAIN_LINES_REAL_SPACE, y_start + secondary_y_start}, offset),
color: SECONDARY_LINES_COLOR,
)
secondary_line_h_buffer_1 = SF::Vertex.new(
absolute_coordinates({x_end, y_start + secondary_y_start}, offset),
color: SECONDARY_LINES_COLOR,
)
secondary_line_v_buffer = Slice[secondary_line_v_buffer_0, secondary_line_v_buffer_1]
secondary_line_h_buffer = Slice[secondary_line_h_buffer_0, secondary_line_h_buffer_1]
secondary_line_v.update(secondary_line_v_buffer, 0)
secondary_line_h.update(secondary_line_h_buffer, 0)
end
end
main_lines.each do |line|
draw(line)
end
secondary_lines.each do |line|
draw(line)
end
end
end