Last weekend we managed to get a decent amount of basic mechanics into Project ZATO. The basic things like movement and collision were done with no issues. The trickier work came when it was time to start implementing sight and hearing for the enemy AI.
I started with the sight. This basically consisted of creating a cone of view for the enemy with an allocated viewing distance. To do that the first thing was to define the viewable distance. This was as simple as defining a maximum distance in pixels that the enemy could see up till. Then each frame we check the distance from the point of the enemy to the player. If that distances is less than the viewable distance defined then the enemy can see the player. This is then further refined to a cone based in the direction of sight. This is basically done by taking the direction the enemy is facing and then defining a lower and upper angle to create the cone e.g. 60 degrees counter clockwise or clockwise from the direction gives a view cone of 120 degrees. We then check to see if the player that was detected in the viewing distance also falls between these two angles and if so then the enemy can see them. There is some manipulation needed for certain angles e.g when the enemy is facing straight on at 0 degrees this gives us an upper angle of 60 and a lower angle of 300. As you can see this won’t work with a standard less than or lower than check. Ideally we would say upper angle of 60 and lower angle of -60 but GameMaker angles don’t work that way so we need to do some wrap around checks. I won’t go into the details as there’s a lot of material available to help solve that problem.
With the sight sorted the next thing to add was the hearing. Hearing is similar to sound except it doesn’t require a cone of view as we can hear all around us. So it should have been a lot easier. So basically what we do or sound is we have a noise level which corresponds to how far the sound travels in pixels and when a sound is generated we check the distance from the enemy to the sound and check to see if the enemy is within the noise range. If yes then the enemy heard the sound. Unlike the player, where there is just one instance of the object oPlayer, there can be many sounds. We achieve this by creating an object (oSoundSource) and generate that for each sound made with a corresponding loudness or noise level. Each enemy then checks every frame for all the existing sound objects and check to see if is close enough to hear it, that simple. But for some reason it wasn’t working? I would generate sounds and some enemies seemed to respond no matter how far it was whilst other wouldn’t even if it was right next to them? This had me scratching my head for days as I couldn’t quite figure out where it was going wrong. I went over the code numerous times and couldn’t immediately see anything wrong. I then started to question how GameMaker checked for and referenced instances of objects. It must have been something major as I was sure the code was as I intended and it shouldn’t really be that different from the sight behaviour.
So anyway I left it for a couple of days and focused on Gym Empire. After resetting my mind I took a look again yesterday and then I noticed a pattern. If I made above (north) of the enemy they would hear it no matter how far away, if I made a sound below (south) of the enemy they wouldn’t hear it no matter how close I was. And then suddenly it became clear! The enemy wasn’t checking the distance of the sound it was checking the angle (direction) relative to itself. Instead of checking if it was less than 200 pixels away it was checking if it was less 200 degrees in relative angle! I so I fired up the code and yes… of course… how did I miss the most obvious thing after reading over the code multiple times! I was using the check_direction function not the check_distance function! The rookiest of mistakes! But it was such a relief to figure it out. I could now battle on and get the rest of the mechanics programmed in. Progress today has been blisteringly fast compared to the start of the week and it feels great.
My little stumble made me think of two things. How much I love those eureka moments, even when they are for the dumbest of mistakes and how useful it is to take yourself away from a problem for some time to reset your thinking.
