在基于时间的动画中取消移动的逻辑

时间:2019-02-26 09:27:51

标签: javascript animation math

我在我的简单游戏中设计了一个运动引擎,其中您具有特定的坐标(x,y),并且通过单击可以转到任何目的地(x,y)。这个想法是您有speedfuel consumption,整个动作都是基于时间的。因此,最后,如果您决定从A点到达B点,将需要X的时间(由速度决定)和X的燃料(由消耗决定)。我面临的问题是计算的准确性,可能不是到达目的地后停止旅行的最佳逻辑。

进行的计算是正确的,但是其准确性导致了一些问题。

在我所包含的演示中,可以看到我当前的取消逻辑正在产生剩余物(例如,应燃烧20升燃油,但我剩下0.12 ...):

if ( Math.floor( this.distance ) === 0 ) {

我的上一个永远不会结束(因为如果没有小数位数,它永远都不可能达到0):

if ( this.distance > 0 ) {

我的问题是,如何改进代码,使行程始终在正确的点结束,燃油始终处于应有的状态。

const tools = {
	distance: (p1, p2) => Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)),
	rftv: (p1, p2) => Math.atan2(p2.y - p1.y, p2.x - p1.x)
};

this.fuel = 200;
this.x = 100;
this.y = 50;
this.rad = 0; // radian angle between current and destination
this.speed = 100; // 100 pixels per second
this.consumption = 10; // 10 liters of fuel per 100 pixels
this.destination = {
	x: 220,
	y: 140
};

/*
Based on above

distance : 150
time : ( distance / speed ) => 150 / 100 => 1.5s
fuel : ( distance / consumption ) => 150 / 10 => 15 liters

So to summary, between two points we have 150 pixels of distance,
this trip should take 1.5s and burn 15 liters of fuel
*/

this.now = undefined;
this.delta = undefined;
this.then = Date.now();

this.setDelta = function() {
	this.now = Date.now();
	this.delta = (this.now - this.then) / 1000;
	this.then = this.now;
};

this.update = function() {
	this.rad = tools.rftv(
		{ x: this.x, y: this.y },
		{ x: this.destination.x, y: this.destination.y }
	);
  
  let step = this.speed * this.delta;
	this.x += Math.cos(this.rad) * step;
	this.y += Math.sin(this.rad) * step;

	this.fuel -= step / this.consumption;
};

this.move = function() {
	this.distance = tools.distance(
		{ x: this.x, y: this.y },
		{ x: this.destination.x, y: this.destination.y }
	);
	
	if ( Math.floor( this.distance ) === 0 ) {
		clearInterval(tsid);
		console.log('done', this.x, this.y, this.fuel, this.distance, '[ ' + (Date.now() - startedAt) + ' ]');
	} else {
		this.setDelta();
		this.update();
		console.log('going', this.x, this.y, this.fuel, this.distance, '[ ' + (Date.now() - startedAt) + ' ]');
	}
};



let tsid;
let startedAt = Date.now();
tsid = setInterval(function() {
	this.move();
}, 10);

1 个答案:

答案 0 :(得分:1)

  • 如果您的对象始终直接向目标行进,则不需要任何三角函数。只需使用向量数学即可。

  • 逻辑上update应该调用move,而不是相反。

  • 距离计算应与运动代码相同。

  • move中检查距离并设置完成标记。

  • 一步使用的燃料=消耗(使用量/像素)×步长(以像素为单位),因此this.fuel -= step / this.consumption;不正确。

代码:

this.fuel = 200;
this.x = 100;
this.y = 50;
// no need for rad
this.speed = 100;
this.consumption = 10;
this.destination = {
    x: 220,
    y: 140
};
this.complete = false; // completion flag

...

// swap functions

this.update = function() {
    this.update();

    if (this.complete) {
        clearInterval(tsid);
        console.log('done', this.x, this.y, this.fuel, this.distance, '[ ' + (Date.now() - startedAt) + ' ]');
    } else {
        this.setDelta();
        this.move();
        console.log('going', this.x, this.y, this.fuel, this.distance, '[ ' + (Date.now() - startedAt) + ' ]');
    }
};

this.move = function() {
    let step = this.speed * this.delta;
    let dist = tools.distance(
        { x: this.x, y: this.y },
        { x: this.destination.x, y: this.destination.y }
    );
    /*
       would be cleaner to replace this with:
       Math.hypot(this.destination.x - this.x, this.destination.y - this.y);
    */

    // check distance
    if (dist <= step) {
        step = dist;
        this.complete = true;
    }

    // vector math not trigonometry
    this.x += (this.destination.x - this.x) * (step / dist);
    this.y += (this.destination.y - this.y) * (step / dist);

    this.distance -= step;
    this.fuel -= step * this.consumption; // should be * not /
};

...

tsid = setInterval(function() {
    this.update();
}, 10);