持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
一、前言
接上期raycaster选取物品后,今天带大家浅浅试用下gasp动画库,听说还挺nb的这个库。
二、过程
1、 引入
首先还是老套路
npm install gsap
然后在项目里按需引入
import gsap from "gsap"
2、动画函数
首先我们来完成一下小车的动画函数carAnimate
核心就是gsap.to函数
gsap.to(参数1,参数2) 就是告诉动画对象,最终要达到的运动状态
- 参数1告知需要绑定哪个动画对象
- 参数2就是要告知动画最终效果的对象:动画时长、是旋转还是位移变化、或者其它属性的变化
具体函数如下,使用gsap.to函数,确定好动画效果,并绑定了两个函数onComplete和onStart,分别会在动画开始时和动画完成时调用
// 车辆动画
let animateGasp: gsap.core.Tween | null
function carAnimate(): void {
animateGasp = gsap.to(car.position, {
z: 4, // 这里是小车最终会停下的位置
duration: 5, // 开始动画到结束动画一共5秒
ease: "power1.inOut",
// 设置重复次数 -1无限次, 0就是1次,1就是2次
repeat: 0,
// 往返运动
yoyo: true,
// 延迟动画
delay: 2, // 延迟辆2秒
onComplete: () => {
console.log("动画完成了");
// 碰到了,碰撞函数在下一小节实现
if (onIntersect()) {
// 撞倒
gsap.to(build.rotation, {
x: -1.57,
duration: 0,
ease: 'power1.inOut',
repeat: 0
})
}
},
onStart: () => {
console.log("动画开始了");
}
})
}
3、检测碰撞函数
这里的碰撞函数,我是打算实现小车撞倒大楼的效果才加的
下面说到的顶点对象,我也只采取了小车的其中一个点作为检测
car.children[0].geometry.attributes.position
函数内容如下,其中car对象是小车模型,build对象是大楼模型,其余基本可以直接copy了用
// 碰撞检测函数
function onIntersect() {
// 声明一个变量用来表示是否碰撞
let bool = false
// .position 对象局部位置
// .clone() 复制一个新的三维向量
// 网格中心 世界坐标
const centerCoord = car.position.clone()
// 获取网格中 几何对象的顶点对象这里我只取了其中一个点作为碰撞检测
// 而且结构也需要根据实际情况进行调整
const position = car.children[0].geometry.attributes.position
// 顶点三维向量
const vertices = []
// .count 矢量个数
for (let i = 0; i < position.count; i++) {
// .getX() 获取给定索引的矢量的第一维元素
vertices.push(new THREE.Vector3(position.getX(i), position.getY(i), position.getZ(i)))
}
for (let i = 0; i < vertices.length; i++) {
// .matrixWorld 物体的世界坐标变换 -- 物体旋转、位移 的四维矩阵
// .applyMatrix4() 将该向量乘以四阶矩阵
// 获取世界坐标下 网格变换后的坐标
let vertexWorldCoord = vertices[i].clone().applyMatrix4(car.matrixWorld)
// .sub(x) 从该向量减去x向量
// 获得由中心指向顶点的向量
var dir = vertexWorldCoord.clone().sub(centerCoord)
// .normalize() 将该向量转换为单位向量
// 发射光线 centerCoord 为投射的原点向量 dir 向射线提供方向的方向向量
let raycaster = new THREE.Raycaster(centerCoord, dir.clone().normalize())
// 放入要检测的 物体build,也就是大楼,返回相交物体
let intersects = raycaster.intersectObjects([build], true)
if (intersects.length > 0) {
// intersects[0].distance:射线起点与交叉点之间的距离(交叉点:射线和模型表面交叉点坐标)
// dir.length():几何体顶点和几何体中心构成向量的长度
// intersects[0].distance小于dir.length() 表示物体相交
if (intersects[0].distance < dir.length()) {
bool = true
}
}
}
return bool
}
4、整体逻辑
点击元素,调用carAnimate
<div @click="carAnimate">点击启用车辆动画</div>
延迟2s后,小车开动,5s后停下,触发onComplete函数,检测小车与大楼是否相撞,相撞了触发大楼倒下动画
放个效果图给大家伙看看
三、总结
由于是刚刚上手threejs,这个检测碰撞的时机还抓得不够准,可以看到小车已经和大楼重合了,但是得等动画结束,才会触发onComplete函数,从而去调用碰撞检测,但是放render函数里每帧刷新又比较耗性能。
后面得想想法子解决一下这个问题。
今天就时间比较仓促,就只带大家体验了gsap.to函数,还有其他函数我们等下期再一起试试吧。
ps:我是地霊殿__三無,希望本文能对你有所帮助。