【问题标题】:Skill cooldown animation effect similar to games like WoW in css/js?技能冷却动画效果类似于css/js中的魔兽之类的游戏?
【发布时间】:2021-04-26 06:24:27
【问题描述】:

我正在尝试制作一种效果,当点击技能图标时,它会进入“冷却”状态,类似于典型 MMO(如 WoW)中的技能进入冷却时间。

我找到了下面的代码来实现这样的效果,但它没有记录在案,我不是很了解,但想对其进行更改。

html:

<table>
<tr>
    <td>
        <div class="skill"></div>
    </td>
    <td>
        <div class="skill"></div>
    </td>
    <td>
        <div class="skill"></div>
    </td>
    <td>
        <div class="skill"></div>
    </td>
    <td>
        <div class="skill"></div>
    </td>
</tr>
</table>

css:

.skill {
    margin: 0px;
    padding: 0px;
    position: relative;
    border: 1px solid #36393E;
    border-radius: 5%;
    width: 44px;
    height: 44px;
    overflow: hidden;
    background-color: transparent;
    background-image: url("skill.png");
    background-repeat: no-repeat;
    background-size: 100%;
}

.cooldown {
    position: absolute;
    opacity: 0.8;
    top: 0px;
    left: 0px;
    height: 100%;
    width: 100%;
}

js:

function cooldown(container, percent) {
    var div = $(container);
    div.empty();
    
    var total = 100;
    if(percent < total) {
        var data = [percent, total - percent];
        var width = div.width();
        var height = div.height();
        var cx = width / 2;
        var cy = height / 2;
        var r = cx * Math.SQRT2;
        var colors = [null, '#AAA'];
        var svgns = "http://www.w3.org/2000/svg";
        var chart = document.createElementNS(svgns, "svg:svg");
        chart.setAttribute("width", width);
        chart.setAttribute("height", height);
        chart.setAttribute("viewBox", "0 0 " + width + " " + height);
        
        var angles = []
        for(var i = 0; i < data.length; i++) angles[i] = data[i] / total * Math.PI * 2;
        startangle = 0;
        for(var i = 0; i < data.length; i++) {
            var endangle = startangle + angles[i];
            
            var x1 = cx + r * Math.sin(startangle);
            var y1 = cy - r * Math.cos(startangle);
            var x2 = cx + r * Math.sin(endangle);
            var y2 = cy - r * Math.cos(endangle);
            
            var big = 0;
            if (endangle - startangle > Math.PI) big = 1;
            
            var path = document.createElementNS(svgns, "path");
            
            var d = "M " + cx + "," + cy + " L " + x1 + "," + y1 +
                " A " + r + "," + r + " 0 " + big + " 1 " +
                x2 + "," + y2 + " Z";
            
            path.setAttribute("d", d);
            if(colors[i]) {
                path.setAttribute("fill", colors[i]);
            } else {
                path.setAttribute("opacity", 0);
            }
            chart.appendChild(path);
            startangle = endangle;
        }   
        
        chart.setAttribute('overflow', 'hidden');
        div.append(chart);
    }
}

$(window).ready(function() {
    $('.skill').each(function() {
        var skill = $(this);
        var div = $('<div />').appendTo(skill).addClass('cooldown');
        var radius = div.parent().width() / 2;
        
        skill.click(function() {
            $({pct: 0}).animate({pct: 100}, {
                duration: 5000,
                step: function (curLeft) { cooldown(div, curLeft); }
            });
        });
    });
});

我设法对其进行了一项我想要的更改,即添加带有冷却时间的文本,如下所示:(尚未在 js 中对其进行更新,但我认为这是我可以自己做的事情)

<div class="skill"><div class="text">5</div></div>

.skill .text {
    font-size: 14px;
    color: #E1E5EB;
    text-shadow: 1px 1px 1px #000000;
    line-height: 44px;
    text-align: center;
    background-color: transparent;
}

我需要帮助的其他更改是:

  • 逆时针而不是顺时针填充。

  • 翻转填充/未填充部分的不透明度(当前为 填充部分是暗的,未填充的部分是亮的,但我想要相反)

【问题讨论】:

  • 翻转不透明度听起来只需要将opacity: 0.8;放入.skill CSS规则集中(因此将0.8设为默认值)并将opacity 1放入.cooldown规则集中(因为1意味着完全不透明。)逆时针填充可能涉及将for(...){ angles[i] = ...}更改为for(...){ angles[data.length - i] = ...}
  • 我实际上已经设法让它按照我想要的方式工作。我在 js var colors = ['#AAA', null]; 中翻转了颜色数组,并在 css 中添加了 background-color: transparent; 以进行冷却。现在我只需要弄清楚如何反转填充方向。

标签: javascript jquery css animation


【解决方案1】:

另一种方法是将conic-gradient 与一些CSS variables 一起使用。这样我们就不需要构建 SVG。

PS:JS里面有cmets来解释它是如何工作的。

const SECOND_IN_MS = 1000;
const UPDATE_INTERVAL = SECOND_IN_MS / 60; // Update 60 times per second (60 FPS)
const SKILL_CLASS = 'skill';
const DISABLED_CLASS = 'disabled';

// Cooldowns per skill in milliseconds
const COOLDOWN_MAP = new Map([
  ['run', 1000],
  ['jump', 2000],
  ['crawl', 3000],
  ['slide', 4000],
  ['tumble', 5000],
]);

// Get skills table from the DOM
const skillsTable = document.querySelector('.skills-table');

// Activate clicked skill
const activateSkill = (event) => {
  const {target} = event;
  
  // Exit if we click on anything that isn't a skill
  if(!target.classList.contains(SKILL_CLASS)) return;
  
  target.classList.add(DISABLED_CLASS);
  target.style = '--time-left: 100%';
  
  // Get cooldown time
  const skill = target.dataset.skill;
  let time = COOLDOWN_MAP.get(skill) - UPDATE_INTERVAL;
  
  // Update remaining cooldown
  const intervalID = setInterval(() => {
    // Pass remaining time in percentage to CSS
    const passedTime = time / COOLDOWN_MAP.get(skill) * 100;
    target.style = `--time-left: ${passedTime}%`;
    
    // Display time left
    target.textContent = (time / SECOND_IN_MS).toFixed(2);
    time -= UPDATE_INTERVAL;
    
    // Stop timer when there is no time left
    if(time < 0) {
      target.textContent = '';
      target.style = '';
      target.classList.remove(DISABLED_CLASS);
      
      clearInterval(intervalID);
    }
  }, UPDATE_INTERVAL);
}

// Add click handler to the table
skillsTable.addEventListener('click', activateSkill, false);
.skill {
  position: relative;
  border: 1px solid #36393E;
  border-radius: 5%;
  width: 44px;
  height: 44px;
  overflow: hidden;
  cursor: pointer;
}

/* Prevents you from clicked the button multiple times */
.skill.disabled {
  pointer-events: none;
}

/* Makes sure we click the skill not anything in it */
.skill > * {
  pointer-events: none;
}

.skill::before {
  content: "";
  background: conic-gradient(
    rgba(0, 0, 0, 0.7) var(--time-left),
    rgba(0, 0, 0, 0.1) var(--time-left));
  position: absolute;
  opacity: 0.8;
  top: 0;
  left: 0p;
  height: 100%;
  width: 100%;
}
<table class='skills-table'>
  <tr>
    <td>
      <!-- data-skill refers to the COOLDOWN_MAP in JS -->
      <div class="skill" data-skill='run'></div>
    </td>
    <td>
      <!-- data-skill refers to the COOLDOWN_MAP in JS -->
      <div class="skill" data-skill='jump'></div>
    </td>
    <td>
      <!-- data-skill refers to the COOLDOWN_MAP in JS -->
      <div class="skill" data-skill='crawl'></div>
    </td>
    <td>
      <!-- data-skill refers to the COOLDOWN_MAP in JS -->
      <div class="skill" data-skill='slide'></div>
    </td>
    <td>
      <!-- data-skill refers to the COOLDOWN_MAP in JS -->
      <div class="skill" data-skill='tumble'></div>
    </td>
  </tr>
</table>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多