0
\$\begingroup\$

I am using a tweening library to move my units around. The problem is that the speed varies depending on the distance that the unit has to move because of the tweening:

var time = 1000;
var tween = new TWEEN.Tween({ x: startX, y: startY })
    .to({ x: endX, y: endY }, time)
    .start();

^No matter the x and y values it will always take the same amount of time.

I tried fixing this by dividing the distance by the speed:

// distance = speed * time
// time = distance / speed
var x = endX - startX;
var y = endY - startY;
var distance = Math.sqrt(x * x + y * y);

var time = distance / speed * dt;
var tween = new TWEEN.Tween({ x: startX, y: startY })
    .to({ x: endX, y: endY }, time)
    .start();

However it still doesn't move at the same speed! Grr!

I made a snippet that shows a square endlessly moving in a rectangle, when done correctly ( which this isnt... ) it should move at the same velocity no matter the distance.

var rect = document.getElementById("rect");

var pos = [ [0, 0], [200, 0], [200, 50], [0, 50] ];
var i = 0;
var time = 1000;
var speed = 10 * 1000; // 10px per second

var tweenStart = { x: 0, y: 0 };
var tweenEnd = { x: pos[i][0], y: pos[i][1] };

var tween = new TWEEN.Tween(tweenStart)
    .to(tweenEnd, time)
    .onUpdate(function () {
        rect.style.top = this.y + "px";
        rect.style.left = this.x + "px";
    })
    .onComplete(function () {
        tweenStart.x = pos[i][0];
        tweenStart.y = pos[i][1];
        i += 1;
        if (i >= pos.length) i = 0;
        tweenEnd.x = pos[i][0];
        tweenEnd.y = pos[i][1];
        // time = distance / speed
        var x = tweenEnd.x - tweenStart.x;
        var y = tweenEnd.y - tweenEnd.y;
        var distance = Math.sqrt(x * x + y * y);
        time = distance / speed * dt;
        tween.start();
});

setTimeout(initiate, 0);

var now, then, dt;

function tick() {

    now = perfNow();
    dt = now - then;
    then = now;

    TWEEN.update();

    requestAnimationFrame(tick);

};

var perfNow = (self.performance && self.performance.now) ? self.performance.now.bind(performance) : Date.now;

function initiate() {

    var x = tweenEnd.x - tweenStart.x;
    var y = tweenEnd.y - tweenEnd.y;
    var distance = Math.sqrt(x * x + y * y);
    time = distance / speed * dt;

    tween.start();

    then = perfNow();

    tick();

};
body {
    margin: 0;
    overflow: hidden;
}
div {
    position: absolute;
    width: 10px;
    height: 10px;
    background-color: black;
}
<script src="https://dl.dropboxusercontent.com/u/53738503/tween.min.js"></script>
<div id="rect"></div>

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

For some reason the tween library requires you to update the tween inside your onComplete function, and calculate the time using something like the following:

.onComplete(function () {
        tweenStart.x = pos[i][0];
        tweenStart.y = pos[i][1];
        i += 1;
        if (i >= pos.length) i = 0;
        tweenEnd.x = pos[i][0];
        tweenEnd.y = pos[i][1];

        var x = tweenEnd.x - tweenStart.x;
        var y = tweenEnd.y - tweenStart.y;

        var distance = Math.sqrt(x * x + y * y);
        time = (distance / speed) * dt;
        tween.to(tweenEnd, time);

        tween.start();
}

So the main point is the tween.to line inside the function, which I suppose updates the tweening time. Also make sure to use a small speed, or tweak the time calculation otherwise. A speed of 2 seems to look nice to me.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .