前言

看本文章前建议先看上一篇《Cocos Creator 制作仿DNF血条》,这样就会明白优化的处理有哪些了。

上一章中,我们的血条它的逻辑是两条血条来回切换,包括颜色,宽度,层级,控制起来其实是非常不方便的, 逻辑也变得复杂了,而且没有考虑到秒杀的情况下血条的处理,所以这次根据同事提供的好主意我重新写了一版。

教程

原理

我们可以将第二条血条作为一个固定的底色来控制,只有当第二条血没有的时候,我们将其设置白色的,这样每次血条width控制其实都在第一条上面。

也就是说,血条的宽度控制其实一直是第一条在循环控制,扣完了马上切换成第二条的颜色,然后宽度设满,第二条的颜色变成第三条,直到没有血条了,第二条变成白色的就行了。

第二条血条宽度一直不变。

所以我们的层级结构就变得更加简单了。

三个子节点就完成了,一个bg底色,两个血条,two同时是血条,也是白色的底色。

代码

代码上就更加简单了,我想了下没必要拆分一个独立脚本来控制血条,直接给他们的父级节点boss_blood挂载一个脚本即可。

import { _decorator, Component, Node, UITransform, Sprite, math } from "cc";
const { ccclass, property } = _decorator;

@ccclass("BossBlood")
export class BossBlood extends Component {
  @property({ type: Node, displayName: "第一条血条" })
  private one: Node;
  @property({ type: Node, displayName: "第二条血条" })
  private two: Node;
  private maxWidth: number = 0;
  private colors: Array<string> = ["#AB1A22", "#FA8600", "#92C702", "#007CC8"];
  private activeColorIndex: number = 0;
  private defaultColor: math.Color = math.color("#ffffff");
  //计算
  private total: number = 0; //总血条数
  private rate: number = 1; //比例
  private hp: number = 0; //总hp
  private activeHp: number = 0; //当前hp
  private activeIndex: number = 1; //当前第几条血条

  onLoad() {
    //获取ui和精灵组件
    this.one["_mySprite"] = this.one.getComponent(Sprite);
    this.one["_myUITransform"] = this.one.getComponent(UITransform);
    this.two["_mySprite"] = this.two.getComponent(Sprite);
    this.two["_myUITransform"] = this.two.getComponent(UITransform);
    //获取血条宽度
    this.maxWidth = this.one["_myUITransform"].width;

    this.setBlood(2000, 500);
    setInterval(() => {
      this.buckleBlood(20);
    }, 30);
  }

  /**
   * @description: 设置血条
   * @param {number} hp
   * @param {number} max
   * @Date: 2022-07-31 17:21:20
   * @Author: mulingyuer
   */
  public setBlood(hp: number, max: number) {
    //重置血条
    this.resetBlood();
    //重置数据
    this.total = Math.floor(hp / max);
    this.rate = this.maxWidth / max;
    this.hp = hp;
    this.activeHp = hp;
    this.activeColorIndex = 0;

    //初次血条颜色
    if (this.total === 1) {
      this.one["_mySprite"].color = this.getNextColor();
      this.one.active = true;
    } else {
      this.one["_mySprite"].color = this.getNextColor();
      this.one.active = true;
      this.two["_mySprite"].color = this.getNextColor();
      this.two.active = true;
    }
  }

  /**
   * @description: 扣血
   * @param {number} val
   * @Date: 2022-07-31 17:35:28
   * @Author: mulingyuer
   */
  public buckleBlood(val: number): void {
    if (this.activeHp <= 0) return;

    //秒杀的情况
    if (val >= this.activeHp) {
      this.activeHp = 0;
      this.activeColorIndex = this.total - 1;
      this.activeIndex = this.total;
      if (this.total === 1) {
        this.one["_myUITransform"].width = 0;
      } else {
        this.two["_mySprite"].color = this.defaultColor;
        this.one["_myUITransform"].width = 0;
        this.one["_mySprite"].color = this.getNextColor();
      }
      return;
    }

    //指定血条扣除
    let remainder: number = this.specBloodBuckle(this.one, val);
    while (remainder > 0) {
      //一条血不够扣
      this.activeIndex += 1;
      this.one["_mySprite"].color = this.two["_mySprite"].color;
      this.one["_myUITransform"].width = this.maxWidth;
      //第二条血颜色变成下一条的颜色或者没有了就变成默认色
      if (this.activeIndex >= this.total) {
        this.two["_mySprite"].color = this.defaultColor;
      } else {
        this.two["_mySprite"].color = this.getNextColor();
      }

      //继续扣第一条血
      remainder = this.specBloodBuckle(this.one, remainder, true);
    }
  }

  /** 指定血条扣血 */
  private specBloodBuckle(blood: Node, val: number, isRemainder = false): number {
    //扣除血量
    if (!isRemainder) this.activeHp -= val;
    if (this.activeHp < 0) this.activeHp = 0;
    //控制血条
    const activeWidth = blood["_myUITransform"].width;
    const buckleVal = isRemainder ? val : val * this.rate;
    const resultVal = activeWidth - buckleVal;

    if (this.activeHp <= 0) {
      //没血了
      blood["_myUITransform"].width = 0;
      return 0;
    } else if (resultVal < 0) {
      //一条血不够扣了
      blood["_myUITransform"].width = 0;
      return Math.abs(resultVal);
    } else {
      //正常扣血
      blood["_myUITransform"].width = resultVal;
      return 0;
    }
  }

  /** 初始化血条 */
  private resetBlood() {
    const arr = [this.one, this.two];
    arr.forEach((node) => {
      node["_myUITransform"].width = this.maxWidth;
      node["_mySprite"].color = this.defaultColor;
      node.active = true;
    });
  }

  /** 获取指定下标的血条颜色 */
  private getNextColor(): math.Color {
    if (this.activeColorIndex >= this.colors.length) {
      this.activeColorIndex = 0;
    }

    return math.color(this.colors[this.activeColorIndex++]);
  }
}

基本上就这样,当我们需要使用血条的时候,只需要通过boss_blood节点,获取到它挂载的脚本BossBlood组件,调用即可。

import { BossBlood } from "../blood/BossBlood";

const bossBloodScript = this.bossBlood.getComponent(BossBlood);
bossBloodScript.setBlood(2000, 500);
bossBloodScript.buckleBlood(50);  //扣血操作
分类: Cocos Creator 标签: Cocos Creator血条dnf血条

评论

暂无评论数据

暂无评论数据

目录