木灵鱼儿
阅读:598
Cocos Creator 制作仿DNF血条
前言
最近在想boss的血条制作,比较简单的就是单条血条,但是我想弄个想类似dnf那种,血条减完一条还有一条的那种,于是有了本篇文章
预览图
教程
节点结构
由于cocos原生没有这种血条,我们需要手动创建,我先通过两个单色精灵模拟血条的框架,大概就是一个大的节点里面包含一个小的节点,两个节点颜色不一致,里面的节点宽高都小4px,这样就模拟出边框的效果了。
然后就是血条了,我的原理是通过两个血条节点进行来回替换实现的,当血量有两管血的时候,一开始就扣除时控制第一条血条的width,然后这是这个计算非常重要,它需要return出余值,当它存在余值的时候,说明还能扣血, 此时一瞬间将第一条置于第二条的底下,然后继续扣除第二条的width,从而往复循环,达到效果。
血条来来回的切换的时候,需要控制好它的层级结构。
源码
/*
* @Author: mulingyuer
* @Date: 2022-07-27 21:00:02
* @LastEditTime: 2022-07-30 01:04:37
* @LastEditors: mulingyuer
* @Description: boss血条
* @FilePath: \cocos-aircraft-war\assets\script\article_blood\BossArticleBlood.ts
* 怎么可能会有bug!!!
*/
import { Node, Sprite, math, UITransform } from "cc";
type BloodOptions = {
twoBlood: Node;
oneBlood: Node;
};
class BossArticleBlood {
private colors: Array<string> = ["#AB1A22", "#FA8600", "#92C702", "#007CC8"];
private oneBlood: Node;
private twoBlood: Node;
private totalBlood: number = 0;
private maxBloodVolume: number = 0;
//当前激活的属性
private activeColorIndex: number = 0;
private activeBloodIndex: number = 0;
private hp: number = 0; //最大值
private rate: number = 1; //扣除的比例
constructor(options: BloodOptions) {
const { twoBlood, oneBlood } = options;
this.oneBlood = oneBlood;
this.twoBlood = twoBlood;
//获取血条宽度
const bloodUIData = this.oneBlood.getComponent(UITransform);
this.maxBloodVolume = bloodUIData.width;
this.oneBlood["_mySprite"] = this.oneBlood.getComponent(Sprite);
this.oneBlood["_myUITransform"] = bloodUIData;
this.twoBlood["_mySprite"] = this.twoBlood.getComponent(Sprite);
this.twoBlood["_myUITransform"] = this.twoBlood.getComponent(UITransform);
this.reset();
}
/* 重置 */
private reset() {
this.activeColorIndex = 0;
this.oneBlood.active = false;
this.twoBlood.active = false;
this.oneBlood["_myUITransform"].width = this.maxBloodVolume;
this.twoBlood["_myUITransform"].width = this.maxBloodVolume;
this.oneBlood.setSiblingIndex(1);
this.twoBlood.setSiblingIndex(0);
}
/**
* @description: 设置血条
* @param {number} hp
* @param {number} max
* @Date: 2022-07-27 22:44:45
* @Author: mulingyuer
*/
public setBlood(hp: number, max: number) {
this.reset();
this.hp = hp;
this.rate = this.maxBloodVolume / max;
//计算血条数量
this.totalBlood = Math.floor(hp / max);
this.activeBloodIndex = this.totalBlood;
//设置血条颜色
if (this.totalBlood === 1) {
this.twoBlood.active = false;
this.oneBlood["_mySprite"].color = this.getColor(0);
this.oneBlood.active = true;
} else {
this.oneBlood["_mySprite"].color = this.getColor(this.getNextIndex());
this.twoBlood["_mySprite"].color = this.getColor(this.getNextIndex());
this.oneBlood.setSiblingIndex(1);
this.twoBlood.setSiblingIndex(0);
this.oneBlood.active = true;
this.twoBlood.active = true;
}
}
/**
* @description: 扣血
* @param {number} val
* @Date: 2022-07-27 22:48:10
* @Author: mulingyuer
*/
public buckleBlood(val: number): void {
if (this.hp <= 0) return;
//一条血
if (this.totalBlood === 1) {
this.specBloodBuckle(this.oneBlood, val);
return;
}
//多条血条
let remeaning = this.specBloodBuckle(this.oneBlood, val);
while (remeaning > 0) {
this.activeBloodIndex -= 1;
const oldBlood = this.oneBlood;
//更改定义
this.oneBlood = this.twoBlood;
this.twoBlood = oldBlood;
this.oneBlood.setSiblingIndex(1);
this.twoBlood.setSiblingIndex(0);
this.twoBlood["_mySprite"].color = this.getColor(this.getNextIndex());
this.twoBlood["_myUITransform"].width = this.maxBloodVolume;
if (this.activeBloodIndex <= 1 && this.twoBlood.active) {
this.twoBlood.active = false;
}
//再次扣第一条血
remeaning = this.specBloodBuckle(this.oneBlood, remeaning, true);
}
}
/* 指定进度条扣血 */
private specBloodBuckle(blood: Node, val: number, isRateVal = false): number {
if (!isRateVal) this.hp -= val;
if (this.hp < 0) this.hp = 0;
const activeWidth = blood["_myUITransform"].width;
const realVal = isRateVal ? val : this.getBloodVal(val);
if (this.hp <= 0) {
blood["_myUITransform"].width = 0;
return 0;
} else if (activeWidth - realVal >= 0) {
blood["_myUITransform"].width = activeWidth - realVal;
return 0;
} else {
blood["_myUITransform"].width = 0;
return realVal - activeWidth;
}
}
/* 获取实际血条减的伤害 */
private getBloodVal(val: number) {
return Math.ceil(val * this.rate);
}
/* 获取下一个下标 */
private getNextIndex() {
if (this.activeColorIndex >= this.colors.length) {
this.activeColorIndex = 0;
}
return this.activeColorIndex++;
}
/* 获取指定下标的颜色 */
private getColor(index: number): math.Color {
return math.color(this.colors[index]);
}
}
export default BossArticleBlood;
我封装了BossArticleBlood
类,接受两个node节点,需要的时候new出来,保存起来实例,用的时候先通过setBlood
方法定好血条,然后扣血时通过buckleBlood
处理。
这里这是我的一次思路,后续的应用,比如如何知道boss没血了,通过通过接收回调的方式处理,这就自行延展了。
版权申明
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿 - 有梦就能远航站点。未经许可,禁止转载。
相关推荐
解决Cocos Creator单屏开发改动脚本文件后还需要切换到Cocos Creator以触发脚本编译
问题起源可能Cocos Creator软件的开发人员认为每个开发者都是有两个电脑屏幕的(苦笑);它的脚本检测逻辑是:当你改动完脚本文件后,切换到Cocos Creator面板,此时才会触发预览更新,如果你是双屏的话,就不用切换,一个屏幕打开Cocos Creator,一个屏幕打开vscode,然后vscode保存后就会自动更新,此时切换到浏览器预览,一切都是那么的正常,前提你得有两块屏幕。非常蛋疼!!!这真是一个糟糕的体验!如果我们是单屏,你vscode改动脚本保存后,还得切换到Cocos Creator软件上,然后再切到浏览器去查看,超恶心有没有,怎么会有这种体验,都2022年了,文件...

Cocos Creator 制作仿DNF血条优化版
前言看本文章前建议先看上一篇《Cocos Creator 制作仿DNF血条》,这样就会明白优化的处理有哪些了。上一章中,我们的血条它的逻辑是两条血条来回切换,包括颜色,宽度,层级,控制起来其实是非常不方便的, 逻辑也变得复杂了,而且没有考虑到秒杀的情况下血条的处理,所以这次根据同事提供的好主意我重新写了一版。教程原理我们可以将第二条血条作为一个固定的底色来控制,只有当第二条血没有的时候,我们将其设置白色的,这样每次血条width控制其实都在第一条上面。也就是说,血条的宽度控制其实一直是第一条在循环控制,扣完了马上切换成第二条的颜色,然后宽度设满,第二条的颜色变成第三条,直到没有血条了,第...

Cocos Creator 事件穿透
前言Cocos Creator 中可以通过挂载 BlockInputEvents组件来防止事件穿透,但是如果我们想让它能够事件穿透,官方的文档只字不提。这个需求也是有场景的,比如我们有两个元素,A和B,B会浮动到A上,从而导致click被B给挡住了,从而A事件无法触发了,这种场景在打地鼠游戏中是常见的。解决办法我们需要给挡住的那个元素添加允许事件穿透,用上面的例子,那就是需要给B节点添加一个事件穿透。import { _decorator, Component, Node } from "cc"; const { ccclass, property } = _deco...