Opened 11 years ago

Last modified 4 years ago

#1724 new enhancement

[PATCH] adding some collective behaviour of wild animals when attacked

Reported by: mimo Owned by:
Priority: Nice to Have Milestone: Backlog
Component: Simulation Keywords: patch design
Cc: Patch:

Description (last modified by Freagarach)

The present behaviour of animals is quite odd : when an animal is attacked, either it flees or attacks, but none of the animals around react while we would expect that all animals around will react to the agression either by fleeing or defending the member of their herd. This is implemented in the patch attached. This could still be improved because I've not find how to determine that two animals are from the same specy. For the time being, I use their specificName but there are cases (elephant and elephant calf) where this would not work. Is there an unambiguous way to solve this question ? This patch works much better with the fix of #1723

Attachments (6)

animal.patch (2.3 KB ) - added by mimo 11 years ago.
collectiveBehavior.patch (5.8 KB ) - added by mimo 11 years ago.
collectiveBehavior-edit.patch (7.8 KB ) - added by leper 11 years ago.
collectiveBehavior-v3.patch (14.6 KB ) - added by mimo 11 years ago.
collectiveBehavior-v4.diff (14.6 KB ) - added by mimo 11 years ago.
basically the same as previous patch, but some cleanings added
collectiveBehavior-v5.diff (17.6 KB ) - added by mimo 11 years ago.

Download all attachments as: .zip

Change History (39)

by mimo, 11 years ago

Attachment: animal.patch added

comment:1 by Kieran P, 11 years ago

Component: Core engineUI & Simulation
Milestone: BacklogAlpha 13
Priority: Should HaveNice to Have
Type: defectenhancement

comment:2 by fcxSanya, 11 years ago

This could still be improved because I've not find how to determine that two animals are from the same specy. For the time being, I use their specificName but there are cases (elephant and elephant calf) where this would not work. Is there an unambiguous way to solve this question ?

It is better to use classes, rather than names. All elephants already have the 'Elephant' class. Giraffes do not, but you can add one for them.

in reply to:  2 comment:3 by fcxSanya, 11 years ago

Replying to fcxSanya:

It is better to use classes, rather than names. All elephants already have the 'Elephant' class. Giraffes do not, but you can add one for them.

Hm, but in this case you will need to find an interesting class amongst others somehow. May be clearer to introduce a separate schema element.

Edit:

E.g. you can add something like optional 'AnimalType' element into the UnitAI schema, maybe inside NaturalBehaviour or separately. When performing the check if it is not present you can fall-back to the template name or something to not set the 'AnimalType' for animals with only one template.

Last edited 11 years ago by fcxSanya (previous) (diff)

comment:4 by Jonathan Waller, 11 years ago

Why should this be done on a per species basis? I think it is more realistic to have all easily scareable animals run.

comment:5 by historic_bruno, 11 years ago

Also, doesn't this seem likely to overlap with desired human unit behavior? For example if a female in a group is attacked, they should all flee, if a soldier in a group is attacked, they should all respond (by stance)? Just thinking ahead, before we write a bunch of animal-specific logic :)

comment:6 by Kieran P, 11 years ago

I agree, provided it only affects idle units. No one is going to stand around doing nothing and watch someone else being attacked. But if I have tasked units to gather food or something, I don't want them to stop doing that and go off and fight. And yes, it should be based on stance.

So animals in idle or feeding states, when an animal in range is attacked either flee if skittish, or fight if defensive. Agrrsive animals already attack enemies in range, so they don't need any changes.

And humans in idle, when another human in range attacked either flee if passive (women), or fight is defensive or higher (all other units).

in reply to:  4 comment:7 by mimo, 11 years ago

Replying to quantumstate:

Why should this be done on a per species basis? I think it is more realistic to have all easily scareable animals run.

yes, of course all scareable animals should run, but what about defensive ones for example : we don't want nearby elephants to attack if we are hunting a giraffe, but we do want them to attack if we are hunting an elephant calf.

in reply to:  5 ; comment:8 by mimo, 11 years ago

Replying to historic_bruno:

Also, doesn't this seem likely to overlap with desired human unit behavior? For example if a female in a group is attacked, they should all flee, if a soldier in a group is attacked, they should all respond (by stance)? Just thinking ahead, before we write a bunch of animal-specific logic :)

Yes, I agree that human behaviour should also be modified. But the present code in UnitAI treat separately humans and animals, so let's start to improve the simplest one first. But may-be you mean that we should merge these two part of code and have a common treatment ? as the situations are quite different, I'm note sure you will gain anything except complexity by doing that.

comment:9 by historic_bruno, 11 years ago

Keywords: patch review added

comment:10 by mimo, 11 years ago

If you would review the code, here is a modified version with a hack to treat correctly the elephant case, waiting for a more general way to find the animal specy. This patch contains two parts :

  • all skittish animals around the attacked animal will flee. I suppose this is wanted.
  • if the attacked animal is defensive or agressive, all animals around from the same specy will defend it. Reading a bit different comments, It seems that not everybody wanted this feature. I think it is nice, and force you to think twice before hunting such animals, but this part could be dropped.

in reply to:  10 ; comment:11 by leper, 11 years ago

Keywords: review removed

Replying to mimo:

If you would review the code, here is a modified version with a hack to treat correctly the elephant case, waiting for a more general way to find the animal specy.

Why don't you add something to the templates? (See fcxSanya's comment above)

This patch contains two parts :

  • all skittish animals around the attacked animal will flee. I suppose this is wanted.
  • if the attacked animal is defensive or agressive, all animals around from the same specy will defend it. Reading a bit different comments, It seems that not everybody wanted this feature. I think it is nice, and force you to think twice before hunting such animals, but this part could be dropped.

So if an elphant is attacked and there is a calf nearby it will attack too? (This needs some thought and research, but attacking should be based on the animal behaviour IMO).
I can't think of any real reason why this shouldn't be limited to gaia units only, so I think this can be left as it is.
historic_bruno's comment about something similar for units still applies. If you don't want to do this (or you think it shouldn't be done as a part of this patch) I would at least rename the method so that it is obvious that it only applies to animals.

Please readd the review keyword when you have addressed these comments in a new patch.

in reply to:  11 ; comment:12 by mimo, 11 years ago

Replying to leper:

Replying to mimo:

If you would review the code, here is a modified version with a hack to treat correctly the elephant case, waiting for a more general way to find the animal specy.

Why don't you add something to the templates? (See fcxSanya's comment above)

because it is out of my competences : I don't know how these templates work.

This patch contains two parts :

  • all skittish animals around the attacked animal will flee. I suppose this is wanted.
  • if the attacked animal is defensive or agressive, all animals around from the same specy will defend it. Reading a bit different comments, It seems that not everybody wanted this feature. I think it is nice, and force you to think twice before hunting such animals, but this part could be dropped.

So if an elphant is attacked and there is a calf nearby it will attack too? (This needs some thought and research, but attacking should be based on the animal behaviour IMO).

No, calf elephants are skittish, not defensive, so they won't attack. But on the opposite, if a calf is attacked, surrounding adult elephants will attack.

I can't think of any real reason why this shouldn't be limited to gaia units only, so I think this can be left as it is.
historic_bruno's comment about something similar for units still applies. If you don't want to do this (or you think it shouldn't be done as a part of this patch) I would at least rename the method so that it is obvious that it only applies to animals.

Player units behaviour is more involved. In some cases, we will want them to flee or fight, while in other cases, we'd prefer them to finish their task whatever the risks. So I think it should be adressed separately. I agree I should change the name of the method.

Please readd the review keyword when you have addressed these comments in a new patch.

in reply to:  12 comment:13 by leper, 11 years ago

Replying to mimo:

Replying to leper:

Why don't you add something to the templates? (See fcxSanya's comment above)

because it is out of my competences : I don't know how these templates work.

Working with the templates is way easier than UnitAI IMO, so you should be able to handle that :-). Take a look at Identity.js to get an idea of how it works and if you have any questions just ask (here, in #0ad-dev or on the forums).

No, calf elephants are skittish, not defensive, so they won't attack. But on the opposite, if a calf is attacked, surrounding adult elephants will attack.

Ah, I misread that part of the code.

Player units behaviour is more involved. In some cases, we will want them to flee or fight, while in other cases, we'd prefer them to finish their task whatever the risks. So I think it should be adressed separately. I agree I should change the name of the method.

What about just applying to idle units?

comment:14 by mimo, 11 years ago

OK I will see if I can do something with templates. But as they are only needed for the part involving retaliation of defensive animals when one of them is attacked, I need first to be sure this is the way you want to go. Hunting elephants will become harder, you'll have to gather a small group of units to do it, or look only for isolated elephants. I use it in my games as I find it more realistic, but that may not be wanted by everybody.

Yes, we could apply something also for idle units. Here again, if I'm sure this is the way you want to go, I can try and find some implementation for it. It should be quite easy : I think all units who should fight already does (but to be checked), so I guess we should only make all others idle units around the attacked one to flee ?

in reply to:  14 comment:15 by leper, 11 years ago

Replying to mimo:

OK I will see if I can do something with templates. But as they are only needed for the part involving retaliation of defensive animals when one of them is attacked, I need first to be sure this is the way you want to go.

I think it adds some realism to hunting of some animals, so yes.

Hunting elephants will become harder, you'll have to gather a small group of units to do it, or look only for isolated elephants. I use it in my games as I find it more realistic, but that may not be wanted by everybody.

We can still change some stats (health, armour, attack) if it is too hard, but I think a player should be punished if he sends just one unit to hunt an elephant.

Yes, we could apply something also for idle units. Here again, if I'm sure this is the way you want to go, I can try and find some implementation for it. It should be quite easy : I think all units who should fight already does (but to be checked), so I guess we should only make all others idle units around the attacked one to flee ?

Not if you get attacked by a ranged unit, but I think we should leave this part out of this ticket and just rename the method.

comment:16 by mimo, 11 years ago

I've produced a new patch with the proposed changes : I've added an optional Species in Identity.js (only for Elephants up to now), and use this in UnitAI to determine the species. When Species is not present (i.e. for all animals except elephants), the specificName is used. The method has also been renamed to indicate that it applies on animals.

Note that, instead of adding this new Species, we could may-be reuse the GenericName ? It is always "fauna" for such fauna animals, and does not seem to be used for animals.

by mimo, 11 years ago

Attachment: collectiveBehavior.patch added

comment:17 by mimo, 11 years ago

Keywords: review added

by leper, 11 years ago

comment:18 by leper, 11 years ago

I attached a slightly modified version of your last patch, but I noticed something:

Hunting deer is pretty hard with this patch, as the herd flees quite a distance (too much to make hunting useful IMO).

Do you have an idea how to alleviate this issue?

EDIT: Species is Elephant for elephants as we use African infant elephants in some maps with only Asian elephants.

Last edited 11 years ago by leper (previous) (diff)

comment:19 by mimo, 11 years ago

yes, I agree with your point. I've already thought about it and could propose two ways to go (and in fact using both would look better to me) :

1) presently, this patch has a strict cut : animal with dist<24 would flee, while those above 24 would not. That's not really nice because of the discontinuity it creates. What I propose is that for animals which would flee, we use a fleeFactor = (24-dist)/24 and use as effective FleeDistance = FleeDistance*Fleefactor. So that would restore continuity, and make animals around flee a bit less.

2) the other possibility would be to change a bit the MoveRandomly method of UnitAT.js for idle animals. Presently, it is purely random, but there is a TODO point saying that we should have a 'home' point. I fully agree with that TODO and this home point would allow to restore the herd between huntings when animals are idle : we would have to store the initial position of each animal, and modify MoveRandomly to be part random and part drifting towards this initial position.

in reply to:  19 comment:20 by leper, 11 years ago

Replying to mimo:

1) presently, this patch has a strict cut : animal with dist<24 would flee, while those above 24 would not. That's not really nice because of the discontinuity it creates. What I propose is that for animals which would flee, we use a fleeFactor = (24-dist)/24 and use as effective FleeDistance = FleeDistance*Fleefactor. So that would restore continuity, and make animals around flee a bit less.

This would probably reduce the fleeing distance of the herd, but as the hunter will follow the target (and skittish animals will just flee) the herd will still drift away. (This could need a Math.floor())

2) the other possibility would be to change a bit the MoveRandomly method [...] we would have to store the initial position of each animal, and modify MoveRandomly to be part random and part drifting towards this initial position.

Sounds like a good idea (check the uses heldposition as that could ease the implementation a bit), but there are still some small issues:

  • A hunter will still keep the herd from moving back to the home/held position, if he moves to the herd from that point. (Not really a problem)
  • If someone builds a town there the animals will still drift there (which is a bit unrealistic), but they will flee from movements there so I'm not sure if that will actually look bad.

I think starting with one of your points and testing how that works out would be a good idea.

comment:21 by mimo, 11 years ago

Yes, I've to think a bit more about the different possibilities, and let you know if I can find something satisfactory.

But for the time being, I've a small technical question : what is the best place if I want to initialise some quantities at the start of the game ? in my case, I'd like to save the starting position of the animals. I've tried the UnitAI.js init method, but the position is not yet defined when this method is called. It seems that helpers/InitGame.js would work for such an initialisation : is this the right place ? or is there something more adequate ?

comment:22 by leper, 11 years ago

Init is called on the component initialisation, where other components may not be initialised yet.

I would put the position storing in ANIMAL.IDLE.enter (with a check if it isn't already set), and change the initial state (OnCreate()) to ANIMAL.IDLE, but this needs a small change in helpers/FSM.js in the Init() which should have a loop like the one in ProcessMessage().

by mimo, 11 years ago

Attachment: collectiveBehavior-v3.patch added

comment:23 by mimo, 11 years ago

Here is a new version of the patch, where the different proposed ideas have been implemented. In addition, the direction of the flee has been a bit randomized (this should also fix #1709) : now, instead of fleeing with the targeted animal, the rest of herd will have a tendency to move aside.

Last edited 11 years ago by leper (previous) (diff)

by mimo, 11 years ago

Attachment: collectiveBehavior-v4.diff added

basically the same as previous patch, but some cleanings added

comment:24 by Kieran P, 11 years ago

Milestone: Alpha 13Alpha 14

in reply to:  8 ; comment:25 by historic_bruno, 11 years ago

Keywords: review removed

I've reviewed the latest patch. It works well in my testing, so I mostly have comments about cosmetic/logic issues:

  • Adding "Species" to CmpIdentity makes it seem like we care about entity species, in general we don't. I would favor fcxSanya's suggestion of adding an element to UnitAI instead. It would also slightly simplify the species checks, not needing to query an additional component. It's better to use simple English names to avoid details like exactly which Latin species a particular animal is (e.g. Wikipedia says the Asian elephant is Elephas maximus and the African elephant is Loxodonta africana). Panthera leo should be lion, etc.
  • It's weird that the attacked animal determines the response range, but I suppose that's done for efficiency (a single range query should be more efficient than requiring all entities on the map to test their distance)? It looks OK in practice. Would using vision range instead of FleeDistance be a bit less extreme? It would apparently be 10 instead of 24.
  • I don't like the idea of NearbyAnimalsRespondToAttack() controlling other entities' UnitAIs directly, it seems like it might work better as a message, which the other entities can handle as needed. It's related to this point:

Replying to mimo:

Replying to historic_bruno:

Also, doesn't this seem likely to overlap with desired human unit behavior? For example if a female in a group is attacked, they should all flee, if a soldier in a group is attacked, they should all respond (by stance)? Just thinking ahead, before we write a bunch of animal-specific logic :)

Yes, I agree that human behaviour should also be modified. But the present code in UnitAI treat separately humans and animals, so let's start to improve the simplest one first. But may-be you mean that we should merge these two part of code and have a common treatment ? as the situations are quite different, I'm note sure you will gain anything except complexity by doing that.

Not sure I agree. The reactions are different but not the cause (an attack) and the need to "notify" other entities in range is also very similar. To make an analogy, we have for example one MT_Attacked message, not a separate one for every type of entity, even though the response to an attack is very specific.

I could envision something like an MT_NearbyAttacked message, sent to "friendly" entities in range when an entity is attacked, it would be handled for animals now and humans would ignore it until we decide what to do there. Unless there's a significant flaw in that approach, it seems like it would be little work now to save more work later.

in reply to:  25 comment:26 by mimo, 11 years ago

Replying to historic_bruno:

I've reviewed the latest patch. It works well in my testing, so I mostly have comments about cosmetic/logic issues:

  • Adding "Species" to CmpIdentity makes it seem like we care about entity species, in general we don't. I would favor fcxSanya's suggestion of adding an element to UnitAI instead. It would also slightly simplify the species checks, not needing to query an additional component. It's better to use simple English names to avoid details like exactly which Latin species a particular animal is (e.g. Wikipedia says the Asian elephant is Elephas maximus and the African elephant is Loxodonta africana). Panthera leo should be lion, etc.

I really don't mind how we implement that. Just need to be sure what is the "preferred" option from the team as what I have now was in fact written by leper some time ago (see previous comments). Also, we should be sure that the chosen option will be usable for other purposes also (in an other ticket about corrals, someone raised the idea to have only one kind of animal at a time in corrals, and we then may need to reuse the same logic for that).

  • It's weird that the attacked animal determines the response range, but I suppose that's done for efficiency (a single range query should be more efficient than requiring all entities on the map to test their distance)? It looks OK in practice. Would using vision range instead of FleeDistance be a bit less extreme? It would apparently be 10 instead of 24.

Exactly, the reason was to not spent too much time. I've made some trials with different ranges and 10 looks really too small. I've temporarily put a fixed range of 20, which will have to be tuned. Anyway we may need different ranges depending if the attacked unit is an animal or not (see answer to your last comment)

  • I don't like the idea of NearbyAnimalsRespondToAttack() controlling other entities' UnitAIs directly, it seems like it might work better as a message, which the other entities can handle as needed. It's related to this point:

I fully agree. And I'm going to rewrite that part using messages.

Replying to mimo:

Replying to historic_bruno:

Also, doesn't this seem likely to overlap with desired human unit behavior? For example if a female in a group is attacked, they should all flee, if a soldier in a group is attacked, they should all respond (by stance)? Just thinking ahead, before we write a bunch of animal-specific logic :)

Yes, I agree that human behaviour should also be modified. But the present code in UnitAI treat separately humans and animals, so let's start to improve the simplest one first. But may-be you mean that we should merge these two part of code and have a common treatment ? as the situations are quite different, I'm note sure you will gain anything except complexity by doing that.

Not sure I agree. The reactions are different but not the cause (an attack) and the need to "notify" other entities in range is also very similar. To make an analogy, we have for example one MT_Attacked message, not a separate one for every type of entity, even though the response to an attack is very specific.

I could envision something like an MT_NearbyAttacked message, sent to "friendly" entities in range when an entity is attacked, it would be handled for animals now and humans would ignore it until we decide what to do there. Unless there's a significant flaw in that approach, it seems like it would be little work now to save more work later.

As I said before, I'm rewriting NearbyAnimalsRespondToAttack() to use messages, and this will also be usable by humans. I can already add something so that idle units react to nearby attacks.

comment:27 by mimo, 11 years ago

here is a new version of the patch with the modifs described previously (using messages, and more generic code to be usable for human units).

for the way to recognize species, I've only simplified it a bit and used english names, but still using cmpIdentity.

by mimo, 11 years ago

Attachment: collectiveBehavior-v5.diff added

comment:28 by Kieran P, 11 years ago

Milestone: Alpha 14Alpha 15

comment:29 by mimo, 10 years ago

Milestone: Alpha 15Alpha 16

comment:30 by mimo, 10 years ago

Milestone: Alpha 16Backlog

Put it in backlog as no need some design choice on animal behaviour (mainly vision range)

comment:31 by Stan, 10 years ago

Keywords: design added

comment:32 by Imarok, 5 years ago

Component: UI & SimulationSimulation

Move tickets to Simulation as UI & Simulation got some sub components.

comment:33 by Freagarach, 4 years ago

Description: modified (diff)

Refs. #3919.

Note: See TracTickets for help on using tickets.