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.
201 lines
7.5 KiB
201 lines
7.5 KiB
import { _decorator, CCInteger, clamp, Component, Enum, EventTouch, game, Node, Rect, UITransform, v3, Vec2, Vec3 } from 'cc';
|
|
const { ccclass, property } = _decorator;
|
|
|
|
enum MoveType {
|
|
Vertical,
|
|
Horizontal,
|
|
}
|
|
|
|
@ccclass('MoveContent')
|
|
export class MoveContent extends Component {
|
|
|
|
/** 当顶部超出时触发 */
|
|
static EVENT_ON_TOP = "MoveContent.EVENT_ON_TOP";
|
|
/** 当底部超出时触发 */
|
|
static EVENT_ON_BOTTOM = "MoveContent.EVENT_ON_BOTTOM";
|
|
/** 当左侧超出时触发 */
|
|
static EVENT_ON_LEFT = "MoveContent.EVENT_ON_LEFT";
|
|
/** 当右侧超出时触发 */
|
|
static EVENT_ON_RIGHT = "MoveContent.EVENT_ON_RIGHT";
|
|
/** 每次验证边界都会触发 */
|
|
static EVENT_ON_CHECKBOUNDARY = "MoveContent.EVENT_ON_CHECKBOUNDARY";
|
|
|
|
@property({ type: Enum(MoveType) })
|
|
moveType: MoveType = MoveType.Vertical;
|
|
|
|
@property({ type: Node })
|
|
content: Node = null;
|
|
|
|
@property({ type: CCInteger })
|
|
top = 0;
|
|
@property({ type: CCInteger })
|
|
bottom = 0;
|
|
@property({ type: CCInteger })
|
|
left = 0;
|
|
@property({ type: CCInteger })
|
|
right = 0;
|
|
|
|
|
|
protected onEnable(): void {
|
|
this.node.on(Node.EventType.TOUCH_START, this.onTouchStart, this);
|
|
this.node.on(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
|
|
this.node.on(Node.EventType.TOUCH_END, this.onTouchEnd, this);
|
|
this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
|
|
this.scheduleOnce(() => {
|
|
this.checkBoundary();
|
|
});
|
|
}
|
|
|
|
protected onDisable(): void {
|
|
this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
|
|
this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
|
|
this.node.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
|
|
this.node.off(Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
|
|
this.startAutoMove = false;
|
|
}
|
|
|
|
protected update(dt: number): void {
|
|
if (this.startAutoMove) {
|
|
if (this.moveDir < 0) {
|
|
this.moveOffset += dt * 10;
|
|
if (this.moveOffset >= 0)
|
|
this.startAutoMove = false;
|
|
}
|
|
else {
|
|
this.moveOffset -= dt * 10;
|
|
if (this.moveOffset <= 0)
|
|
this.startAutoMove = false;
|
|
}
|
|
|
|
this.move();
|
|
}
|
|
}
|
|
|
|
protected lateUpdate(dt: number): void {
|
|
this.canEmit = true;
|
|
}
|
|
|
|
startMove = false;
|
|
moveOffset = 0;
|
|
moveDir = 1;
|
|
startPos = null;
|
|
startTime = 0;
|
|
startAutoMove = false;
|
|
touchDistance = 0;
|
|
canEmit = true;
|
|
|
|
onTouchStart(event: EventTouch) {
|
|
this.moveOffset = 0;
|
|
this.startMove = true;
|
|
this.startAutoMove = false;
|
|
this.startPos = event.getUILocation();
|
|
this.startTime = game.totalTime;
|
|
}
|
|
|
|
onTouchMove(event: EventTouch) {
|
|
if (this.startMove) {
|
|
let pos = event.getDelta();
|
|
//计算滑动方向
|
|
this.moveOffset = this.moveType == MoveType.Vertical ? pos.y : pos.x;
|
|
this.moveDir = this.moveOffset > 0 ? 1 : -1;
|
|
this.move();
|
|
}
|
|
}
|
|
|
|
onTouchEnd(event: EventTouch) {
|
|
this.startMove = false;
|
|
let pos = event.getUILocation();
|
|
let endTime = game.totalTime;
|
|
let duration = endTime - this.startTime;
|
|
|
|
this.startAutoMove = true;
|
|
this.touchDistance = Vec2.distance(pos, this.startPos);
|
|
this.moveOffset = this.moveOffset / duration * 500;
|
|
}
|
|
|
|
move() {
|
|
let x = 0, y = 0;
|
|
if (this.moveType == MoveType.Vertical) y = this.moveOffset;
|
|
if (this.moveType == MoveType.Horizontal) x = this.moveOffset;
|
|
this.content.position = this.content.position.add(new Vec3(x, y, 0));
|
|
this.checkBoundary();
|
|
}
|
|
|
|
checkBoundary() {
|
|
let boundary = this.getBoundary();
|
|
let x = 0, y = 0;
|
|
if (this.moveType == MoveType.Vertical) {
|
|
if (boundary.yMin > -this.node.h * this.node.anchor_y + this.bottom + this.node.worldPosition.y) {
|
|
y = (-this.node.h * this.node.anchor_y + this.bottom) - boundary.yMin + this.node.worldPosition.y;
|
|
this.node.emit(MoveContent.EVENT_ON_BOTTOM, boundary);
|
|
}
|
|
if (boundary.yMax < this.node.h * (1 - this.node.anchor_y) - this.top + this.node.worldPosition.y) {
|
|
y = (this.node.h * (1 - this.node.anchor_y) - this.top) - boundary.yMax + this.node.worldPosition.y;
|
|
this.node.emit(MoveContent.EVENT_ON_TOP, boundary);
|
|
}
|
|
} else {
|
|
if (boundary.xMax < this.node.w * (1 - this.node.anchor_x) - this.right + this.node.worldPosition.x) {
|
|
x = boundary.xMax - (this.node.w * (1 - this.node.anchor_x) - this.right);
|
|
this.node.emit(MoveContent.EVENT_ON_RIGHT, boundary);
|
|
}
|
|
if (boundary.xMin > -this.node.w * this.node.anchor_x + this.left + this.node.worldPosition.x) {
|
|
x = boundary.xMin - (-this.node.w * this.node.anchor_x + this.left);
|
|
this.node.emit(MoveContent.EVENT_ON_LEFT, boundary);
|
|
}
|
|
}
|
|
if (x != 0 || y != 0) {
|
|
this.content.position = this.content.position.add(new Vec3(x, y, 0));
|
|
}
|
|
this.node.emit(MoveContent.EVENT_ON_CHECKBOUNDARY, boundary);
|
|
this.canEmit = false;
|
|
if (this.canEmit) {
|
|
}
|
|
return this._boundaryRect;
|
|
}
|
|
|
|
getBoundary() {
|
|
this._boundaryRect.set(0, 0, 0, 0);
|
|
for (let i = 0; i < this.content.children.length; i++) {
|
|
let c = this.content.children[i];
|
|
if ((i == 0) || (c.worldPosition.y + c.h * (1 - c.anchor_y) > this._boundaryRect.yMax)) { this._boundaryRect.yMax = c.worldPosition.y + c.h * (1 - c.anchor_y); this._topNode = c; }
|
|
if ((i == 0) || (c.worldPosition.y - c.h * c.anchor_y < this._boundaryRect.yMin)) { this._boundaryRect.yMin = c.worldPosition.y - c.h * c.anchor_y; this._bottomNode = c; }
|
|
if ((i == 0) || (c.worldPosition.x + c.w * (1 - c.anchor_x) > this._boundaryRect.xMax)) { this._boundaryRect.xMax = c.worldPosition.x + c.w * (1 - c.anchor_x); this._rightNode = c; }
|
|
if ((i == 0) || (c.worldPosition.x - c.w * c.anchor_x < this._boundaryRect.xMin)) { this._boundaryRect.xMin = c.worldPosition.x - c.w * c.anchor_x; this._leftNode = c; }
|
|
}
|
|
return this._boundaryRect;
|
|
}
|
|
private _boundaryRect = new Rect();
|
|
private _topNode: Node = null;
|
|
private _bottomNode: Node = null;
|
|
private _leftNode: Node = null;
|
|
private _rightNode: Node = null;
|
|
|
|
moveToChild(node: Node) {
|
|
if (this.content.children.indexOf(node) < 0) return;
|
|
|
|
// 获取节点的世界坐标
|
|
let worldPos = node.getWorldPosition();
|
|
// 转换为content节点的本地坐标系统
|
|
let localPos = this.content.getComponent(UITransform).convertToNodeSpaceAR(worldPos);
|
|
|
|
// 计算目标位置:将节点移动到视图中心
|
|
let targetX = this.moveType == MoveType.Vertical ? 0 : -localPos.x;
|
|
let targetY = this.moveType == MoveType.Vertical ? -localPos.y : 0;
|
|
|
|
// 应用移动并检查边界
|
|
this.content.setPosition(targetX, targetY, 0);
|
|
this.checkBoundary();
|
|
}
|
|
|
|
moveToXY(x: number = 0, y: number = 0) {
|
|
let pso = this.content.position;
|
|
x = x == 0 || this.moveType == MoveType.Vertical ? pso.x : x;
|
|
y = y == 0 || this.moveType == MoveType.Horizontal ? pso.y : y;
|
|
this.content.position = v3(x, y, 0);
|
|
this.checkBoundary();
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|