将时间增量和速度纳入速度/摩擦运动

时间:2019-03-14 09:22:40

标签: javascript animation math time html5-canvas

我正在简单的游戏中尝试运动机制,并且发现了非常不错的文章,并举例说明了如何通过速度和摩擦(使其非常流行的方法)使其“逼真”。因此,对象开始缓慢移动,加速到上限,一旦释放键,它就会开始释放速度直到0。

关键部分添加了“油门”:

if(keys[38]) {
    spaceship.ax = Math.cos(spaceship.r) * 0.05;
    spaceship.ay = Math.sin(spaceship.r) * 0.05;
} else {
    spaceship.ax = spaceship.ay = 0;
}

并利用该油门来提高受摩擦限制的速度

var friction = 0.97;
function updatePosition(obj) {
    //update velocity
    obj.vx += obj.ax;
    obj.vy += obj.ay;

    //apply friction
    obj.vx *= friction;
    obj.vy *= friction;

    //update position
    obj.x += obj.vx;
    obj.y += obj.vy;
}

尽管它看起来非常漂亮并且感觉不错,但它打破了我关于基于时间移动的逻辑。它是强制性的,因此玩家可以看到每秒的速度,因为它可以进行计划的升级,计划的行程和燃油消耗。

所以当前的实现如下:

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

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

this.speed = 100; // 100 pixels per second
this.move = function() {
    this.setMoveDelta();
    var partialDistance = this.speed * this.delta;
    this.x += Math.cos(this.rad) * partialDistance;
    this.y += Math.sin(this.rad) * partialDistance;
}

现在,当您运行附带的演示时,可以注意到由于摩擦力帽而有某种“最大”速度。问题是可以通过某种方式将此上限设置为this.speed * this.delta吗?还是使用其他方法以声明的参数(例如每秒100像素)使船舶以最大速度行驶?

这个想法是让加速和减速保持原样,但是一旦船达到最大速度,它将是声明的速度(并显示给用户)。然后,该速度用于计算从点A到点B所需的时间以及将使用多少燃料。目前感觉随机。

var canvas = document.createElement('canvas'),
	ctx = canvas.getContext('2d'),
	w = 400,
	h = 400;
canvas.width = w;
canvas.height = h;

document.body.appendChild(canvas);

var spaceship = {
	x: w / 2, y: h / 2,
	vx: 0, vy: 0,
	ax: 0, ay: 0,
	r: 0,
	draw: function(){
		ctx.save();
		ctx.translate(this.x, this.y);
		ctx.rotate(this.r);
		ctx.fillStyle = 'white';
		ctx.fillRect(-10, -5, 20, 10);
		ctx.restore();
	}
};

var friction = 0.97;

function updatePosition(obj) {
	//update velocity
	obj.vx += obj.ax;
	obj.vy += obj.ay;

	applyFriction(obj);

	//update position
	obj.x += obj.vx;
	obj.y += obj.vy;
}

//user interactivity

var keys = [];
document.addEventListener('keydown', function(e){
	keys[e.which] = true;
});
document.addEventListener('keyup', function(e){
	keys[e.which] = false;
});

function applyFriction(obj){
	obj.vx *= friction;
	obj.vy *= friction;
}

(function animloop(){
	requestAnimationFrame(animloop, canvas);
	ctx.fillStyle = '#000';
	ctx.fillRect(0, 0, w, h);

	//rotation
	if(keys[37]) spaceship.r -= 0.05;
	if(keys[39]) spaceship.r += 0.05;

	//thrust
	if(keys[38]){
		spaceship.ax = Math.cos(spaceship.r) * 0.05;
		spaceship.ay = Math.sin(spaceship.r) * 0.05;
	}else{
		spaceship.ax = spaceship.ay = 0;
	}

	updatePosition(spaceship);
	spaceship.draw();
})();

-----编辑

我实现了建议的解决方案,但是即使使用此公式,最大速度也要比声明的速度稍低一些,从而导致其他对象以每秒实际100px的速度移动,从长远来看,速度更快。这是新的演示:

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

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

this.speed = 100; // 100 pixels per second

var secondObj = {
	x: 0,
	y: 250,
	r: 0,
	active: false,
	draw: function(){
		ctx.save();
		ctx.translate(this.x, this.y);
		ctx.rotate(this.r);
		ctx.fillStyle = 'white';
		ctx.fillRect(-10, -5, 20, 10);
		ctx.restore();
	}
};

var canvas = document.createElement('canvas'),
	ctx = canvas.getContext('2d'),
	w = 1200,
	h = 400;
canvas.width = w;
canvas.height = h;

document.body.appendChild(canvas);

var spaceship = {
	x: 0, y: 200,
	vx: 0, vy: 0,
	ax: 0, ay: 0,
	r: 0,
	draw: function(){
		ctx.save();
		ctx.translate(this.x, this.y);
		ctx.rotate(this.r);
		ctx.fillStyle = 'white';
		ctx.fillRect(-10, -5, 20, 10);
		ctx.restore();
	}
};

var friction = 0.97;

function updatePosition(obj) {
	//update velocity
	obj.vx += obj.ax;
	obj.vy += obj.ay;

	applyFriction(obj);

	//update position
	obj.x += obj.vx;
	obj.y += obj.vy;
}

//user interactivity

var keys = [];
document.addEventListener('keydown', function(e){
	keys[e.which] = true;
	setTimeout(function() {
	secondObj.active = true;
	}, 600);
});
document.addEventListener('keyup', function(e){
	keys[e.which] = false;
});

function applyFriction(obj){
	obj.vx *= friction;
	obj.vy *= friction;
}

var is = function(c, num) {
	if(parseInt(c) < num + 1 || parseInt(c) > num - 1) {
	   return true;
	}
	return false;
};

(function animloop(){
	requestAnimationFrame(animloop, canvas);
	ctx.fillStyle = '#000';
	ctx.fillRect(0, 0, w, h);

	//rotation
	if(keys[37]) spaceship.r -= 0.05;
	if(keys[39]) spaceship.r += 0.05;

	//thrust
	this.setMoveDelta();
	if(keys[38]){
		spaceship.ax = Math.cos(spaceship.r) * (this.speed * this.delta * (1-0.97));
		spaceship.ay = Math.sin(spaceship.r) * (this.speed * this.delta * (1-0.97));
	}else{
		spaceship.ax = spaceship.ay = 0;
	}
	
	updatePosition(spaceship);
	spaceship.draw();
	
	if(secondObj.active) {
	secondObj.x += Math.cos(0) * ( this.speed * this.delta );
}
	secondObj.draw();
})();

1 个答案:

答案 0 :(得分:1)

现在速度为root_of(obj.vx ^ 2 + obj.vy ^ 2)/this.delta,最大速度为0.05 /(1-0.97)/this.delta。 vx和vy之后的第一个在每个时间增量中都在移动。后者由于速度的增加0.05与速度的减少*(1-0.97)平衡。

答案是可以通过调整加速度常数0.05或摩擦常数0.97来设置速度上限。让我们使用加速度一:

加速度常数= max_speed * this.delta *(1-0.97)