Smooth Custom AS3 Movieclip функция отталкивания - PullRequest
0 голосов
/ 30 октября 2010

Я написал эту функцию отталкивания (ниже) для 2 мувиклипов и вызываю ее по таймеру вместо прослушивателя enter_frame (скорость), но она имеет тенденцию к рывку и не очень плавная.Как я могу сгладить движения?Я подумала, может быть, добавив какой-нибудь вид отступов или что-то в этом роде, но я не знаю ... Любая помощь будет принята с благодарностью.

Спасибо:)

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;
        }
    }
}

1 Ответ

3 голосов
/ 30 октября 2010

Я не уверен, какой именно отталкивающий эффект вы хотите достичь, но вы можете основывать свой код на простом физическом принципе: гравитационная сила между двумя массами.Вы можете прочитать больше об этом в wikipedia .Вот формула (из Википедии):

F = G * (m1 * m2) / r²

F - величина гравитационной силы между двумя точечными массами,
G - гравитационная постоянная (около 9,81 м / с²),
m1 - масса первой точечной массы,
m2 - масса второй точечной массы, а
r - расстояние между двумя точечными массами.

Вы можете упростить это, если не хотите учитывать массу (то есть масса обоих объектов равна 1):

F = G / r²

Это здорово, но, как говорится в определении, Fэто только величина силы, т.е. вы не знаете направление, только количество.Чтобы получить направление, вам понадобится некоторый вектор:

F_12 = - G / r_12² * ru_12

Где:

F_12 - вектор силы на объекте 2из-за объекта 1.
G - это гравитационная постоянная
r_12 - расстояние между объектом 1 и объектом 2.
ru_12 - это единичный вектор от объекта 1 до объекта 2.

Проверка этот сайт для плавного введения векторов и освобождения себя от всего этого тригонометрического материала.

Но учтите, что гравитационная сила - это сила притяжения.Вы можете легко изменить это на силу отталкивания, инвертировав ее направление.

Реализация

Хорошо, достаточно о теории.Я реализовал функцию, которая имитирует это.

//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;
    }

}

Чтобы использовать его, вызывайте метод repeat через равные промежутки времени.Обратите внимание, что на obj1 симуляция не повлияет.В моем прототипе obj1 следует за мышью.

Попробуйте и скажите мне, что вы думаете.

Кстати, использование класса Timer не быстрее, чем прослушивание ENTER_FRAME любым способом.См. эту статью и две соответствующие статьи для лучшего понимания.

...