Smooth Custom AS3 Movieclip repel function
I wrote this repel function (below) for 2 movieclips and I call it from a timer instead of an enter_frame listener (speed), but it has the tendency to jerk and not be very smooth. How can I smooth the movements? I was thinking maybe adding some sort of padding or something, but idk...Any help would be greatly appreciated.
Thanx :)
function repel(mover2, mover) {
var xdiff:Number = mover2.x - mover.x;
var ydiff:Number = mover2.y - mover.y;
var dist:Number = Math.sqrt(xdiff*xdiff + ydiff*ydiff);
if (dist < (mover2.width/2 + mover.width/2)){
var angle:Number = Math.atan2(ydiff, xdiff);
if ((mover.x - Math.cos(angle)*10) - (mover.width/2) > minx && (mover.x - Math.cos(angle)*10) + (mover.width/2) <开发者_如何学编程; maxx) {
mover.x -= (Math.cos(angle)*10)*1;
}
if ((mover.y - Math.sin(angle)*10) - (mover.height/2) > miny && (mover.y - Math.sin(angle)*10) + (mover.height/2) < maxy) {
mover.y -= (Math.sin(angle)*10)*1;
}
if ((mover2.x - Math.cos(angle)*10) - (mover2.width/2) > minx && (mover2.x - Math.cos(angle)*10) + (mover2.width/2) < maxx) {
mover2.x += (Math.cos(angle)*10)*1;
}
if ((mover2.y - Math.sin(angle)*10) - (mover2.height/2) > miny && (mover2.y - Math.sin(angle)*10) + (mover2.height/2) < maxy) {
mover2.y += (Math.sin(angle)*10)*1;
}
}
}
I'm not sure exactly what kind of repelling effect you want to achieve, but you can base your code on a simple physic principle : the gravitational force between two mass. You can read more about it on wikipedia. Here's the formula (from wikipedia) :
F = G * (m1 * m2) / r²
F is the magnitude of the gravitational force between the two point masses,
G is the gravitational constant (about 9.81 m/s²),
m1 is the mass of the first point mass,
m2 is the mass of the second point mass, and
r is the distance between the two point masses.
You can simplify this if you don't want to account mass (i.e. both object have a mass of 1) :
F = G / r²
This is great, but as the definition says, F is only the magnitude of the force, i.e. you don't know the direction, only the amount. To get the direction, you'll need some vector :
F_12 = - G / r_12² * ru_12
Where :
F_12 is the vector of the force on object 2 due to object 1.
G is still the gravitationnal constant
r_12 is the distance between object 1 and object 2.
ru_12 is the unit vector from object 1 to object 2.
Check out this site for a smooth introduction on vectors and liberate yourself from all this trigonometric stuff.
But note that the gravitationnal force is an attraction force. You can easily change this to a repulsion force by inverting its direction.
Implementation
Alright, enough about theory. I've implemented a function which simulate this.
//make sure you set your initial conditions
obj2.vx = 0;
obj2.vy = 0;
function repel(obj1:MovieClip, obj2:MovieClip) {
var G:Number = 100; // gravitationnal constant. You can play with this to get more or less force.
var res:Number = 0.9; //a coeffient which reduce the speed when the object hits a wall.
//this is a vector from obj1 pointing to obj2
var distVector:Point = new Point();
distVector.x = obj2.x - obj1.x;
distVector.y = obj2.y - obj1.y;
var distance:Number = Math.sqrt(distVector.x*distVector.x + distVector.y*distVector.y);
//a unit vector is a vector of length 1
var unit:Point = distVector.clone();
unit.x /= distance;
unit.y /= distance;
//here's the actual formula
var force:Point = new Point();
force.x = G / (distance*distance) * unit.x;
force.y = G / (distance*distance) * unit.y;
//we don't have any mass, so a = F
var ax:Number = force.x;
var ay:Number = force.y;
//simple integration
obj2.vx += ax;
obj2.vy += ay;
obj2.x += obj2.vx;
obj2.y += obj2.vy;
// bounce to stage dimension
if(obj2.x < 0){
obj2.x = 0;
obj2.vx = -res*obj2.vx;
}
if(obj2.x > stage.stageWidth){
obj2.x = stage.stageWidth;
obj2.vx = -res*obj2.vx;
}
if(obj2.y < 0){
obj2.y = 0;
obj2.vy = -res*obj2.vy;
}
if(obj2.y > stage.stageHeight){
obj2.y = stage.stageHeight;
obj2.vy = -res*obj2.vy;
}
}
To use it, call repel at a regular interval. Note that obj1 will not be affected by the simulation. In my prototype, obj1 follow the mouse.
Try it and tell me what you think.
On a side note, using the Timer class is not faster than listening to ENTER_FRAME in any way. See this article and its two related articles for a better understanding.
精彩评论