Lingo Collision Detection, Part 1
April 26, 2000
by Gary Rosenzweig
In order to build many types of games and some other types of interactive movies, you need to use collision detection. Collision detection is simply when you detect that one object on the screen overlaps another. They collide. This could be a laser blast hitting a target, or a character hitting a wall. In both cases, the two objects will overlap and action must be taken.
Director has several Lingo functions that are meant to be used for collision detection. Unfortunately, these functions fall far short of what is needed for quality collision detection. This week, we will look at what Director 8 has got and why it is inadequate.
The easiest function to use is the intersects function. By using an unconventional syntax, you can simply ask if two sprites intersect on the Stage.
if sprite 8 intersects 12 then
One thing to note about the intersects function is that it will work with irregularly-shaped objects. However, the ink of such sprites should be set to matte. Only then will you be able to rule out false collisions that happen when the rectangles of the sprites intersect, but the shape of the sprites do not. This movie demonstrates using intersects with the matte ink.
Move the red ball around by clicking and dragging it.
Director 8 download for Mac or Windows.
This method has one major flaw. You cannot use it until the sprites have repositioned themselves on the screen. This means that you must either use updateStage, or let the frame loop, before you can accurately use intersects to determine if there has been a collision.
For some things, like a laser blast hitting a spaceship, this is fine. You can deal with the fact that for a fraction of a second, the laser blast appears over or under the ship, then in the next fraction of a second, the explosion occurs. However, for other things, like a character hitting a wall, this is unacceptable. You should not be showing the character embedded in the wall, even for just a fraction of a second.
Another method for detecting collisions is to use the intersect function. This is intersect, with no "s", which is a totally different function than intersects. It also behaves like a normal function, taking two rects as parameters and returning a rect. Here is an example from the Message window:
r1 = rect(50,50,100,100) r2 = rect(80,80,120,120) put intersect(r1,r2) -- rect(80, 80, 100, 100)
The returned value is the rectangle shared by both of the other rectangles. If the two rectangles do not intersect, then it returns rect(0,0,0,0). You can use this for collision detection by testing the intersect of two rectangles to see if it is rect(0,0,0,0). If it is not, then they have collided.
if intersect(sprite(1).rect,sprite(2).rect) <> rect(0,0,0,0) then
This method suffers from two flaws. The first is that you can only test to see if the sprite's rectangles have intersected. You cannot use this with irregular shapes the way you can with intersects and the matte ink. The second flaw is the same flaw as intersects: you cannot determine if a collision has occurred until the stage has been updated. However, intersect offers a way around this that we will look at next week.
One function like the intersect function is the inside function. It will check to see if a single point is inside a rectangle. Here is an example:
if inside(sprite(1).loc,sprite(2).rect) then
This is useful when the moving object, such as a laser blast, is very small. In this case, you don't need to be that precise as to whether the whole shape of the moving object has intruded on the other object.
The inside function suffers from the same two flaws that the intersect function suffers from: no shape precision and no pre-screen update use.
There are also some other ways to determine whether two objects collide. These don't use a specific Lingo function, but will use some mathematical Lingo instead. One of my favorites is the distance formula. You can use this to determine how close points are from each other. Here is an example. "p1" and "p2" are two point variables:
dist = sqrt(power(p1.locH-p2.locH,2)+power(p1.locV-p2.locV,2))
if dist < 10 then
What's all this? If you are not into mathematics, then you probably don't know. The first line of this function takes the difference between the horizontal and vertical locations of the points, squares them, adds the two, and then takes the square root of the whole thing. It is the distance formula used in high school math class. The end result is the actual distance, in pixels between point "p1" and point "p2".
You can use this to determine when circular objects collide. If a ball is 5 pixels in diameter, and another ball is also 5 pixels in diameter, then they have collided if the distance between the center of both balls is less than 10 pixels.
You can also use it to estimate collisions among objects that are nearly circular. For instance, if you have a spaceship shaped like a triangle, and it is about 12 pixels long, then you may want to look for objects that come closer than 5 or 6 pixels.
You can use this same mathematical approach for a variety of forms of collision detection. For instance, if you have an object that is short and wide, you can detect if the other object is within a certain number of pixels to the left or right of the object, and a certain amount of pixels above or below it. This piece of code checks to see if one point is within ten pixels horizontally and 4 pixels vertically of the other object.
if abs(p1.locH-p2.locV) < 10 and abs(p1.locV-p2.locV) < 4 then
The abs function (absolute value) simply takes a number and returns it as a positive number, regardless of its sign beforehand. So abs(-7) is 7, and abs(7) is also 7. By using abs, we avoid having to make sure that the point is both less than 10 pixels to the right and less than ten pixels to the left. Instead, we can just figure out if it is within 10 pixels.
If you are good at math, you can use even more complex formulae to look for collisions in objects of other shapes. I occasionally use the ellipse formula, for instance.
One last Lingo function, that I would be remiss if I did not mention, is the hitTest function. This works with vector shape and Flash members only. When given a point, it will return either #background or #normal, depending on what is present at that location. Its use is limited because of the huge speed hit that vector shapes and Flash movies deliver to a movie, and because you can only use it with a single point. There is no easy way to use hitTest to determine if any part of one object intersects another.
Next week, I will take a second look at the intersect function and show you how to use it without updating the Stage first.
Gary Rosenzweig's latest book is "Advanced Lingo for Games." In it, you can find the source code for more than 20 complete games. More information about the book can be found at http://clevermedia.com/resources/bookstore/book4.html. It can be purchased there, or in your local bookstore.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.