马黑黑 发表于 2025-7-6 21:25

使用tween实现对象的抛物线运动

本帖最后由 马黑黑 于 2025-7-6 21:36 编辑 <br /><br /><div id="papa"></div>

<script type="module">
        import TWEEN from 'https://638183.freep.cn/638183/3dev/examples/jsm/libs/tween.module.js';

        let sons = [], tweens = [], total = 10, time = 1000;

        Array.from({length: total}).forEach(son => {
                son = document.createElement('div');
                son.className = 'son';
                son.style.cssText += `
                        transform: translate3d(0, 0, -1000px);
                        background: linear-gradient(
                                35deg,
                                #${Math.random().toString(16).substring(2,8)},
                                #${Math.random().toString(16).substring(2,8)}
                        );
                `;
                sons.push(son);
                papa.appendChild(son);
        });

        sons.forEach((son, key) => {
                const pos = { x: 0, z: -1000, a: 0 };
                const target = { x: papa.offsetWidth, z: 0, a: 30 };
                const tween = new TWEEN.Tween(pos)
                        .to(target, time)
                        .onUpdate( () => {
                                son.style.setProperty('transform', `rotateZ(${pos.a}deg) translate3d( ${pos.x}px, 0, ${pos.z}px )`);
                        })
                        .onStart( () => {
                                son.style.setProperty('opacity', 0.9);
                        })
                        .onComplete ( () => {
                                setTimeout( () => {son.style.setProperty('opacity', 0); }, time);
                        });
                tweens.push(tween);
        });

        tweens.forEach( (tween, key) => {
                tween.chain(tweens[(key + 1) % tweens.length]);
        });

        const animate = () => {
                TWEEN.update();
                requestAnimationFrame(animate);
        };

        tweens.start();
        animate();
</script>

<style>
        #papa {
                margin: auto;
                margin-top: 30px;
                width: 760px;
                height: 480px;
                border: 1px solid gray;
                perspective: 600px;
                position: relative;
        }
        .son {
                position: absolute;
                width: 60px;
                height: 60px;
                border-radius: 50%;
                background: linear-gradient(35deg, tan, skyblue);
                opacity: 0;
                filter: drop-shadow(4px 6px 8px gray);
        }
</style>

马黑黑 发表于 2025-7-6 21:26

本帖最后由 马黑黑 于 2025-7-6 22:57 编辑

代码:
<div id="papa"></div>

<script type="module">
        import TWEEN from 'https://638183.freep.cn/638183/3dev/examples/jsm/libs/tween.module.js';

        let sons = [], tweens = [], total = 10, time = 1000;

        Array.from({length: total}).forEach(son => {
                son = document.createElement('div');
                son.className = 'son';
                son.style.cssText += `
                        transform: translate3d(0, 0, -1000px);
                        background: linear-gradient(
                                35deg,
                                #${Math.random().toString(16).substring(2,8)},
                                #${Math.random().toString(16).substring(2,8)}
                        );
                `;
                sons.push(son);
                papa.appendChild(son);
        });

        sons.forEach((son, key) => {
                const pos = { x: 0, z: -1000, a: 0 };
                const target = { x: papa.offsetWidth, z: 0, a: 30 };
                const tween = new TWEEN.Tween(pos)
                        .to(target, time)
                        .onUpdate( () => {
                                son.style.setProperty('transform', `rotateZ(${pos.a}deg) translate3d( ${pos.x}px, 0, ${pos.z}px )`);
                        })
                        .onStart( () => {
                                son.style.setProperty('opacity', 0.9);
                        })
                        .onComplete ( () => {
                                setTimeout( () => {son.style.setProperty('opacity', 0); }, time);
                        });
                tweens.push(tween);
        });

        tweens.forEach( (tween, key) => {
                tween.chain(tweens[(key + 1) % tweens.length]);
        });

        const animate = () => {
                TWEEN.update();
                requestAnimationFrame(animate);
        };

        tweens.start();
        animate();
</script>

<style>
        #papa {
                margin: auto;
                margin-top: 30px;
                width: 760px;
                height: 480px;
                border: 1px solid gray;
                perspective: 600px;
                position: relative;
        }
        .son {
                position: absolute;
                width: 60px;
                height: 60px;
                border-radius: 50%;
                background: linear-gradient(35deg, tan, skyblue);
                opacity: 0;
                filter: drop-shadow(4px 6px 8px gray);
        }
</style>

马黑黑 发表于 2025-7-6 21:32

本帖最后由 马黑黑 于 2025-7-6 21:33 编辑

tween.js 并不能驱动对象做曲线运动。一楼,通过持续改变 class="son" 的元素的相关值:

—— x : X轴位置
—— z : Z轴位置
—— a : 旋转角度

这些值的改变,使得对象从{ x1, y1, z1 } 到 { x2, y2, z2) 的移动轨迹从直线变为了曲线,之所以酱紫,是利用了CSS的 transform 特征——当对象先旋转在平移,它就会做曲线运动。

红影 发表于 2025-7-6 21:43

还以为是给了路径,原来是利用了css的对象先旋转再平移就会走曲线的特性。
这个做法很巧妙{:4_199:}

红影 发表于 2025-7-6 21:46

本来小球是从左上角过来的,黑黑修改后,成了从远方过来的了{:4_187:}

花飞飞 发表于 2025-7-6 22:02

矮油,这是定点投篮,各种颜色都有。。小球有立体感,漂亮。。
小球从同一点出发,到达同一目的。。
起点和终点不变,球体却在无休止的重复且颜色随机变化。。。。

花飞飞 发表于 2025-7-6 22:05

马黑黑 发表于 2025-7-6 21:32
tween.js 并不能驱动对象做曲线运动。一楼,通过持续改变 class="son" 的元素的相关值:

—— x : X轴位 ...

这么说来之前的粒子能量交换是不是就可以曲线到达了。。。
旋转再平移而成曲线运动,这创意真是绝了。。{:4_173:}妙。。

花飞飞 发表于 2025-7-6 22:13

大哥,你二楼的代码没给全。。少了十几行。。
原来粒子颜色是10个一组在循环。。不是无限的
球体给了线性渐变的颜色,这随机设了两组,上下两次出现的不一样。。

花飞飞 发表于 2025-7-6 22:18

不仅位置有抛物曲线变化,球体还给了阴影,更具立体感。。。。球体大小也有变化。。。颜色有变色。。百忙之中还设了透明度变化。。{:4_170:}

这么复杂又精密的设计,怎么做到了。。神人。。

马黑黑 发表于 2025-7-6 22:56

花飞飞 发表于 2025-7-6 22:18
不仅位置有抛物曲线变化,球体还给了阴影,更具立体感。。。。球体大小也有变化。。。颜色有变色。。百忙之 ...

这个应该是简单的吧,就是繁琐一点而已

马黑黑 发表于 2025-7-6 22:57

花飞飞 发表于 2025-7-6 22:13
大哥,你二楼的代码没给全。。少了十几行。。
原来粒子颜色是10个一组在循环。。不是无限的
球体给了线性 ...

修改的时候系统给吞掉了一部分

马黑黑 发表于 2025-7-6 22:59

花飞飞 发表于 2025-7-6 22:05
这么说来之前的粒子能量交换是不是就可以曲线到达了。。。
旋转再平移而成曲线运动,这创意真是绝了。。 ...

这个N年前用过的了,现在是使用tween驱动数值而已

马黑黑 发表于 2025-7-6 22:59

花飞飞 发表于 2025-7-6 22:02
矮油,这是定点投篮,各种颜色都有。。小球有立体感,漂亮。。
小球从同一点出发,到达同一目的。。
起点 ...

这是N个小球在轮流执勤

马黑黑 发表于 2025-7-6 23:00

红影 发表于 2025-7-6 21:46
本来小球是从左上角过来的,黑黑修改后,成了从远方过来的了

对,原来是做二维的,现在改为三维了

马黑黑 发表于 2025-7-6 23:00

红影 发表于 2025-7-6 21:43
还以为是给了路径,原来是利用了css的对象先旋转再平移就会走曲线的特性。
这个做法很巧妙

这基本是炒旧饭,加了点料子

杨帆 发表于 2025-7-6 23:00

效果惊艳!谢谢马老师经典讲授与示范{:4_191:}

马黑黑 发表于 2025-7-6 23:02

杨帆 发表于 2025-7-6 23:00
效果惊艳!谢谢马老师经典讲授与示范

知识是一脉相承的。这个抛物线运动需要一个基础:

transform: rotate(deg) translate(px);

这样的设定,当deg角度发生变化,对象就会做曲线运动

杨帆 发表于 2025-7-6 23:05

马黑黑 发表于 2025-7-6 23:02
知识是一脉相承的。这个抛物线运动需要一个基础:

transform: rotate(deg) translate(px);


是的,一脉相承,有点明白了,谢谢老师{:4_190:}

马黑黑 发表于 2025-7-6 23:11

杨帆 发表于 2025-7-6 23:05
是的,一脉相承,有点明白了,谢谢老师

{:4_191:}

红影 发表于 2025-7-7 13:04

马黑黑 发表于 2025-7-6 23:00
对,原来是做二维的,现在改为三维了

嗯嗯,还是三维的好看,更迷幻的感觉{:4_173:}
页: [1] 2 3 4 5 6
查看完整版本: 使用tween实现对象的抛物线运动