mk_bezier_animation/assets/RollingLottery.ts
2022-07-14 00:45:51 +08:00

223 lines
7.6 KiB
TypeScript

import { _decorator, Component, Node } from 'cc';
import * as cc from 'cc';
import { BezierCurveAnimation } from './BezierCurveAnimation';
const { ccclass, property, requireComponent } = _decorator;
/** 旋转抽奖方向 */
export enum RollingLotteryDirection {
/** 竖 */
VERTICAL,
/** 横 */
HORIZONTAL
}
/** 循环滚动抽奖 */
@ccclass('RollingLottery')
@requireComponent(BezierCurveAnimation)
@requireComponent(cc.Layout)
export class RollingLottery extends Component {
/* --------------- 属性 --------------- */
/** 滚动方向 */
@property({ displayName: '滚动方向', type: cc.Enum(RollingLotteryDirection) })
dire = RollingLotteryDirection.VERTICAL;
/** 子节点刷新事件 */
@property({ displayName: '子节点刷新事件', tooltip: '(子节点_node, 下标_indexN)', type: cc.EventHandler })
itemUpdateEvent = new cc.EventHandler();
/* --------------- private --------------- */
/** 曲线组件 */
private _curveComp: BezierCurveAnimation;
/** transform 组件 */
private _uiTransform: cc.UITransform;
/** 周长 */
private _perimeterN: number;
/** 当前距离 */
private _currDistN = 0;
/** 总距离 */
private _totalDistN: number;
/** 当前下标 */
private _currIndexN: number;
/** 子节点大小 */
private _ItemSize: cc.Size;
/** 运动状态 */
private _scrollB = false;
/** 自己矩形 */
private _selfRect = cc.rect();
/* --------------- 临时变量 --------------- */
private _tempM4 = cc.mat4();
private _temp2M4 = cc.mat4();
/* ------------------------------- 生命周期 ------------------------------- */
onLoad() {
this._initData();
this._initView();
this._initEvent();
}
/* ------------------------------- 功能 ------------------------------- */
/**
* 获取格子移动后距离
* @param currIndexN_ 当前格子下标
* @param targetIndexN_ 目标格子下标
* @returns
*/
private _getItemMovePos(currIndexN_: number, targetIndexN_: number): void {
/** 当前节点 */
let currNode = this.node.getChildByName(currIndexN_ + '');
/** 节点矩形 */
let currRect = this._getBoundingBoxToWorld(currNode);
/** 移动距离 */
let moveDistV3 = cc.v3(this._ItemSize.x, this._ItemSize.y).multiplyScalar(targetIndexN_ - currIndexN_);
/** 移动距离 */
let moveDistN: number;
if (this.dire === RollingLotteryDirection.HORIZONTAL) {
moveDistV3.y = 0;
moveDistN = moveDistV3.x;
} else {
moveDistV3.x = 0;
moveDistN = moveDistV3.y;
}
currRect.x += moveDistV3.x;
currRect.y += moveDistV3.y;
/** 终点坐标 */
let endPosV3 = this.node
.getChildByName(currIndexN_ + '')
.worldPosition.clone()
.add(moveDistV3);
/** 圈数 */
let circleN = Math.floor(moveDistN / this._perimeterN);
// /** 额外移动距离 */
// let extraMoveDistN = moveDistN - circleN * this._perimeterN;
}
/** 获取在世界坐标系下的节点包围盒(不包含自身激活的子节点范围) */
private _getBoundingBoxToWorld(node_: cc.Node): cc.Rect {
node_.getWorldMatrix(this._temp2M4);
cc.Mat4.fromRTS(this._tempM4, this.node.getRotation(), this.node.getPosition(), this.node.getScale());
let width = this._uiTransform.contentSize.width;
let height = this._uiTransform.contentSize.height;
let rect = new cc.Rect(
-this._uiTransform.anchorPoint.x * width,
-this._uiTransform.anchorPoint.y * height,
width,
height
);
cc.Mat4.multiply(this._temp2M4, this._temp2M4, this._tempM4);
rect.transformMat4(this._temp2M4);
return rect;
}
/** 检测参数节点是否与当前节点碰撞 */
private _checkCollision(node_: cc.Node): boolean {
let rect = this._getBoundingBoxToWorld(this.node);
let rect2 = this._getBoundingBoxToWorld(node_);
// 增加保险范围
rect.width += rect.width * 0.5;
rect.height += rect.height * 0.5;
rect.x -= rect.width * 0.25;
rect.y -= rect.height * 0.25;
return rect.intersects(rect2);
}
/** 更新运动距离 */
private _updateMoveDist(indexN_: number): void {
/** 间隔格子 */
let intervalN = indexN_ - this._currIndexN;
/** 格子距离 */
let boxDistN = this.dire === RollingLotteryDirection.HORIZONTAL ? this._ItemSize.width : this._ItemSize.height;
/** 超出当前格子距离 */
let overDistN = this._currDistN - boxDistN * this._currIndexN;
// 设置总距离
this._totalDistN = intervalN * boxDistN - overDistN;
}
/** 更新数据 */
private _updateData(): void {
// 单圈长度
this._perimeterN = 0;
this.node.children.forEach((v1) => {
this._perimeterN += v1.getComponent(cc.UITransform).height;
});
// 重置距离
this._currDistN = 0;
}
/** 初始化数据 */
private _initData(): void {
this._curveComp = this.node.getComponent(BezierCurveAnimation);
this._uiTransform = this.node.getComponent(cc.UITransform);
this._ItemSize = this.node.children[0].getComponent(cc.UITransform).contentSize.clone();
// 设置更新事件
this._curveComp.updateEvent.component = cc.js.getClassName(this);
this._curveComp.updateEvent.handler = 'updateEvent';
// 设置结束事件
this._curveComp.endEvent.component = cc.js.getClassName(this);
this._curveComp.endEvent.handler = 'updateEvent';
// 更新当前距离
{
let distV3 = this.node.worldPosition.clone().subtract(this.node.children[0].worldPosition);
this._currDistN = this.dire === RollingLotteryDirection.HORIZONTAL ? distV3.x : distV3.y;
}
// 自己矩形
this._selfRect = this._getBoundingBoxToWorld(this.node);
this._updateData();
}
/** 初始化视图 */
private _initView(): void {
this.scroll(0);
}
/** 初始化事件 */
private _initEvent(): void {
this.node.on(cc.Node.EventType.SIBLING_ORDER_CHANGED, this._nodeSiblingOrderChanged, this);
}
/**
* 循环滚动
* @param speedN_ 速度
* @param timeSN_ 时间(秒),不填则一直滚动
*/
loop(speedN_: number, timeSN_?: number): void {}
/** 滚动到指定下标 */
scroll(indexN_: number, timeSN_?: number): void {
this._scrollB = true;
this._updateMoveDist(indexN_);
/** 移动距离 */
let moveDistN = this._totalDistN - this._currDistN;
// 直接跳转
if (!timeSN_) {
/** 圈数 */
let circleN = Math.floor(moveDistN / this._perimeterN);
/** 额外移动距离 */
let extraMoveDistN = moveDistN - circleN * this._perimeterN;
}
}
/* ------------------------------- 自定义事件 ------------------------------- */
tweenSwitchEvent(indexN_: number): void {
// cc.log('缓动切换', indexN_);
}
updateEvent(yN_: number): void {
// cc.log('缓动更新', yN_);
}
endEvent(): void {
// cc.log('缓动结束');
}
/** 子节点更新 */
childUpdate(node_: cc.Node, indexN_: number): void {
node_.getComponentInChildren(cc.Label).string = indexN_ + '';
}
/* ------------------------------- 节点事件 ------------------------------- */
private _nodeSiblingOrderChanged(): void {
this._updateData();
}
}