# Swarming the mouse

June 22, 1998
by Pat McClellan

Dear Multimedia Handyman,

I've seen a lot of demos that when you move the cursor, a sprite follows in a delayed smooth movement and then moves accordingly by its own. The best sample is the Director 6's "About Director " in the Apple menu when the Director Application is open, how can I do this?

Daniel

Daniel,

Director 6's "About Director" movie is a work of art. Be sure to let it play long enough to hear the song. Blockbuster Video has stolen this singing smiley face for a recent series of ads... but they just don't do it as well as About Director.

Regarding the movement of the other sprites in this movie... I don't know that I can duplicate the behavior. There are many things interacting to generate the motion and I don't know how these things were prioritized. But, we can take a shot at it and then you can tweak the code until you're happy with it.

Getting a sprite to follow the cursor is easy. Simply set the locH and locV to the mouseH and mouseV. The tricky part is getting the motion to be fluid and delayed. To accomplish this, we'll need to set the location to be a point between where the sprite currently is and the cursor's location.

This behavior will make several sprites on the stage "swarm" toward the cursor at varying speeds. The math involved is easy. First we'll calculate the difference in the current loc and the cursor. Then we'll divide that by a property I call pSpeed. I've set this randomly in the beginSprite handler, though you might want to make this a property to be set in the getPropertyDescriptionList handler.

```
-- Swarm Behavior (simple)
property pSpeed, pMySprite
on beginSprite me
set pMySprite = the spriteNum of me
set pSpeed = random(10) + 5
end
on exitFrame me
set deltaLoc = (point(the mouseH, the mouseV)¬
- the loc of sprite pMySprite)/pSpeed
set newLoc = the loc of sprite pMySprite + deltaLoc
set the loc of sprite pMySprite to newLoc
end

```

Now let's expand on this. In addition to responding to the location of the mouse, the motion of the sprites need to be restricted to the stage. We can do this with a simple if statement about the newLoc. If the newLoc is within the stage's rect, then we'll move the sprite to the newLoc. Otherwise, it just stops. We'll set a property called pStageRect in our beginSprite handler. This value is the rect of the stage, less 1/2 the width and 1/2 the height of the sprite. This adjustment is necessary because the loc of sprite refers to the registration point (regPoint) which I have set to the center of these sprites.

```
-- Swarm Behavior with stage limit
property pSpeed, pMySprite, pStageRect
on beginSprite me
set pMySprite = the spriteNum of me
set pSpeed = random(30) + 10
set hMargin = the width of sprite pMySprite/2
set vMargin = the height of sprite pMySprite/2
set pStageRect = rect(0 + hMargin, 0 + vMargin, ¬
the stageRight - the stageLeft - hMargin, the ¬
stageBottom - the stageTop - vMargin)
end
on exitFrame me
set mouseLoc = point(the mouseH, the mouseV)
set deltaLoc = (mouseLoc - the loc of sprite  ¬
pMySprite)/pSpeed
set newLoc = the loc of sprite pMySprite + deltaLoc
if inside (newLoc, pStageRect) then
set the loc of sprite pMySprite to newLoc
end if
end

```
Finally, the difficult part is making the sprites pay attention to each other. Let's say we want the sprites to avoid each other. They don't have to repel each other, just no overlaps. This behavior reminds me of Soccer for six-year-olds. They all just swarm around the ball, bouncing off each other.

For this, we'll need to create a global list of all the sprites which are "in the swarm". Start with an on startMovie script that initializes the variable.

```
on startMovie
global gSpriteList
set gSpriteList = []
end

```
In the beginSprite handler of the behavior, add the last line which adds the pMySprite value to the gRectList. Now, after checking to make sure that the new location will be on the stage, we'll also check to see if the new location will intersect any of the other sprites. If so, then we don't move the sprite.

The checkIntersect handler is where we look through the gSpriteList, checking the intersect value of the new rect of our sprite with the rect of the other sprites. As soon as any intersection is found (greater than our "slop" amount), then we jump out of that handler and return a value of 1 for overlap. The sprite is moved only if overlap = 0.

```
-- Swarm Behavior with stage limit and avoidance
property pSpeed, pMySprite, pStageRect
global gSpriteList
on beginSprite me
set pMySprite = the spriteNum of me
set pSpeed = random(30) + 10
set hMargin = the width of sprite pMySprite/2
set vMargin = the height of sprite pMySprite/2
set pStageRect = rect(0 + hMargin,  + vMargin, ¬
the stageRight - the stageLeft - hMargin, the ¬
stageBottom - the stageTop - vMargin)
end
on exitFrame me
set mouseLoc = point(the mouseH, the mouseV)
set deltaLoc = (mouseLoc - the loc of sprite ¬
pMySprite)/pSpeed
set newLoc = the loc of sprite pMySprite + deltaLoc
set newRect = offset(the rect of sprite pMySprite, ¬
the locH of deltaLoc, the locV of deltaLoc)
if inside (newLoc, pStageRect) then
-- test overlap
set overlap = checkIntersect (me, newRect)
if NOT overlap then
set the loc of sprite pMySprite to newLoc
end if
end if
end
on checkIntersect me, newRect
set spritesToCheck = count(gSpriteList)
repeat with i = 1 to spritesToCheck
set whichSprite = getAt(gSpriteList, i)
if whichSprite = pMySprite then
next repeat
else
set checkRect = the rect of sprite whichSprite
set slopRect = rect(0,0,20,20)
if intersect(newRect, checkRect) > slopRect then
return 1
end if
end if
end repeat
return 0
end

```
This is just a start. There are infinite ways you can manipulate the sprites... setting up priorities of motion, dependencies, gravity, etc. Each sprite can also have its own sub-pattern of motion; spinning on a small radius around it's own center of gravity for example. For some great examples of this type of interaction and interdependence, be sure to take some time examining Mark Peden's Amoebic Lifeforms [http://www.mousedown.demon.co.uk/amoebic.lifeforms/start.htm]. (You can also read an interview with Mark in the Developer Profile archives in the Features section.)

Have fun experimenting with the behaviors and good luck with your program.

Patrick McClellan is Director Online's co-founder. Pat is Vice President, Managing Director for Jack Morton Worldwide, a global experiential marketing company. He is responsible for the San Francisco office, which helps major technology clients to develop marketing communications programs to reach enterprise and consumer audiences.