消消方块阵换皮表情
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

/**
* 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);
}
}