完成 技能选择和英雄选择
This commit is contained in:
9
assets/script/game/BezierMove.meta
Normal file
9
assets/script/game/BezierMove.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "1.2.0",
|
||||||
|
"importer": "directory",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "6c227a87-4bae-4eb8-b109-39b5444eb904",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
571
assets/script/game/BezierMove/BezierMove.ts
Normal file
571
assets/script/game/BezierMove/BezierMove.ts
Normal file
@@ -0,0 +1,571 @@
|
|||||||
|
import { _decorator, Component, Node, view, UITransform, Vec3, math, EventHandler, Graphics, Color, TweenEasing, Enum } from 'cc';
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
// 定义缓动类型枚举
|
||||||
|
export enum EasingType {
|
||||||
|
linear = 'linear',
|
||||||
|
smooth = 'smooth',
|
||||||
|
fade = 'fade',
|
||||||
|
quadIn = 'quadIn',
|
||||||
|
quadOut = 'quadOut',
|
||||||
|
quadInOut = 'quadInOut',
|
||||||
|
quadOutIn = 'quadOutIn',
|
||||||
|
cubicIn = 'cubicIn',
|
||||||
|
cubicOut = 'cubicOut',
|
||||||
|
cubicInOut = 'cubicInOut',
|
||||||
|
cubicOutIn = 'cubicOutIn',
|
||||||
|
quartIn = 'quartIn',
|
||||||
|
quartOut = 'quartOut',
|
||||||
|
quartInOut = 'quartInOut',
|
||||||
|
quartOutIn = 'quartOutIn',
|
||||||
|
quintIn = 'quintIn',
|
||||||
|
quintOut = 'quintOut',
|
||||||
|
quintInOut = 'quintInOut',
|
||||||
|
quintOutIn = 'quintOutIn',
|
||||||
|
sineIn = 'sineIn',
|
||||||
|
sineOut = 'sineOut',
|
||||||
|
sineInOut = 'sineInOut',
|
||||||
|
sineOutIn = 'sineOutIn',
|
||||||
|
expoIn = 'expoIn',
|
||||||
|
expoOut = 'expoOut',
|
||||||
|
expoInOut = 'expoInOut',
|
||||||
|
expoOutIn = 'expoOutIn',
|
||||||
|
circIn = 'circIn',
|
||||||
|
circOut = 'circOut',
|
||||||
|
circInOut = 'circInOut',
|
||||||
|
circOutIn = 'circOutIn',
|
||||||
|
elasticIn = 'elasticIn',
|
||||||
|
elasticOut = 'elasticOut',
|
||||||
|
elasticInOut = 'elasticInOut',
|
||||||
|
elasticOutIn = 'elasticOutIn',
|
||||||
|
backIn = 'backIn',
|
||||||
|
backOut = 'backOut',
|
||||||
|
backInOut = 'backInOut',
|
||||||
|
backOutIn = 'backOutIn',
|
||||||
|
bounceIn = 'bounceIn',
|
||||||
|
bounceOut = 'bounceOut',
|
||||||
|
bounceInOut = 'bounceInOut',
|
||||||
|
bounceOutIn = 'bounceOutIn',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ControlPointSideType {
|
||||||
|
Left = 1,
|
||||||
|
Right = -1,
|
||||||
|
Random = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
@ccclass('BezierMove')
|
||||||
|
export class BezierMove extends Component {
|
||||||
|
@property({ displayName: '速度' })
|
||||||
|
speed: number = 600; // 移动速度,单位:像素/秒
|
||||||
|
|
||||||
|
@property({ displayName: '控制点方向', tooltip: '0=随机, 1=左侧,-1=右侧(相对于从起点到终点的方向)' })
|
||||||
|
controlPointSide: ControlPointSideType = ControlPointSideType.Left; // 控制点位置:0=随机,1=左侧,-1=右侧(相对于从起点到终点的方向)
|
||||||
|
|
||||||
|
@property({ displayName: '控制点偏移系数', tooltip: '0~1之间,控制点偏移系数,值越大曲线越弯曲' })
|
||||||
|
controlPointOffset: number = 0.5; // 控制点偏移系数,值越大曲线越弯曲
|
||||||
|
|
||||||
|
@property({ displayName: '控制点随机性', tooltip: '0~1之间,控制点随机性,值越大随机性越强' })
|
||||||
|
controlPointRandomness: number = 0.3; // 控制点随机性,值越大随机性越强
|
||||||
|
|
||||||
|
@property({ displayName: '自动旋转' })
|
||||||
|
autoRotate: boolean = true; // 是否自动旋转以面向移动方向
|
||||||
|
|
||||||
|
@property({ displayName: '显示轨迹' })
|
||||||
|
showTrajectory: boolean = true; // 是否显示移动轨迹
|
||||||
|
|
||||||
|
@property({ displayName: '轨迹颜色' })
|
||||||
|
trajectoryColor: Color = new Color(0, 255, 0, 255); // 轨迹颜色,默认绿色
|
||||||
|
|
||||||
|
@property({ displayName: '轨迹宽度' })
|
||||||
|
trajectoryWidth: number = 3; // 轨迹宽度
|
||||||
|
|
||||||
|
@property({ displayName: '缓动函数', type: Enum(EasingType) })
|
||||||
|
easing: TweenEasing = EasingType.linear; // 缓动效果类型,默认为线性
|
||||||
|
|
||||||
|
@property({ displayName: '角度平滑系数', tooltip: '0~1之间,值越小旋转越平滑,0表示不旋转,1表示立即旋转' })
|
||||||
|
rotationSmoothness: number = 0.6; // 角度平滑系数,值越小旋转越平滑
|
||||||
|
|
||||||
|
private _graphics: Graphics | null = null; // Graphics组件引用
|
||||||
|
private _currentAngle: number = 0; // 当前角度
|
||||||
|
|
||||||
|
private _startPoint: Vec3 = new Vec3();
|
||||||
|
private _endPoint: Vec3 = new Vec3();
|
||||||
|
private _controlPoint: Vec3 = new Vec3();
|
||||||
|
private _t: number = 0; // Bezier曲线参数 (0 到 1)
|
||||||
|
private _totalTime: number = 0; // 完成当前曲线所需的时间
|
||||||
|
private _isMoving: boolean = false; // 是否正在移动
|
||||||
|
private _moveEndCallback: Function = null; // 移动完成回调函数
|
||||||
|
private _moveEndTarget: any; // 移动完成回调函数的目标对象
|
||||||
|
private _moveStartCallback: Function = null; // 移动开始回调函数, (totalTime: number) => void
|
||||||
|
private _moveStartTarget: any; // 移动开始回调函数的目标对象
|
||||||
|
|
||||||
|
onEnable() {
|
||||||
|
// 初始化起点为当前位置
|
||||||
|
this._startPoint.set(this.node.position);
|
||||||
|
|
||||||
|
// 初始化当前角度为节点当前角度
|
||||||
|
this._currentAngle = this.node.angle;
|
||||||
|
|
||||||
|
// 初始化Graphics组件用于绘制轨迹
|
||||||
|
this._initGraphics();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onDisable() {
|
||||||
|
|
||||||
|
// 清理Graphics资源
|
||||||
|
if (this._graphics) {
|
||||||
|
this._graphics.clear();
|
||||||
|
// 确保Graphics节点也被销毁
|
||||||
|
if (this._graphics.node && this._graphics.node.isValid) {
|
||||||
|
// 查找并销毁与当前实例关联的唯一轨迹节点
|
||||||
|
const uniqueNodeName = `TrajectoryGraphics_${this.node.uuid}`;
|
||||||
|
this._graphics.node.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMoveComplete(callback: Function, target: any) {
|
||||||
|
this._moveEndCallback = callback;
|
||||||
|
this._moveEndTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
onMoveStart(callback: Function, target: any) {
|
||||||
|
this._moveStartCallback = callback;
|
||||||
|
this._moveStartTarget = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
update(deltaTime: number) {
|
||||||
|
if (!this._isMoving || this._totalTime <= 0) return; // 如果没有移动或路径生成失败,则返回
|
||||||
|
|
||||||
|
// 更新进度
|
||||||
|
this._t += deltaTime / this._totalTime;
|
||||||
|
|
||||||
|
// 应用缓动效果
|
||||||
|
let easedT = this._applyEasing(this._t);
|
||||||
|
|
||||||
|
if (this._t >= 1.0) {
|
||||||
|
// 到达终点
|
||||||
|
this.node.setPosition(this._endPoint);
|
||||||
|
this._isMoving = false;
|
||||||
|
// 触发移动完成事件
|
||||||
|
// EventHandler.emitEvents(this.onMoveComplete, this);
|
||||||
|
this._moveEndCallback && this._moveEndCallback.apply(this._moveEndTarget);
|
||||||
|
// 清除轨迹
|
||||||
|
if (this.showTrajectory && this._graphics) {
|
||||||
|
this._graphics.clear();
|
||||||
|
// 确保Graphics节点回到原始父节点
|
||||||
|
if (this._graphics.node.parent !== this.node) {
|
||||||
|
const graphicsNode = this._graphics.node;
|
||||||
|
if (graphicsNode.parent) {
|
||||||
|
graphicsNode.removeFromParent();
|
||||||
|
}
|
||||||
|
this.node.addChild(graphicsNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 计算贝塞尔曲线上的当前位置,使用缓动后的t值
|
||||||
|
const currentPos = this._calculateQuadraticBezierPoint(easedT, this._startPoint, this._controlPoint, this._endPoint);
|
||||||
|
this.node.setPosition(currentPos);
|
||||||
|
|
||||||
|
// 如果启用了自动旋转,计算切线(方向)进行旋转
|
||||||
|
if (this.autoRotate) {
|
||||||
|
const tangent = this._calculateQuadraticBezierTangent(easedT, this._startPoint, this._controlPoint, this._endPoint);
|
||||||
|
if (tangent.lengthSqr() > 0.001) { // 避免除以零或NaN角度
|
||||||
|
// 计算角度(度)。Atan2给出弧度。
|
||||||
|
// 加90度是因为角度0指向上方(在Cocos Creator 2D中沿Y轴)
|
||||||
|
const targetAngle = math.toDegree(Math.atan2(tangent.y, tangent.x)) - 90;
|
||||||
|
|
||||||
|
// 使用平滑插值方法计算新角度
|
||||||
|
this._currentAngle = this._smoothAngle(this._currentAngle, targetAngle, this.rotationSmoothness);
|
||||||
|
this.node.angle = this._currentAngle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移动到指定位置
|
||||||
|
* @param targetPos 目标位置
|
||||||
|
*/
|
||||||
|
public moveTo(targetPos: Vec3): void {
|
||||||
|
// 设置起点为当前位置
|
||||||
|
this._startPoint.set(this.node.position);
|
||||||
|
// 设置终点为目标位置
|
||||||
|
this._endPoint.set(targetPos);
|
||||||
|
|
||||||
|
// 记录当前角度,用于平滑过渡
|
||||||
|
this._currentAngle = this.node.angle;
|
||||||
|
|
||||||
|
// 自动生成控制点
|
||||||
|
this._generateControlPoint();
|
||||||
|
|
||||||
|
// 估算曲线长度以计算总时间
|
||||||
|
const approxLength = Vec3.distance(this._startPoint, this._controlPoint) + Vec3.distance(this._controlPoint, this._endPoint);
|
||||||
|
this._totalTime = approxLength / this.speed;
|
||||||
|
if (this._totalTime < 0.1) { // 确保最小持续时间
|
||||||
|
this._totalTime = 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果启用了轨迹显示,绘制轨迹
|
||||||
|
if (this.showTrajectory) {
|
||||||
|
this._drawTrajectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置进度并开始移动
|
||||||
|
this._t = 0;
|
||||||
|
this._isMoving = true;
|
||||||
|
|
||||||
|
this._moveStartCallback && this._moveStartCallback.apply(this._moveStartTarget, [this._totalTime]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动生成控制点
|
||||||
|
*/
|
||||||
|
private _generateControlPoint(): void {
|
||||||
|
// 计算起点和终点的中点
|
||||||
|
const midPoint = new Vec3();
|
||||||
|
Vec3.lerp(midPoint, this._startPoint, this._endPoint, 0.5);
|
||||||
|
|
||||||
|
// 计算从起点到终点的向量
|
||||||
|
const direction = new Vec3();
|
||||||
|
Vec3.subtract(direction, this._endPoint, this._startPoint);
|
||||||
|
|
||||||
|
// 计算垂直于方向的向量(在2D中,交换x和y并取反其中一个)
|
||||||
|
const perpendicular = new Vec3(-direction.y, direction.x, 0);
|
||||||
|
Vec3.normalize(perpendicular, perpendicular);
|
||||||
|
|
||||||
|
// 根据controlPointSide参数决定控制点在哪一侧
|
||||||
|
let sideMultiplier = 1;
|
||||||
|
if (this.controlPointSide === ControlPointSideType.Random) {
|
||||||
|
// 随机选择一侧(与原来的行为一致)
|
||||||
|
sideMultiplier = Math.random() < 0.5 ? 1 : -1;
|
||||||
|
} else {
|
||||||
|
// 使用指定的侧面
|
||||||
|
sideMultiplier = this.controlPointSide;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据控制点偏移系数和随机性计算控制点
|
||||||
|
const distance = Vec3.distance(this._startPoint, this._endPoint);
|
||||||
|
const offset = distance * this.controlPointOffset;
|
||||||
|
const randomFactor = (Math.random() * 2 - 1) * this.controlPointRandomness;
|
||||||
|
|
||||||
|
// 设置控制点 = 中点 + 垂直向量 * 偏移 * (1 + 随机因子) * 侧面乘数
|
||||||
|
this._controlPoint.set(
|
||||||
|
midPoint.x + perpendicular.x * offset * (1 + randomFactor) * sideMultiplier,
|
||||||
|
midPoint.y + perpendicular.y * offset * (1 + randomFactor) * sideMultiplier,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止当前移动
|
||||||
|
*/
|
||||||
|
stopMoving(): void {
|
||||||
|
this._isMoving = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算二次贝塞尔曲线上的点
|
||||||
|
*/
|
||||||
|
private _calculateQuadraticBezierPoint(t: number, p0: Vec3, p1: Vec3, p2: Vec3): Vec3 {
|
||||||
|
const u = 1 - t;
|
||||||
|
const tt = t * t;
|
||||||
|
const uu = u * u;
|
||||||
|
|
||||||
|
const p = new Vec3();
|
||||||
|
// p = (u^2 * p0) + (2 * u * t * p1) + (t^2 * p2)
|
||||||
|
Vec3.multiplyScalar(p, p0, uu);
|
||||||
|
const temp1 = new Vec3();
|
||||||
|
Vec3.multiplyScalar(temp1, p1, 2 * u * t);
|
||||||
|
Vec3.add(p, p, temp1);
|
||||||
|
const temp2 = new Vec3();
|
||||||
|
Vec3.multiplyScalar(temp2, p2, tt);
|
||||||
|
Vec3.add(p, p, temp2);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算二次贝塞尔曲线的切线(导数)
|
||||||
|
*/
|
||||||
|
private _calculateQuadraticBezierTangent(t: number, p0: Vec3, p1: Vec3, p2: Vec3): Vec3 {
|
||||||
|
|
||||||
|
const u = 1 - t;
|
||||||
|
const tangent = new Vec3();
|
||||||
|
|
||||||
|
// tangent = 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1)
|
||||||
|
const term1 = new Vec3();
|
||||||
|
Vec3.subtract(term1, p1, p0);
|
||||||
|
Vec3.multiplyScalar(term1, term1, 2 * u);
|
||||||
|
|
||||||
|
const term2 = new Vec3();
|
||||||
|
Vec3.subtract(term2, p2, p1);
|
||||||
|
Vec3.multiplyScalar(term2, term2, 2 * t);
|
||||||
|
|
||||||
|
Vec3.add(tangent, term1, term2);
|
||||||
|
|
||||||
|
return tangent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用缓动效果到t值
|
||||||
|
* @param t 原始t值(0-1之间)
|
||||||
|
* @returns 应用缓动后的t值
|
||||||
|
*/
|
||||||
|
private _applyEasing(t: number): number {
|
||||||
|
// 确保t在0-1范围内
|
||||||
|
t = Math.max(0, Math.min(1, t));
|
||||||
|
|
||||||
|
// 使用tween.easing函数应用缓动
|
||||||
|
switch (this.easing) {
|
||||||
|
case EasingType.linear:
|
||||||
|
return t; // 线性不需要额外处理
|
||||||
|
case EasingType.smooth:
|
||||||
|
return t * t * (3 - 2 * t); // 平滑过渡
|
||||||
|
case EasingType.fade:
|
||||||
|
return t * t * (3 - 2 * t); // 平滑过渡
|
||||||
|
case EasingType.quadIn:
|
||||||
|
return t * t; // 二次方加速
|
||||||
|
case EasingType.quadOut:
|
||||||
|
return t * (2 - t); // 二次方减速
|
||||||
|
case EasingType.quadInOut:
|
||||||
|
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; // 二次方加速然后减速
|
||||||
|
case EasingType.quadOutIn:
|
||||||
|
return t < 0.5 ? 0.5 * (1 - Math.pow(-2 * t + 1, 2)) : 0.5 * Math.pow(2 * t - 1, 2) + 0.5; // 二次方减速然后加速
|
||||||
|
case EasingType.cubicIn:
|
||||||
|
return t * t * t; // 三次方加速
|
||||||
|
case EasingType.cubicOut:
|
||||||
|
return (--t) * t * t + 1; // 三次方减速
|
||||||
|
case EasingType.cubicInOut:
|
||||||
|
return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; // 三次方加速然后减速
|
||||||
|
case EasingType.cubicOutIn:
|
||||||
|
return t < 0.5 ? 0.5 * ((t = t * 2 - 1) * t * t + 1) : 0.5 * (t = t * 2 - 1) * t * t + 0.5; // 三次方减速然后加速
|
||||||
|
case EasingType.quartIn:
|
||||||
|
return t * t * t * t; // 四次方加速
|
||||||
|
case EasingType.quartOut:
|
||||||
|
return 1 - (--t) * t * t * t; // 四次方减速
|
||||||
|
case EasingType.quartInOut:
|
||||||
|
return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t; // 四次方加速然后减速
|
||||||
|
case EasingType.quartOutIn:
|
||||||
|
return t < 0.5 ? 0.5 * (1 - Math.pow(-2 * t + 1, 4)) : 0.5 * Math.pow(2 * t - 1, 4) + 0.5; // 四次方减速然后加速
|
||||||
|
case EasingType.quintIn:
|
||||||
|
return t * t * t * t * t; // 五次方加速
|
||||||
|
case EasingType.quintOut:
|
||||||
|
return 1 + (--t) * t * t * t * t; // 五次方减速
|
||||||
|
case EasingType.quintInOut:
|
||||||
|
return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t; // 五次方加速然后减速
|
||||||
|
case EasingType.quintOutIn:
|
||||||
|
return t < 0.5 ? 0.5 * (1 - Math.pow(-2 * t + 1, 5)) : 0.5 * Math.pow(2 * t - 1, 5) + 0.5; // 五次方减速然后加速
|
||||||
|
case EasingType.sineIn:
|
||||||
|
return 1 - Math.cos(t * Math.PI / 2); // 正弦加速
|
||||||
|
case EasingType.sineOut:
|
||||||
|
return Math.sin(t * Math.PI / 2); // 正弦减速
|
||||||
|
case EasingType.sineInOut:
|
||||||
|
return 0.5 * (1 - Math.cos(Math.PI * t)); // 正弦加速然后减速
|
||||||
|
case EasingType.sineOutIn:
|
||||||
|
return t < 0.5 ? 0.5 * Math.sin(t * Math.PI) : 0.5 - 0.5 * Math.cos((t * 2 - 1) * Math.PI / 2); // 正弦减速然后加速
|
||||||
|
case EasingType.circIn:
|
||||||
|
return 1 - Math.sqrt(1 - t * t); // 圆形加速
|
||||||
|
case EasingType.circOut:
|
||||||
|
return Math.sqrt(1 - (t - 1) * (t - 1)); // 圆形减速
|
||||||
|
case EasingType.circInOut:
|
||||||
|
return t < 0.5
|
||||||
|
? (1 - Math.sqrt(1 - 4 * t * t)) / 2
|
||||||
|
: (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2; // 圆形加速然后减速
|
||||||
|
case EasingType.circOutIn:
|
||||||
|
return t < 0.5 ? 0.5 * Math.sqrt(1 - Math.pow(-2 * t + 1, 2)) : 0.5 * (2 - Math.sqrt(1 - Math.pow(2 * t - 1, 2))); // 圆形减速然后加速
|
||||||
|
case EasingType.expoIn:
|
||||||
|
return t === 0 ? 0 : Math.pow(2, 10 * t - 10); // 指数加速
|
||||||
|
case EasingType.expoOut:
|
||||||
|
return t === 1 ? 1 : 1 - Math.pow(2, -10 * t); // 指数减速
|
||||||
|
case EasingType.expoInOut:
|
||||||
|
return t === 0 ? 0 : t === 1 ? 1 : t < 0.5
|
||||||
|
? Math.pow(2, 20 * t - 10) / 2
|
||||||
|
: (2 - Math.pow(2, -20 * t + 10)) / 2; // 指数加速然后减速
|
||||||
|
case EasingType.expoOutIn:
|
||||||
|
return t === 0 ? 0 : t === 1 ? 1 : t < 0.5
|
||||||
|
? 0.5 * (1 - Math.pow(2, -20 * t))
|
||||||
|
: 0.5 * Math.pow(2, 20 * (t - 0.5) - 10) + 0.5; // 指数减速然后加速
|
||||||
|
case EasingType.backIn:
|
||||||
|
const s = 1.70158;
|
||||||
|
return t * t * ((s + 1) * t - s); // 回弹加速
|
||||||
|
case EasingType.backOut:
|
||||||
|
const s2 = 1.70158;
|
||||||
|
return (t = t - 1) * t * ((s2 + 1) * t + s2) + 1; // 回弹减速
|
||||||
|
case EasingType.backInOut:
|
||||||
|
const s3 = 1.70158 * 1.525;
|
||||||
|
if (t < 0.5) {
|
||||||
|
return (t * 2) * (t * 2) * ((s3 + 1) * (t * 2) - s3) / 2;
|
||||||
|
} else {
|
||||||
|
return ((t * 2 - 2) * (t * 2 - 2) * ((s3 + 1) * (t * 2 - 2) + s3) + 2) / 2;
|
||||||
|
} // 回弹加速然后减速
|
||||||
|
case EasingType.backOutIn:
|
||||||
|
const s4 = 1.70158;
|
||||||
|
return t < 0.5
|
||||||
|
? 0.5 * ((t = t * 2 - 1) * t * ((s4 + 1) * t + s4) + 1)
|
||||||
|
: 0.5 * (t = t * 2 - 1) * t * ((s4 + 1) * t - s4) + 0.5; // 回弹减速然后加速
|
||||||
|
case EasingType.elasticIn:
|
||||||
|
return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * (t - 1)) * Math.sin((t - 1.1) * 5 * Math.PI); // 弹性加速
|
||||||
|
case EasingType.elasticOut:
|
||||||
|
return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t - 0.1) * 5 * Math.PI) + 1; // 弹性减速
|
||||||
|
case EasingType.elasticInOut:
|
||||||
|
if (t === 0) return 0;
|
||||||
|
if (t === 1) return 1;
|
||||||
|
if (t < 0.5) {
|
||||||
|
return -0.5 * Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * Math.PI / 2.25);
|
||||||
|
} else {
|
||||||
|
return 0.5 * Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * Math.PI / 2.25) + 1;
|
||||||
|
} // 弹性加速然后减速
|
||||||
|
case EasingType.elasticOutIn:
|
||||||
|
if (t === 0) return 0;
|
||||||
|
if (t === 1) return 1;
|
||||||
|
if (t < 0.5) {
|
||||||
|
return 0.5 * Math.pow(2, -20 * t) * Math.sin((20 * t - 0.5) * 5 * Math.PI) + 0.5;
|
||||||
|
} else {
|
||||||
|
return 0.5 * -Math.pow(2, 10 * (2 * t - 1.5)) * Math.sin((2 * t - 1.6) * 5 * Math.PI) + 0.5;
|
||||||
|
} // 弹性减速然后加速
|
||||||
|
case EasingType.bounceIn:
|
||||||
|
return 1 - this._bounceOut(1 - t); // 弹跳加速
|
||||||
|
case EasingType.bounceOut:
|
||||||
|
return this._bounceOut(t); // 弹跳减速
|
||||||
|
case EasingType.bounceInOut:
|
||||||
|
return t < 0.5
|
||||||
|
? (1 - this._bounceOut(1 - 2 * t)) / 2
|
||||||
|
: (1 + this._bounceOut(2 * t - 1)) / 2; // 弹跳加速然后减速
|
||||||
|
case EasingType.bounceOutIn:
|
||||||
|
return t < 0.5
|
||||||
|
? this._bounceOut(t * 2) / 2
|
||||||
|
: (1 - this._bounceOut(2 - 2 * t)) / 2 + 0.5; // 弹跳减速然后加速
|
||||||
|
default:
|
||||||
|
return t; // 默认线性
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 辅助函数:弹跳减速效果
|
||||||
|
*/
|
||||||
|
private _bounceOut(t: number): number {
|
||||||
|
if (t < 1 / 2.75) {
|
||||||
|
return 7.5625 * t * t;
|
||||||
|
} else if (t < 2 / 2.75) {
|
||||||
|
return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
|
||||||
|
} else if (t < 2.5 / 2.75) {
|
||||||
|
return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
|
||||||
|
} else {
|
||||||
|
return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化Graphics组件
|
||||||
|
*/
|
||||||
|
private _initGraphics(): void {
|
||||||
|
// 为每个MovingTarget实例创建唯一的轨迹节点名称,避免多个实例共享同一个轨迹节点
|
||||||
|
const uniqueNodeName = `TrajectoryGraphics_${this.node.uuid}`;
|
||||||
|
|
||||||
|
// 尝试查找已存在的轨迹节点(基于唯一ID)
|
||||||
|
let graphicsNode = this.node.parent?.getChildByName(uniqueNodeName);
|
||||||
|
|
||||||
|
// 如果不存在,则创建新的轨迹节点
|
||||||
|
if (!graphicsNode) {
|
||||||
|
graphicsNode = new Node(uniqueNodeName);
|
||||||
|
// 初始时先添加到场景中,但不设置父节点,会在_drawTrajectory中设置
|
||||||
|
if (this.node.parent) {
|
||||||
|
this.node.parent.addChild(graphicsNode);
|
||||||
|
} else {
|
||||||
|
this.node.addChild(graphicsNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取或添加Graphics组件到节点
|
||||||
|
this._graphics = graphicsNode.getComponent(Graphics);
|
||||||
|
if (!this._graphics) {
|
||||||
|
this._graphics = graphicsNode.addComponent(Graphics);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除轨迹
|
||||||
|
*/
|
||||||
|
public clearTrajectory(): void {
|
||||||
|
if (!this._graphics) return;
|
||||||
|
// 清除之前的轨迹
|
||||||
|
this._graphics.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 绘制轨迹
|
||||||
|
*/
|
||||||
|
private _drawTrajectory(): void {
|
||||||
|
if (!this.showTrajectory) return;
|
||||||
|
|
||||||
|
if (!this._graphics) return;
|
||||||
|
// 清除之前的轨迹
|
||||||
|
this._graphics.clear();
|
||||||
|
|
||||||
|
// 设置轨迹样式
|
||||||
|
this._graphics.lineWidth = this.trajectoryWidth;
|
||||||
|
this._graphics.strokeColor = this.trajectoryColor;
|
||||||
|
|
||||||
|
// 获取Graphics所在节点
|
||||||
|
const graphicsNode = this._graphics.node;
|
||||||
|
|
||||||
|
// 将Graphics节点设置为与主节点的父节点相同,确保轨迹在世界坐标系中绘制
|
||||||
|
if (this.node.parent) {
|
||||||
|
graphicsNode.parent = this.node.parent;
|
||||||
|
|
||||||
|
// 移动到起点(世界坐标系中的实际位置)
|
||||||
|
this._graphics.moveTo(this._startPoint.x, this._startPoint.y);
|
||||||
|
|
||||||
|
// 直接使用控制点和终点的世界坐标绘制贝塞尔曲线
|
||||||
|
this._graphics.quadraticCurveTo(
|
||||||
|
this._controlPoint.x, this._controlPoint.y,
|
||||||
|
this._endPoint.x, this._endPoint.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用绘制
|
||||||
|
this._graphics.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 平滑角度插值,确保选择最短路径旋转
|
||||||
|
* @param currentAngle 当前角度
|
||||||
|
* @param targetAngle 目标角度
|
||||||
|
* @param smoothFactor 平滑系数(0-1),值越小越平滑
|
||||||
|
* @returns 插值后的新角度
|
||||||
|
*/
|
||||||
|
private _smoothAngle(currentAngle: number, targetAngle: number, smoothFactor: number): number {
|
||||||
|
// 确保平滑系数在有效范围内
|
||||||
|
smoothFactor = Math.max(0.001, Math.min(1, smoothFactor));
|
||||||
|
|
||||||
|
// 标准化角度到 0-360 范围
|
||||||
|
const normalizeAngle = (angle: number): number => {
|
||||||
|
angle = angle % 360;
|
||||||
|
return angle < 0 ? angle + 360 : angle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 标准化当前角度和目标角度
|
||||||
|
const normCurrent = normalizeAngle(currentAngle);
|
||||||
|
const normTarget = normalizeAngle(targetAngle);
|
||||||
|
|
||||||
|
// 计算最短路径旋转方向
|
||||||
|
let delta = normTarget - normCurrent;
|
||||||
|
|
||||||
|
// 如果角度差大于180度,选择另一个方向旋转(最短路径)
|
||||||
|
if (delta > 180) {
|
||||||
|
delta -= 360;
|
||||||
|
} else if (delta < -180) {
|
||||||
|
delta += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用平滑系数进行插值
|
||||||
|
return currentAngle + delta * smoothFactor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
9
assets/script/game/BezierMove/BezierMove.ts.meta
Normal file
9
assets/script/game/BezierMove/BezierMove.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.23",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "f680d91a-831f-4f99-b7ea-b45e3adff51a",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { VM } from "../../../../extensions/oops-plugin-framework/assets/libs/mod
|
|||||||
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
|
||||||
import { Initialize } from "../initialize/Initialize";
|
import { Initialize } from "../initialize/Initialize";
|
||||||
import { GameMap } from "../map/GameMap";
|
import { GameMap } from "../map/GameMap";
|
||||||
|
import { MissionData, MissionMons, Missions } from "./config/Mission";
|
||||||
|
|
||||||
|
|
||||||
// import { Role } from "../role/Role";
|
// import { Role } from "../role/Role";
|
||||||
@@ -17,13 +18,6 @@ export class SingletonModuleComp extends ecs.Comp {
|
|||||||
status:0, //0:未开始 1:进行中 2:胜利 3:失败
|
status:0, //0:未开始 1:进行中 2:胜利 3:失败
|
||||||
play:false,
|
play:false,
|
||||||
pause:false,
|
pause:false,
|
||||||
is_victory:false,
|
|
||||||
is_defeat:false,
|
|
||||||
is_battle:false,
|
|
||||||
lv:0,
|
|
||||||
victory:0,
|
|
||||||
mskill:6001,
|
|
||||||
mmskill:6002,
|
|
||||||
};
|
};
|
||||||
fight_heros=[]
|
fight_heros=[]
|
||||||
mheros:any = [];
|
mheros:any = [];
|
||||||
@@ -41,45 +35,11 @@ export class SingletonModuleComp extends ecs.Comp {
|
|||||||
game_over:false,
|
game_over:false,
|
||||||
game_pause:false,
|
game_pause:false,
|
||||||
mission_data:{
|
mission_data:{
|
||||||
gold:10,//金币
|
|
||||||
refresh_gold:1,//刷新金币
|
|
||||||
refrsh_time:1, //刷新时间
|
|
||||||
call_gold:3,//召唤金币
|
|
||||||
add_gold:1,//金币增加
|
|
||||||
change_gold:1,//金币变化
|
|
||||||
exp:0,//经验
|
|
||||||
skp:0,//技能点
|
|
||||||
box:0,//宝箱
|
|
||||||
energy:0,//能量
|
|
||||||
hp:0,//血量
|
|
||||||
ap:0,//攻击
|
|
||||||
},
|
},
|
||||||
mission:{
|
|
||||||
once:6, //每波刷新怪物数量
|
|
||||||
total:1, //总怪物数
|
|
||||||
exp:0,
|
|
||||||
exp_max:100,
|
|
||||||
mexp:0,
|
|
||||||
mexp_max:100,
|
|
||||||
drop:0,
|
|
||||||
hp:0,
|
|
||||||
ap:0,
|
|
||||||
def:0,
|
|
||||||
crit:0,
|
|
||||||
dodge:0,
|
|
||||||
dead:0,
|
|
||||||
reward_num:0, //怪物死亡数
|
|
||||||
reward_gold:0,
|
|
||||||
reward_exp:0,
|
|
||||||
},
|
|
||||||
gold:{num:999999,x1:0},
|
|
||||||
exp:{num:1000,x1:0},
|
|
||||||
skp:{num:2000,x1:0}, //技能升级点数
|
|
||||||
energy:{num:10,x1:0},
|
|
||||||
box:{num:10,x1:0},
|
|
||||||
|
|
||||||
};
|
};
|
||||||
vmAdd() {
|
vmAdd() {
|
||||||
|
this.vmdata.mission_data=MissionData
|
||||||
VM.add(this.vmdata, "data");
|
VM.add(this.vmdata, "data");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const MonsetList = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BossList = {
|
export const BossList = {
|
||||||
1:{
|
1:{
|
||||||
1:[5001],
|
1:[5001],
|
||||||
@@ -22,8 +23,6 @@ export const Missions = [
|
|||||||
[5213,5214,5215,5216,5217,5218],
|
[5213,5214,5215,5216,5217,5218],
|
||||||
[5225,5226,5227],
|
[5225,5226,5227],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
export const MissionReward = {
|
export const MissionReward = {
|
||||||
1:[1001,1002,1003,1004,1005,1006,1021,1022,1023,1024,1025,1026,1027,1028],
|
1:[1001,1002,1003,1004,1005,1006,1021,1022,1023,1024,1025,1026,1027,1028],
|
||||||
2:[1001,1002,1003,1004,1005,1006,1021,1022,1023,1024,1025,1026,1027,1028],
|
2:[1001,1002,1003,1004,1005,1006,1021,1022,1023,1024,1025,1026,1027,1028],
|
||||||
@@ -45,11 +44,11 @@ export const MBSet = {
|
|||||||
crit_cost:2,
|
crit_cost:2,
|
||||||
dodge_cost:2,
|
dodge_cost:2,
|
||||||
}
|
}
|
||||||
export const MissStatus = {
|
export const MissionStatus = {
|
||||||
ready:0,
|
ready:0,
|
||||||
playing:1,
|
ready_skill_select:1,
|
||||||
pause:2,
|
ready_hero_select:2,
|
||||||
choose:3,
|
playing:3,
|
||||||
end:4,
|
end:4,
|
||||||
}
|
}
|
||||||
export enum FightSet {
|
export enum FightSet {
|
||||||
@@ -66,3 +65,18 @@ export enum FightSet {
|
|||||||
AP_UPDATE_RATE=100,
|
AP_UPDATE_RATE=100,
|
||||||
AP_CHANGE_RATE=0,
|
AP_CHANGE_RATE=0,
|
||||||
}
|
}
|
||||||
|
export const MissionData = {
|
||||||
|
gold:10,//金币
|
||||||
|
refresh_gold:1,//刷新金币
|
||||||
|
refrsh_time:1, //刷新时间
|
||||||
|
call_gold:3,//召唤金币
|
||||||
|
add_gold:1,//金币增加
|
||||||
|
change_gold:1,//金币变化
|
||||||
|
exp:0,//经验
|
||||||
|
skp:0,//技能点
|
||||||
|
box:0,//宝箱
|
||||||
|
energy:0,//能量
|
||||||
|
hp:0,//血量
|
||||||
|
ap:0,//攻击
|
||||||
|
lv:0,
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,15 +3,11 @@ import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ec
|
|||||||
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
|
||||||
import { smc } from "../common/SingletonModuleComp";
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||||
import { Missions} from "../common/config/Mission";
|
import { MissionData, Missions, MissionStatus} from "../common/config/Mission";
|
||||||
import { Timer } from "../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer";
|
import { Timer } from "../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer";
|
||||||
import { VictoryComp } from "./VictoryComp";
|
|
||||||
import { CardControllerComp } from "./CardController";
|
|
||||||
import { GameEvent } from "../common/config/GameEvent";
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
import { HeroViewComp } from "../hero/HeroViewComp";
|
import { HeroViewComp } from "../hero/HeroViewComp";
|
||||||
import { Hero } from "../hero/Hero";
|
import { Hero } from "../hero/Hero";
|
||||||
import { TimerManager } from "db://oops-framework/core/common/timer/TimerManager";
|
|
||||||
import { HeroList } from "../common/config/heroSet";
|
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
/** 视图层对象 */
|
/** 视图层对象 */
|
||||||
@@ -41,6 +37,7 @@ export class MissionComp extends CCComp {
|
|||||||
this.on(GameEvent.MissionStart,this.mission_start,this)
|
this.on(GameEvent.MissionStart,this.mission_start,this)
|
||||||
this.on(GameEvent.FightEnd,this.fight_end,this)
|
this.on(GameEvent.FightEnd,this.fight_end,this)
|
||||||
this.on(GameEvent.MissionEnd,this.mission_end,this)
|
this.on(GameEvent.MissionEnd,this.mission_end,this)
|
||||||
|
this.on(GameEvent.CardsClose,this.after_used_skill_card,this)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected update(dt: number): void {
|
protected update(dt: number): void {
|
||||||
@@ -52,12 +49,9 @@ export class MissionComp extends CCComp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mission_start(){
|
async mission_start(){
|
||||||
/* todo 关卡设定完善*/
|
smc.mission.status=MissionStatus.ready
|
||||||
console.log("战斗开始 关卡怪物:",Missions[smc.mission.lv])
|
|
||||||
this.node.active=true
|
this.node.active=true
|
||||||
this.data_init()
|
this.data_init()
|
||||||
this.hart_hero_load()
|
this.hart_hero_load()
|
||||||
@@ -72,17 +66,38 @@ export class MissionComp extends CCComp {
|
|||||||
to_hero_skill_select(){
|
to_hero_skill_select(){
|
||||||
console.log("英雄技能选择")
|
console.log("英雄技能选择")
|
||||||
oops.message.dispatchEvent(GameEvent.HeroSkillSelect)
|
oops.message.dispatchEvent(GameEvent.HeroSkillSelect)
|
||||||
|
smc.mission.status=MissionStatus.ready_skill_select
|
||||||
|
}
|
||||||
|
after_used_skill_card(){
|
||||||
|
switch(smc.mission.status){
|
||||||
|
case MissionStatus.ready_skill_select:
|
||||||
|
console.log("next to_hero_select")
|
||||||
|
this.scheduleOnce(()=>{
|
||||||
|
this.to_hero_select()
|
||||||
|
},0.3)
|
||||||
|
|
||||||
|
break
|
||||||
|
case MissionStatus.ready_hero_select:
|
||||||
|
console.log("netx to_fight")
|
||||||
|
this.to_fight()
|
||||||
|
break
|
||||||
|
case MissionStatus.playing:
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
to_hero_select(){
|
to_hero_select(){
|
||||||
|
smc.mission.status=MissionStatus.ready_hero_select
|
||||||
oops.message.dispatchEvent(GameEvent.HeroSelect)
|
oops.message.dispatchEvent(GameEvent.HeroSelect)
|
||||||
}
|
}
|
||||||
|
|
||||||
to_fight(){
|
to_fight(){
|
||||||
|
smc.mission.status=MissionStatus.playing
|
||||||
oops.message.dispatchEvent(GameEvent.FightStart)
|
oops.message.dispatchEvent(GameEvent.FightStart)
|
||||||
}
|
}
|
||||||
|
|
||||||
to_end_fight(){
|
to_end_fight(){
|
||||||
|
smc.mission.status=MissionStatus.end
|
||||||
oops.message.dispatchEvent(GameEvent.FightEnd)
|
oops.message.dispatchEvent(GameEvent.FightEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,12 +116,9 @@ export class MissionComp extends CCComp {
|
|||||||
data_init(){
|
data_init(){
|
||||||
//局内数据初始化
|
//局内数据初始化
|
||||||
console.log("局内数据初始化")
|
console.log("局内数据初始化")
|
||||||
this.GlodAddTimer=new Timer(smc.vmdata.mission_data.refrsh_time)
|
|
||||||
smc.mission.status=1
|
|
||||||
smc.mission.play = true;
|
smc.mission.play = true;
|
||||||
smc.mission.is_victory=false
|
smc.vmdata.mission_data =MissionData
|
||||||
smc.mission.is_defeat=false
|
this.GlodAddTimer=new Timer(smc.vmdata.mission_data.refrsh_time)
|
||||||
smc.vmdata.mission_data ={...smc.vmdata.mission_data}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//角色初始化
|
//角色初始化
|
||||||
@@ -129,8 +141,6 @@ export class MissionComp extends CCComp {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private cleanComponents() {
|
private cleanComponents() {
|
||||||
ecs.query(ecs.allOf(HeroViewComp)).forEach(entity => {entity.remove(HeroViewComp);entity.destroy()});
|
ecs.query(ecs.allOf(HeroViewComp)).forEach(entity => {entity.remove(HeroViewComp);entity.destroy()});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user