Hello! When I was going through the code I realised I was repeating myself, so I decided to leave the code part more high level. If you'd like to analyse it better check the repository github.com/viniciusgerevini/godot-goap. There you can also find a link for the live demo.
Hey, thanks for the video! Just wanted to let you know that the GitHub link on your comment is broken (it has an extra parenthesis at the end). Cheers!
I think this is what you call a rare timeless coding tutorial, because no matter what language or engine you're using, the base logic still applies. Well done.
1:37 What about choosing a plan with more points? For example, it costs more points, but the NPC will get "pleasure" from it and will take on a more difficult plan because of it. I think it's worth changing the concept of "cost" to "profit", then it will be possible to make different ideas about profit for different NPCs, for example, when all vital needs are satisfied - depending on the resource behavior, the NPC will choose plan to idle or explore/etc.
Hey, good thought exercise. The trade off doesn't seem worth it to me though. I think one good thing of thinking as "cost" is that 0 will always be the least effort / most desirable action. If we invert the scores, when adding a new most desirable action we will need to know what is the current highest score and there is no guarantee that action will remain being the most desirable one. It should still work, but I think it would require more maintenance. However, that doesn't invalidate your idea of making the plans cheaper using other variables (i.e. pleasure). This can be achieved with dynamic costs without needing to invert the scores. Also for your example of choosing the idle/explore plan, that is usually defined by the plan priority and not for the plan cost. What I mean is that if the vitals are satisfied, idle or explore will become the highest priority goal, so only plans to achieve idle/explore will be considered. Thanks
Thank you. It' s nice of you. This kind of videos usually take more time to make than my normal devlogs, that's why I don' t do them as often. But I intend to keep making them whenever I find an interesting subject. Suggestions are welcome :)
Thanks for making this. It looks to me like a hybrid approach is needed whereby a behavioir tree handles general logic and then GOAP can exist within a constrained state for more dynamic behavioir. This would ensure undesirable outcomes are isolated within a particular state.
Very interesting, actually never heard of goap before. Sadly doesn't fit well into my current project but will certainly test it out in the future if I do a project where this would fit well.
Hello, Vini. Is there any chance you can change the renderer of the project to compatibility as my laptop can't handle the OpenGL3 Renderer. It's all good if not, I just wanted a better idea of how the project works as I'm struggling with implementation. Thanks!
It seems that the biggest drawback for this method is the inability to predict the future. For instance, if the fire pit will burn out before the satyr can get wood to build another pit, that is a failure and the satyr should not spend any time chillaxing but should go to get firewood. Similarly, if the troll is near and there are two possible sanctuaries, the satyr should be able to determine which one would allow them to flee the troll better. Again, not a critique on your specific method, just pointing out that evaluating the GOAP only based on the *now* lacks planning for the future.
How do you let the ai know to prioritise something lower priority when it's easier to get? Like here, the character was hungry the whole time, but didn't prioritise it until it got too much, when quickly just picking up a mushroom while going from A to B would have been super simple
I think this is just because of the priorities I defined for this project. In the example the hunger was being ignored because I deliberately made the "relax" goal priority way higher than the other ones so it's basically unstoppable. However, in a real game indeed we might want the hunger to at some point surpass the need to hide. That can be achieved by adjusting the dynamic priority for that goal. One other idea (I didn't put much thought on that) would be maybe allowing goals with tied priorities to be calculated together. That might be too complex and likely have performance drawbacks, but might work. The idea is that if two goals (i.e. "Calm down", "keep fed") have the same priority, we calculate plans for both of them and pick the cheapest one. In your example, as the mushroom is so close, the agent could prioritize feeding over hiding. Having said that, before implementing anything crazy I'd definitely try to tinker with the priorities. Cheers.
I've watched this through a couple of times and read through the code and i can't really understand how you'd make this work with multiple bots? So much of how ti operates seems bound to just working with one blackboard.
Hello @haxtrad. That's correct. The planner will always work with only one blackboard. When instantiating multiple agents, each one will have their own planner, working with their blackboard instance in isolation.
Hey Vini! I was curious about the code base and tried importing it but I am getting a bunch of errors. Do you know I am getting those errors? (like: indentation errors, stack-overflow errors - after fixing the indentation etc)
Hello. Sorry the late response. That's weird. Maybe something broke with the new releases. I've definitely seen some stack overflow while developing it, because the implementation does not handle circular dependencies, but the code as-is shouldn't cause it. I'll take a look as soon I have time. Thanks for letting me know :)
Personally, I'd still use variables instead of methods because they get exposed in the inspector. There's also custom set/get methods one can define with the variable, too, so one wouldn't lose out on the custom logic. anyway, cool vidoe :>
One of the things that seems to elude me is how you pick the initial goal to then send through GOAP. But maybe I’m misidentifying the utility of GOAP and in a simplistic situation of you have an enemy AI only has two goals, kill or flee then you can simplify the logic to pick the higher order goals? Idk
Oh yeah. If the behaviour is too simple I guess GOAP might be unnecessary complexity. Having said that if you have multiple ways to achieve the "kill" or "flee" goals it might still be useful. For how to pick the goal, it's all about dynamic priorities. I guess your flee goal would have an increased priority if HP is low, while the kill goal priority could increase if the player is too close. For two goals only it's hard to justify, but if you throw another goal in the mix things start becoming more interesting due to unplanned emergent behaviour.
Very nice project. Could you perhaps port it to Godot 4? I just tried to let Godot 4 convert it but it was not functional afterwards. As I am new to Godot I do not know how to fix it. Thanks!
@@ThisIsVini Did you already have time to convert the project? I hope I do not bother you too much, but I would really be excited to experiment with a Godot 4 version. Thanks in advance!
@@blocklib1932 Hello there! I migrated it this afternoon. The main branch has the Godot 4 code now. github.com/viniciusgerevini/godot-goap . It seems to be running correctly, but let me know in case you find issues. Cheers.
Thanks for this, works great. One thing I'm missing though is making the actions perform for an amount of time, not instantly. For example, an NPC cooking food for 5 seconds. How would I go about making this? I tried just adding await but it broke everything.
In my example the `perform` method in the GoapAction returns true when finished and false when it is still going. Your actor.cook() method would be the one to control if the action is finished or not. You could also have a property actor.is_cooking used in the action which is set to true when cooking starts and set to false once the timer completes. The caveat with doing only that is that this does not prevent your planner from replacing your current plan with something more important and stop it mid cooking. If that is a concern to you, you could have some kind of flag in your actor, like actor.is_busy which would stop the GoapAgent from calling the planner while the actor is busy. I hope that's helpful. Cheers.
With this code, if you add another Satyr they share current goals because stuff like is_frightened is set in the World State. How do you suggest making each actor behave on it's own?
You could create member variables that hold all the necessary enemy states and keep them all in an Enemy class which would become the parent class of every Enemy type, and with every instance of an Enemy in that class, you'd get individually editable variables for each Enemy. Of course, every different type of Enemy would have to have a script that extends this Enemy class in order to get access to those variables.
Hello Andrew. That's a really good question. I didn't think about that when I was making this experiment. The first thing that comes to my mind is changing the goals and actions to no look into the raw world state, but into a projection of it. Basically, world state wouldn't include actor related info. The goal would access a local world state that would contain the global world state and be hydrated with all relevant info from the actor. This local world state would then be passed to the actions and goals. This would require some extra thought as it raises other questions like, how to keep both states in sync? Or, who decides which actor's info is relevant? Thanks for the question. That makes me want to revisit the problem and come up with a better solution. Cheers.
@@ThisIsVini In the current plan, adding multiple Satyr will still share goals and actions. Is it possible to assign a different PLANER to each npc? I have reviewed the introduction related to Goap, and my understanding is that each different NPC will have its own PLAENER and a copy of WORLDSTATE? But my code level is terrible, I really can't do this🥲. Firstly, thank you very much for your work on AI in Godot. Would you like to continue updating this system? Can each NPC have different goals and actions? This is very important to me
Thanks. What do you mean from scratch? Including the planning logic? I feel that one is better to check the code for it. I added a bunch of comments to make it easier to understand.
@@ThisIsVini he probably means seeing it implemented. I often find it best to learn to see how someone is arriving at the decisions rather than it just being put out there with comments. You would not believe just how much you can learn seeing it done in real time rather than heres my code and this is what it does. So if you didnt mind doing a tutorial series of implementing it with commentary i know i and many others would appreciate it. otherwise fantastic video
@@ThisIsVini you have any idea how to make these plans with data you dont know about. For example say i placed a building down that requires resources to build. I would want my plan to check a building is placed, what material from its requirements and for the next step of the plan to then know what this material is so it can check if its in the players inventory. In all the examples i have seen its assumed your only working with a small handful of pre existing data and if theres a procedural check its just to make sure a target isnt null. I tried something by adding in a function in the planner to perform a check which told each thing to add a precondition but i kept stumbling on the thing not knowing what thing wanted what item because its its own action.
I would love to give this a try, does anyone know of some good c# implementations of this, or some good step by step tutorials on this subject rather than a general overview. I learn better when i see the process take place rather than it being briefly explained.
I think it may be interesting, I created a GOAP sample inspired by this video, but in Unity. It is in the GOAP section in github.com/m039/CommonUnitySamples You can try it in a browser. I used the same goals (bonfire, hunger / mushrooms, fear / troll), but I've added procedurally generation and the house where a bot can store food or wood (and take from it too). You also can click on the bot and see all his properties.
Hello!
When I was going through the code I realised I was repeating myself, so I decided to leave the code part more high level. If you'd like to analyse it better check the repository github.com/viniciusgerevini/godot-goap. There you can also find a link for the live demo.
Hey, thanks for the video! Just wanted to let you know that the GitHub link on your comment is broken (it has an extra parenthesis at the end). Cheers!
@@EnricLlagostera thanks a lot
I think this is what you call a rare timeless coding tutorial, because no matter what language or engine you're using, the base logic still applies. Well done.
Thank you! I definitely try to explain these things in an engine agnostic way. I'm glad you found so. Cheers
Thank you Sir for your contribution to Game AI in Godot :)
Nice intro, and thanks for making the code publicly available!
1:37 What about choosing a plan with more points? For example, it costs more points, but the NPC will get "pleasure" from it and will take on a more difficult plan because of it.
I think it's worth changing the concept of "cost" to "profit", then it will be possible to make different ideas about profit for different NPCs, for example, when all vital needs are satisfied - depending on the resource behavior, the NPC will choose plan to idle or explore/etc.
Hey, good thought exercise. The trade off doesn't seem worth it to me though. I think one good thing of thinking as "cost" is that 0 will always be the least effort / most desirable action. If we invert the scores, when adding a new most desirable action we will need to know what is the current highest score and there is no guarantee that action will remain being the most desirable one. It should still work, but I think it would require more maintenance. However, that doesn't invalidate your idea of making the plans cheaper using other variables (i.e. pleasure). This can be achieved with dynamic costs without needing to invert the scores.
Also for your example of choosing the idle/explore plan, that is usually defined by the plan priority and not for the plan cost. What I mean is that if the vitals are satisfied, idle or explore will become the highest priority goal, so only plans to achieve idle/explore will be considered. Thanks
Analog Studios has some amazing CC-0 artwork. Thanks for shouting them out in your video!
Nice. This actually helped me better sort out my game mechanics. Thanks
Thanks for sharing. I'm glad it was helpful. Cheers.
Hey Vini, just wanted to drop a huge YOU'RE AMAZING here. Great content, I hope you keep up with them -- thanks! :)
Thank you. It' s nice of you. This kind of videos usually take more time to make than my normal devlogs, that's why I don' t do them as often. But I intend to keep making them whenever I find an interesting subject. Suggestions are welcome :)
Wow, heavy stuff but very fascinating, thanks for sharing!
Thanks for making this. It looks to me like a hybrid approach is needed whereby a behavioir tree handles general logic and then GOAP can exist within a constrained state for more dynamic behavioir. This would ensure undesirable outcomes are isolated within a particular state.
Thank you! Yeah, that would be a nice approach to cover scripted and unscripted behaviour and play with both strengths
Very good video - thanks
Very interesting, actually never heard of goap before. Sadly doesn't fit well into my current project but will certainly test it out in the future if I do a project where this would fit well.
Thanks. Yeah, same with me. I think it works best for systemic games that can benefit from unpredictable complex behaviours.
Very cool! 👏
It reminded me of Fred George’s Need Pattern, used in event-driven systems.
Interesting. I haven't read about Need Pattern yet. I'll look it up.
Yeah! Thanks for this video. I tried to make my own goap thing in Godot but that was not successful. Thank you so much.
Thanks Greg. I hope this helps with your implementation. Cheers
wow this was a big help getting me started, thanks!
Thanks a lot for this man, you're awesome
Thank you. Nice of you to say that :D
Nice concise overview, thanks :)
Thanks. I'm happy you find so. :)
Thank you, great video 👍
Hello, Vini. Is there any chance you can change the renderer of the project to compatibility as my laptop can't handle the OpenGL3 Renderer. It's all good if not, I just wanted a better idea of how the project works as I'm struggling with implementation. Thanks!
Hello @fznbu. I might be missing something, but you can change the renderer in your editor. That will require a restart but things should work. Cheers
It seems that the biggest drawback for this method is the inability to predict the future. For instance, if the fire pit will burn out before the satyr can get wood to build another pit, that is a failure and the satyr should not spend any time chillaxing but should go to get firewood. Similarly, if the troll is near and there are two possible sanctuaries, the satyr should be able to determine which one would allow them to flee the troll better.
Again, not a critique on your specific method, just pointing out that evaluating the GOAP only based on the *now* lacks planning for the future.
That's a very good point. Indeed this video only covers a simplified reactive behaviour. Thanks for the comment and for the example.
How do you let the ai know to prioritise something lower priority when it's easier to get? Like here, the character was hungry the whole time, but didn't prioritise it until it got too much, when quickly just picking up a mushroom while going from A to B would have been super simple
I think this is just because of the priorities I defined for this project. In the example the hunger was being ignored because I deliberately made the "relax" goal priority way higher than the other ones so it's basically unstoppable. However, in a real game indeed we might want the hunger to at some point surpass the need to hide. That can be achieved by adjusting the dynamic priority for that goal.
One other idea (I didn't put much thought on that) would be maybe allowing goals with tied priorities to be calculated together. That might be too complex and likely have performance drawbacks, but might work. The idea is that if two goals (i.e. "Calm down", "keep fed") have the same priority, we calculate plans for both of them and pick the cheapest one. In your example, as the mushroom is so close, the agent could prioritize feeding over hiding.
Having said that, before implementing anything crazy I'd definitely try to tinker with the priorities. Cheers.
Great video, I’ve learnt a lot 👏
I've watched this through a couple of times and read through the code and i can't really understand how you'd make this work with multiple bots? So much of how ti operates seems bound to just working with one blackboard.
Hello @haxtrad. That's correct. The planner will always work with only one blackboard. When instantiating multiple agents, each one will have their own planner, working with their blackboard instance in isolation.
Very neat - thx
This was a great video.
Thanks. I'm glad you liked it.
Hey Vini! I was curious about the code base and tried importing it but I am getting a bunch of errors. Do you know I am getting those errors? (like: indentation errors, stack-overflow errors - after fixing the indentation etc)
Hello. Sorry the late response. That's weird. Maybe something broke with the new releases. I've definitely seen some stack overflow while developing it, because the implementation does not handle circular dependencies, but the code as-is shouldn't cause it. I'll take a look as soon I have time. Thanks for letting me know :)
Personally, I'd still use variables instead of methods because they get exposed in the inspector. There's also custom set/get methods one can define with the variable, too, so one wouldn't lose out on the custom logic.
anyway, cool vidoe :>
Nice! The set/get tip is a great suggestion. Thank you.
One of the things that seems to elude me is how you pick the initial goal to then send through GOAP. But maybe I’m misidentifying the utility of GOAP and in a simplistic situation of you have an enemy AI only has two goals, kill or flee then you can simplify the logic to pick the higher order goals? Idk
Oh yeah. If the behaviour is too simple I guess GOAP might be unnecessary complexity. Having said that if you have multiple ways to achieve the "kill" or "flee" goals it might still be useful.
For how to pick the goal, it's all about dynamic priorities. I guess your flee goal would have an increased priority if HP is low, while the kill goal priority could increase if the player is too close. For two goals only it's hard to justify, but if you throw another goal in the mix things start becoming more interesting due to unplanned emergent behaviour.
Very nice project. Could you perhaps port it to Godot 4? I just tried to let Godot 4 convert it but it was not functional afterwards. As I am new to Godot I do not know how to fix it. Thanks!
Hello there! Yeah, of course. I'll try to set some time aside next week to convert it. Thanks
@@ThisIsVini That would be great!!! :) Could you answer to this post, when you were able to convert the project? Thank you so much!
@@ThisIsVini Did you already have time to convert the project? I hope I do not bother you too much, but I would really be excited to experiment with a Godot 4 version. Thanks in advance!
@@blocklib1932 Hello there! I migrated it this afternoon. The main branch has the Godot 4 code now. github.com/viniciusgerevini/godot-goap . It seems to be running correctly, but let me know in case you find issues. Cheers.
@@ThisIsVini Thank you so much!! :)
Thanks for this, works great. One thing I'm missing though is making the actions perform for an amount of time, not instantly. For example, an NPC cooking food for 5 seconds. How would I go about making this? I tried just adding await but it broke everything.
In my example the `perform` method in the GoapAction returns true when finished and false when it is still going. Your actor.cook() method would be the one to control if the action is finished or not. You could also have a property actor.is_cooking used in the action which is set to true when cooking starts and set to false once the timer completes.
The caveat with doing only that is that this does not prevent your planner from replacing your current plan with something more important and stop it mid cooking. If that is a concern to you, you could have some kind of flag in your actor, like actor.is_busy which would stop the GoapAgent from calling the planner while the actor is busy.
I hope that's helpful. Cheers.
With this code, if you add another Satyr they share current goals because stuff like is_frightened is set in the World State. How do you suggest making each actor behave on it's own?
You could create member variables that hold all the necessary enemy states and keep them all in an Enemy class which would become the parent class of every Enemy type, and with every instance of an Enemy in that class, you'd get individually editable variables for each Enemy. Of course, every different type of Enemy would have to have a script that extends this Enemy class in order to get access to those variables.
Hello Andrew. That's a really good question. I didn't think about that when I was making this experiment. The first thing that comes to my mind is changing the goals and actions to no look into the raw world state, but into a projection of it. Basically, world state wouldn't include actor related info. The goal would access a local world state that would contain the global world state and be hydrated with all relevant info from the actor. This local world state would then be passed to the actions and goals. This would require some extra thought as it raises other questions like, how to keep both states in sync? Or, who decides which actor's info is relevant?
Thanks for the question. That makes me want to revisit the problem and come up with a better solution. Cheers.
@@ThisIsVini that's exactly what I want! thank you so much!!
@@ThisIsVini In the current plan, adding multiple Satyr will still share goals and actions. Is it possible to assign a different PLANER to each npc? I have reviewed the introduction related to Goap, and my understanding is that each different NPC will have its own PLAENER and a copy of WORLDSTATE? But my code level is terrible, I really can't do this🥲. Firstly, thank you very much for your work on AI in Godot. Would you like to continue updating this system? Can each NPC have different goals and actions? This is very important to me
Could we get a tutorial from scratch? Regardless, thanks for this. Nice vid
Thanks. What do you mean from scratch? Including the planning logic? I feel that one is better to check the code for it. I added a bunch of comments to make it easier to understand.
@@ThisIsVini Cool. I'll look at the code. Thanks.
@@ThisIsVini he probably means seeing it implemented. I often find it best to learn to see how someone is arriving at the decisions rather than it just being put out there with comments. You would not believe just how much you can learn seeing it done in real time rather than heres my code and this is what it does.
So if you didnt mind doing a tutorial series of implementing it with commentary i know i and many others would appreciate it.
otherwise fantastic video
@@charg1nmalaz0r51 that makes sense. Thanks for the suggestion. I'll consider it. Cheers
@@ThisIsVini you have any idea how to make these plans with data you dont know about. For example say i placed a building down that requires resources to build. I would want my plan to check a building is placed, what material from its requirements and for the next step of the plan to then know what this material is so it can check if its in the players inventory. In all the examples i have seen its assumed your only working with a small handful of pre existing data and if theres a procedural check its just to make sure a target isnt null. I tried something by adding in a function in the planner to perform a check which told each thing to add a precondition but i kept stumbling on the thing not knowing what thing wanted what item because its its own action.
I would love to give this a try, does anyone know of some good c# implementations of this, or some good step by step tutorials on this subject rather than a general overview. I learn better when i see the process take place rather than it being briefly explained.
I think it may be interesting, I created a GOAP sample inspired by this video, but in Unity. It is in the GOAP section in github.com/m039/CommonUnitySamples You can try it in a browser. I used the same goals (bonfire, hunger / mushrooms, fear / troll), but I've added procedurally generation and the house where a bot can store food or wood (and take from it too). You also can click on the bot and see all his properties.
Thanks for sharing. I don't use unity myself, but it's great to see other implementations. Cheers.