Random Motion

I am trying to make the movieClip named “fish” go to a randomly generated spot. I tried using the tutorial, but I didn’t understand the math, so I tried it with my own code. I’m not as much interested in getting this to work as I am knowing why it doesn’t work. So if someone could please explain why my code doesn’t work, I’d be very appreciative.


fish.onLoad = function() {
	generatePoint();
}
fish.onEnterFrame = function() {
	x = _x;
	y = _y;
	changeX = pointX-x;
	changeY = pointY-y;
	slope = changeY/changeX;
	goX = speed;
	goY = slope*speed;
	if(_x<pointX) {
		_x += goX;
	} else {
		_x -= goX;
	}
	if(_y<pointY) {
		_y += goY;
	} else {
		_y -= goY;
	}
	if(hitTest(pointX, pointY, true)) {
		generatePoint();
	}
}
function generatePoint() {
	pointX = random(Stage.width);
	pointY = random(Stage.height);
	speed = random(10)+1;
}

Thanks :thumb:

Attached is a movie that uses a modified version of the script you posted.

I’m assuming your script was a frame script, and not attached to a button.
I renamed your fish movie to fish_mc, and added a movie point_mc so that the target can be visualized.

There were two problems that made it not work:

a) The onLoad() handler was not being called. In my version, the fish was
already on the stage, so this handler didn’t get loaded. I changed the script to simply generate the first point directly.

b) In the onEnterFrame() handler, the variables associated with the fish were being referred to as _x and _y. In a script attached to a frame, you must consistently use this._x and this._y to refer to properties of the object executing the function. Otherwise, you are referring to _root._x and _root._y, which you don’t want.

once those issues were solved, there was one problem that made it work poorly:

c) The function that tracked the point moved at constant X speed, and varied the y speed to suit, rather than moving at a constant speed. If
the speed was too large, it could oscillate around the target point and never hit it.

changeX and changeY are the distance on each axis to the target point.
You can use Pythagoras’ law to determine the distance to the target point:

dist = Math.sqrt(changeXchangeX + changeYchangeY);

Once you know the distance you can use it to modulate your speed more
effectively. The ‘unit vector’ (a vector whose length is one) to the target is
given by:

uX = changeX/dist;
uY = changeY/dist;

And you can travel in the direction of the target at any speed by using:

x = x + uXspeed;
y = y + uY
speed;

I’ve modified your script to use this kind of arithmetic - it computes the
distance to the target, and then adjusts the speed by using a
unit vector calculation:

speedX = speedchangeX/dist
speedX = speed
changeY/dist

This way, you are moving the fish at a constant speed, regardless of
the angle of travel.

This also eliminates the need to have condiitions to check for positive or negative motion. Whenever I see this kind of thing:

if (x < y)
// move in positive direction
else
// move in negative direction

I know it can be simplified, as I’ve done here.

Here’s the modified script:


// got rid of this
// 
// fish_mc.onLoad = function()
// {
// trace('onload');
// generatePoint();
// }
// 
fish_mc.onEnterFrame = function() {
	changeX = pointX-this._x;
	changeY = pointY-this._y;
	// figure out 'unit vector'
	dist = Math.sqrt(changeX*changeX+changeY*changeY);
	goX = changeX*speed/dist;
	goY = changeY*speed/dist;
	this._x += goX;
	this._y += goY;
	if (this.hitTest(pointX, pointY, true)) {
		generatePoint();
	}
};
function generatePoint() {
	pointX = random(Stage.width);
	pointY = random(Stage.height);
	speed = random(10)+1;
	point_mc._x = pointX;
	point_mc._y = pointY;
}

generatePoint();


This script can be further shortened by eliminating the variables goX and goY which are only used once - just use the calcuations directly.

Also note that you can eliminate the call to Math.sqrt() by pre-squaring your speed when you change the random point. Since we’re only using the square root like so:

speed/dist

We can also use

speedSquared/distSquared

and we’ll get the same result, avoiding an expensive square root
calculation. Then your onEnterFrame handler is simplified to:


fish_mc.onEnterFrame = function() 
{
	changeX = pointX-this._x;
	changeY = pointY-this._y;
	distSquared = changeX*changeX+changeY*changeY;
	this._x += changeX*speedSquared/distSquared;
	this._y += changeY*speedSquared/distSquared;
	if (this.hitTest(pointX, pointY, true)) {
		generatePoint();
	}
};

  • Jim

thanks, that works awesomely :slight_smile:

If you want to see the final product of this experiment, it can be found at www.barbdwyer.com/misc/fish.php