-
-
Notifications
You must be signed in to change notification settings - Fork 47
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
Sorry if this seems basic but I'm struggling #141
Comments
I'm not quite sure about your requirements yet. Before I can recommend any approach I would need to know exactly what it is we want to model. And for that let's maybe take a step back from the state machines and really just draw out what we want to happen. Here's what I gathered so far:
From this, I can come up with this high level state diagram: Now this alone wont help solve the problem just yet, because we still need to answer a few questions:
If we answer these questions we can use the information we gather from that to refine our state diagram. And then we can repeat this process until we have no more open questions and have a diagram which tells us exactly how our unit should behave. And only then we start implementation. I found this way to be a lot less frustrating because it makes me think about my problem and understand it really good before getting down into the nitty-gritty of the implementation. So maybe you can help fill in the blanks on these questions and then we can find a nice solution for the problem. |
Thank you, I really appreciate the help and I hope it's not too bothersome for you to entertain what is essentially just a newbie developer asking game design questions. With that in mind I don't want to take up a lot of your time so I will keep it to a few questions that should hopefully get me on a foundation I can build out from on my own. Okay so, during Idle, it should do one of several things:
The first couple of questions arise here: Is state_entered a bad choice for this? Should I be thinking about using _processing instead? Because one of the major issues I keep running into is how do I get it to wander idly sometimes if it's in Idle and Idle never gets retriggered? (That's when I started trying to use a To Idle transition with a delay, and that caused more problems) Then we have Seeking Food:
The other issue is, I'm hoping to avoid needlessly bloating the state chart with many many copies of "walking" or "going somewhere" nodes, so I thought to separate this out into its own "Travelling" state. But that means that when its mood changes to "Seeking Food" for instance, it then has to immediately switch into "Travelling", but if this "Travelling" is generic and is going to have a multitude of "To [mood]" transitions all listening to a single event "navigation_finished", the transitions always seem to ignore their state guards (like when I check for "mood" to be "hunger" or "fine") and always picks the first transition (i.e. back To Idle) and the logic tends to break. So is having a generic Travelling state not the way to go? If not, that prompts me to ask: If this creature ends up with 5+ different moods, any number of which may need to travel to a target first, am I going to need them all to have their own travel nodes? The more I thought about this, the more I felt moods should not be states, and instead my states should be limited to actual "I'm doing something" concepts, agnostic of whatever mood it's in. For example, "I'm fine and not doing anything" vs. "I'm hungry and not doing anything" should both just be "Idle". Similarly, "I'm fine and wandering somewhere" vs. "I'm hungry and seeking food" should both be "Travelling", and the statechart doesn't care what the target object or position is. That seemed like a good idea at first, but then I started to realise I'm inching back towards "everything handled in code" territory, and the statechart becomes less and less useful. I stop setting expression properties and just trigger states based on mood, and that's all handled in code, and the chart ends up doing nothing for me. I want to move in the opposite direction, exactly what this addon was developed for, to handle the logic of switching to appropriate states so I don't have to be telling it explicitly every time. That's where I'm at right now. Again, I'm sorry to bother you with this, and I have no expectations or demands to be helped, but I am truly appreciative that you responded kindly and offered to help. If there is a better place to ask about all this, I'll happily go there and you can close this thread. Thank you again! |
Well no need to be sorry for anything these are all interesting questions to raise. So after reading through it, this is a first draft of what might work in your case: As you rightly point out we would get a bit of a state explosion if every "mood" had its copy of the travel tree. But since we have state charts here, we can factor this out into a parallel state which does its own thing. So traveling now is a subsystem that can be incorporated into other systems. We do this by using events to signal our needs. So whenever a subsystem needs to travel somewhere, it will acquire the travel target (which is depending on the use case, e.g. the Foraging system would acquire the next food item as target ,while the Idle system would just pick a random point nearby) and send the With this set up, we can create the rest of the behaviour. We have an Idle state. When this is entered it will randomly pick one of three actions (we can use two transitions with an expression guard
Now for the foraging. We said there should be some hunger system that triggers foraging behaviour. I have modeled this as another parallel "state" below. On Now whenever we're in some idle state and the hungry signal is sent, we change to the Foraging state. There the objective is to get some food, so we enter Acquire target state. This works very similarly to the wandering around we had in idle, the only difference is that this time the code on If a location is found the code sets it as current target and then sends the And now this can be extended with all kinds of other behaviours. The division of work between code and state chart is that our code controls what happens while our state chart controls when it happens. So all our code does is to pick targets, play animations, increase hunger, move towards a given target and signals important events like I hope this is somewhat helpful. Please feel free to ask additional questions, it's always very interesting and useful for me to get a peek into how other people approach their projects. This helps a lot in designing the library and writing useful documentation. |
This is incredibly helpful, thank you so much for taking the time. I'll read through this a few times and experiment with it, and will let you know how I get on with it. I think I should be able to learn enough from this to expand it further without additional help, but if I run into any specific issues, I'll ask about them. You are awesome :) |
What do I do about transitions being triggered multiple times in the same frame? I send the "target_acquired" event to set the Travelling parallel state going, and while this works, my wander() function is being called two, three, sometimes ten times in a single frame before the statechart decides to take the event seriously and actually do the thing. Edit: I think I fixed it. I removed all the transitions from the main Idle state, and I also had to set a 0.1 delay on the transitions within each sub-state. So my Idle tree now looks like this:
Another lesson I believe I've picked up correctly is that the order of transitions is very important, moreso than any of the documentation I've read would suggest. I had to make sure To Interact was at the top, otherwise it was always ignored in favour of one of the other transitions. |
The idea is to have a handler that is called on |
That's what I had, but I had a print in the handler to tell me when a target was being acquired and it was triggering multiple times per frame before it would decide to actually start moving to the target. |
Let me build this up here locally, maybe there is a bug... |
Ok I definitely just found a problem here: #143 As a workaround, you can delay sending the event by one frame, e.g. |
That's good to know. I'm actually quite glad this is a bug and not just me being a dummy, lol! It looked like it should have worked and yet wasn't, I couldn't figure out what I was missing. |
I can't seem to reproduce that. Could you maybe open another issue for this and give me some details on the setup that is triggering this behaviour? Thanks a lot! |
Apologies, I deleted that comment as I was mistaken. There's no problem. |
The last entry in your transitions list (Idle01 Variant) is probably not going to work the way you intend it to work. I assume you want to pick a random idle animation, so you have added an automatic transition that randomly transitions to the idle variant. However automatic transitions are only triggered when the state that contains them is entered or an expression property is set. Since your Animations state is below a parallel state it will always be active so this transition will never be run again on state enter because you will not enter the Animations state again. You can model this with another compound state that wraps your idle variants: And the you transition to your Idle compound state which in turn will pick a random variant of Idle00 or Idle01. Also the automatic transition at the end will always evaluate when you set an expression property which probably is the reason why your animations seem to be broken. Whenever you set an expression property there is a 50% chance that your whole animation subtree transitions to the Idle01 state. If you do this every frame then this effectively breaks the whole animation subtree. With the new structure it will only break the idle subtree. To fix this problem I'd recommend making picking the idle animation an explicit event that is sent when the idle state is entered, e.g. like this: So this way when you enter idle state the |
Hey again. I'm going to close this issue, as I don't think I'm going to be continuing to use the addon for the time being. After spending several days with it, I do feel as though I fairly understand how to use it. But I have several usability issues with it that I feel make creating behaviours more convoluted and bothersome than they should be. If you check the Youtube video, I have a comment there (user MoogieSRO) that I've edited to give my feedback thoughts, which you may or may not find useful. I don't think there's necessarily anything wrong with the addon, but it's not fitting my needs, and I think I need to find a different solution to work with. But maybe some of the notes I made could be useful for improving the addon. I may come back to the addon at some point, if exploring other options doesn't yield anything better, but for now I wish you luck with continuing the development of the addon. Thanks again for all the time you took to handhold me and explaining the concepts. This time was not wasted on me, as it's helped me expand my knowledge on the subject of state-based mechanics in general, which is going to help me no matter what solution I settle with. I found everything you explained in this thread enlightening and helpful. |
Sure, if it isn't a good fit for your use case there is really no point in using it. Thanks for sharing your insights! |
Here's a pared down example of what I'm trying to do.
I have two states: "Passing Time" and "Seeking Food". Over time, a varaible "hunger":int increases. When "hunger" is over a certain threshold, I set_expression_property("mood", "hungry") to let the statechart know that we're not "mood == "fine" anymore.
Now I want to stop "Passing TIme" and do "Seeking Food" instead. What is the best, simplest method state tree to accomplish this?
Because I feel like I've tried everything to make this work and I can't, even after watching the tutorial video multiple times and reading the documentation and looking at the examples (which I only half-understand, it's all too abstract for me). Trust me, it's not through lack of effort. I've spent the past two days solid working on this simple thing.
Specifics:
Ok so, I've tried To Idle without the expression, I've tried it without the event, I've tried every combination of with/without. It either breaks the statechart in an infinite loop, or it gets stuck in Idle and never allows a different transition to happen, or it just plays Idle once and then never transitions to anything, even To Idle.
Why do I have To Idle? Because without it, Idle is never re-triggered and mood is never evaluated and no other transitions have a chance of happening.
So clearly, I'm doing it wrong, but this is the 4th re-do of this very basic foundation I'm trying to set up before doing anything more complex, and I'm honestly just getting frustrated with it. The more I mess with it, the more code I end up writing, and needing the statechart less and less because it's not doing anything for me. I want to move in the opposite direction, but I need better examples or something because it's just not sinking in and the provided examples are too complex. I thought the ants one would be good to model off of, but they don't have an "Idle" state and my hacky attempts to modify it to include "Idle" obviously aren't working.
I read somehwhere that setting an expression property is supposed to immediately re-evaluate them, but that doesn't seem to happen. Nothing happens when I set the expression property, and if I fire a generic "mood_decided" event to all the transitions, they don't seem to listen to their expression guards and just always pick To Idle no matter what mood is. And yes, I'm using the debugger and "mood" is definitely switching to "hungry" when it should, so that's not the problem.
Sorry, I don't know how to tag this as not a bug, just a question.
The text was updated successfully, but these errors were encountered: