gpt4 book ai didi

javascript - 如何使用重力沿弯曲路径制作动画

转载 作者:数据小太阳 更新时间:2023-10-29 04:17:49 26 4
gpt4 key购买 nike

我正在尝试创建一个模拟,在该模拟中,球会遵循类似于此的运动路径:

https://bl.ocks.org/mbostock/1705868

但是,我不使用补间,而是希望球的运动由重力 和物体的速度决定——类似于过山车,如下所示:

https://www.myphysicslab.com/roller/roller-single-en.html

这是我目前所拥有的,但有一个小问题,即过山车在每一帧中都略微获得能量,而不是失去能量:

https://jsbin.com/jidazom/edit?html,js,output


X

如有任何关于如何解决此问题的建议,我们将不胜感激!

最佳答案

你可以试试这个JS Bin .我修改了代码以符合我自己对重力影响的理解。在计算中,我使用斜率的垂直分量,在当前位置计算(在每一侧使用一个小的增量,而不依赖于之前的位置):

function getEffectiveGravityFactor() {
// Get the vertical component of the slope at current position
var delta = 0.001;
var pathPos1 = Math.min(maxRange, Math.max(delta, pathPos));
var pos1 = pathEl.getPointAtLength(pathPos1 - delta);
var pos2 = pathEl.getPointAtLength(pathPos1 + delta);
var dx, dy;
if (direction) {
dx = pos2.x - pos1.x;
dy = pos2.y - pos1.y;
} else {
dx = pos1.x - pos2.x;
dy = pos1.y - pos2.y;
}
var total = Math.sqrt(dx * dx + dy * dy);
return dy / total;
}

路径的限制就像台球 table 垫一样。我不知道那是不是你打算做的。回弹并不总是完全有弹性,因此当达到极限时可能会有轻微的能量增加或损失。

我还介绍了一个摩擦系数,虽然很粗糙,但给出了一个可能的实现思路。

因为我不确定 requestAnimationFrame 是否以非常固定的间隔执行,所以我在计算中考虑了实际的时间间隔。该部分可能不是必需的。

完整代码如下:

var svg = d3.select("#line").append("svg:svg").attr("width", "100%").attr("height", "100%");
var data = d3.range(50).map(function(){return Math.random()*10;});
var x = d3.scale.linear().domain([0, 10]).range([0, 700]);
var y = d3.scale.linear().domain([0, 10]).range([10, 290]);
var line = d3.svg.line()
.interpolate("cardinal")
.x(function(d,i) {return x(i);})
.y(function(d) {return y(d);})

var path = svg.append("svg:path").attr("d", line(data));
var circle =
svg.append("circle")
.attr("cx", 100)
.attr("cy", 350)
.attr("r", 3)
.attr("fill", "red");

var circleBehind =
svg.append("circle")
.attr("cx", 50)
.attr("cy", 300)
.attr("r", 3)
.attr("fill", "blue");

var circleAhead =
svg.append("circle")
.attr("cx", 125)
.attr("cy", 375)
.attr("r", 3)
.attr("fill", "green");

var pathEl = path.node();
var pathLength = pathEl.getTotalLength();
var BBox = pathEl.getBBox();
var scale = pathLength/BBox.width;
var offsetLeft = document.getElementById("line").offsetLeft;
var randomizeButton = d3.select("#randomize");
var pathPos = 600;
var pos = {x: 0, y: 0};
var speed = 10;
var friction = 0;
var direction = true;
var gravity = 0.01;
var maxRange = 1500;
var speedChange;
var currentTime, prevTime, diffTime;

function getEffectiveGravityFactor() {
// Get the vertical component of the slope at current position
var delta = 0.001;
var pathPos1 = Math.min(maxRange, Math.max(delta, pathPos));
var pos1 = pathEl.getPointAtLength(pathPos1 - delta);
var pos2 = pathEl.getPointAtLength(pathPos1 + delta);
var dx, dy;
if (direction) {
dx = pos2.x - pos1.x;
dy = pos2.y - pos1.y;
} else {
dx = pos1.x - pos2.x;
dy = pos1.y - pos2.y;
}
var total = Math.sqrt(dx * dx + dy * dy);
return dy / total;
}

function play() {
requestAnimationFrame(play);

currentTime = Date.now();
diffTime = currentTime - prevTime;

if (diffTime > 20) {

prevTime = currentTime;

if (pathPos < 0 || pathPos > maxRange) {
// The limit was reached: change direction
direction = !direction;
pathPos = Math.min(maxRange, Math.max(0, pathPos));
} else {
speedChange = gravity * diffTime * getEffectiveGravityFactor();
if (speedChange < -speed) {
// Direction change caused by gravity
direction = !direction;
speed = 0;
} else {
speed += speedChange;
speed = Math.max(0, speed - friction * diffTime * (0.0002 + 0.00002 * speed));
}
}

pathPos += (direction ? 1 : -1) * speed;
pos = pathEl.getPointAtLength(pathPos);

circle
.attr("opacity", 1)
.attr("cx", pos.x)
.attr("cy", pos.y);

posBehind = pathEl.getPointAtLength(pathPos - 10);
circleBehind
.attr("opacity", 1)
.attr("cx", posBehind.x)
.attr("cy", posBehind.y);

posAhead = pathEl.getPointAtLength(pathPos + 10);
circleAhead
.attr("opacity", 1)
.attr("cx", posAhead.x)
.attr("cy", posAhead.y);
}
}

prevTime = Date.now();
play();

var txtSpeed = document.getElementById("txtSpeed");
var txtFriction = document.getElementById("txtFriction");

txtSpeed.value = speed;
txtFriction.value = friction;

randomizeButton.on("click", function(){
speed = parseFloat(txtSpeed.value);
friction = parseFloat(txtFriction.value);
pathPos = 400;
direction = true;
prevTime = Date.now();
data = d3.range(50).map(function(){return Math.random()*10;});
circle.attr("opacity", 0);
path
.transition()
.duration(300)
.attr("d", line(data));
});

关于javascript - 如何使用重力沿弯曲路径制作动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45305768/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com