<七>UI跟随模型实现(例如人物头上的血条、昵称条等)

引擎提供了UICoordinateTracker 组件,又叫UI 坐标跟踪映射组件,可以在 UI 上执行坐标转换以及模拟透视相机下 3D 物体近大远小效果。通过事件的方式将转换后的坐标以及物体在视口下的占比返回。适用于 3D 人物血条以及姓名条之类功能。
UICoordinateTracker 属性
Target 目标对象(UI)。需要转换到哪一个 UI 节点下。
Camera 照射相机(3D)。
UseScale 是否启用缩放。在透视相机下,根据 3D 节点坐标与相机的距离,调整映射后物体的缩放比例,实现近大远小效果。需要结合 distance 使用。
Distance 距相机多少距离为正常显示计算大小。根据模型在相机下的照射效果调整最佳位置,以该位置为分界线计算在视口占比。
SyncEvents 映射数据事件。回调的第一个参数是映射后的本地坐标,第二个是距相机距离比。
实现:
1.创建一个Capsule,在Capsule下创建一个test_node做为参考点(要转化的3D点)
2.创建UI(血条)
3.在参考点上添加UICoordinateTracker 组件,把对应的引用填好。
4.创建坐标更新脚本,实现UICoordinateTracker的事件回调

import { _decorator, Component, Node, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('TestCoord')
export class TestCoord extends Component {
    // 目标(UI)节点
    @property(Node)
    target: Node = null;

    start() {

    }
    /**
     * 
     * @param localUIPos 映射后的 UI 坐标(本地坐标,不需要再转换)
     * @param distanceScale 距离相机的比
     * @param customEventData 自定义数据,可在事件面板上配置
     */
    onSyncEvents(localUIPos: Vec3, distanceScale: number, customEventData?: string) {
        this.target.setPosition(localUIPos);
        this.target.setScale(distanceScale, distanceScale, 1);
    }

    update(deltaTime: number) {

    }
}


运行:

扩展

可以根据源代码实现,ui跟随、相机跟随等效果。

import { _decorator, Camera, CCBoolean, CCFloat, Component, Node, UICoordinateTracker, v3, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('UICoord3D')
export class UICoord3D extends Component {
    @property(Camera)
    camera: Camera = null;
    @property(Node)
    target: Node = null;
    @property(CCBoolean)
    useScale: boolean = true;
    @property(CCFloat)
    distance: number = 10;

    _canMove: boolean = true;

    _lastWPos = v3();
    _lastCameraPos = v3();
    _transformPos = v3();
    _viewPos = v3();
    start() {
    }


    update(deltaTime: number) {
        const wPos = this.node.worldPosition;
        const camera = this.camera;
        if (!this._canMove || !camera || !camera.camera || (this._lastWPos.equals(wPos) && this._lastCameraPos.equals(camera.node.worldPosition))) {
            return;
        }

        this._lastWPos.set(wPos);
        this._lastCameraPos.set(camera.node.worldPosition);
        // [HACK]
        camera.camera.update();
        camera.convertToUINode(wPos, this.target!, this._transformPos);
        if (this.useScale) {
            Vec3.transformMat4(this._viewPos, this.node.worldPosition, camera.camera.matView);
        }
        this.target.setPosition(this._transformPos);

        if (this.useScale) {
            const data = this.distance / Math.abs(this._viewPos.z);
            this.target.setScale(data, data, 1);
        }
    }
}


posted @ 2024-10-25 15:33  EricShx  阅读(144)  评论(0)    收藏  举报