defmodule Grav do use VElixir.GenServer def start_link(opts \\ []) do GenServer.start_link(__MODULE__, nil, opts) end # def g, do: 6.67408e-11 def init(_) do {:ok, _} = VElixir.start_link state = %{ objects: Enum.map(1..100, fn _ -> %{vtype: Sphere, pos: V.random(0.85), radius: 0.05, color: Color.random, mass: 5, vel: V.new} end), # arrow: %{vtype: Arrow, pos: V.new}, dt: 0, t: 0, render: [:objects] } {:ok, state} end def handle_cast({:update, dt, t}, state) do state = %{state|dt: dt, t: t} objects = state.objects |> VElixir.Misc.worker_map(10, fn obj -> update(obj, state) end) {:noreply, %{state|objects: objects}}#, arrow: Map.put(state.arrow, :dir, hd(objects).pos)}} end def update(obj, state) do obj |> calc_force(state.objects) |> calc_kinematics(state.dt) end def calc_force(obj, objects) do Map.put(obj, :net_force, Enum.reduce(objects, V.new, fn other_obj, net_force -> if obj == other_obj do net_force #make sure not to count force from ourselves else r = other_obj.pos - obj.pos net_force + (norm(r) * ((1/length(objects)) * obj.mass * other_obj.mass / :math.pow(mag(r), 1))) end end)) end def calc_kinematics(obj, dt) do accel = obj.net_force / obj.mass obj |> Map.put(:vel, obj.vel + accel*dt) |> Map.put(:pos, obj.pos + obj.vel*dt) end end