You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
3.2 KiB
97 lines
3.2 KiB
import { _decorator, Component, Node, UITransform, Vec2, Vec3 } from 'cc';
|
|
const { ccclass, executeInEditMode } = _decorator;
|
|
|
|
/**
|
|
* line 长度/角度随 startPos→endPos 更新(移动 endPos 即自动拉线)。
|
|
* 子节点 Spine 动画不改;收招须 resetEndPos,否则拆字换格后 endPos 留在旧世界坐标会拉出乱线。
|
|
*/
|
|
@ccclass('SkillEye')
|
|
@executeInEditMode(true)
|
|
export class SkillEye extends Component {
|
|
|
|
startPos: Node;
|
|
endPos: Node;
|
|
line: Node;
|
|
|
|
dir: Vec2 = new Vec2();
|
|
|
|
private _endPosRestLocal: Vec3 | null = null;
|
|
/** line UITransform 宽度:scale=1 时光束本地长度(戬/杨 prefab ≈543) */
|
|
private _beamBaseLen = 0;
|
|
|
|
protected onLoad(): void {
|
|
this.ensureBound();
|
|
}
|
|
|
|
ensureBound(): void {
|
|
if (!this.startPos?.isValid) {
|
|
this.startPos = this.node.getChildByName('startPos');
|
|
}
|
|
if (!this.endPos?.isValid) {
|
|
this.endPos = this.node.getChildByName('endPos')
|
|
?? this.node.getChildByPath('line/endPos');
|
|
}
|
|
if (!this.line?.isValid) {
|
|
this.line = this.node.getChildByName('line');
|
|
}
|
|
if (this.endPos?.isValid && !this._endPosRestLocal) {
|
|
this._endPosRestLocal = this.endPos.position.clone();
|
|
}
|
|
if (this.line?.isValid && this._beamBaseLen <= 0) {
|
|
this._beamBaseLen = this.line.getComponent(UITransform)?.width ?? 200;
|
|
}
|
|
}
|
|
|
|
protected update(_dt: number): void {
|
|
if (this.line?.active) this.refreshBeam();
|
|
}
|
|
|
|
refreshBeam(): void {
|
|
this.ensureBound();
|
|
if (!this.startPos?.isValid || !this.endPos?.isValid || !this.line?.isValid) return;
|
|
if (!this.endPos.active) return;
|
|
|
|
this.line.setPosition(this.startPos.position);
|
|
|
|
const sx = this.startPos.position.x;
|
|
const sy = this.startPos.position.y;
|
|
const ex = this.endPos.position.x;
|
|
const ey = this.endPos.position.y;
|
|
const dx = ex - sx;
|
|
const dy = ey - sy;
|
|
const distance = Math.hypot(dx, dy);
|
|
if (distance <= 1e-4) {
|
|
this.line.setScale(0, 1, 1);
|
|
return;
|
|
}
|
|
|
|
this.dir.set(sx - ex, sy - ey);
|
|
this.dir.normalize();
|
|
this.line.angle = Math.atan2(this.dir.y, this.dir.x) * 180 / Math.PI - 180;
|
|
|
|
const baseLen = this._beamBaseLen > 0 ? this._beamBaseLen : 200;
|
|
this.line.setScale(distance / baseLen, 1, 1);
|
|
}
|
|
|
|
/** endPos 落到目标世界坐标(UI 层级走父节点 convertToNodeSpaceAR) */
|
|
setEndWorldPos(world: Readonly<Vec3>): void {
|
|
this.ensureBound();
|
|
if (!this.endPos?.isValid) return;
|
|
const parent = this.endPos.parent;
|
|
const ui = parent?.getComponent(UITransform);
|
|
if (ui) {
|
|
this.endPos.setPosition(ui.convertToNodeSpaceAR(world as Vec3));
|
|
} else {
|
|
this.endPos.setWorldPosition(world);
|
|
}
|
|
this.refreshBeam();
|
|
}
|
|
|
|
/** 收招/隐藏:endPos 回到预制体本地坐标,避免换格后 startPos/endPos 各画一条线 */
|
|
resetEndPos(): void {
|
|
this.ensureBound();
|
|
if (this.endPos?.isValid && this._endPosRestLocal) {
|
|
this.endPos.setPosition(this._endPosRestLocal);
|
|
}
|
|
}
|
|
}
|
|
|