-
Notifications
You must be signed in to change notification settings - Fork 4
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
Seeking AI behaviour #18
base: master
Are you sure you want to change the base?
Conversation
@@ -28,6 +29,9 @@ defmodule Entice.Logic.Movement do | |||
|> Map.put(Position, new_pos) | |||
|> Map.put(Movement, new_movement) | |||
end) | |||
{:ok, %MapInstance{map: map, players: _}} = Entity.fetch_attribute(entity, MapInstance) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the player have a map-instance attribute? I thought it was for maps only...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added it to be able to notify the player's map's agents but I'll remove it now that we're gonna use :entity_change instead.
@@ -22,36 +22,35 @@ defmodule Entice.Logic.Seek do | |||
def init(entity, %{aggro_distance: aggro_distance, escape_distance: escape_distance}), | |||
do: {:ok, entity |> put_attribute(%Seek{aggro_distance: aggro_distance, escape_distance: escape_distance})} | |||
|
|||
def init(entity, _args), | |||
def init(entity, _args), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whitespace change - kittens gonna die! :'(
|
||
def terminate(_reason, entity), | ||
do: {:ok, entity |> remove_attribute(Movement)} | ||
|
||
defp start_update_trigger_timer(message, time) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a need for this check? Otherwise just simply always use Process.send_after for simplicity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know. I copied it from here 20aa29d#diff-366987ce92dde211ad3e5f552c55e0d4R148 and assumed there was some kind of problem with send_after(message, 0). Although looking at it again it seems it might have just been to return nil so the calling function could interpret it as a timer ref so I'll replace it as you said.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the other case we needed either the nil
or the timer to cancel the timer appropriately - here we don't do anything with it, so we can just use the send_after
I think :)
@@ -8,7 +8,7 @@ defmodule Entice.Logic.Movement do | |||
Note that velocity is actually a coefficient for the real velocity thats used inside | |||
the client, but for simplicities sake we used velocity as a name. | |||
""" | |||
defstruct goal: %Coord{}, plane: 1, move_type: 9, velocity: 1.0 | |||
defstruct goal: %Coord{}, plane: 1, move_type: 9, velocity: 1.0, update_self: false, update_delay: 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking maybe we can shorten this a bit - for starters, I guess the update interval is static and can be compile with @update_interval 1
(also note the naming... delay sounds like waiting for something, which we don't do)
Second, I think 1ms for the interval is too short, considering that all NPCs are doing it and there will spam the whole map with position updates. I think for clients we have something like a position update every 50ms or so.
Next, maybe we can find a better name for update_self
? Something that tells us that this behaviour is automatically recalculating its state?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about auto_move_update ?
@EtienneDesticourt any updates on this? |
Nope, no time to work on it lately. You can merge if you're good with the current state, the seeking logic is there even though the pathing AI isn't. We could add that in a separate branch. |
Should probably write smarter tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool stuff. Keep going
defstruct target: nil, aggro_distance: 1000, escape_distance: 2000, path: [] | ||
|
||
def register(entity), | ||
do: Entity.put_behaviour(entity, Seek.Behaviour, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens with this behaviour if no params is given? Does it even work then?
do: {:ok, entity |> put_attribute(%Seek{aggro_distance: aggro_distance, escape_distance: escape_distance})} | ||
|
||
def init(entity, _args), | ||
do: {:ok, entity |> put_attribute(%Seek{})} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, no args = what behaviour?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right I'll add an init that only take an entity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here I meant: Do we need this case? Is this actually any use without parameters?
do: {:ok, entity |> put_attribute(%Seek{})} | ||
|
||
#No introspection for npcs ;) | ||
def handle_event({:entity_change, %{entity_id: eid}}, %Entity{id: eid} = entity), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure we can actually receive our own updates, can you verify?
|
||
def handle_event({:entity_change, %{changed: %{Position => %Position{coord: mover_coord}}, entity_id: moving_entity_id}}, | ||
%Entity{attributes: %{Position => %Position{coord: my_coord}, | ||
Movement => _, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we check for Movement here? I mean, if we need it for the behaviour, why not using the deconstructed variable?
defmodule Behaviour do | ||
use Entice.Entity.Behaviour | ||
|
||
def init(entity, %{aggro_distance: aggro_distance, escape_distance: escape_distance}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to check already here if all the attributes we require being present are actually there...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what you mean by that. We match on aggro_distance and escape_distance, if they're not there we get the default init, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No I meant Attributes, as in if the entity has the attributes we need, i.e. Movement etc.
|
||
%Path{vertices: new_path} = case success do | ||
:ok -> result | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Formatting this function and the other below would be nice ;)
|
||
def init(entity, _args), | ||
do: {:ok, entity |> put_attribute(%Movement{})} | ||
|
||
#TODO: Move all this logic to seek |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea ;)
Seek => %Seek{path: path}, | ||
Position => %Position{coord: current_pos}}} = entity) do | ||
#Determine next goal | ||
{entity, goal} = case Enum.count(path) do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively we can also simply match on the List like:
[_ | _] -> ...
_ -> {entity, goal}
Pretty much done, just need to figure out how to pass eid from movement to seek.