|
|
|
|
@ -6,9 +6,9 @@ |
|
|
|
|
//*********************
|
|
|
|
|
import { |
|
|
|
|
_decorator, Color, Collider2D, Component, Contact2DType, ERigidBody2DType, find, |
|
|
|
|
instantiate, IPhysics2DContact, isValid, Layers, Node, ParticleSystem2D, PhysicsSystem2D, ProgressBar, |
|
|
|
|
instantiate, isValid, Layers, Node, ParticleSystem2D, PhysicsSystem2D, ProgressBar, |
|
|
|
|
RigidBody2D, sp, Tween, UITransform, tween, v3, Vec3, |
|
|
|
|
Label, |
|
|
|
|
Label, IPhysics2DContact, |
|
|
|
|
} from 'cc'; |
|
|
|
|
import { AelementLayer } from './AelementLayer'; |
|
|
|
|
import { Aelement } from './Aelement'; |
|
|
|
|
@ -61,8 +61,6 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
private static readonly MUBAN_PREFAB_NAMES = [ |
|
|
|
|
'木板1_2','木板2_2','木板3_2','木板4_2','木板5_2','木板6_1','木板7_3','木板8_2' |
|
|
|
|
]; |
|
|
|
|
/** 与 settings physics.collisionGroups index 11「muban1」一致 */ |
|
|
|
|
private static readonly MUBAN_PHYSICS_GROUP = 1 << 11; |
|
|
|
|
onLoad(): void { |
|
|
|
|
super.onLoad(); |
|
|
|
|
} |
|
|
|
|
@ -70,24 +68,24 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
onEnable(): void { |
|
|
|
|
super.onEnable(); |
|
|
|
|
this._ensureJiujiuwoyaPhysics(); |
|
|
|
|
this._bindMubanNoBouncePhysics(); |
|
|
|
|
GEvent.Ins.on(GEvent.playerHit, this.onPlayerHit, this); |
|
|
|
|
GEvent.Ins.on(GEvent.tetriGameStart, this.onTetriGameStart, this); |
|
|
|
|
GEvent.Ins.on(GEvent.GameReborn, this.gameReborn, this); |
|
|
|
|
GEvent.Ins.on(GEvent.UpdateDps, this.updateDps, this); |
|
|
|
|
GEvent.Ins.on(GEvent.UpdateWallHp, this.refreshWallHp, this); |
|
|
|
|
GEvent.Ins.on(GEvent.BattleWaveRefresh, this.onBattleWaveRefresh, this); |
|
|
|
|
PhysicsSystem2D.instance.on(Contact2DType.PRE_SOLVE, this._onMubanPreSolve, this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
onDisable(): void { |
|
|
|
|
super.onDisable(); |
|
|
|
|
this._unbindMubanNoBouncePhysics(); |
|
|
|
|
GEvent.Ins.off(GEvent.playerHit, this.onPlayerHit, this); |
|
|
|
|
GEvent.Ins.off(GEvent.tetriGameStart, this.onTetriGameStart, this); |
|
|
|
|
GEvent.Ins.off(GEvent.GameReborn, this.gameReborn, this); |
|
|
|
|
GEvent.Ins.off(GEvent.UpdateDps, this.updateDps, this); |
|
|
|
|
GEvent.Ins.off(GEvent.UpdateWallHp, this.refreshWallHp, this); |
|
|
|
|
GEvent.Ins.off(GEvent.BattleWaveRefresh, this.onBattleWaveRefresh, this); |
|
|
|
|
PhysicsSystem2D.instance.off(Contact2DType.PRE_SOLVE, this._onMubanPreSolve, this); |
|
|
|
|
if (gg.game.CurentBattle) { |
|
|
|
|
gg.game.CurentBattle.onJiujiuwoyaLuosiEnteredSlot = null; |
|
|
|
|
gg.game.CurentBattle.onJiujiuwoyaLuosiPairRemovedFromSlot = null; |
|
|
|
|
@ -104,15 +102,34 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
this.CurentBattle.jiujiuwoyaSoltFullFail = false; |
|
|
|
|
this.CurentBattle.startGame() |
|
|
|
|
this.eliminateTwoScrewPairs(); |
|
|
|
|
this.scheduleOnce(() => this._reconcileAllBoardPhysics(), 1.5); |
|
|
|
|
}, 1.0) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 复活后按场上实际螺丝数恢复木板约束/掉落物理 */ |
|
|
|
|
private _reconcileAllBoardPhysics() { |
|
|
|
|
const parent = this.ui_mubanLayer; |
|
|
|
|
if (!parent?.isValid) return; |
|
|
|
|
for (const layer of parent.children) { |
|
|
|
|
if (!layer?.isValid) continue; |
|
|
|
|
for (const board of layer.children) { |
|
|
|
|
board.getComponent(Aelement)?.reconcilePhysicsState(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updateDps(delay: number = 0) { |
|
|
|
|
if(gg.game.noMonsterShow) return; |
|
|
|
|
|
|
|
|
|
let dps = this.CurentBattle.dps(); |
|
|
|
|
dps = Math.floor(dps); |
|
|
|
|
if (this.CurentBattle?.skipNextDpsFlyAnim) { |
|
|
|
|
this.CurentBattle.skipNextDpsFlyAnim = false; |
|
|
|
|
this._lastDps = dps; |
|
|
|
|
this.lb_dps.string = MTools.formatChineseUnit({ num: dps }); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (dps == this._lastDps || dps == 0) { |
|
|
|
|
if (dps == 0) { |
|
|
|
|
this.lb_dps.string = '0'; |
|
|
|
|
@ -187,55 +204,43 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
Physics2DGate.beginBattle(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 向上找到挂 Aelement 的木板根节点 */ |
|
|
|
|
private _findMubanRoot(from: Node): Node | null { |
|
|
|
|
let n: Node | null = from; |
|
|
|
|
while (n?.isValid) { |
|
|
|
|
if (n.getComponent(Aelement)) return n; |
|
|
|
|
n = n.parent; |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
/** 木板/地板碰撞:解算前强制无弹性(不在此阶段读写 velocity,避免只读 Vec2 报错) */ |
|
|
|
|
private _bindMubanNoBouncePhysics() { |
|
|
|
|
PhysicsSystem2D.instance.on(Contact2DType.PRE_SOLVE, this._onMubanPreSolve, this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 木板所在逻辑层(layer1…layer25,挂 AelementLayer) */ |
|
|
|
|
private _getMubanLogicLayerNode(mubanRoot: Node): Node | null { |
|
|
|
|
const p = mubanRoot.parent; |
|
|
|
|
return p?.isValid && p.getComponent(AelementLayer) ? p : null; |
|
|
|
|
private _unbindMubanNoBouncePhysics() { |
|
|
|
|
PhysicsSystem2D.instance.off(Contact2DType.PRE_SOLVE, this._onMubanPreSolve, this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* muban1 分层碰撞:不同 layer 互不碰撞;掉落板穿透其它木板,仅与 floor 等作用。 |
|
|
|
|
*/ |
|
|
|
|
private _onMubanPreSolve(self: Collider2D, other: Collider2D, contact: IPhysics2DContact | null): void { |
|
|
|
|
private _onMubanPreSolve(self: Collider2D, other: Collider2D, contact: IPhysics2DContact | null) { |
|
|
|
|
if (!contact) return; |
|
|
|
|
if (self.group !== UIjiujiuwoyaGame.MUBAN_PHYSICS_GROUP |
|
|
|
|
|| other.group !== UIjiujiuwoyaGame.MUBAN_PHYSICS_GROUP) return; |
|
|
|
|
|
|
|
|
|
const aRoot = this._findMubanRoot(self.node); |
|
|
|
|
const bRoot = this._findMubanRoot(other.node); |
|
|
|
|
if (!aRoot || !bRoot || aRoot === bRoot) return; |
|
|
|
|
|
|
|
|
|
const aElem = aRoot.getComponent(Aelement); |
|
|
|
|
const bElem = bRoot.getComponent(Aelement); |
|
|
|
|
if (aElem?.isFalling || bElem?.isFalling) { |
|
|
|
|
this._disableMubanContact(contact); |
|
|
|
|
const aeA = this._getAelementFromCollider(self); |
|
|
|
|
const aeB = this._getAelementFromCollider(other); |
|
|
|
|
// 堆叠木板互相穿插,开刚体后分离冲量会表现为弹跳/颤抖:木板之间一律不碰撞
|
|
|
|
|
if (aeA && aeB) { |
|
|
|
|
contact.disabled = true; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const layerA = this._getMubanLogicLayerNode(aRoot); |
|
|
|
|
const layerB = this._getMubanLogicLayerNode(bRoot); |
|
|
|
|
if (!layerA || !layerB || layerA === layerB) return; |
|
|
|
|
|
|
|
|
|
this._disableMubanContact(contact); |
|
|
|
|
const swinging = aeA?.isSwinging || aeB?.isSwinging; |
|
|
|
|
if (swinging) { |
|
|
|
|
contact.disabled = true; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private _disableMubanContact(contact: IPhysics2DContact): void { |
|
|
|
|
try { |
|
|
|
|
const se = (contact as { setEnabled?: (e: boolean) => void }).setEnabled; |
|
|
|
|
if (typeof se === 'function') se.call(contact, false); |
|
|
|
|
} catch { /* ignore */ } |
|
|
|
|
if (!aeA && !aeB) return; |
|
|
|
|
try { contact.setRestitution(0); } catch { /* ignore */ } |
|
|
|
|
try { contact.setFriction(0.4); } catch { /* ignore */ } |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private _getAelementFromCollider(col: Collider2D): Aelement | null { |
|
|
|
|
let n: Node | null = col?.node ?? null; |
|
|
|
|
while (n?.isValid) { |
|
|
|
|
const ae = n.getComponent(Aelement); |
|
|
|
|
if (ae) return ae; |
|
|
|
|
n = n.parent; |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
setLayerMask(n: Node, layerMask: number) { |
|
|
|
|
n.layer = layerMask; |
|
|
|
|
@ -346,7 +351,8 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
let roleNode = roleNodes[i] |
|
|
|
|
if (!roleNode?.isValid) continue; |
|
|
|
|
const carrier = roleNode.getOrAddComponent(tetriWeaponCarrier) |
|
|
|
|
carrier.setConfig(cards[i]) |
|
|
|
|
carrier.setConfig(cards[i], true, true) |
|
|
|
|
carrier.ensureBattleReady() |
|
|
|
|
carriers.push(carrier); |
|
|
|
|
let weaponId = carrier.getCurWeaponId() |
|
|
|
|
if (weaponId) { |
|
|
|
|
@ -388,6 +394,8 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
col.group = floorGroup; |
|
|
|
|
col.sensor = false; |
|
|
|
|
col.enabled = true; |
|
|
|
|
col.restitution = 0; |
|
|
|
|
col.friction = 0.35; |
|
|
|
|
const apply = (col as { apply?: () => void }).apply; |
|
|
|
|
if (typeof apply === 'function') apply.call(col); |
|
|
|
|
} |
|
|
|
|
@ -443,11 +451,24 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
private onMubanSpawnFinished() { |
|
|
|
|
this._mubanSpawnDone++; |
|
|
|
|
if (this._battleStartedAfterMuban || this._mubanSpawnDone < this._mubanSpawnTotal) return; |
|
|
|
|
this._finalizeMubanSpawnPhysics(); |
|
|
|
|
this._battleStartedAfterMuban = true; |
|
|
|
|
this.CurentBattle?.startWarnTime(); |
|
|
|
|
this.CurentBattle.mubanSpawnFinished = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 全部木板与螺丝就位后,仅开启 Polygon 遮挡检测(不启用刚体,避免 128 板 + 铰链拖垮物理) */ |
|
|
|
|
private _finalizeMubanSpawnPhysics() { |
|
|
|
|
const parent = this.ui_mubanLayer; |
|
|
|
|
if (!parent?.isValid) return; |
|
|
|
|
for (const layer of parent.children) { |
|
|
|
|
if (!layer?.isValid) continue; |
|
|
|
|
for (const board of layer.children) { |
|
|
|
|
board.getComponent(Aelement)?.prepareColliderForGameplay(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** 在指定 layer 内生成一块木板,随机位置与角度 */ |
|
|
|
|
private spawnMubanCard(prefabName: string, layerIndex: number) { |
|
|
|
|
const parent = this.ui_mubanLayer; |
|
|
|
|
@ -468,6 +489,7 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
boardNode.parent = layerNode; |
|
|
|
|
boardNode.getComponent(Aelement)?.prepareColliderForGameplay(); |
|
|
|
|
boardNode.scale = v3(0, 0, 0); |
|
|
|
|
tween(boardNode) |
|
|
|
|
.to(0.1, { scale: v3(1.1, 1.1, 1.1) }) |
|
|
|
|
@ -506,7 +528,6 @@ export class UIjiujiuwoyaGame extends Auto_jiujiuwoyaGame { |
|
|
|
|
const parent = this.ui_mubanLayer; |
|
|
|
|
if (!boardNode?.isValid || !parent?.isValid) return; |
|
|
|
|
const aelement = boardNode.getComponent(Aelement); |
|
|
|
|
aelement?.enablePhysics(); |
|
|
|
|
const holes = aelement?.getHoleNodes() ?? []; |
|
|
|
|
aelement?.initScrewCount(holes.length); |
|
|
|
|
for (const hole of holes) { |
|
|
|
|
|