css路径找不到_一个纯CSS的机械臂搬运东西的小动画

213ac8cd0efe3480cced22b2b5c2fc7f.png
fc4011a5a4d90c8deed73f386b005310.png
CSS小动画https://www.zhihu.com/video/1129028940224000000

上周用纯CSS做了个机械臂的动画效果,简单分享下代码心得,希望可以给做类似需求的小伙伴一点参考,然后文末会有一些小问题欢迎大佬解答。

首先是做这个的时候的思路,一开始网上搜了下,CSS+机械臂,然后只看到一些图片,好在这些图片给了我灵感。一开始想用CSS模仿画一个类似的二维平面的机械臂(原谅我画的不美观)然后让部分部位有动的感觉就可以了。接着我在看实物的时候突然想到,实物的运作不就是机械臂关节的部位可以按一定的角度旋转,然后几个部位一起旋转让上方的爪子可以运动到某一个位置吗?用CSS我也可以模拟这样的行为,每一段手臂用一个div,然后让这个div旋转不就好了吗,rotate是关键函数。

<div class="arm-base" :class="[{[arm_type]: arm_type, working: working}]">
  <div class="arm-section arm-section-1">
    <div class="arm-section arm-section-2">
      <div class="arm-section arm-section-3">
        <div class="arm-section arm-section-4">
          <div class="arm-claw">
            <slot name="captured"></slot>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

html比较简单,一个div画底座,里面连续的四个div画手臂,再往里是一个div画爪子,最后里面放个slot(这里用的是vue的组件写法,react也有类似的玩意,ng应该也有)。这个slot给调用这个组件的地方自由的设置机械臂抓的是什么物体。

  .arm-section {
    position: absolute;
    width: 20px;
    height: 20px;
    background-color: $map_bg;
    border: 3px solid $arm_bg;
    border-radius: 50%;
    bottom: 97px;
    left: -3px;
    transform-origin: center 112px;
    &:after {
      content: '';
      position: absolute;
      left: 7px;
      right: 7px;
      top: 7px;
      bottom: 7px;
      background-color: $arm_bg;
    }
    &:before {
      content: '';
      position: absolute;
      width: 8px;
      height: 70px;
      background-color: $arm_bg;
      top: 25px;
      left: 5px;
      border-radius: 5px;
    }
  }

CSS就不完全贴代码了(主要是写的丑),注意比较关键的一句是transform-origin: center 112px;设置每个“手臂”的旋转基点位置。然后arm-section-1和4的设置会稍微不同。

接下来的就是,想一下机械臂的行动摆放位置和行动路径。我这里是先把这个组件放到页面上去,然后随便设置了一下机械臂的初始状态下各个关键所处在的角度。嗯,这里会记录5个角度的数值,4个手臂的和爪子的旋转角度。

然后我希望机械臂可以依次去抓右边的三个盖子,这里我是把底座固定好之后,先在slot中放一个和盖子相同的div,再一点点的去调试每一个旋转部位的角度,让slot中的这个盖子的div和右边推出来的div的位置基本重合(像素眼大佬看到有点差异不要吐槽啊)。这里提个小问题是,有没有什么更先进和科学的方式可以直接计算出各个部位的旋转角度,而不是手动去测?

测好右边三个点的距离后,再测一下它要到达的右上方的那个点所应该旋转的角度,这里会记录下五组数据。初始点,三个抓取点,一个放置点。这里其实可以有更多的,感兴趣的朋友可以多测定几组,让你的机械臂可以按照你想要的轨迹去运动,跳舞也是没有问题的。

然后的事情就比较简单了,我这里是三组,每组6秒的动画,连在一起18s,每6秒的动画是这样的,先是机械臂从初始位置出发,到达抓取位置,悬停一点时间,抓取位置的盖子消失,爪子上的盖子显示出来,然后机械臂从抓取位置途经初始位置(这里路途中可以是任意的位置,我是偷懒就用了初始位置)移动到放置位置,爪子上的盖子消失,放置位置的动画执行。机械臂回到初始位置。接着再去下一个抓取位置直到动画结束,再循环播放。

@mixin lid-arm-keyframes($name, $start, $first, $second, $threed, $point) {
  animation: $name 18s normal infinite;
  animation-delay: 1.5s;
  @keyframes #{$name} {
    0% {
      // 初始位置
      transform: rotate($start);
    }
    8% {
      // 第一次抓取位置
      transform: rotate($first);
    }
    9% {
      // 悬停
      transform: rotate($first);
    }
    16% {
      // 路径起点位置
      transform: rotate($start);
    }
    25% {
      // 放置位置
      transform: rotate($point);
    }
    26% {
      // 悬停
      transform: rotate($point);
    }
    34% {
      // 路径起点位置
      transform: rotate($start);
    }
    42% {
      // 第二次抓取
      transform: rotate($second);
    }
    43% {
      // 悬停
      transform: rotate($second);
    }
    51% {
      // 路径
      transform: rotate($start);
    }
    58% {
      // 放置位置
      transform: rotate($point);
    }
    59% {
      // 悬停
      transform: rotate($point);
    }
    67% {
      // 路径
      transform: rotate($start);
    }
    75% {
      // 第三次抓取位置
      transform: rotate($threed);
    }
    76% {
      // 悬停
      transform: rotate($threed);
    }
    86% {
      // 路径
      transform: rotate($start);
    }
    91% {
      // 放置位置
      transform: rotate($point);
    }
    92% {
      // 悬停
      transform: rotate($point);
    }
    100% {
      // 回归起点
      transform: rotate($start);
    }
  }
}
&.working {
  .arm-section-1 {
    @include lid-arm-keyframes(arm-section-1-working, -10deg, -12deg, 10deg, 26deg, 12deg);
  }
  .arm-section-2 {
    @include lid-arm-keyframes(arm-section-2-working, -50deg, 45deg, 33deg, 25deg, 22deg);
  }
  .arm-section-3 {
    @include lid-arm-keyframes(arm-section-3-working, 110deg, 85deg, 68deg, 53deg, 20deg);
  }
  .arm-section-4 {
    @include lid-arm-keyframes(arm-section-4-working, 70deg, 50deg, 56deg, 50deg, 20deg);
  }
  .arm-claw {
    @include lid-arm-keyframes(arm-claw-working, 0, 12deg, 13deg, 26deg, 105deg);
  }
}

这里的动画delay了1.5秒是为了配合右下的动画,然后正好是一个循环不断抓取的过程。有一点懒的地方是,没有做爪子张开闭合的抓取动画。

这一段的一开始写的时候我是直接每一个都写了个keyframes,然后copy了四份。后来实在忍不下去,大概想到了sass里的mixin,不知道可以用来写keyframes或者animation之类的,因为之前没这么用过,所以搜了一下,这里想吐槽一下w3cplus,我记得很久以前这个网上应该可以随便看的,现在要付费才能看完整的内容了?怎么,这些知识的价值很高的吗?一篇文章两块多?我觉得知识收费并无不妥,但是个人还是更喜欢把编程中遇到的有意思的解决方式和思路分享出来。然后后面不知道哪里看到可以这样写,然后这个keyframes的name加#[]的地方卡了一下,好吧,原谅我写的太生疏了。写完之后看起来还是蛮清晰的。

最后有个小问题,其实一开始我是想动画中机械臂的行动路径用JS去控制,然后看了一下好像没有找到特别好的方式用JS去控制keyframes中的参数,每次改变都新增一个?写起来给人感觉怪怪的。所以目前是设定好固定一套行动路径,在别的地方用到,再加了一套行动路径的class。我这个场景下用到是没啥问题的,不过还是希望可以找一个比较优雅的用JS改变keyframes的写法。

补一下代码地址

lsl1989/manipulator​github.com
5c559ab4d69f47810f4e26a7feb556eb.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值