JS手写自由落体和抛物线算法,怎么样?

大家好,咱么又见面了,我是能说会道,技术一流的一灯小雨。
本人最近在用Javascript写一个小游戏,其中涉及到抛物线算法,在这里和大家分享一下。我好像听到有人说,什么是抛物线算法?呃,这个。。。你一定玩过愤怒的小鸟这款游戏吧?就是“呜。。。呜。。。砰。。砰。。砰。。”。嗯,对,没错,这就是抛物线算法。要完成抛物线算法呢,得需要从简单的自由落体算法开始,虽然公式简单,谁都会算,但用代码实现起来,也不是那么简单呢?那么,咱么现在就开始吧!

自由落体

1.先通过CSS构建一个球体模型。代码如下:

.ball{
        width:30px;height:30px;
        background-color: black;
        border-radius: 15px;
        position: absolute;
        left:100px;
        top:0;
        transform: translateY(180px);
    }

2.创建球体。想必你通过上述代码已经脑补出球体的模样了吧!那么,接下来咱们要做的就是把球往下扔咯!通过button的click事件创建球体。代码如下:

body:
<button onclick="shoot()">发射</button>
javascript:
    function shoot()
    {
        var ball = document.createElement('div');
        ball.className = 'ball';
        document.body.appendChild(ball);
        ball.style.top = `${vy * t + 0.5 * g * t * t }px`;
    }

3.添加垂直加速度。继续改造shoot函数,代码如下:

    function shoot()
    {
        var t = 8, g = 10, vy = 0;
        var ball = document.createElement('div');
        ball.className = 'ball';
        document.body.appendChild(ball);
        ball.style.top = `${vy * t + 0.5 * g * t * t }px`;
    }

我们声明了几个变量,t表示运动时间, g表示垂直加速度,vy表示垂直方向的初始速度,因为自由落体的初始状态为静止,那么它初始速度为0注意,代码中ball.style.top的属性值用的模板字符串,模板字符串是ES6的字符串新特性。可将它视为普通字符串拼接的简化形式。最终会产生类似’...px‘的普通字符串结果。请注意字符串中的计算公式,这是高一的物理知识,这是整个代码的核心噢!那么,咱们先运行看看效果吧!呃。。。好像哪里不对呢,小球从从空中以迅雷不及掩耳之势直接掉在地上,说好的自由落体呢?实际上上述的计算公式计算出来的是小球最终的落地位置,我们直接这样赋值,可不就瞬移到地上了。不过,还好,落地的位置非常准。现在的情况是知道起点和终点,那么我们怎么模拟中间的运动过程呢?答案是:通过插值。

4.贝塞尔插值算法
贝塞尔插值算法广泛应用于工业领域。最初是用来设计汽车造型的,大家有没有注意到,汽车造型中的那些边角处理都非常圆滑,过渡非常流畅。这些圆滑处理就是用贝塞尔插值算法做到的。当然贝塞尔插值不是一种单一的算法,而是一些列算法,每个算法公式都和具体问题密切相关,汽车设计又汽车设计的插值公式,自由落体也有自由落体的插值公式。很多插值公式甚至需要一篇论文来对它进行理论阐释。那么自由落体的插值公式是怎样的呢?代码如下:

function generateCubicBezier(v, g, t)
{
    var a = v / g;
    var b = t + v / g;
    return [[(a/3+(a+b)/3-a)/(b-a),(a*a/3+a*b*2/3-a*a)/(b*b-a*a)],
            [(b/3+(a+b)/3-a)/(b-a),(b*b/3+a*b*2/3-a*a)/(b*b-a*a)]];
}

传入初始速度,垂直加速度,运动时间,返回一个二维的插值数组。该函数在插值演算时调用。很遗憾,这段算法我无法解释,这是某大神分享的。虽然大神有对算法进行具体阐释,不过本人没有理解,自己都不能理解的东西,最好不要向别人解释,免得误人子弟。源码在此,你大可自己好好参详,也许你天资聪颖,能参透一二也未可知。我呢,就用它就好了,那么,咱们就用它进行插值吧。继续改造shoot函数。代码如下:

function shoot()
{
    var t = 8, g = 10, vy = 0;
    var ball = document.createElement('div');
    ball.className = 'ball';
    document.body.appendChild(ball);;
    ball.style.transition = `top cubic-bezier(${generateCubicBezier(vy, g, t)}) ${t}s`;
    ball.style.top = `${vy * t + 0.5 * g * t * t }px`
}

同样需要注意的是ball.style.transition值用的也是模板字符串,这里对top进行了插值演算。咱么看看效果吧!呃。。。还是以迅雷不及掩耳之势直接掉地上。。接续改造。。

function shoot()
{
    var t = 8, g = 10, vy = 0;
    var ball = document.createElement('div');
    ball.className = 'ball';
    document.body.appendChild(ball);
    setTimeout(()=>{
    ball.style.top = `${vy * t + 0.5 * g * t * t }px`;
    }, 100);
    ball.style.transition = `top cubic-bezier(${generateCubicBezier(vy, g, t)}) ${t}s`;
}

我不想解释什么,插值演算有时候就是这么变态!呃。。。还是强行解释一波吧,在插值演算的时候,你不能直接一开始就把最终值
告诉它,否则它直接就插入最终值了,这里给它延时100毫秒。看效果,OK!!

5.清除资源。
小球运动时间完了,就清除它。继续改造代码,最终代码如下:

function shoot()
{
    var t = 8, g = 10, vy = 0;
    var ball = document.createElement('div');
    ball.className = 'ball';
    document.body.appendChild(ball);
    setTimeout(()=>{
    ball.style.top = `${vy * t + 0.5 * g * t * t }px`;
    }, 100);

    setTimeout(() => {
    document.body.removeChild(ball);
    }, 1000 * t);

    ball.style.transition = `top cubic-bezier(${generateCubicBezier(vy, g, t)}) ${t}s`;
}

好了,自由落体大功告成!注意这里的单位时px,个人觉得下落速度有点慢,可以调整垂直加速度g。那么抛物线就简单了!

抛物线算法

实际上抛物线算法就时在自由落体的基础上加一个水平匀速直线运动就好了,那么,继续改造代码。。。代码如下:

function shoot()
{
    var t = 8, g = 10, vy = 0, vx = 50;
    var ball = document.createElement('div');
    ball.className = 'ball';
    document.body.appendChild(ball);
    setTimeout(() => {
    ball.style.top = `${vy * t + 0.5 * g * t * t }px`;
    ball.style.left += `${vx * t}px`;//加入一个水平初速度
    }, 100);
    setTimeout(() => {
    document.body.removeChild(ball);
    }, 1000 * t);
    //此处加入水平插值
    ball.style.transition = `left linear ${t}s, top cubic-bezier(${generateCubicBezier(vy, g, t)}) ${t}s`
}

这里需要注意的,水平位置因为初始位置为100px,所以这里做的是累加,否则最终计算值水平位置就不对,小球运动轨迹会让人莫名其妙。
大功告成,是不是很简单呢?
好了,就到这里吧,希望你有所收获,如果你有疑问或想法,欢迎给我留言吧,再会吧。。。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 【Android 动画】 动画分类补间动画(Tween动画)帧动画(Frame 动画)属性动画(Property ...
    Rtia阅读 6,115评论 1 38
  • 字符串匹配KMP算法详解 1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有...
    张晨辉Allen阅读 2,390评论 0 3
  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 2,892评论 0 16
  •   引用类型的值(对象)是引用类型的一个实例。   在 ECMAscript 中,引用类型是一种数据结构,用于将数...
    霜天晓阅读 1,044评论 0 1
  • 字符串和字符 甲串是一系列字符,如的"hello, world"或"albatross"。Swift字符串由Str...
    Fuuqiu阅读 1,031评论 0 0