|
|
|
|
@ -17,7 +17,7 @@ const { ccclass, property } = _decorator; |
|
|
|
|
/***方块摆放的item节点, 放在tetraGame上的ui_card的子节点上,会自动根据方块的类型创建对应的方块节点 |
|
|
|
|
* 可以进行触摸移动 |
|
|
|
|
*
|
|
|
|
|
* 点击item节点0秒后item上创建的方块的父节点到_gameRoot的ui_card的子节点上,位置更新一下然后设置item节点opacity==0保证触摸事件继续 |
|
|
|
|
* 点击卡牌后从模板克隆纯视觉预览;松手时再从模板实例化全新战场方块(与预览彻底分离,无物理开关竞态)。 |
|
|
|
|
* 根据类型不同,所以方块有两个脚本 |
|
|
|
|
* tetriCardItem: 自由下落的方块节点 |
|
|
|
|
* tetraFloorNode: 无重力方块,墙体。接触到其他方块会立马停住做为底板使用
|
|
|
|
|
@ -50,8 +50,8 @@ export class tetriCardItem extends Component { |
|
|
|
|
/**绑定地图脚本(用于读取镜头缩放,做 x 坐标换算) */ |
|
|
|
|
private _boundMap: tetriMap | null = null; |
|
|
|
|
|
|
|
|
|
/**外部回调:松手且满足放置条件时触发 */ |
|
|
|
|
onPlaceRequested: ((self: tetriCardItem, worldPos: Vec3) => void) | null = null; |
|
|
|
|
/**外部回调:松手且满足放置条件时触发;返回 true 表示战场已接管 battleNode */ |
|
|
|
|
onPlaceRequested: ((self: tetriCardItem, battleNode: Node, worldPos: Vec3) => boolean) | null = null; |
|
|
|
|
/**外部回调:卡牌被成功消耗(放置成功) */ |
|
|
|
|
onConsumed: (() => void) | null = null; |
|
|
|
|
|
|
|
|
|
@ -63,10 +63,7 @@ export class tetriCardItem extends Component { |
|
|
|
|
private _pieceNode: Node | null = null; |
|
|
|
|
/***预览二号 */ |
|
|
|
|
private _pieceNodeCopyMove: Node | null = null; |
|
|
|
|
private _pieceNodeCopyMoveFixedWorldY: number | null = null; |
|
|
|
|
private _pieceOriginLocalPos: Vec3 = new Vec3(); |
|
|
|
|
/** 拿起预览时 schedule 的「下一帧关物理」令牌;放置后递增以作废,避免松手后把下落块又设回 Static */ |
|
|
|
|
private _previewPhysicsDisableToken = 0; |
|
|
|
|
private _holdScheduled: boolean = false; |
|
|
|
|
private _lastTouchEvent: EventTouch | null = null; |
|
|
|
|
private _startPos: Vec2 = new Vec2(); |
|
|
|
|
@ -123,61 +120,22 @@ export class tetriCardItem extends Component { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 预览态彻底退出物理世界:禁用刚体与全部碰撞体 */ |
|
|
|
|
private _disablePhysicsForPreview(node: Node | null): void { |
|
|
|
|
if (!node?.isValid) return; |
|
|
|
|
// 已交给战场下落(挂在 GameRoot / Tetris 地图下)时禁止再关物理
|
|
|
|
|
if (this._isNodeReleasedToBattlefield(node)) return; |
|
|
|
|
for (const rb of node.getComponentsInChildren(RigidBody2D)) { |
|
|
|
|
rb.linearVelocity = new Vec2(0, 0); |
|
|
|
|
rb.angularVelocity = 0; |
|
|
|
|
rb.gravityScale = 0; |
|
|
|
|
rb.type = ERigidBody2DType.Static; |
|
|
|
|
rb.fixedRotation = true; |
|
|
|
|
rb.enabledContactListener = false; |
|
|
|
|
rb.enabled = false; |
|
|
|
|
} |
|
|
|
|
for (const col of node.getComponentsInChildren(Collider2D)) { |
|
|
|
|
col.enabled = false; |
|
|
|
|
/** |
|
|
|
|
* 拖拽预览专用:剥玩法脚本并移除刚体,仅保留渲染与 Polygon(重叠检测)。 |
|
|
|
|
* 预览节点用完即毁,永不进入战场,从设计上避免「关物理 → 再开物理」竞态。 |
|
|
|
|
*/ |
|
|
|
|
private _stripPreviewForDrag(root: Node | null): void { |
|
|
|
|
if (!root?.isValid) return; |
|
|
|
|
this._stripAlignPreviewGameplay(root); |
|
|
|
|
for (const rb of root.getComponentsInChildren(RigidBody2D)) { |
|
|
|
|
rb.destroy(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 某些脚本会在 next tick 反开 collider,这里做一帧后的兜底再禁用 */ |
|
|
|
|
private _disablePhysicsForPreviewNextFrame(node: Node | null): void { |
|
|
|
|
const token = this._previewPhysicsDisableToken; |
|
|
|
|
this.scheduleOnce(() => { |
|
|
|
|
if (token !== this._previewPhysicsDisableToken) return; |
|
|
|
|
this._disablePhysicsForPreview(node); |
|
|
|
|
}, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 放置瞬间作废所有「预览关物理」延迟任务 */ |
|
|
|
|
private _invalidatePreviewPhysicsDisable(): void { |
|
|
|
|
this._previewPhysicsDisableToken++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 节点是否已移交战场(不再是 chooseMask 上的拖拽预览) */ |
|
|
|
|
private _isNodeReleasedToBattlefield(node: Node | null): boolean { |
|
|
|
|
if (!node?.isValid) return false; |
|
|
|
|
const map = this._boundMap ?? (gg as any)?.game?.CurentBattle?.TetraMap; |
|
|
|
|
const gameRoot = map?._gameRoot as Node | null | undefined; |
|
|
|
|
if (gameRoot?.isValid) { |
|
|
|
|
let cur: Node | null = node; |
|
|
|
|
while (cur) { |
|
|
|
|
if (cur === gameRoot) return true; |
|
|
|
|
cur = cur.parent; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// 已不在卡牌/遮罩下,也视为已释放
|
|
|
|
|
if (this.chooseMask?.isValid) { |
|
|
|
|
let cur: Node | null = node; |
|
|
|
|
while (cur) { |
|
|
|
|
if (cur === this.chooseMask || cur === this.node) return false; |
|
|
|
|
cur = cur.parent; |
|
|
|
|
} |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
return false; |
|
|
|
|
/** 从卡牌模板实例化战场方块(与拖拽预览彻底分离) */ |
|
|
|
|
public createBattlePiece(): Node | null { |
|
|
|
|
if (!this._pieceNode?.isValid) return null; |
|
|
|
|
return instantiate(this._pieceNode); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 递归销毁名为「角色」的子树(预览二号禁止挂角色/武器) */ |
|
|
|
|
@ -194,7 +152,7 @@ export class tetriCardItem extends Component { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 预览二号:在进入场景树之前剥掉玩法脚本,避免 start/onEnable 里创建角色、武器或注册战斗逻辑。 |
|
|
|
|
* 预览:剥掉下落/碰撞玩法脚本,保留 tetriWeaponCarrier 仅作展示(禁止射击)。 |
|
|
|
|
*/ |
|
|
|
|
private _stripAlignPreviewGameplay(root: Node | null): void { |
|
|
|
|
if (!root?.isValid) return; |
|
|
|
|
@ -202,7 +160,7 @@ export class tetriCardItem extends Component { |
|
|
|
|
c.destroy(); |
|
|
|
|
} |
|
|
|
|
for (const c of root.getComponentsInChildren(tetriWeaponCarrier)) { |
|
|
|
|
c.destroy(); |
|
|
|
|
c.setIsShootCan(false); |
|
|
|
|
} |
|
|
|
|
this._destroyRoleNamedSubtrees(root); |
|
|
|
|
for (const c of root.getComponentsInChildren(tetriNode)) { |
|
|
|
|
@ -314,8 +272,6 @@ export class tetriCardItem extends Component { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected onDestroy(): 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); |
|
|
|
|
@ -443,27 +399,15 @@ export class tetriCardItem extends Component { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (this.onPlaceRequested) { |
|
|
|
|
// 交给战场前恢复预制 scale,避免下落块带拖拽期的镜头缩放系数
|
|
|
|
|
this._restorePreviewPieceBaseScale(); |
|
|
|
|
// 作废「下一帧关物理」:HOLD_SECONDS=0 时 createPreview 与松手常隔 1 帧,否则会把已下落块又冻成 Static 悬在白线
|
|
|
|
|
this._invalidatePreviewPhysicsDisable(); |
|
|
|
|
//注册的回调
|
|
|
|
|
this.onPlaceRequested(this, pos); |
|
|
|
|
if (this._pieceNodeCopyMove && this._pieceNodeCopyMove.isValid) { |
|
|
|
|
this._pieceNodeCopyMove.destroy(); |
|
|
|
|
console.log('回收拖拽预览副 this._pieceNodeCopyMove333'); |
|
|
|
|
//gg.res.putNode(this._pieceNodeCopyMove);
|
|
|
|
|
} |
|
|
|
|
this._pieceNodeCopyMove = null; |
|
|
|
|
this._pieceNodeCopyMoveFixedWorldY = null; |
|
|
|
|
this._destroyAlignPreview(); |
|
|
|
|
if(gg.data.doc.chapter == 1 ){ |
|
|
|
|
GEvent.Ins.emit(GEvent.TetriGameTouchEnd); |
|
|
|
|
const battleNode = this.createBattlePiece(); |
|
|
|
|
if (!battleNode) { |
|
|
|
|
this.cancelPlace(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//扣钱(雷电副本不消耗银币)
|
|
|
|
|
if (gg.game.CurentBattle.BattleType !== BattleType.OrangeWeaponMode_Dian) { |
|
|
|
|
gg.game.CurentBattle.subCoinNum(this.config.price); |
|
|
|
|
const placed = this.onPlaceRequested(this, battleNode, pos) === true; |
|
|
|
|
if (!placed) { |
|
|
|
|
if (battleNode.isValid) battleNode.destroy(); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
this.consume(); |
|
|
|
|
@ -473,17 +417,16 @@ export class tetriCardItem extends Component { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**放置成功:预览所有权移交游戏逻辑,卡牌隐藏 */ |
|
|
|
|
/**放置成功:销毁预览、扣银币、隐藏卡牌 */ |
|
|
|
|
public consume(): void { |
|
|
|
|
this._snapTween?.stop(); |
|
|
|
|
this._destroyGuideLine(); |
|
|
|
|
this._destroyAlignPreview(); |
|
|
|
|
this._restorePreviewPieceBaseScale(); |
|
|
|
|
this._previewDragBaseScale = null; |
|
|
|
|
this._previewNode = null; |
|
|
|
|
this._tearDownDragPreview(); |
|
|
|
|
if (gg.game.CurentBattle.BattleType !== BattleType.OrangeWeaponMode_Dian) { |
|
|
|
|
gg.game.CurentBattle.subCoinNum(this.config?.price ?? 0); |
|
|
|
|
} |
|
|
|
|
this.node.active = false; |
|
|
|
|
this.onConsumed?.(); |
|
|
|
|
if(gg.data.doc.chapter == 1){ |
|
|
|
|
if (gg.data.doc.chapter == 1) { |
|
|
|
|
GEvent.Ins.emit(GEvent.TetriGameTouchEnd); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -653,72 +596,48 @@ export class tetriCardItem extends Component { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**创建预览 */ |
|
|
|
|
/**创建预览:从模板克隆纯视觉节点;模板 _pieceNode 始终留在卡牌上 */ |
|
|
|
|
private _createPreview(): void { |
|
|
|
|
if (!this._pieceNode || !this.chooseMask) return; |
|
|
|
|
|
|
|
|
|
// 将方块子节点移入 chooseMask,成为独立预览(最上层)
|
|
|
|
|
this.chooseMask.active = true |
|
|
|
|
this.cancleNode.active = true |
|
|
|
|
this.chooseMask.addChild(this._pieceNode); |
|
|
|
|
this.chooseMask.active = true; |
|
|
|
|
this.cancleNode.active = true; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 确保挪到 GameRoot 后仍会被正确相机渲染(layer 必须与 GameRoot 一致)
|
|
|
|
|
this._setLayerRecursively(this._pieceNode, this.chooseMask.layer); |
|
|
|
|
this._pieceNode.active = true; |
|
|
|
|
|
|
|
|
|
// 预览阶段:彻底禁用物理,防止任何接触/推挤
|
|
|
|
|
this._disablePhysicsForPreview(this._pieceNode); |
|
|
|
|
this._disablePhysicsForPreviewNextFrame(this._pieceNode); |
|
|
|
|
const preview = instantiate(this._pieceNode); |
|
|
|
|
this.chooseMask.addChild(preview); |
|
|
|
|
this._setLayerRecursively(preview, this.chooseMask.layer); |
|
|
|
|
preview.active = true; |
|
|
|
|
preview.angle = this._pieceNode.angle; |
|
|
|
|
this._stripPreviewForDrag(preview); |
|
|
|
|
this._previewDragBaseScale = this._pieceNode.scale.clone(); |
|
|
|
|
//this.config.cubename 在创建一个方块节点,位置放在当前方块的白线正上方,保持一致,用于拖动预览,禁用碰撞器,禁用重力,禁用刚体
|
|
|
|
|
//赋值到this._pieceNodeCopyMove上,用于拖动预览结束的时候回收,原来的逻辑保留
|
|
|
|
|
this._previewNode = preview; |
|
|
|
|
|
|
|
|
|
// 额外的“拖拽预览副本”(不影响原有 _pieceNode 逻辑);isShowBlockDrop 时不在白线展示副本,落点跟手
|
|
|
|
|
if (this._pieceNodeCopyMove && this._pieceNodeCopyMove.isValid) { |
|
|
|
|
|
|
|
|
|
console.log('回收拖拽预览副 this._pieceNodeCopyMove1111'); |
|
|
|
|
//gg.res.putNode(this._pieceNodeCopyMove);
|
|
|
|
|
this._pieceNodeCopyMove.destroy(); |
|
|
|
|
this._pieceNodeCopyMove = null; |
|
|
|
|
} |
|
|
|
|
if (!gg.game.isShowBlockDrop) { |
|
|
|
|
this._pieceNodeCopyMove = instantiate(this._pieceNode); |
|
|
|
|
|
|
|
|
|
if (this._pieceNode.getComponent(tetriNode)) { |
|
|
|
|
this._pieceNodeCopyMove.getOrAddComponent(tetriNode).setConfig(this.config); |
|
|
|
|
} |
|
|
|
|
if (this._pieceNode.getComponent(tetriWeaponCarrier)) { |
|
|
|
|
this._pieceNodeCopyMove.getOrAddComponent(tetriWeaponCarrier).setConfig(this.config); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//this._pieceNodeCopyMove.scale = this._pieceNode.scale
|
|
|
|
|
this._pieceNodeCopyMove.angle = 0 |
|
|
|
|
this._stripPreviewForDrag(this._pieceNodeCopyMove); |
|
|
|
|
this._pieceNodeCopyMove.angle = 0; |
|
|
|
|
this.chooseMask.addChild(this._pieceNodeCopyMove); |
|
|
|
|
//this._pieceNodeCopyMove.scale = this._pieceNode.scale.clone();
|
|
|
|
|
const mapLayer = gg.game.CurentBattle.TetraMap?.node?.layer ?? this.chooseMask.layer; |
|
|
|
|
this._setLayerRecursively(this._pieceNodeCopyMove, mapLayer); |
|
|
|
|
this._pieceNodeCopyMove.active = true; |
|
|
|
|
// 固定在白线处(底边贴线),X 跟随主方块
|
|
|
|
|
const fixedY = this._getWhiteLineFixedWorldYFor(this._pieceNodeCopyMove); |
|
|
|
|
const startX = this._pieceNode.worldPosition.x; |
|
|
|
|
const startX = preview.worldPosition.x; |
|
|
|
|
const startZ = this._pieceNodeCopyMove.worldPosition.z; |
|
|
|
|
this._pieceNodeCopyMoveFixedWorldY = fixedY ?? this._pieceNode.worldPosition.y; |
|
|
|
|
this._pieceNodeCopyMove.setWorldPosition(new Vec3(startX, this._pieceNodeCopyMoveFixedWorldY, startZ)); |
|
|
|
|
// 白线副本同样彻底禁用物理,保证仅作为视觉引导
|
|
|
|
|
this._disablePhysicsForPreview(this._pieceNodeCopyMove); |
|
|
|
|
this._disablePhysicsForPreviewNextFrame(this._pieceNodeCopyMove); |
|
|
|
|
if (fixedY != null) { |
|
|
|
|
this._pieceNodeCopyMove.setWorldPosition(new Vec3(startX, fixedY, startZ)); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
this._pieceNodeCopyMove = null; |
|
|
|
|
this._pieceNodeCopyMoveFixedWorldY = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this._previewNode = this._pieceNode; |
|
|
|
|
this._createAlignPreview(); |
|
|
|
|
this._playPreviewBlockSpine(TetriBlockSpineState.Falling); |
|
|
|
|
// 主预览叠在最上层,避免被预览二号挡住
|
|
|
|
|
if (this._pieceNode?.isValid && this._pieceNode.parent === this.chooseMask) { |
|
|
|
|
this._pieceNode.setSiblingIndex(this.chooseMask.children.length - 1); |
|
|
|
|
if (preview?.isValid && preview.parent === this.chooseMask) { |
|
|
|
|
preview.setSiblingIndex(this.chooseMask.children.length - 1); |
|
|
|
|
} |
|
|
|
|
this._createGuideLine(); |
|
|
|
|
} |
|
|
|
|
@ -735,58 +654,50 @@ export class tetriCardItem extends Component { |
|
|
|
|
this._setLayerRecursively(n, this.chooseMask.layer); |
|
|
|
|
n.active = true; |
|
|
|
|
n.angle = this._pieceNode.angle; |
|
|
|
|
this._disablePhysicsForPreview(n); |
|
|
|
|
this._disablePhysicsForPreviewNextFrame(n); |
|
|
|
|
this._stripPreviewForDrag(n); |
|
|
|
|
this._previewAlignNode = n; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 堆叠升高镜头拉远时与 tetriMap 一致,主预览与预览二号同比例缩小,贴近场上/白线副本观感 */ |
|
|
|
|
private _syncPreviewDragScaleForMapZoom(): void { |
|
|
|
|
if (!this._previewDragBaseScale || !this._pieceNode?.isValid) return; |
|
|
|
|
if (!this._previewDragBaseScale || !this._previewNode?.isValid) return; |
|
|
|
|
const z = this._boundMap?.getVisualZoomScale?.() ?? 1; |
|
|
|
|
const b = this._previewDragBaseScale; |
|
|
|
|
const sx = b.x * z; |
|
|
|
|
const sy = b.y * z; |
|
|
|
|
const sz = b.z * z; |
|
|
|
|
this._pieceNode.setScale(sx, sy, sz); |
|
|
|
|
this._previewNode.setScale(sx, sy, sz); |
|
|
|
|
if (this._previewAlignNode?.isValid) { |
|
|
|
|
this._previewAlignNode.setScale(sx, sy, sz); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private _restorePreviewPieceBaseScale(): void { |
|
|
|
|
if (this._pieceNode?.isValid && this._previewDragBaseScale) { |
|
|
|
|
const b = this._previewDragBaseScale; |
|
|
|
|
this._pieceNode.setScale(b.x, b.y, b.z); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private _destroyPreview(): void { |
|
|
|
|
this._invalidatePreviewPhysicsDisable(); |
|
|
|
|
/** 结束拖拽:销毁预览克隆,模板方块始终留在卡牌上 */ |
|
|
|
|
private _tearDownDragPreview(): void { |
|
|
|
|
this._destroyGuideLine(); |
|
|
|
|
this._destroyAlignPreview(); |
|
|
|
|
if (this._pieceNodeCopyMove && this._pieceNodeCopyMove.isValid) { |
|
|
|
|
if (this._pieceNodeCopyMove?.isValid) { |
|
|
|
|
this._pieceNodeCopyMove.destroy(); |
|
|
|
|
console.log('回收拖拽预览副 this._pieceNodeCopyMove1111'); |
|
|
|
|
//gg.res.putNode(this._pieceNodeCopyMove);
|
|
|
|
|
} |
|
|
|
|
this._pieceNodeCopyMove = null; |
|
|
|
|
this._pieceNodeCopyMoveFixedWorldY = null; |
|
|
|
|
if (this._pieceNode && this._previewNode === this._pieceNode) { |
|
|
|
|
this._restorePreviewPieceBaseScale(); |
|
|
|
|
// 将方块归还给卡牌
|
|
|
|
|
this.node.addChild(this._pieceNode); |
|
|
|
|
this._pieceNode.setPosition(this._pieceOriginLocalPos); |
|
|
|
|
playTetriBlockSpine(this._pieceNode, TetriBlockSpineState.Shop); |
|
|
|
|
if (this._previewNode?.isValid) { |
|
|
|
|
this._previewNode.destroy(); |
|
|
|
|
} |
|
|
|
|
this._previewNode = null; |
|
|
|
|
this._previewDragBaseScale = null; |
|
|
|
|
this.chooseMask.active = false; |
|
|
|
|
this.cancleNode.active = false |
|
|
|
|
if (this._pieceNode?.isValid) { |
|
|
|
|
playTetriBlockSpine(this._pieceNode, TetriBlockSpineState.Shop); |
|
|
|
|
} |
|
|
|
|
if (this.chooseMask) this.chooseMask.active = false; |
|
|
|
|
if (this.cancleNode) this.cancleNode.active = false; |
|
|
|
|
this._restoreCancelNodeScale(); |
|
|
|
|
this._clampRelAABB = null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private _destroyPreview(): void { |
|
|
|
|
this._tearDownDragPreview(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**拖入取消区时做一次轻微放大反馈 */ |
|
|
|
|
private _playCancelHoverFeedback(): void { |
|
|
|
|
if (!this.cancleNode?.isValid) return; |
|
|
|
|
@ -1023,6 +934,26 @@ export class tetriCardItem extends Component { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 白线预览块:每帧按当前高度线重算 Y(堆叠升高时白线会平滑上移) */ |
|
|
|
|
private _syncWhiteLinePreviewPosition(): void { |
|
|
|
|
if (gg.game.isShowBlockDrop) return; |
|
|
|
|
if (!this._pieceNodeCopyMove?.isValid || !this._previewNode?.isValid) return; |
|
|
|
|
const fixedY = this._getWhiteLineFixedWorldYFor(this._pieceNodeCopyMove); |
|
|
|
|
if (fixedY == null) return; |
|
|
|
|
const x = this._toGameWorldXFromUiWorldX(this._previewNode.worldPosition.x); |
|
|
|
|
const z = this._pieceNodeCopyMove.worldPosition.z; |
|
|
|
|
this._pieceNodeCopyMove.setWorldPosition(new Vec3(x, fixedY, z)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected lateUpdate(): void { |
|
|
|
|
if (!this._previewNode?.isValid) return; |
|
|
|
|
this._syncPreviewDragScaleForMapZoom(); |
|
|
|
|
this._syncWhiteLinePreviewPosition(); |
|
|
|
|
if (this._guideLine?.active) { |
|
|
|
|
this._updateGuideLine(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private _syncPreviewToTouch(event: EventTouch): void { |
|
|
|
|
if (!this._previewNode || !this.chooseMask) return; |
|
|
|
|
const uiPos = event.getUILocation(); |
|
|
|
|
@ -1063,14 +994,8 @@ export class tetriCardItem extends Component { |
|
|
|
|
// this._clampPreviewByPosition(maskUT, this._previewNode);
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// 白线预览块:Y 固定在白线上,X 跟随主拖拽方块(受钳制后的最终位置)
|
|
|
|
|
if (!gg.game.isShowBlockDrop && this._pieceNodeCopyMove && this._pieceNodeCopyMove.isValid && this._pieceNodeCopyMoveFixedWorldY != null) { |
|
|
|
|
const x = this._toGameWorldXFromUiWorldX(this._previewNode.worldPosition.x); |
|
|
|
|
const z = this._pieceNodeCopyMove.worldPosition.z; |
|
|
|
|
this._pieceNodeCopyMove.setWorldPosition(new Vec3(x, this._pieceNodeCopyMoveFixedWorldY, z)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this._syncPreviewDragScaleForMapZoom(); |
|
|
|
|
this._syncWhiteLinePreviewPosition(); |
|
|
|
|
|
|
|
|
|
let time = Date.now() - this._startTime; |
|
|
|
|
const wasOverCancel = this._isOverCancel; |
|
|
|
|
@ -1272,9 +1197,10 @@ export class tetriCardItem extends Component { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 同步主预览、白线副本、对齐预览的表情 Spine */ |
|
|
|
|
/** 同步主预览、白线副本、对齐预览的方块表情 Spine */ |
|
|
|
|
private _playPreviewBlockSpine(state: TetriBlockSpineState): void { |
|
|
|
|
playTetriBlockSpine(this._pieceNode, state); |
|
|
|
|
playTetriBlockSpine(this._previewNode, state); |
|
|
|
|
playTetriBlockSpine(this._pieceNodeCopyMove, state); |
|
|
|
|
playTetriBlockSpine(this._previewAlignNode, state); |
|
|
|
|
} |
|
|
|
|
|