1
\$\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\$
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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.