- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
本文,我们将一起学习,使用纯 CSS,实现如下所示的动画效果:
上面的动画效果,非常有意思,核心有两点:
嗯?很有意思的效果。 看上去,我们好像使用 CSS 实现了碰撞检测 .
然而,实际情况真的是这样吗?让我们一起一探究竟! 。
这里其实我们并没有实现碰撞检测,因为小球和小球之间接触时,并没有发生碰撞效果.
我们只实现了,小球与边界之间的碰撞反应。不过这里,也并非碰撞检测,我们只需要设置好单个方向的运动动画,并且设置 animation-direction: alternate; 即可! 。
下面,我们一起来实现单个方向上的运动动画:
<div></div>
div {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border-radius: 50%;
background: #0cf;
animation: horizontal 3s infinite linear alternate;
}
@keyframes horizontal {
from {
left: 0;
}
to {
left: calc(100vw - 100px);
}
}
简单解读一下:
position: absolute
绝对定位,利用 left
进行 X 轴方向的运动 div
运动的距离为 left: calc(100vw - 100px)
,元素本身的高宽都是 100px
,因此相当于运动到屏幕的最右侧 alternate
也就是 animation-direction: alternate;
的简写,表示 动画在每个循环中正反交替播放 这样,我们就巧妙的实现了,在视觉上,小球元素移动到最右侧边界时,回弹的效果:
好,有了上面的铺垫,我们只需要再如法炮制 Y 轴方向的运动即可.
利用元素的 top 进行 Y 轴方向的运动:
div {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border-radius: 50%;
background: #0cf;
animation:
horizontal 3s infinite linear alternate,
vertical 3s infinite linear alternate;
}
@keyframes horizontal {
from {
left: 0;
}
to {
left: calc(100vw - 100px);
}
}
@keyframes vertical {
from {
top: 0;
}
to {
top: calc(100vh - 100px);
}
}
我们增加了一个 vertical 3s infinite linear alternate Y 轴的运动动画,实现小球从 top: 0 到 top: calc(100vh - 100px); 的运动.
这样,我们就成功的得到了 X、Y 两个方向上的小球运动,它们叠加在一起的效果如下:
颜色的变化可以忽略,GIF 录制问题.
当然,此时的问题在于,缺少了随机性,小球的始终在左上和右下角之间来回运动.
为了解决这个问题,我们需要添加一定的随机性,这个问题也要解决,我们只需要让两个方向上运动时间不一致即可.
我们修改一下代码,让 X、Y 轴的运动时长不一致即可:
div {
position: absolute;
// ...
animation:
horizontal 2.6s infinite linear alternate,
vertical 1.9s infinite linear alternate;
}
如此一来,整体的效果就好上了不少,由于整个动画是无限反复进行的,随着时间的推进,整个动画呈现出来的就是 无序、随机的运动 :
当然,上面的效果基本上没有什么太大的问题了,但是代码层面不够优雅,主要有两点问题:
top
和 left
,性能相对较差,需要使用 transform
进行替代 100px
,由于 DEMO 中小球的大小是 100px x 100px
,并且在动画的代码中也使用了 100px
这个值进行了运动终态的计算,因此如果想修改小球的元素大小,需要改动地方较多 上述两个问题,使用 transform: translate() 都可以解决,但是我们为什么一开始不用 transform 呢?
我们来尝试一下,使用 transform 替代 top、left:
div {
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
border-radius: 50%;
background: #0cf;
animation:
horizontal 2.6s infinite linear alternate,
vertical 1.9s infinite linear alternate;
}
@keyframes horizontal {
from { transform: translateX(0); }
to { transform: translateX(calc(100vw - 100%)); }
}
@keyframes vertical {
from { transform: translateY(0); }
to { transform: translateY(calc(100vh - 100%)); }
}
上述代码中,我们使用了 transform 替代 top、left 运动。并且,将动画代码中的 100px 替换成了 100% ,这一点的好处是,在 transform: translate 中, 100% 表示的是元素本身的高宽,这样,当我们改变元素本身的大小时,就无需再改变 @keyframes 中的代码,通用性更强.
我们来看看修改后的效果:
有点问题!预想中的效果并没有出现,整个动画只有 Y 轴方向上的动画效果.
这是什么原因呢?
其本质在于,定义的 vertical 1.9s infinite linear alternate 的垂直方向的动画效果覆盖了在其之前定义的 transform: translateX(calc(100vw - 100%)) 动画效果.
说人话就是 X、Y 轴的动画都使用了 transform 属性, 两者之间造成了冲突 .
在之前,这种情况基本是无解的,常见的解决方案就是:
top
、 left
替代 transform 不过,到今天,这个问题有了更好的解法!也就是 CSS animation 家族中的新属性 —— animation-composition .
这是一个非常新的属性,表示 动画合成属性 ,从 Chrome 112 版本开始支持.
有三种不同的取值:
{
animation-composition: replace; // 表示动画值替换
animation-composition: add; // 表示动画值追加
animation-composition: accumulate; // 表示动画值累加
}
本文不会详细介绍 animation-composition ,感兴趣的可以看看 MDN 的属性介绍或者 XBOXYAN 大佬的这篇文章 -- 了解一下全新的CSS动画合成属性animation-composition 。
这里,基于上面的代码,我们只需要再多设置一个 animation-composition: accumulate 即可解决问题:
div {
animation:
horizontal 2.6s infinite linear alternate,
vertical 1.9s infinite linear alternate;
animation-composition: accumulate;
}
此时,我们就能通过一个元素,利用 transform 得到 X、Y 两个方向位移动画的合成效果,也就是我们想要的效果:
解决了位移动画的问题,我们就只剩下最后一个问题了,如何在碰撞的瞬间,实现颜色的切换?
这里也非常好解决,由于我们是知道每一轮 X、Y 方向上的动画时长的,那我们只需要在每次这个结点上,切换一次颜色即可.
并且,由于颜色不是过渡变换,而是直接的跳变,所以,我们需要用到 animation 中的 animation-timing-function: steps() ,也就是步骤缓动函数.
对 animation-timing-function: steps() 还不太了解的,可能需要先补一补基础,可以看看这一篇文章: 深入浅出 CSS 动画 。
举个例子,假设 X 方向上,单次的动画时长为 3s,那我们可以设置一个 steps(10) 的颜色动画,总时长为 30s,这样,每隔 3s 就会触发一次 steps() 步骤动画,颜色的变化就能够和小球与边界的碰撞动画发生在同一时刻.
那如何快速实现颜色的变化呢?利用 filter: hue-rotate() 即可快速实现颜色的变化.
理解一下下面的代码:
<div class="normal"></div>
<div class="steps"></div>
div {
width: 200px;
height: 200px;
background: #fc0;
}
.normal {
animation: colorChange 10s linear infinite;
}
.steps {
animation: colorChange 10s steps(5) infinite;
}
@keyframes colorChange {
100% {
filter: hue-rotate(360deg);
}
}
这里,我们用 filter: hue-rotate(360deg) 的改变,实现颜色的变化,观察下面的动图,理解 steps(5) 的作用.
animation: colorChange 10s linear infinite
表示背景动画的过渡变化 animation: colorChange 10s steps(5) infinite
,这里表示 10s 的动画分成 5 步,每两秒,会触发一次动画: 效果如下:
理解了这一步,我们就可以把颜色的变化,也一起叠加到上述的小球变化中:
div {
animation:
horizontal 2.6s infinite linear alternate,
vertical 2s infinite linear alternate,
colorX 26s infinite steps(10),
colorY 14s infinite steps(7);
animation-composition: accumulate;
}
@keyframes horizontal {
from { transform: translateX(0); }
to { transform: translateX(calc(100vw - 100%)); }
}
@keyframes vertical {
from { transform: translateY(0); }
to { transform: translateY(calc(100vh - 100%)); }
}
@keyframes colorX {
to {
filter: hue-rotate(360deg);
}
}
@keyframes colorY {
to {
filter: hue-rotate(360deg);
}
}
这样,我们就成功的得到了题图中的效果:
完整的代码,你可以戳这里: Random Circle Path 。
OK,上面,我们就把整个效果的完整原理剖析了一遍.
掌握了整个原理之后,我们就可以把这个效果应用于不同场景中.
譬如,假设我们有这么一张图片:
基于上面的效果,稍加改造,我们就可以得到类似的如下效果:
<div></div>
div {
width: 220px;
height: 97px;
background: linear-gradient(#f00, #f00), url(https://s1.ax1x.com/2023/08/15/pPQm9oT.jpg);
background-blend-mode: lighten;
background-size: contain;
animation: horizontal 3.7s infinite -1.4s linear alternate,
vertical 4.1s infinite -2.1s linear alternate,
colorX 37s infinite -1.4s steps(10),
colorY 28.7s infinite -2.1s steps(7);
animation-composition: accumulate;
}
@keyframes horizontal {
from { transform: translateX(0); }
to { transform: translateX(calc(100vw - 100%)); }
}
@keyframes vertical {
from { transform: translateY(0); }
to { transform: translateY(calc(100vh - 100%)); }
}
@keyframes colorX {
to {
filter: hue-rotate(2185deg);
}
}
@keyframes colorY {
to {
filter: hue-rotate(1769deg);
}
}
效果如下:
上面的 DEMO 是基于元素背景色的,本 DEMO 是基于图片的,因此这里多了一步,利用 mix-blend-mode ,实现了图片颜色的变化.
完整的代码,你可以戳这里: CodePen Demo -- Random DVD Path 。
OK,我们再进一步,基于上面的效果,我们可以实现各种有趣的粒子效果,如果同时让页面存在 1000 个粒子呢?
下面是我使用 CSS-Doodle 实现的纯 CSS 的粒子效果,其核心原理与上面的保持一致,只是添加了更多的随机性:
Amazing!是不是非常有趣,整个效果的代码基于 CSS-doodle 的语法,不超过 40 行。完整的代码,你可以戳这里: CSS Doodle - CSS Particles Animation 。
总结一下,本文介绍了如何巧妙的利用 CSS 中的各种高阶技巧,组合实现类似于碰撞场景的动画效果。创建出了非常有趣的 CSS 动画,期间各种技巧的组合运用,值得好好琢磨学习.
OK,本文到此结束,希望本文对你有所帮助 😃 。
想 Get 到最有意思的 CSS 资讯,千万不要错过我的公众号 -- iCSS前端趣闻 😄 。
更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏.
如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知.
想 Get 到最有意思的 CSS 资讯,千万不要错过我的 iCSS 公众号 😄 :
最后此篇关于震惊!CSS也能实现碰撞检测?的文章就讲到这里了,如果你想了解更多关于震惊!CSS也能实现碰撞检测?的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在用 jQuery Collision 编写这个游戏,它使用键盘按键来移动 div,当一个 div 接触另一个 div 时,它应该防止重叠。 我到底该怎么做? HTML ----
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: Java 2D Collision? 嘿,大家好,我有另一篇关于这个问题的帖子刚刚消失了,所以我想我会尝试得到一些关
嘿伙计们,我正在制作一个 2D java 游戏,我正在尝试找出如何制作一个好的碰撞代码。我目前正在使用以下代码: public void checkCollision() { Rect
我的意思是,当我与实体的侧面碰撞并想要跳跃时,我无法向右/向左移动,因为当我与右侧/左侧的实体碰撞时,我有一个标志可以防止这种情况发生,例如所以: 这是我用来检测碰撞的代码: public void
所以我正在运行 collide_mask 检查,以删除与玩家 Sprite 碰撞时的生物实例。它工作得很好。 pygame.sprite.spritecollide(player, mobs, Tru
我正在研究我的砖 block splinter 机,并制作一个适当的碰撞系统,以便使球逻辑地切换方向,我必须检测球与砖 block 的哪一侧碰撞。这是我当前的脚本: int sprite_collid
我做了一个类似颜色切换的游戏。唯一的问题是玩家与每种颜色发生碰撞...... 这是我从github上获取的代码: https://github.com/prometheon/MLNimbleNinja
测试我的游戏,当用户和怪物发生碰撞时,我希望弹出警报但没有成功: function die() { for (var i = 0; i < monster.length; i++) { i
我对 vector 很陌生,这是我第一次真正使用它们进行碰撞检查。这是我的项目,我对如何实现碰撞感到困惑。我目前的碰撞检查和响应代码似乎是……糟糕的设计。 这是我的代码: for(auto it =
我是 javascript 的新手,正在尝试找出如何与球和木板发生碰撞,这将停止游戏并提醒玩家“你输了”。但我只想让红球击中木板,让蓝球不接触地继续前进。这是我正在处理的代码。 (我不介意你是否可以帮
很抱歉提出奇怪的问题,我还是 Android 编程的新手。 我有以下代码: import android.content.DialogInterface.OnClickListener; import
我有 6 个 UIImageView,每个都连接到 UIPanGestureRecognizer,它们都连接到相同的方法。方法是: - (IBAction)handlePan:(UIPanGestur
我想根据某些对象的轴对齐边界框检查视锥体,以粗略检查这些对象是否在视野中。速度不是什么大问题。 最佳答案 我发现构建视锥体的世界空间模型并检查与它的 bbox 碰撞是错误的方法。 一个更简单的方法是以
我项目中的所有这些代码都运行良好,但我遇到了一些问题。当飞机接触到屏幕的边界时,它会在接触后开始旋转。我不知道如何让它在碰到屏幕边界时不旋转。只有在我使用时才会出现这个问题: plane.physic
在应用程序启动时,我在后台线程中删除旧的 CoreData 行,下面是我的代码。我的问题类似于城市街道问题。所以,我有两个实体,Street 和 City,我有一个关系 City > Street,因
我试图不接触穴居人和其他带有碰撞位掩码的图像,但我的穴居人击中了一切。 func addCaveManBitMasks(){ caveManNode.physicsBody?.category
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
如何在 PyGame 中找到字符和图像之间的碰撞?我已经从图像中绘制了一个玩家,并从瓷砖中绘制了墙壁,那么我如何检测这些碰撞? 最佳答案 如果你使用pygame Rect类来表示对象的边界,您可以使用
我正在使用 ftok() 为 C 应用程序使用的共享内存段生成标识符。我有问题,在一个盒子上我与 root 使用的标识符发生冲突。在这种情况下,我可以通过破解代码来修复它,但我想要一个更强大的解决方案
这个问题在这里已经有了答案: JavaScript: Collision detection (10 个回答) 10 个月前关闭。 检测 2 个物体(墙壁)碰撞的好方法。是的,不仅仅是检测,还有进一步
我是一名优秀的程序员,十分优秀!