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.
203 lines
7.1 KiB
203 lines
7.1 KiB
/**
|
|
* MoveDashedLine.ts
|
|
* Author: David de ShineYoung
|
|
* Creation Date: 2025/10/27
|
|
* Description: 绘制带箭头指示的虚线移动路径
|
|
*
|
|
*/
|
|
import { _decorator, Component, Graphics, Vec3, Color, Node, Vec2 } from 'cc';
|
|
const { ccclass, property } = _decorator;
|
|
|
|
@ccclass('MoveDashedLine')
|
|
export class MoveDashedLine extends Component {
|
|
|
|
@property(Graphics)
|
|
graphics: Graphics = null!;
|
|
|
|
@property([Vec2])
|
|
paths: Vec2[] = [];
|
|
|
|
@property
|
|
dashLength: number = 10; // 虚线每段长度
|
|
|
|
@property
|
|
gapLength: number = 8; // 虚线间隙长度
|
|
|
|
@property
|
|
lineWidth: number = 2; // 线宽
|
|
|
|
@property(Color)
|
|
lineColor: Color = Color.WHITE; // 线条颜色
|
|
|
|
@property
|
|
moveSpeed: number = 3; // 移动速度
|
|
|
|
@property
|
|
arrowCount: number = 3; // 箭头数量
|
|
|
|
@property
|
|
arrowSize: number = 20; // 箭头大小
|
|
|
|
@property
|
|
arrowSpacingFactor: number = 20; // 箭头间距因子,值越大间距越大
|
|
|
|
private _currentOffset: number = 0;
|
|
private _totalPathLength: number = 0;
|
|
private _pathSegments: {start: Vec3, end: Vec3, length: number}[] = [];
|
|
|
|
onLoad() {
|
|
this.calculatePathData();
|
|
}
|
|
|
|
start() {
|
|
|
|
}
|
|
|
|
setLineColor(color: Color) {
|
|
this.lineColor = color;
|
|
}
|
|
|
|
startSchedule() {
|
|
this.schedule(this.updateLine); // 约60帧
|
|
}
|
|
|
|
private calculatePathData() {
|
|
this._pathSegments = [];
|
|
this._totalPathLength = 0;
|
|
|
|
for (let i = 0; i < this.paths.length - 1; i++) {
|
|
const start = this.paths[i].toVec3();
|
|
const end = this.paths[i + 1].toVec3();
|
|
const length = Vec3.distance(start, end);
|
|
|
|
this._pathSegments.push({
|
|
start: start.clone(),
|
|
end: end.clone(),
|
|
length: length
|
|
});
|
|
|
|
this._totalPathLength += length;
|
|
}
|
|
}
|
|
|
|
private updateLine() {
|
|
this._currentOffset += this.moveSpeed;
|
|
// 当偏移超过路径长度时,循环
|
|
if (this._currentOffset > this._totalPathLength) {
|
|
this._currentOffset = 0;
|
|
}
|
|
//this.drawDashedLine();
|
|
this.drawArrows();
|
|
}
|
|
|
|
|
|
// 绘制箭头>
|
|
private drawArrows() {
|
|
if (!this.graphics || this._pathSegments.length === 0) return;
|
|
|
|
// 清除之前的绘制内容
|
|
this.graphics.clear();
|
|
|
|
this.graphics.lineWidth = this.lineWidth;
|
|
this.graphics.strokeColor = this.lineColor;
|
|
this.graphics.fillColor = this.lineColor;
|
|
// 使用arrowSpacingFactor作为箭头之间的最小间距(像素单位)
|
|
const minArrowSpacing = Math.max(this.arrowSpacingFactor, this.arrowSize * 0.8);
|
|
|
|
// 计算需要绘制的箭头数量
|
|
// 从起点开始绘制,每隔minArrowSpacing距离绘制一个箭头,直到终点
|
|
const totalArrows = Math.max(1, Math.floor(this._totalPathLength / minArrowSpacing));
|
|
|
|
// 计算实际的间距,确保箭头均匀分布在整个路径上
|
|
const actualSpacing = this._totalPathLength / totalArrows;
|
|
|
|
for (let i = 0; i <= totalArrows; i++) {
|
|
// 计算箭头位置:从起点到终点均匀分布
|
|
const arrowPosition = (this._currentOffset + actualSpacing * i) % this._totalPathLength;
|
|
this.drawArrowAtPosition(arrowPosition);
|
|
}
|
|
}
|
|
|
|
// 在指定位置绘制箭头>
|
|
private drawArrowAtPosition(position: number) {
|
|
if (!this.graphics) return;
|
|
|
|
let accumulatedLength = 0;
|
|
for (const segment of this._pathSegments) {
|
|
if (accumulatedLength + segment.length > position) {
|
|
// 计算箭头在当前线段上的位置
|
|
const arrowSegmentPosition = position - accumulatedLength;
|
|
const segmentDirection = new Vec3();
|
|
Vec3.subtract(segmentDirection, segment.end, segment.start);
|
|
Vec3.normalize(segmentDirection, segmentDirection);
|
|
|
|
// 计算箭头中心点
|
|
const arrowCenter = new Vec3();
|
|
Vec3.multiplyScalar(arrowCenter, segmentDirection, arrowSegmentPosition);
|
|
Vec3.add(arrowCenter, segment.start, arrowCenter);
|
|
|
|
// 计算垂直于路径方向的向量(用于确定箭头宽度)
|
|
const perpendicular = new Vec3(-segmentDirection.y, segmentDirection.x, 0);
|
|
|
|
// 计算箭头的三个点
|
|
const arrowSize = this.arrowSize;
|
|
const halfWidth = arrowSize * 0.3; // 箭头宽度的一半
|
|
|
|
// 箭头尖端点(沿路径方向前方)
|
|
const arrowTip = new Vec3();
|
|
Vec3.multiplyScalar(arrowTip, segmentDirection, arrowSize * 0.5);
|
|
Vec3.add(arrowTip, arrowCenter, arrowTip);
|
|
|
|
// 箭头左底部点(沿路径方向后方,垂直方向左侧)
|
|
const arrowLeft = new Vec3();
|
|
Vec3.multiplyScalar(arrowLeft, segmentDirection, -arrowSize * 0.3);
|
|
Vec3.add(arrowLeft, arrowCenter, arrowLeft);
|
|
|
|
// 使用Vec3.multiplyScalar和Vec3.add替代multiplyScalarAndAdd
|
|
const leftOffset = new Vec3();
|
|
Vec3.multiplyScalar(leftOffset, perpendicular, halfWidth);
|
|
Vec3.add(arrowLeft, arrowLeft, leftOffset);
|
|
|
|
// 箭头右底部点(沿路径方向后方,垂直方向右侧)
|
|
const arrowRight = new Vec3();
|
|
Vec3.multiplyScalar(arrowRight, segmentDirection, -arrowSize * 0.3);
|
|
Vec3.add(arrowRight, arrowCenter, arrowRight);
|
|
|
|
// 使用Vec3.multiplyScalar和Vec3.add替代multiplyScalarAndAdd
|
|
const rightOffset = new Vec3();
|
|
Vec3.multiplyScalar(rightOffset, perpendicular, -halfWidth);
|
|
Vec3.add(arrowRight, arrowRight, rightOffset);
|
|
|
|
// 绘制箭头三角形
|
|
this.graphics.moveTo(arrowTip.x, arrowTip.y);
|
|
this.graphics.lineTo(arrowLeft.x, arrowLeft.y);
|
|
this.graphics.lineTo(arrowRight.x, arrowRight.y);
|
|
this.graphics.lineTo(arrowTip.x, arrowTip.y);
|
|
|
|
this.graphics.stroke();
|
|
|
|
break;
|
|
}
|
|
accumulatedLength += segment.length;
|
|
}
|
|
}
|
|
// 设置新的路径点
|
|
public setPaths(newPaths: Vec2[]) {
|
|
this.paths = newPaths;
|
|
this.calculatePathData();
|
|
this._currentOffset = 0;
|
|
this.arrowSpacingFactor = 50;
|
|
//this.drawDashedLine();
|
|
this.drawArrows();
|
|
|
|
}
|
|
|
|
// 设置移动速度
|
|
public setMoveSpeed(speed: number) {
|
|
this.moveSpeed = speed;
|
|
}
|
|
|
|
onDestroy() {
|
|
this.unschedule(this.updateLine);
|
|
}
|
|
} |