Yesterday evening I found and fixed the bug that was haunting me for a couple of days and it was one of those bugs I'll probably see return every now and then, because that's the kind of programmer I am. I overused a method that did more than I intended.
You see, units are supposed to be able to go places and for that, they have a navmesh agent that moves once a destination is set and the destination is not their current position. So far so good. Can't have that fail (well, we can, but I won't bother you with that right now).
The other main part of the unit script is a finite state machine AI system. In short, units have a state and a task. The state says what the unit is doing and the task what its objective is. So when we want to cut a tree over there, clicking the tree will cause the unit to have Cut as task, the tree as target and Moving as state. The moving state will find out if the unit is near enough to the target to change the state to Fighting. Etc.
Now the problem with the bug was that the task was no longer to Cut. The unit went to the tree and that was it. It turned to the Idle state with Nothing on its mind. Actually, that was easy, because I made the mistake of messing with the Moving state. It had a simple statement to set the destination and I, thinking that it would be smart, replaced that by a GoThere method.
And that method set the destination, so the guy did go to the tree. That was good. It also set the state to Moving, which is fine. But is ALSO set the task to Move. That was the problem.
The unit made its way to the tree and stopped near it. That was good. Then the Moving state wondered what to do next, so it asked the script. The script said. If you're moving and the task is to move, then once you reach your destination, you're done and you can run SetIdle(), whatever that may mean. No cutting the tree.
Now, dear rubber duck, this is a clash of principles. We have the DRY-principle (Don't Repeat Yourself) that will stop you from writing the same code multiple times. I try to live by this principle as much as possible.
Then there is this programming thing to keep things small. I wrongly assumed that the GoThere method would just set the destination even though I just added the messing up code for another aim. I wanted to make things consistent, but did not think about it enough. Because some things should be different from other things.
Lesson learned, but by no means expecting not to make the mistake again. I do think it should now be easier to detect.
No comments:
Post a Comment