Skip to content

1122 test path smoothing #1138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 113 additions & 114 deletions apps/bot_manager/lib/bot_state_machine.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ defmodule BotManager.BotStateMachine do

@skill_1_key "1"
@skill_2_key "2"
@dash_skill_key "3"
# @dash_skill_key "3"

# The minimum distance a tracked player has to move for the tracking path to get recalculated
@path_recalculation_min_diff 300

# The force used to steer the current velocity into the new target velocity
@steering_force 0.1

@type bot_player() :: %BotManager.Protobuf.Entity{}
@type players() :: %{binary() => bot_player()}
Expand All @@ -32,25 +38,22 @@ defmodule BotManager.BotStateMachine do
bot_state_machine = preprocess_bot_state(bot_state_machine, bot_player)
next_state = BotStateMachineChecker.move_to_next_state(bot_player, bot_state_machine, game_state.players)

if System.get_env("PATHFINDING_TEST") == "true" do
move(bot_player, bot_state_machine, game_state.zone.radius)
else
case next_state do
:moving ->
move(bot_player, bot_state_machine, game_state.zone.radius)

:attacking ->
use_skill(%{
bot_player: bot_player,
bot_state_machine: bot_state_machine,
game_state: game_state,
attack_blocked: attack_blocked,
bot_skills: skills
})

:tracking_player ->
track_player(game_state, bot_player, bot_state_machine)
end
case next_state do
:moving ->
move(bot_state_machine, game_state.zone.radius)

:attacking ->
use_skill(%{
bot_player: bot_player,
bot_state_machine: bot_state_machine,
game_state: game_state,
attack_blocked: attack_blocked,
bot_skills: skills
})

:tracking_player ->
bot_state_machine = maybe_set_tracking_path(game_state, bot_player, bot_state_machine)
track_player(game_state, bot_player, bot_state_machine)
end
end

Expand Down Expand Up @@ -84,7 +87,7 @@ defmodule BotManager.BotStateMachine do
)

if Enum.empty?(players_with_distances) do
move(bot_player, bot_state_machine, game_state.zone.radius)
move(bot_state_machine, game_state.zone.radius)
else
bot_state_machine =
Map.put(
Expand All @@ -111,7 +114,7 @@ defmodule BotManager.BotStateMachine do
)

if Enum.empty?(players_with_distances) do
move(bot_player, bot_state_machine, game_state.zone.radius)
move(bot_state_machine, game_state.zone.radius)
else
bot_state_machine =
Map.put(
Expand All @@ -127,46 +130,48 @@ defmodule BotManager.BotStateMachine do
end

true ->
move(bot_player, bot_state_machine, game_state.zone.radius)
end
end

# This function will determine the direction and action the bot will take.
defp determine_player_move_action(bot_player, direction) do
{:player, bot_player_info} = bot_player.aditional_info

if System.get_env("PATHFINDING_TEST") == "true" do
{:move, direction}
else
if Map.has_key?(bot_player_info.cooldowns, @dash_skill_key) do
{:move, direction}
else
{:use_skill, @dash_skill_key, bot_player.direction}
end
move(bot_state_machine, game_state.zone.radius)
end
end

defp track_player(game_state, bot_player, bot_state_machine) do
defp maybe_set_tracking_path(game_state, bot_player, bot_state_machine) do
players_with_distances =
Utils.map_directions_to_players(
game_state.players,
bot_player,
Utils.get_action_distance_based_on_action_type(
Utils.get_action_distance_by_type(
bot_state_machine.is_melee,
bot_state_machine.melee_tracking_range,
bot_state_machine.ranged_tracking_range
)
)

if Enum.empty?(players_with_distances) do
move(bot_player, bot_state_machine, game_state.zone.radius)
closest_player = Enum.min_by(players_with_distances, & &1.distance)

cond do
is_nil(bot_state_machine.path_towards_position) or Enum.empty?(bot_state_machine.path_towards_position) or
Vector.distance(bot_state_machine.position_to_move_to, closest_player.position) > @path_recalculation_min_diff ->
try_pathing_towards(bot_state_machine, closest_player.position)

BotStateMachineChecker.current_waypoint_reached?(bot_state_machine) ->
Map.put(bot_state_machine, :path_towards_position, tl(bot_state_machine.path_towards_position))

true ->
bot_state_machine
end
end

defp track_player(game_state, bot_player, bot_state_machine) do
if is_nil(bot_state_machine.path_towards_position) || Enum.empty?(bot_state_machine.path_towards_position) do
move(bot_state_machine, game_state.zone.radius)
else
closest_player = Enum.min_by(players_with_distances, & &1.distance)
current_waypoint = hd(bot_state_machine.path_towards_position)

%{
action: determine_player_move_action(bot_player, closest_player.direction),
bot_state_machine: bot_state_machine
}
direction =
Vector.sub(current_waypoint, bot_player.position)
|> Vector.normalize()

handle_move_in_direction(bot_state_machine, direction)
end
end

Expand Down Expand Up @@ -216,9 +221,9 @@ defmodule BotManager.BotStateMachine do
end
end

defp move(bot_player, bot_state_machine, safe_zone_radius) do
defp move(bot_state_machine, safe_zone_radius) do
bot_state_machine =
determine_position_to_move_to(bot_state_machine, safe_zone_radius, System.get_env("PATHFINDING_TEST") == "true")
determine_position_to_move_to(bot_state_machine, safe_zone_radius)

# TODO instead of using `get_distance_and_direction_to_positions, use the pathfinding module`
cond do
Expand All @@ -229,10 +234,7 @@ defmodule BotManager.BotStateMachine do
hd(bot_state_machine.path_towards_position)
)

%{
action: determine_player_move_action(bot_player, direction),
bot_state_machine: bot_state_machine
}
handle_move_in_direction(bot_state_machine, direction)

not is_nil(bot_state_machine.position_to_move_to) ->
%{direction: direction} =
Expand All @@ -241,11 +243,7 @@ defmodule BotManager.BotStateMachine do
bot_state_machine.position_to_move_to
)

%{
action: determine_player_move_action(bot_player, direction),
bot_state_machine: bot_state_machine
}

handle_move_in_direction(bot_state_machine, direction)
true ->
%{
action: :idling,
Expand All @@ -254,53 +252,18 @@ defmodule BotManager.BotStateMachine do
end
end

defp determine_position_to_move_to(bot_state_machine, safe_zone_radius, true = _pathfinding_on) do
cond do
is_nil(bot_state_machine.collision_grid) ->
bot_state_machine

is_nil(bot_state_machine.path_towards_position) ->
position_to_move_to = BotManager.Utils.random_position_within_safe_zone_radius(floor(safe_zone_radius))

from = %{x: bot_state_machine.current_position.x, y: bot_state_machine.current_position.y}
to = %{x: position_to_move_to.x, y: position_to_move_to.y}

shortest_path = AStarNative.a_star_shortest_path(from, to, bot_state_machine.collision_grid)
defp determine_position_to_move_to(%{collision_grid: nil} = bot_state_machine, _safe_zone_radius) do
bot_state_machine
end

# If we don't have a path, retry finding new position in map
if Enum.empty?(shortest_path) do
Map.put(bot_state_machine, :path_towards_position, nil)
|> Map.put(:position_to_move_to, nil)
else
Map.put(bot_state_machine, :position_to_move_to, position_to_move_to)
|> Map.put(
:path_towards_position,
shortest_path
)
|> Map.put(:last_time_position_changed, :os.system_time(:millisecond))
end
defp determine_position_to_move_to(bot_state_machine, safe_zone_radius) do
cond do
is_nil(bot_state_machine.path_towards_position) || Enum.empty?(bot_state_machine.path_towards_position) ->
try_pick_random_position_to_move_to(bot_state_machine, safe_zone_radius)

BotStateMachineChecker.current_waypoint_reached?(bot_state_machine) and
BotStateMachineChecker.should_bot_move_to_another_position?(bot_state_machine) ->
position_to_move_to = BotManager.Utils.random_position_within_safe_zone_radius(floor(safe_zone_radius))

from = %{x: bot_state_machine.current_position.x, y: bot_state_machine.current_position.y}
to = %{x: position_to_move_to.x, y: position_to_move_to.y}

shortest_path = AStarNative.a_star_shortest_path(from, to, bot_state_machine.collision_grid)

# If we don't have a path, retry finding new position in map
if Enum.empty?(shortest_path) do
Map.put(bot_state_machine, :path_towards_position, nil)
|> Map.put(:position_to_move_to, nil)
else
Map.put(bot_state_machine, :position_to_move_to, position_to_move_to)
|> Map.put(
:path_towards_position,
shortest_path
)
|> Map.put(:last_time_position_changed, :os.system_time(:millisecond))
end
try_pick_random_position_to_move_to(bot_state_machine, safe_zone_radius)

BotStateMachineChecker.current_waypoint_reached?(bot_state_machine) ->
Map.put(bot_state_machine, :path_towards_position, tl(bot_state_machine.path_towards_position))
Expand All @@ -310,23 +273,59 @@ defmodule BotManager.BotStateMachine do
end
end

defp determine_position_to_move_to(bot_state_machine, safe_zone_radius, false = _pathfinding_on) do
cond do
is_nil(bot_state_machine.position_to_move_to) ||
not Utils.position_within_radius(bot_state_machine.position_to_move_to, safe_zone_radius) ->
position_to_move_to = BotManager.Utils.random_position_within_safe_zone_radius(floor(safe_zone_radius))
defp try_pick_random_position_to_move_to(bot_state_machine, safe_zone_radius) do
position_to_move_to = BotManager.Utils.random_position_within_safe_zone_radius(floor(safe_zone_radius))

Map.put(bot_state_machine, :position_to_move_to, position_to_move_to)
|> Map.put(:last_time_position_changed, :os.system_time(:millisecond))
try_pathing_towards(bot_state_machine, position_to_move_to)
end

BotStateMachineChecker.should_bot_move_to_another_position?(bot_state_machine) ->
position_to_move_to = BotManager.Utils.random_position_within_safe_zone_radius(floor(safe_zone_radius))
defp try_pathing_towards(bot_state_machine, position_to_move_to) do
from = %{x: bot_state_machine.current_position.x, y: bot_state_machine.current_position.y}
to = %{x: position_to_move_to.x, y: position_to_move_to.y}

Map.put(bot_state_machine, :position_to_move_to, position_to_move_to)
|> Map.put(:last_time_position_changed, :os.system_time(:millisecond))
shortest_path = AStarNative.a_star_shortest_path(from, to, bot_state_machine.collision_grid)

true ->
bot_state_machine
# If we don't have a path, retry finding new position in map
if Enum.empty?(shortest_path) do
Map.put(bot_state_machine, :path_towards_position, nil)
|> Map.put(:position_to_move_to, nil)
else
Map.put(bot_state_machine, :position_to_move_to, position_to_move_to)
|> Map.put(
:path_towards_position,
shortest_path
)
|> Map.put(:last_time_position_changed, :os.system_time(:millisecond))
end
end

defp handle_move_in_direction(%{current_move_direction: direction} = bot_state_machine, desired_direction) when is_nil(direction) do
%{
action: {:move, desired_direction},
bot_state_machine: Map.put(bot_state_machine, :current_move_direction, desired_direction)
}
end

defp handle_move_in_direction(bot_state_machine, desired_direction) do
current_direction = bot_state_machine.current_move_direction

if abs(Vector.angle_between(current_direction, desired_direction)) < 15 or abs(Vector.angle_between(current_direction, desired_direction)) > 95 do
%{
action: {:move, desired_direction},
bot_state_machine: Map.put(bot_state_machine, :current_move_direction, desired_direction)
}
else
direction_force = Vector.sub(desired_direction, current_direction)
|> Vector.normalize()
|> Vector.mult(@steering_force)

displaced_direction = Vector.add(current_direction, direction_force)
|> Vector.normalize()

%{
action: {:move, displaced_direction},
bot_state_machine: Map.put(bot_state_machine, :current_move_direction, displaced_direction)
}
end
end
end
Loading
Loading