I have this project where the AI Hunters are supposed to hunt for apples until they have reached the amount of 2 apples. However when I try to start they often have problems collecting the food infront of them because of some collider problem.
Whenever the scanners starts scanning, theyre supposed to find the nearest apple inside that scanning area which you can see in the video I sent.
Heres a pic of the colliding blueprint, I have 2 different colliding checkers to make sure both the body and the colliders of the character actually touches the apple.
Heres a video to show the problem. Numbers above their head are how many apples theyve eaten. Ive seen hunters eat 2 but the main point is that they cant touch the apple that good
INFO: Those 3 Hunters are spawned from the HunterCharacterClass. The apples are made from the same mechanic just that they are stationary actors with no AI from the AppleActor.
Can you share the collision profiles for your hunters and apples? Also, does this same behavior occur when only one hunter AI is in the level? They may have an issue navigating around each other. If the issue is resolved by only including one hunter AI in the level, consider using a Detour Crowd Controller. Detour Crowd is a great way for multiple AI to navigate around each other, especially while moving. More information on Detour Crowd can be found here.
Looks like the problem you are facing is related to the collisions between the hunters and the apples, what I would try to do is instead of using the Hit event (when 2 actors block each other), use the Overlap event.
What I suspect is happening, is that the collisions (the physics part) are happening before the event gets triggered, so in your case, the hunters are pushing away the apples (and the apples are pushing away the hunters) before actually counting as an OnHit.
So, TL;DR: change the responses of the hunters to the PhysicsBody (what the apples are according to the images you sent) to Overlap, then change the response of the apples to Pawn to Overlap. And then instead of using that function on the OnHit event, use it on the OnOverlapBegin
This gave me different results each time I played.
One crashed because of an infinite loop,
one got too many and by that I mean they got 2+ instead of 1+ collected apple values
and lastly one was the same as it was before.
Can you send a screenshot or video showing this loop? Maybe it can be avoided.
This could be solved by adding a BeginDestroy() on the OnBeginOverlap event of the apple, be cautious to not reference the apple after destroying it.
I got another idea of what could be happening with the collisions, how are you moving the hunters to the apples? If you are using the MoveTo() on the controller, maybe it is a problem with the range that marks it as acceptable.
which has a float value AcceptanceRadius, which denotes the minimum distance between the target and the actor before marking as a successful move.
EDIT: I just noticed that on the blueprint of the overlap, the Equals (==) node is not connected to the Branch node. So right now if it overlaps with anything that it can overlap, it would mark it as the hunter eating the apple.
You could also instead of checking if the other actor is the apple that it went looking for, check if the OtherActor can be cast as an AClassOfTheApple, that way you can make sure that the hunter only picks up apples instead of the specific apple its following.
BeginDestroy gets called when the UObject (Actors are objects too, but are spawned in the world) is destroyed, to destroy an actor you have to call AMyActor->Destroy(). Objects will automatically be garbage collected when no active actors have a reference to them.
Sure, no problem! In c++ it would be something like this:
AAppleClass* Apple = Cast<AAppleClass>(OtherActor)
if(Apple)
{
// OtherActor is an AAppleClass
}
else
{
// OtherActor is not an AAppleClass
}
or
if(AAppleClass* Apple = Cast<AAppleClass>(OtherActor))
{
// OtherActor is an AAppleClass
}
else
{
// OtherActor is not an AAppleClass
}
or
AAppleClass* Apple = Cast<AAppleClass>(OtherActor)
if(IsValid(Apple))
{
// OtherActor is an AAppleClass
}
else
{
// OtherActor is not an AAppleClass
}
If the cast fails, it will be a null pointer. So asking if it is valid should let you know if it is an Apple or not.
For the infinite loop thing, you could place breakpoints on the code or blueprint and it should tell you where it got stuck when on runtime. To place a breakpoint on a blueprint, you have to do this or press F9:
I didnt really understand how to convert AMyActor->Destroy() to blueprint code but what I did instead was to destroy the actor that was touched && could be casted to and that left me with no errors so I could only assume it was one of the right ways.
The cast to apple seem to have done its job
Some hunters still has issues now and some of them dont, heres a vid of that:
All right, that’s great to hear! Looks like there is only one thing missing, and that would be to adjust the AcceptanceRadius of the MoveTo function. To do that you have to change the node of MoveToLocationOrActor for a AIMoveTo function.
For this example I assumed it’s gonna move on the tick, you can set it whenever you want. They should both do the same, and now you have a new attribute which you can configure AcceptanceRadius, try setting it more close to the apples (reduce the number).
That’s great, I think this is the equivalent for what I’ve told you on blueprints
EDIT: I also just realized that I got some errors too
“Attemted to access AppleActor_C_0 via property CallFunc_FindNearestActor_ReturnValue”
Which is here
Since the aimoveto was in the “on component begin overlap (scannerobject)” The AI moveto couldnt work there since it doesnt always go along with tickspeed; so what I had to do was to put a whileloop in my event tick and when the condition is true, it begins hunting, in this case: do the AI MoveTo as long as the condition is true each tick.
What you are doing there is a little weird, what it is doing is that whenever the hunter overlaps with something, then it asks the world for all the apples, then find the nearest and then assign it to FoundApple. What could be better is use The Other Actor attribute in the OnComponentBeginOverlap, that already gives you the apple that the hunter is touching, so there’s no need for it to ask the world about all the apples in the level. So after casting it to make sure that the hunter is indeed touching an apple and not another thing, then you can assign it to FoundApple.
The error you were having is due to the hunters trying to find apples, when there are not anymore. To avoid that you have to make some sanity checks, like for instance, checking if the arrays are empty or not (like the one returned by the get all actors of class function)
Your first solution was a bit hard for me to understand, If I got this correctly: Wouldnt the Hunters in the scene be trying to go for the platform that is underneath the hunters since it also collides with the hunters scanners?
I did this sort of section of blueprint code to find the nearest apple inside the scanners radius and assign it to the variable “foundapple”; the hunter is then supposed to catch that foundapple object. If I could do this better, would you please show me a blueprint/code example? I come from unity development so I hardly know how blueprint works
The error you were having is due to the hunters trying to find apples, when there are not anymore. To avoid that you have to make some sanity checks, like for instance, checking if the arrays are empty or not (like the one returned by the get all actors of class function)
I dont know how to check if ALL the apples in the class array are valid sadly but this is what I found as an alternative solution :
It should not, as it is colliding with a OnHit with the ground and not an OnBeginOverlap, that is because of the collision channels and if they are blocking or overlapping, this may help you understanding more about collisions in UE Collision Overview | Unreal Engine 4.27 Documentation
What I meant is this, without needing to search for every apple every time the hunter overlaps with something.
Where it checks for all actors of class Apple in the world, then for each of them found, it will check if they are valid or not, and if it founds one apple that is not valid, it will interrupt the for each iterator.
As this makes the characters find the fastest way to the apples, I did notice that they dont really go for apples that are inside the radius, they take whatever the closest apples are in the world.
Heres a vid:
Heres the blueprint, its the same as before just that it now prints whatever the found apples location is: