логика отмены движения во временной анимации - PullRequest
0 голосов
/ 26 февраля 2019

Я разработал движок в моей простой игре, в которой у вас есть определенные координаты (x,y), и, нажав, вы можете перейти к любому месту назначения (x,y).Идея в том, что у вас есть speed и fuel consumption, также все движение основано на времени.Таким образом, в конце концов, если вы решите перейти из точки А в точку Б, потребуется 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 голосов
/ 26 февраля 2019
  • Если ваш объект всегда движется прямо к цели, нет необходимости в какой-либо тригонометрии.Просто используйте векторную математику.

  • Логически 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...