0

我想为达到特定峰值(点(x,y))的玩家(左下)添加一个提升。玩家的水平速度 (v_x) 是恒定的,但其垂直速度可以变化。我想计算到达点 (x,y) 所需的最终速度 v_y(这必须是峰值),这也是给出的。我想也许我可以得到矢量播放器和矢量点之间的角度并用运动学公式计算,但它没有给我正确的结果。

在此处输入图像描述

4

2 回答 2

1

跳?多高?

重力是恒定的,但到障碍物的距离会随着我们的接近而变化。

在某个点,距离障碍物有一段距离,其中跳跃速度是清除障碍物所需的最小速度。

更靠后将需要更大的速度才能在空气中停留足够长的时间以清除它,或者更近的速度必须更大才能在铰孔时间内清除。

目前尚不清楚您是否想要最佳跳跃速度来清除物体,这也将定义何时跳跃。

因此,我们只需将重力作为加速度和水平速度,就可以让它跳过高度和距离的障碍物所需的垂直速度。

获得跳跃速度

为了保持简单,我们首先标准化水平速度

使用的术语

  • v是跳跃速度,或初始速度(正向上)
  • t是时间
  • a是重力加速度(负是向下)
  • h是障碍物高度。积极向上
  • d是到障碍物的距离。相当于归一化水平速度
  • s是水平速度。假设对障碍物是积极的。

用于解决的步骤

下落(自由落体)时的速度方程为v + at

有了这个方程f'(t) = v + at,那个方程的反导数f(t) = vt + (1/2)at^2告诉我们在任何时候我们有多高t

因为我们已经标准化了水平速度s,所以到障碍物的距离等于到障碍物的时间t或到障碍物的距离d

我们还可以使用反导数来求解给定距离的高度h = vd+(1/2)ad^2 (替换td

现在我们在一个方程中拥有了我们想要的所有项。h = vd+(1/2)ad^2

我们希望跳跃速度重新排列h = vd+(1/2)ad^2v我们得到v = -ad/2+h/d

最后一件事。水平速度被归一化,因此始终为 1。我们需要使用任何速度。我们可以通过将到障碍物的距离除以d水平速度(速度)来做到这一点s。换句话说,以秒为单位d的速度以多长时间覆盖距离s

最终结果是v = -a(d/s)/2+h/(d/s)

作为代码

让我们把它放到代码中(JavaScript)

该功能jumpObstacle(jumper, obstacle)将设置物体的跳跃速度,以仅在跳跃者向障碍物移动时jumper清除物体。obstacle

Jumper 有一个jumpClear提供间隙和一个最大跳跃速度maxJumpVel。这意味着跳跃可能无法清除障碍物。

该函数返回跳跃高度,如果没有跳跃,则返回 0。

// Assuming +y is up
const gravity = 9.0;
const jumper = {
    vx: 1,
    vy: 0,
    x: 0,
    y: 0,
    maxJumpVel: 3,  // max jump velocity y
    jumpClear: 0.5, // clearance when jumping. May not if max jump to high
};
const wall = {
    x: 4,
    y: 0,   // base
    h: 4,  // height
};
function jumpObstacle(jumper, obstacle) {
    const dist = obstacle.x - jumper.x;
    if (jumper.vx && Math.sign(jumper.vx) === Math.sign(dist)) {
        const nd = dist / jumper.vx;                    // normalize dist (time)
        const h = (obstacle.h + obstacle.y + jumper.jumpClear) - jumper.y; // height to clear
        const vy = -(gravity * nd) / 2 + h / nd;
        jumper.vy = Math.min(vy, jumper.maxJumpVel);
        return jumper.y + vy * nd + gravity * nd * nd * 0.5;
    }
    return 0;
}

演示

我不确定答案是否应该清楚。该演示将上述内容实现为交互式演示。

当盒子在墙壁范围内时单击或点击动画。jumpObstacle 函数将计算清除墙壁所需的跳跃速度。

我还添加了框的宽度和 x 跳跃间隙,以确保跳跃在视觉上越过墙壁。

如果跳线不能清除墙壁,它会闪烁红色。下次再试一次。

地底下的红色方框表示跳线者能够越墙的大约距离。

注意坐标是Y+向下

注意我的最低跳跃速度是每秒 271 像素

// Note y is + down the page
requestAnimationFrame(update);
const ctx = canvas.getContext("2d");
ctx.fillStyle = "red";
const h = 120, w = 200;
const ground = h - 10;
canvas.addEventListener("click", () => {
    jumper.onGround && (jumper.jumpNextFrame = true); 
});

const gravity = 900.0;
const jumper = {
    vx: 60,
    vy: 0,
    x: 0,
    y: ground,
    h: 24,
    w: 8,
    jumpTime: 0,    
    jumpNextFrame: false,
    get onGround() { return this.y >= ground },
    maxJumpVel: -490, 
    jumpClear: -5,
    jumpClearX: 5,
    jumpFail: 0,
    draw(ctx) { 
        this.jumpFail-- > 0 && ctx.fillRect(this.x - this.w / 2, this.y - this.h, this.w, this.h);
        ctx.strokeRect(this.x - this.w / 2, this.y - this.h, this.w, this.h);
    },
    jump(time, what) {
        this.jumpNextFrame = false;
        this.jumpTime = time;
        const h = jumpObstacle(this, what);
        if (h < 0 || h > what.h) { 
            this.jumpTime = 0;
            this.jumpFail = 10;
            this.vy = 0;
        } else {
            console.clear();
            console.log("Jump vel: " + (-this.vy).toFixed(0) + "px per second");
        }
    },
    update(time) {
        this.x = this.vx * time;
        if (this.x > w ) { this.x = this.x % w }  
        if (this.jumpTime > 0) {
            const t = time - this.jumpTime;
            this.y = ground + this.vy * t + gravity * t * t * 0.5;
            if (this.y > ground) {
                this.vy = 0;
                this.jumpTime = 0;
                this.y = ground;
            }            
        }
    }
};
const wall = {
    x: 140,
    y: ground,   
    h: 34,  
    draw(ctx) { ctx.strokeRect(this.x - 1, this.y - this.h, 2, this.h) },
};
function jumpObstacle(jumper, obstacle) {
    const dist = (obstacle.x - (jumper.x - jumper.w)) + jumper.jumpClearX;
    if (jumper.vx && Math.sign(jumper.vx) === Math.sign(dist)) {
        const nd = (dist / jumper.vx) ;                    
        const h = -((obstacle.h + obstacle.y + jumper.jumpClear) - jumper.y); 
        const vy = -(gravity * nd) / 2 + h / nd;
        jumper.vy = vy < jumper.maxJumpVel ? jumper.maxJumpVel : vy;
        return (jumper.vy * nd + gravity * nd * nd * 0.5) - h;
    }
    return 0;
}

function update(time) {
    time /= 1000;
    ctx.clearRect(0, 0, w, h);
    ctx.strokeRect(-1, ground, w + 2, h - ground + 2); // draw ground
    ctx.fillRect(wall.x - 50, ground + 2, 30, 2);
    if (jumper.jumpNextFrame) { jumper.jump(time , wall) }
    jumper.update(time);
    jumper.draw(ctx);
    wall.draw(ctx);
    requestAnimationFrame(update);
}
  console.log("Click animation to jump. Will flash red is not able to clear wall");
canvas { border: 1px solid black; }
<canvas id="canvas" width ="200" height="120"></canvas>

于 2021-07-28T06:52:30.130 回答
1

希望我正确理解您的问题。首先,您要计算爬到那个高峰需要多长时间。

// distance left to travel horizontally
delta.x = peak.x - player.x 

// time left to reach peak
t = delta.x / speed.x

假设delta.x是 200 像素,玩家的速度(水平)是每秒 40 像素。这给了我们 5 秒的时间从player.y爬到peak.y

现在我们计算我们需要垂直移动多远。

// We have 5 seconds to move vertically by this much
delta.y = peak.y - player.y

// How fast to move per second to reach peak in 5 seconds.
speed.y = delta.y / t

关于重力的说明:

如果重力是 3m/s(为了更容易数学而简化),那么重力在它继续施加的每一秒都会更大(因为它正在加速)。

second - m/s
1 - 3
2 - 6
3 - 9
4 - 12
5 - 15

这并不意味着 5 秒后重力将您的物体拉了 15 米。这是序列中每一秒的力,所以你实际上将它们全部加起来,即为 45。所以你将在上面计算的总距离上加上 45。

于 2021-07-27T16:21:34.920 回答