Home > Game Maker, GMC/YYG, SoulHow > SoulHow to make an Arc Of Sight

SoulHow to make an Arc Of Sight

August 20, 2009

NOTE: Comments are locked. I no longer answer questions about the Game Maker tutorials on this blog; I suggest you take any questions to the Game Maker Community. For more info, view the FAQ page.

I decided to write up a more detailed SoulHow article on my old Arc of Sight tutorial. I’ve been getting some PMs on the Game Maker Community lately asking questions about it, so I thought I’d describe it a bit better here in my blog.

Tutorial Partner file: Link

Note: This example was created for GM7, and it works in either Pro or Lite. However, if you have the Lite version, go to the constants section of the game settings in the example and set “drawrotated” to 0. That will turn off the use of draw_sprite_ext. The sprites won’t rotate as the objects move in different directions, but that’s okay because sprite rotation doesn’t have to do with what’s actually being described in the tutorial. As long as you keep the drawarc constant set to 1, you’ll still be able to easily observe the intended effect inside this example; though you can set that constant to 0 to have a more “realistic” view. Best keep it to 1, though, while you’re still learning what’s going on in each part of the code.

So in case you haven’t even seen this on the GMC, it’s a tutorial in which you will learn how to make an object test for another object inside an “arc of sight”. The first thing that probably comes to your mind is the similarity to “line of sight”. A line of sight is a line usually drawn from one object to another object to make sure nothing is in the way. For example, an enemy must shoot towards the player, but only if a wall is not between them.

There’s collision_line() for that, and collision_* for other types of shapes (rectangle, circle, etc.). But we want to use more of a circle sector shape. Essentially, an arc of sight.

This is very useful for effects such as a guard carrying around a flashlight; if the light shines on you, you’re seen and the guard chases after you. But since there’s no collision_arc() function, you can’t get that effect without being a little creative.

I have included a partner gmk file (linked above), so you can see the effect visually. In this file you play as a little blue guy walking around trying to find the diamonds. Also in the area are red guys sauntering around, guarding these diamonds. If they see you, they chase after you and if they catch you, you die. Run out of their sight and they continue pacing around again. Apparently they’re not very intelligent, but at least they know enough to chase you when they can see you.

First I’d like you to download and run this file to see the final effect.

Note: this tutorial assumes you have at least a basic knowledge of geometry. More specifically, you must know what a circle’s radius is.

Anyhoo, the partner file includes most of the direct info for a practical example, but here I will describe the concept behind this arc of sight. The basic theory is that we need a different shape than can be provided by Game Maker’s functions. This is the circle sector.

The orange portion is the shape I’m referring to:

How do we achieve that? Quite simply, we fake it.

What do you notice about this circle, and circles in general? The length of any line starting from their center (marked with a black dot in the picture) and ending on the circle’s rim is equal to the circle’s radius. Therefore, no matter where the object is inside the circle sector, the distance from the object to the center point must always be smaller than the radius of the full circle. Imagine the small red circle is the object, and the lines marked with “r“s are the circle’s radii (plural of radius):


Then there’s the issue of being inside the circle, but not being outside the desired orange region. We only want to “see” the object when it’s inside the orange region; after all, we can’t see behind us, or a certain angle to our sides. If the distance from the object to the center point is smaller than the radius, then the object is inside the “circle” somewhere, but not necessarily in the region we want. It could be like this:

As you can see, the object is still inside the full circle (the distance from the object to the centerpoint is smaller than the circle’s radius), but the object is not inside the orange region.

So we have to make sure the direction does not stray too far from the direction that would point straight through the center of the circle segment. Shown by the white line here:

There is an equal amount of space on each side of the white line, so the angles formed at the center point on either side of the white line are also equal. Thus we need to define an angle offset. The greater this value, the more of the circle is included in the sector.

So now we have the basic theory. For the object to be inside the circle at all, the distance from the object to the circle’s centerpoint must be less than the circle’s radius. For the object to then be also inside the circle sector, we must make sure the angle from the center point to the object does not differ from the center angle (white line) by more than the offset value. Note that the circle sector does not have to be in the top part of the circle. The “center angle” could point to the right and the same idea still comes into play:

I encourage you now to examine the .gmk file which explains how all this is done in GML coding. Basically we use point_distance() and point_direction() to “make” the arc of sight as described above.

There is quite a lot of other code besides this one script in the example. Most of it is for general game mechanics, such as collecting diamonds and dying. But one section of the code people seem to be having a little trouble understanding is the sections that govern the guard-like roaming AI motion.

It’s actually rather simple once you know the basic strategy behind it, but I’ll describe how it works (be sure to be following along with the code, reading the comments, etc. so it’s easier to keep your place):

First of all, the bad guy has to have a sort of “random” motion so he looks like he really is roaming. To do this, we use a random variable and test its value to have a certain chance to either start/stop moving, or turn clockwise/counterclockwise/in no direction. Note, the bad guy object is not actually moved or turned in this section.

Next, the bad guy has to check whether it can see the good guy using the script we described in the greater part of the tutorial. If he can see the good guy, it triggers a “run” variable which is used later to decide at what speed the bad guy should move, and it also overrides the “move” variable so that it’s always set to 1/true, and in that way when the bad guy sees the good guy he won’t just randomly stop moving.

After that, we check whether we have seen the player, and if so, we have to run towards him. In order for the bad guy to run towards the good guy, we have to tell the bad guy to turn towards the good guy, and that’s what we do at this point. Again, we don’t actually turn in this section; we are only overriding the random turning we did in the earlier section when the bad guy is giving chase.

After we have determined which way to turn (which is actually a little more complicated than it sounds because we have to be able to go past the 360->0 boundary in angles), we actually get to turn. That is, we increment our bad guy’s direction by our turn direction (either 1 or -1) multiplied by our turn speed (thus turning by either turnspeed or -turnspeed).

After all that, we get to actually move. First we check whether we should move (due to random roaming; the variable used to check is always set to 1/true when chasing the good guy). If not, we stop animation and exit the script. If so, however, we set the animation speed so we see the bad guy walking, and continue on.

Now for the final section. First we have to make sure the bad guy doesn’t “roam” off the screen. Therefore, before moving at all, we have to check if the bad guy will be going outside the boundary if he were to move. If that check returns true, we don’t move but instead only turn until we are facing away from a boundary; otherwise we check whether we should run (due to chasing) or just walk (for simple roaming).

And there you have it. Hopefully this clears up any confusion based around the roaming system in the example.

Anyways, I think I did a good job of over-commenting, so you should be able to find your way around the example and discover the answer to any question you might have. Here’s a list of some of the goodies that are in the gmk:

-A single script for testing an arc of sight which can be used in any game, including non-topdown games
-Another script which draws a circle sector on the screen
-Topdown guard-like A.I.

Enjoy the tutorial. If you use it, some credit would be cool. Thanks.

If you enjoyed this article, please consider checking out the rest of the blog.

If you have a technical question, such as “How do I do this” or “this is not working right” (relative to something with your Game Maker game after reading this tutorial, such as posting an error message), please head over to the Game Maker Community and ask there. I can’t answer any such questions in this blog and the members at the GMC will be more than capable to help you. For more info, go to the FAQ page on this blog.

To discuss this article in particular, you can view it on the Game Maker Community.

Categories: Game Maker, GMC/YYG, SoulHow
  1. No comments yet.
  1. August 20, 2009 at 1:20 pm
Comments are closed.
%d bloggers like this: