全民打枪!在3D模型上的2D血条如何实现?
时间:2022-07-23
本文章向大家介绍全民打枪!在3D模型上的2D血条如何实现?,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
作者:杨宗宝 排版:张晓衡
在大多数 3D 对战或者打怪游戏中,角色身上的血量条会很直观的显示出生命值,伤害值等信息,让游戏效果更加完美,先上两张简单的效果图:
1
3D角色血量条的实现
从上边的图片可以很清楚的看到,此功能主要分为两部分:
- 3D角模型
- 2D血条UI
将这两部分结合起来(说白了就是将 3D 角色坐标转化到 UI 界面上)就实现了这个功能
1. 首先将 3D 角色放到场景中去,可以简单的让其在场景中行走 2. 创建脚本 Monster.ts 将脚本挂载 3D 角色节点上 3. 在脚本的start生命周期中动态创建血条(提前将血条做成一个预制体)
initLifeBarUi(): void {
this.lifeBarNode = PoolController.getDictPool(PoolRes.MONSTER_LIFE_BAR_KEY);
let monsterLifePanel: Node = find("monsterLifePanel", GameEntity.mGameUI);
monsterLifePanel.addChild(this.lifeBarNode);
this.lifeBarNode.getComponent(MonsterLifeBar).initLife(this.mLife);
this.lifeBarNode.active = false;
}
考虑到了性能,我将血条预制体放在了对象池中,PoolController是自己封装的一个对象池类,通过键值去从对象池中拿。将创建的血条添加到界面上,(在这里本人对血条创建了一个单独的脚本进行血条属性的控制刷新MonsterLifeBar)
4. 实时去刷新进度条的位置
refreshLifeBarUi(): void {
if (!this.lifeBarNode) return;
let _v3_0: Vec3 = new Vec3(0, 0, 0);
this.lifeBarParentNode.getWorldPosition(_v3_0);
GameEntity.mCamera.getComponent(CameraComponent).convertToUINode(_v3_0, this.lifeBarNode.parent, _v3_0);
this.lifeBarNode.setPosition(_v3_0);
let distance: any = Math.sqrt(Math.pow(this.node.position.x, 2) + Math.pow(this.node.position.z, 2));
this.lifeBarNode.getComponent(MonsterLifeBar).refresh(distance)
}
主要代码就是下面三行,将 3D 坐标转换到 2D 下:
let _v3_0: Vec3 = new Vec3(0, 0, 0);
this.lifeBarParentNode.getWorldPosition(_v3_0);
GameEntity.mCamera.getComponent(CameraComponent).convertToUINode(_v3_0, this.lifeBarNode.parent, _v3_0);
this.lifeBarParentNode—这个节点是 3D 角色节点下创建的一个用来与血条对应的空节点,位置是在默认角色头部偏高一点的位置,为了防止血条和模型重叠。GameEntity.mCamera—摄像机节点。
大家也可以直接使用this.node.getWorldPosition(_v3_0),然后再this.lifeBarNode.setPosition(_v3_0)设置血条坐标的时候,对y轴的坐标适当的向上调整来避免模型个血条重叠。
let distance: any = Math.sqrt(Math.pow(this.node.position.x, 2) + Math.pow(this.node.position.z, 2));
this.lifeBarNode.getComponent(MonsterLifeBar).refresh(distance)
这两句代码大家可以忽略,主要是根据角色离摄像机的位置对血条的大小进行缩放,实现近大远小的效果
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 将InputSteram转换成文件输出并下载至本地
- sql serve2008是否自带互斥锁
- Flutter基础widgets教程-CupertinoSwitch篇
- Flutter基础widgets教程-CupertinoTabScaffold篇
- C++11 move 语义
- 论函数的设计应如何才好,返回临时变量 | 返回引用 | 传递引用
- Flutter基础widgets教程-CupertinoTabView篇
- 关于time的使用
- class priority_queue<> 简单介绍
- C++ share_prt 简单设计和实现
- 使用函数对象与使用函数的比较
- C++ 函数指针的定义方法及使用
- C++ 线程池的简易实现
- Flutter基础widgets教程-DataTable篇
- 2015-C++研发附加题第一题