一个可以射击的3D直升机的js源码
今天我们来聊一聊一段有趣的前端代码实现——“可以射击的3D直升机”。这段代码结合了3D变换、动画和用户交互,构建出了一个可以射击的3D直升机模型。在这个过程中,我会带你逐步分析代码,看看如何实现一个如此炫酷的效果,并且讲解其中的技术细节。
3D模型的构建
首先,这个项目的核心是通过CSS来构建一个3D直升机模型。整个直升机模型是由多个立方体(cuboids)组合而成。让我们来分析一下核心部分:
.cuboid {
width: 100%;
height: 100%;
position: relative;
}
在这个项目中,每个“立方体”由六个面组成,CSS通过3D变换和绝对定位来创建立方体的各个面。这里的.cuboid__side
类定义了每个立方体面的样式和位置:
.cuboid__side:nth-of-type(1) {
height: calc(var(--thickness) * 1vmin);
width: 100%;
position: absolute;
top: 0;
transform: translate(0, -50%) rotateX(90deg);
}
在这里,calc
函数用于动态计算立方体的尺寸,而translate
和rotate
函数则实现了3D旋转,确保每个面都能精确定位在立方体的相应位置。
核心思路
这些立方体的组合形成了直升机的不同部分,比如驾驶舱、尾翼、螺旋桨等。每个部件都由多个div
组成,利用CSS的transform
属性完成旋转、平移以及3D效果的模拟。通过多个立方体组合起来,这样就实现了一个复杂的3D模型。
技术难点: 在3D世界里,位置和角度的变化都是基于三维坐标系的,所以要确保各个面可以正确地组合,既要考虑到X、Y、Z轴的旋转,也要确保在不同的屏幕尺寸下模型的比例是合适的。
直升机的浮动和旋转动画
构建好模型后,动画效果是让直升机更加生动的关键部分。代码中用了@keyframes
来定义旋转和浮动的动画:
@keyframes float {
50% {
transform: translate(-50%, -65%);
}
}
这个动画会让直升机产生一个上下浮动的效果,模仿了直升机在空中悬浮的状态。这个动画的实现非常简单,通过周期性地改变translate
的Y值,直升机就像在空中轻微飘动一样。
旋转的螺旋桨
直升机的螺旋桨是动态旋转的,使用了@keyframes
和rotate
函数来实现:
@keyframes rotate-tri {
to {
transform: translate3d(-25%,-75%,calc(var(--base-size) * 0.07vmin))
scale(1.25) rotate(-360deg);
}
}
螺旋桨的旋转效果利用rotate
函数实现一个持续的360度旋转,同时加上scale
放大效果,使其看起来更加立体和真实。
技术难点: 如何确保动画的平滑流畅是一个关键点。这里利用了gsap
库来优化动画,保证不同帧率下的动画效果都足够顺滑。同时,多个keyframes
的叠加,也需要确保在不同设备上效果不会产生不必要的卡顿。
用户交互与射击效果
接下来,我们来看一下代码中最有趣的部分:用户交互和射击效果。
document.addEventListener('pointermove', ({ x, y }) => {
const newX = gsap.utils.mapRange(0, window.innerWidth, -BOUNDS, BOUNDS, x);
const newY = gsap.utils.mapRange(0, window.innerHeight, BOUNDS, -BOUNDS, y);
gsap.set(document.documentElement, {
'--rotate-x': newY,
'--rotate-y': newX,
});
});
在这段代码中,监听了pointermove
事件,意味着当用户移动鼠标时,直升机会跟随鼠标的移动进行旋转。这种效果通过gsap.utils.mapRange
函数将屏幕宽度和高度的范围映射到一定的角度范围,实现了用户鼠标移动和直升机旋转的联动。
射击实现
最酷的部分莫过于直升机的射击功能了。当用户按下鼠标时,直升机会从发射器中射出子弹:
document.addEventListener('pointerdown', () => {
FIRING = true;
});
document.addEventListener('pointerup', () => {
FIRING = false;
});
射击的逻辑是在按下鼠标时开启FIRING
状态,每隔一帧生成一个子弹元素,并通过gsap
将它快速移动出视野:
if (FIRING) {
const AMMO = document.createElement('div');
AMMO.innerHTML = `<div class="cuboid cuboid--ammo"><div class="cuboid__side"></div></div>`;
AMMO.className = 'helicopter__ammo';
gsap.to(AMMO, {
xPercent: () => gsap.utils.random(-3000, -2000),
onComplete: () => AMMO.remove(),
});
}
射击功能的实现并不复杂,但是如何确保子弹的生成和动画效果保持高效和流畅是一个需要注意的点。代码中使用了gsap.ticker.fps(24)
来设置动画的帧率,确保动画不会因为频繁的子弹生成而导致页面卡顿。
夜间模式切换
代码最后实现了一个夜间模式和日间模式的切换功能,通过点击按钮来改变页面的主题。代码监听了用户的点击事件,使用gsap.set
来动态切换页面的颜色主题:
BUTTON.addEventListener('click', () => {
const NEW_THEME = window.__THEME === THEMES.DARK ? THEMES.LIGHT : THEMES.DARK;
window.__setTheme(NEW_THEME);
gsap.set('button', {
attr: { 'aria-pressed': NEW_THEME === THEMES.DARK ? 'false' : 'true' },
});
gsap.set('html', { '--on': window.__THEME === THEMES.DARK ? 0 : 1 });
});
这种主题切换的实现很常见,但通过gsap
的动画效果让切换过程显得更加流畅。
结语
这段代码展示了一个复杂且有趣的3D直升机模型,结合了3D建模、动画和用户交互等多种技术。在这个过程中,我们利用了CSS的transform
属性来构建3D效果,并通过gsap
库实现平滑的动画和用户交互体验。整体项目的核心思路是将3D建模和前端动画技术相结合,创造一个动态且可交互的页面效果。
这个实现看似简单,但在实际开发中,如何确保动画的流畅、模型的精度以及用户交互的实时响应都是关键难点。如果你也对这种炫酷的前端技术感兴趣,不妨试着自己实现一个,可能会有意想不到的收获哦!