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.
AdLike2048/assets/script/ui/BattleGame/BattleGameItemAdPresenter.ts

234 lines
8.2 KiB

2 weeks ago
import { game, Node } from 'cc';
3 weeks ago
import { BattlePhase } from 'db://assets/mx/module/battle';
import { GEvent } from '../../../mx/module/event/GEvent';
import { getShieldAdTriggerDist } from '../../battle/bag/BagPrepConfig';
import { BattleUiPauseGate } from '../../battle/BattleUiPauseGate';
import type { ProjectBattleHandle } from '../../battle/runtime/BattleRuntime';
import type { BattleGameMenShenTrapController } from './BattleGameMenShenTrapController';
import { BattleGameItemAdBtnPulse } from './BattleGameItemAdBtnPulse';
/** 广告类型 */
enum ItemAdKind {
/** 无 */
None = 0,
2 weeks ago
/** 门神盾牌 */
3 weeks ago
MenShen = 1,
}
/** 观看广告期间暂停 */
const AD_PAUSE_TOKEN = 'ad:battleItem';
/**
2 weeks ago
* BattleGame btnItem:门神盾牌广告入口。
3 weeks ago
* - 盾牌:怪首次离终点 Const23 格内触发,每局 1 次;放置陷阱后隐藏
*/
export class BattleGameItemAdPresenter {
private _btnItem: Node | null = null;
private _menIcon: Node | null = null;
private _videoIcon: Node | null = null;
private _battle: ProjectBattleHandle | null = null;
private _menShenTrap: BattleGameMenShenTrapController | null = null;
private _adPending = false;
private _activeKind = ItemAdKind.None;
private _shieldScanDone = false;
/** 盾牌广告已点击并放置陷阱 */
private _shieldBtnDismissed = false;
private _onBoardChanged: (() => void) | null = null;
private readonly _btnPulse = new BattleGameItemAdBtnPulse();
private _btnPulseActive = false;
/** 威胁扫描降频 */
private _threatScanAcc = 0;
/** 缓存:Const23 内是否有进攻怪 */
private _threatInZone = false;
/**
* @param btnItem ui_ready/btnItem 根节点
* @param menShenTrap 门神陷阱控制器
*/
2 weeks ago
bind(battle: ProjectBattleHandle | null, btnItem: Node | null, menShenTrap: BattleGameMenShenTrapController | null): void {
3 weeks ago
this.unbind();
this._battle = battle;
this._menShenTrap = menShenTrap;
this._btnItem = btnItem;
if (!btnItem?.isValid) {
console.log('[BattleItemAd] btnItem 缺失');
return;
}
2 weeks ago
const shovelIcon = btnItem.getChildByName('shovelIcon');
const goldShovelIcon = btnItem.getChildByName('goldShovelIcon');
const numNode = btnItem.getChildByName('num');
this._setNodeActive(shovelIcon, false);
this._setNodeActive(goldShovelIcon, false);
this._setNodeActive(numNode, false);
3 weeks ago
this._menIcon = btnItem.getChildByName('menIcon');
this._videoIcon = btnItem.getChildByName('video');
btnItem.on(Node.EventType.TOUCH_END, this._onBtnClick, this);
this._onBoardChanged = () => this._refreshVisibility();
GEvent.Ins.on(GEvent.UpdateBestPlace, this._onBoardChanged, this);
this._refreshVisibility();
}
/** 解除绑定 */
unbind(): void {
if (this._btnItem?.isValid) {
this._btnItem.off(Node.EventType.TOUCH_END, this._onBtnClick, this);
}
if (this._onBoardChanged) {
GEvent.Ins.off(GEvent.UpdateBestPlace, this._onBoardChanged, this);
}
this._onBoardChanged = null;
if (this._adPending) {
this._adPending = false;
BattleUiPauseGate.release(AD_PAUSE_TOKEN);
}
this._btnItem = null;
this._menIcon = null;
this._videoIcon = null;
this._battle = null;
this._menShenTrap = null;
this._activeKind = ItemAdKind.None;
this._shieldScanDone = false;
this._shieldBtnDismissed = false;
this._btnPulseActive = false;
this._threatScanAcc = 0;
this._threatInZone = false;
this._syncBtnPulse(false);
}
/** 帧更新:扫描盾牌触发条件并刷新显隐 */
tick(_dt: number): void {
this._threatScanAcc++;
if (this._threatScanAcc % 12 === 1) {
this._threatInZone = this._scanThreatInZone();
}
this._tickShieldOffer();
this._refreshVisibility();
}
/** 首次满足距离时触发盾牌广告 */
private _tickShieldOffer(): void {
const battle = this._battle;
const trap = this._menShenTrap;
if (!battle || !trap || battle.menShenAdConsumed) return;
if (battle.canShowMenShenAd()) {
this._shieldScanDone = true;
return;
}
if (this._shieldScanDone) return;
if (battle.session.phase !== BattlePhase.COMBAT || battle.session.ended) return;
const triggerDist = getShieldAdTriggerDist();
if (!(triggerDist > 0)) return;
if (!this._threatInZone) return;
battle.triggerMenShenAdOffer();
this._shieldScanDone = true;
}
/** 刷新 btnItem 显隐与图标 */
private _refreshVisibility(): void {
const kind = this._resolveActiveKind();
this._activeKind = kind;
const btn = this._btnItem;
if (!btn?.isValid) return;
const show = kind !== ItemAdKind.None;
if (btn.active !== show) btn.active = show;
this._syncBtnPulse(show);
if (!show) return;
const showMen = kind === ItemAdKind.MenShen;
this._setNodeActive(this._menIcon, showMen);
this._setNodeActive(this._videoIcon, true);
}
2 weeks ago
/** 解析当前应展示的广告类型(仅门神盾牌) */
3 weeks ago
private _resolveActiveKind(): ItemAdKind {
const battle = this._battle;
if (!battle || battle.session.ended) return ItemAdKind.None;
const canMenShen = !this._shieldBtnDismissed && battle.canShowMenShenAd();
const hasThreatInConst23 = this._hasMonsterInShieldTriggerZone();
if (canMenShen && hasThreatInConst23) return ItemAdKind.MenShen;
if (canMenShen) return ItemAdKind.MenShen;
return ItemAdKind.None;
}
/** Const23 触发距离内是否存在进攻怪(用降频缓存) */
private _hasMonsterInShieldTriggerZone(): boolean {
return this._threatInZone;
}
/** 扫描 Const23 内进攻怪 */
private _scanThreatInZone(): boolean {
const trap = this._menShenTrap;
if (!trap || !this._battle) return false;
const triggerDist = getShieldAdTriggerDist();
if (!(triggerDist > 0)) return false;
return trap.shouldOfferShieldAd(triggerDist);
}
private readonly _onBtnClick = (): void => {
2 weeks ago
if (this._adPending) return;
3 weeks ago
const kind = this._activeKind;
if (kind === ItemAdKind.MenShen) {
this._playMenShenAd();
}
};
/** 观看门神广告并布置陷阱 */
private _playMenShenAd(): void {
const battle = this._battle;
const trap = this._menShenTrap;
if (!battle?.canShowMenShenAd() || !trap) return;
this._adPending = true;
BattleUiPauseGate.acquire(AD_PAUSE_TOKEN);
gg.sdk.showVideoAd((res) => {
if (!this._adPending) return;
this._adPending = false;
BattleUiPauseGate.release(AD_PAUSE_TOKEN);
if (game.isPaused()) game.resume();
if (!res) {
gg.ui.showToast('观看视频失败');
return;
}
const b = this._battle;
const t = this._menShenTrap;
if (!b?.canShowMenShenAd() || !t) return;
b.IsWatchAd = true;
b.consumeMenShenAd();
if (!t.tryPlaceTraps()) {
console.log('[BattleItemAd] 门神陷阱放置失败');
}
const curWaveNum = gg.game.CurentBattle.CurentWaveNum;
gg.sdk.reportDY('inLevel', `${gg.game.getReportDYBattleCountLabel(curWaveNum)}-AD-广告门神盾牌`);
this._shieldBtnDismissed = true;
this._refreshVisibility();
});
}
private _setNodeActive(node: Node | null, active: boolean): void {
if (node?.isValid && node.active !== active) node.active = active;
}
/** btnItem 显示时循环跳动,隐藏时停止 */
private _syncBtnPulse(active: boolean): void {
if (active === this._btnPulseActive) return;
this._btnPulseActive = active;
if (active) {
this._btnPulse.bind(this._btnItem);
} else {
this._btnPulse.unbind();
}
}
}