Skip to content

Instantly share code, notes, and snippets.

@Sephi-Chan
Created March 23, 2020 12:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Sephi-Chan/97a7c6ecbcea3196a43beb21fbd28a96 to your computer and use it in GitHub Desktop.
Save Sephi-Chan/97a7c6ecbcea3196a43beb21fbd28a96 to your computer and use it in GitHub Desktop.
# {:ok, pid} = Rts.RoomEngine.start_link([%{id: "Corwin", location: {0, 200}}])
# Rts.RoomEngine.move_to(pid, "Corwin", {200, 0})
# Rts.RoomEngine.stop(pid)
defmodule Rts.RoomEngine do
use GenServer
@speed 200/1000 # per seconds.
@step_duration round(1000/5) # milliseconds
def start_link(units) do
GenServer.start_link(__MODULE__, units)
end
def stop(pid) do
GenServer.call(pid, :stop)
end
def move_to(pid, unit_id, {x, y}) do
GenServer.call(pid, {:move_to, unit_id, {x, y}, :os.system_time(:millisecond)})
end
def init(units) do
units_as_map = Enum.reduce(units, %{}, fn (unit, acc) ->
Map.put(acc, unit.id, unit)
end)
{:ok, units_as_map}
end
def handle_call(:stop, _from, units) do
{:stop, :normal, units, units}
end
def handle_call({:move_to, unit_id, {toX, toY}, now}, _from, units) do
unit = units[unit_id]
timer = Process.send_after(self(), {:step, unit_id, now}, @step_duration)
unit = Map.merge(unit, %{destination: {toX, toY}, step_timer: timer})
{:reply, :ok, Map.put(units, unit_id, unit)}
end
def handle_info({:step, unit_id, began_step_at}, units) do
now = :os.system_time(:millisecond)
unit = units[unit_id]
{fromX, fromY} = unit.location
{toX, toY} = unit.destination
duration = now - began_step_at
distance = distance(fromX, fromY, toX, toY)
total_duration = distance / @speed
distance_ratio = min(duration / total_duration, 1)
unit = if distance_ratio == 1 do
Process.cancel_timer(unit.step_timer)
Map.merge(unit, %{location: {toX, toY}, destination: nil, step_timer: nil})
else
x = fromX + (toX - fromX) * duration / total_duration
y = fromY + (toY - fromY) * duration / total_duration
timer = Process.send_after(self(), {:step, unit_id, now}, @step_duration)
Map.merge(unit, %{location: {x, y}, step_timer: timer})
end
{:noreply, Map.put(unit, unit_id, unit)}
end
defp distance(fromX, fromY, toX, toY) do
:math.sqrt(:math.pow(toX - fromX, 2) + :math.pow(toY - fromY, 2))
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment