This is a continuation of Swarm, Lesson 2
In the last lesson we learned how to make the circle move. At the end I
posed a challenge: to make the ball bounce around a set rectangle. Here
is the code I used:
var dx = 0 // Directional controls every cycle the circle
var dy = 1 // moves 2 right and not at all vertically
// Note that these are global variables
function DoWork()
{
var RedCircle = SVGDocument.getElementById('RedCircle') // Get the RedCircle via the DOM
var Bounds = SVGDocument.getElementById('BoundingBox') // Get the RedCircle via the DOM
var X = RedCircle.getAttribute('cx') * 1
var Y = RedCircle.getAttribute('cy') * 1
var Rad = RedCircle.getAttribute('r') * 1
// Get Bounds
var MinX = Bounds.getAttribute('x') * 1
var MaxX = Bounds.getAttribute('width') * 1 + MinX
var MinY = Bounds.getAttribute('y') * 1
var MaxY = Bounds.getAttribute('height') * 1 + MinY
// Out of bounds testing
if ((X + Rad + dx > MaxX) && (dx > 0)) dx *= -1
if ((X - Rad + dx < MinX) && (dx < 0)) dx *= -1
if ((Y + Rad + dy > MaxY) && (dy > 0)) dy *= -1
if ((Y - Rad + dy < MinY) && (dy < 0)) dy *= -1
X += dx
Y += dy
RedCircle.setAttribute('cx', X);
RedCircle.setAttribute('cy', Y);
setTimeout('window.doSwarmWork()', 25);
}
I also added the following element to the svg group object before the circles
<rect x="5" y="5" width="200" height="150" id="BoundingBox" style="fill:white;stroke:black"/>
Modifying the x, y, width and height of this bounding box change how much space the ball has to
bounce in. There's a tiny bug which has to do with the ball hitting the edge. This can be fixed
by detecting the width of the rectangle if you care enough.
Animation 2
Alright, next we should do something interesting. Up until this point, everything we've done can
be accomplished by about two declarative animation tags. Hardly worth all that effort. Now
we will add mouse detection. First, I'm going to decrease the radius of my red circle, and move
rid of the green circle.
Now we are going to make the red circle head straight for a specific point. To do this we need
to remember our high school or college algebra. We want to use a few features of triangles,
namely that when scaled, a triangles sides stay in proportion to each other.
Our circle is at (x1, y1), the point we want to head for is (x2, y2). The distance is:
d = (((x1 - x2) ^ 2) + ((y1 - y2) ^ 2)) ^ (1/2)
Now, we don't want our circle to be able to move there in one jump. Instead, we'd prefer it be
able to move at about 2 units (delineated by "s"). So our proportion is as follows:
(dx / (x2 - x1)) = (s / d)
dx = ((s * x2) - (s * x1)) / d
So lets put this into code. The target x and y will be global variables (DestinationX, DestinationY).
Let's make the circle head for an arbitrary point. I chose (100, 75). We could easily calculate an
appropriate dx and dy ourselves, but let's make the machine do it. Add the following code to DoWork()
just after we get X and Y but before bounds checking:
Math.pow(Math.pow(DestinationX - X, 2) + Math.pow(DestinationY - Y, 2), .5)
dx = ((Speed * DestinationX) - (Speed * X)) / Distance
dy = ((Speed * DestinationY) - (Speed * Y)) / Distance
And add this to the global variables about DoWork():
Speed = 2
DestinationX = 100
DestinationY = 75
Animation 3
See the circle moves to that point and wiggles around. Don't worry about that wiggle. It won't be
noticable at all later. We'll actually be changing this routine later to better approximate insect
motion and swarm behavior.
Now you'll see the other reason for the bounding box. It acts as a trap for mouse events. Using
this we can get the x and y locations of the mouse. First add the following event handler to
the rectangle:
onmousemove="HandleMouseMove(evt)"
Now the cool part. We update the Destination X and Y via this routine. It's no sweat. We just
capture those mouse moves and update the variables accordingly.
function HandleMouseMove(MouseEvent)
{
DestinationX = MouseEvent.getClientX();
DestinationY = MouseEvent.getClientY();
}
Tah dah. Now you have a little red dot that follows you around the screen, as long as you stay in
that little box. At this point you want to make sure it runs as smoothly as possible. If it does
not run smoothly on your screen, try tweaking a couple parameters. The best to play with is the
second parameter of the setTimeout() routine. Also tweak the speed if you like. For right now I'd
suggest that Timeout * Speed is about 50. Later we'll pull this up to about 100 to get the speed
of bugs. We'll also be adding a few more bugs so you definitely want this smooth. These
settings should work down to about a P200, though later on you may not want to add as many bugs as
specified unless you don't mind your system crawling.
Next time we'll see how to expand this out for several dots and implement a few timesaving methods.
Swarm, Lesson 4