整理文档并接入 H5 体验测试链路
This commit is contained in:
@@ -13,7 +13,8 @@ import { type OrienteeringCourseData } from '../../utils/orienteeringCourse'
|
||||
import { isTileWithinBounds, type RemoteMapConfig, type TileZoomBounds } from '../../utils/remoteMapConfig'
|
||||
import { formatAnimationLevelText, resolveAnimationLevel, type AnimationLevel } from '../../utils/animationLevel'
|
||||
import { GameRuntime } from '../../game/core/gameRuntime'
|
||||
import { type GameControlDisplayContentOverride } from '../../game/core/gameDefinition'
|
||||
import { type GameControl, type GameControlDisplayContentOverride } from '../../game/core/gameDefinition'
|
||||
import { type H5ExperienceFallbackPayload, type H5ExperienceRequest } from '../../game/experience/h5Experience'
|
||||
import { type GameEffect, type GameResult } from '../../game/core/gameResult'
|
||||
import { buildGameDefinitionFromCourse } from '../../game/content/courseToGameDefinition'
|
||||
import { FeedbackDirector } from '../../game/feedback/feedbackDirector'
|
||||
@@ -228,6 +229,8 @@ export interface MapEngineViewState {
|
||||
contentCardVisible: boolean
|
||||
contentCardTitle: string
|
||||
contentCardBody: string
|
||||
pendingContentEntryVisible: boolean
|
||||
pendingContentEntryText: string
|
||||
punchButtonFxClass: string
|
||||
panelProgressFxClass: string
|
||||
panelDistanceFxClass: string
|
||||
@@ -245,6 +248,18 @@ export interface MapEngineViewState {
|
||||
|
||||
export interface MapEngineCallbacks {
|
||||
onData: (patch: Partial<MapEngineViewState>) => void
|
||||
onOpenH5Experience?: (request: H5ExperienceRequest) => void
|
||||
}
|
||||
|
||||
interface ContentCardEntry {
|
||||
title: string
|
||||
body: string
|
||||
motionClass: string
|
||||
contentKey: string
|
||||
once: boolean
|
||||
priority: number
|
||||
autoPopup: boolean
|
||||
h5Request: H5ExperienceRequest | null
|
||||
}
|
||||
|
||||
export interface MapEngineGameInfoRow {
|
||||
@@ -368,6 +383,8 @@ const VIEW_SYNC_KEYS: Array<keyof MapEngineViewState> = [
|
||||
'contentCardVisible',
|
||||
'contentCardTitle',
|
||||
'contentCardBody',
|
||||
'pendingContentEntryVisible',
|
||||
'pendingContentEntryText',
|
||||
'punchButtonFxClass',
|
||||
'panelProgressFxClass',
|
||||
'panelDistanceFxClass',
|
||||
@@ -889,17 +906,22 @@ export class MapEngine {
|
||||
contentCardTimer: number
|
||||
currentContentCardPriority: number
|
||||
shownContentCardKeys: Record<string, true>
|
||||
currentContentCard: ContentCardEntry | null
|
||||
pendingContentCards: ContentCardEntry[]
|
||||
currentH5ExperienceOpen: boolean
|
||||
mapPulseTimer: number
|
||||
stageFxTimer: number
|
||||
sessionTimerInterval: number
|
||||
hasGpsCenteredOnce: boolean
|
||||
gpsLockEnabled: boolean
|
||||
onOpenH5Experience?: (request: H5ExperienceRequest) => void
|
||||
|
||||
constructor(buildVersion: string, callbacks: MapEngineCallbacks) {
|
||||
this.buildVersion = buildVersion
|
||||
this.animationLevel = resolveAnimationLevel(wx.getSystemInfoSync())
|
||||
this.compassTuningProfile = 'balanced'
|
||||
this.onData = callbacks.onData
|
||||
this.onOpenH5Experience = callbacks.onOpenH5Experience
|
||||
this.accelerometerErrorText = null
|
||||
this.renderer = new WebGLMapRenderer(
|
||||
(stats) => {
|
||||
@@ -1144,6 +1166,9 @@ export class MapEngine {
|
||||
this.contentCardTimer = 0
|
||||
this.currentContentCardPriority = 0
|
||||
this.shownContentCardKeys = {}
|
||||
this.currentContentCard = null
|
||||
this.pendingContentCards = []
|
||||
this.currentH5ExperienceOpen = false
|
||||
this.mapPulseTimer = 0
|
||||
this.stageFxTimer = 0
|
||||
this.sessionTimerInterval = 0
|
||||
@@ -1258,6 +1283,8 @@ export class MapEngine {
|
||||
contentCardVisible: false,
|
||||
contentCardTitle: '',
|
||||
contentCardBody: '',
|
||||
pendingContentEntryVisible: false,
|
||||
pendingContentEntryText: '',
|
||||
punchButtonFxClass: '',
|
||||
panelProgressFxClass: '',
|
||||
panelDistanceFxClass: '',
|
||||
@@ -1707,6 +1734,196 @@ export class MapEngine {
|
||||
}
|
||||
}
|
||||
|
||||
getPendingManualContentCount(): number {
|
||||
return this.pendingContentCards.filter((item) => !item.autoPopup).length
|
||||
}
|
||||
|
||||
buildPendingContentEntryText(): string {
|
||||
const count = this.getPendingManualContentCount()
|
||||
if (count <= 1) {
|
||||
return count === 1 ? '查看内容' : ''
|
||||
}
|
||||
return `查看内容(${count})`
|
||||
}
|
||||
|
||||
syncPendingContentEntryState(immediate = true): void {
|
||||
const count = this.getPendingManualContentCount()
|
||||
this.setState({
|
||||
pendingContentEntryVisible: count > 0,
|
||||
pendingContentEntryText: this.buildPendingContentEntryText(),
|
||||
}, immediate)
|
||||
}
|
||||
|
||||
resolveContentControlByKey(contentKey: string): { control: GameControl; displayMode: 'auto' | 'click' } | null {
|
||||
if (!contentKey || !this.gameRuntime.definition) {
|
||||
return null
|
||||
}
|
||||
|
||||
const isClickContent = contentKey.indexOf(':click') >= 0
|
||||
const controlId = isClickContent ? contentKey.replace(/:click$/, '') : contentKey
|
||||
const control = this.gameRuntime.definition.controls.find((item) => item.id === controlId)
|
||||
if (!control || !control.displayContent) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
control,
|
||||
displayMode: isClickContent ? 'click' : 'auto',
|
||||
}
|
||||
}
|
||||
|
||||
buildContentH5Request(
|
||||
contentKey: string,
|
||||
title: string,
|
||||
body: string,
|
||||
motionClass: string,
|
||||
once: boolean,
|
||||
priority: number,
|
||||
autoPopup: boolean,
|
||||
): H5ExperienceRequest | null {
|
||||
const resolved = this.resolveContentControlByKey(contentKey)
|
||||
if (!resolved) {
|
||||
return null
|
||||
}
|
||||
|
||||
const displayContent = resolved.control.displayContent
|
||||
if (!displayContent) {
|
||||
return null
|
||||
}
|
||||
|
||||
const experienceConfig = resolved.displayMode === 'click'
|
||||
? displayContent.clickExperience
|
||||
: displayContent.contentExperience
|
||||
if (!experienceConfig || experienceConfig.type !== 'h5' || !experienceConfig.url) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
kind: 'content',
|
||||
title: title || resolved.control.label || '内容体验',
|
||||
url: experienceConfig.url,
|
||||
bridgeVersion: experienceConfig.bridge || 'content-v1',
|
||||
context: {
|
||||
eventId: this.configAppId || '',
|
||||
configTitle: this.state.mapName || '',
|
||||
configVersion: this.configVersion || '',
|
||||
mode: this.gameMode,
|
||||
sessionStatus: this.gameRuntime.state ? this.gameRuntime.state.status : 'idle',
|
||||
controlId: resolved.control.id,
|
||||
controlKind: resolved.control.kind,
|
||||
controlCode: resolved.control.code,
|
||||
controlLabel: resolved.control.label,
|
||||
controlSequence: resolved.control.sequence,
|
||||
displayMode: resolved.displayMode,
|
||||
title,
|
||||
body,
|
||||
},
|
||||
fallback: {
|
||||
title,
|
||||
body,
|
||||
motionClass,
|
||||
contentKey,
|
||||
once,
|
||||
priority,
|
||||
autoPopup,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
hasActiveContentExperience(): boolean {
|
||||
return this.state.contentCardVisible || this.currentH5ExperienceOpen
|
||||
}
|
||||
|
||||
enqueueContentCard(item: ContentCardEntry): void {
|
||||
if (item.once && item.contentKey && this.shownContentCardKeys[item.contentKey]) {
|
||||
return
|
||||
}
|
||||
if (item.contentKey && this.pendingContentCards.some((pending) => pending.contentKey === item.contentKey && pending.autoPopup === item.autoPopup)) {
|
||||
return
|
||||
}
|
||||
this.pendingContentCards.push(item)
|
||||
this.syncPendingContentEntryState()
|
||||
}
|
||||
|
||||
openContentCardEntry(item: ContentCardEntry): void {
|
||||
this.clearContentCardTimer()
|
||||
if (item.h5Request && this.onOpenH5Experience) {
|
||||
this.setState({
|
||||
contentCardVisible: false,
|
||||
contentCardFxClass: '',
|
||||
pendingContentEntryVisible: false,
|
||||
pendingContentEntryText: '',
|
||||
}, true)
|
||||
this.currentContentCardPriority = item.priority
|
||||
this.currentContentCard = item
|
||||
this.currentH5ExperienceOpen = true
|
||||
if (item.once && item.contentKey) {
|
||||
this.shownContentCardKeys[item.contentKey] = true
|
||||
}
|
||||
try {
|
||||
this.onOpenH5Experience(item.h5Request)
|
||||
return
|
||||
} catch {
|
||||
this.currentH5ExperienceOpen = false
|
||||
this.currentContentCardPriority = 0
|
||||
this.currentContentCard = null
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
contentCardVisible: true,
|
||||
contentCardTitle: item.title,
|
||||
contentCardBody: item.body,
|
||||
contentCardFxClass: item.motionClass,
|
||||
pendingContentEntryVisible: false,
|
||||
pendingContentEntryText: '',
|
||||
}, true)
|
||||
this.currentContentCardPriority = item.priority
|
||||
this.currentContentCard = item
|
||||
if (item.once && item.contentKey) {
|
||||
this.shownContentCardKeys[item.contentKey] = true
|
||||
}
|
||||
this.contentCardTimer = setTimeout(() => {
|
||||
this.contentCardTimer = 0
|
||||
this.currentContentCardPriority = 0
|
||||
this.currentContentCard = null
|
||||
this.setState({
|
||||
contentCardVisible: false,
|
||||
contentCardFxClass: '',
|
||||
}, true)
|
||||
this.flushQueuedContentCards()
|
||||
}, 2600) as unknown as number
|
||||
}
|
||||
|
||||
flushQueuedContentCards(): void {
|
||||
if (this.state.contentCardVisible || !this.pendingContentCards.length) {
|
||||
this.syncPendingContentEntryState()
|
||||
return
|
||||
}
|
||||
|
||||
let candidateIndex = -1
|
||||
let candidatePriority = Number.NEGATIVE_INFINITY
|
||||
|
||||
for (let index = 0; index < this.pendingContentCards.length; index += 1) {
|
||||
const item = this.pendingContentCards[index]
|
||||
if (!item.autoPopup) {
|
||||
continue
|
||||
}
|
||||
if (item.priority > candidatePriority) {
|
||||
candidatePriority = item.priority
|
||||
candidateIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
if (candidateIndex < 0) {
|
||||
this.syncPendingContentEntryState()
|
||||
return
|
||||
}
|
||||
|
||||
const nextItem = this.pendingContentCards.splice(candidateIndex, 1)[0]
|
||||
this.openContentCardEntry(nextItem)
|
||||
}
|
||||
|
||||
clearMapPulseTimer(): void {
|
||||
if (this.mapPulseTimer) {
|
||||
clearTimeout(this.mapPulseTimer)
|
||||
@@ -1734,6 +1951,8 @@ export class MapEngine {
|
||||
contentCardVisible: false,
|
||||
contentCardTitle: '',
|
||||
contentCardBody: '',
|
||||
pendingContentEntryVisible: this.getPendingManualContentCount() > 0,
|
||||
pendingContentEntryText: this.buildPendingContentEntryText(),
|
||||
contentCardFxClass: '',
|
||||
mapPulseVisible: false,
|
||||
mapPulseFxClass: '',
|
||||
@@ -1744,11 +1963,20 @@ export class MapEngine {
|
||||
panelDistanceFxClass: '',
|
||||
}, true)
|
||||
this.currentContentCardPriority = 0
|
||||
this.currentContentCard = null
|
||||
this.currentH5ExperienceOpen = false
|
||||
}
|
||||
|
||||
resetSessionContentExperienceState(): void {
|
||||
this.shownContentCardKeys = {}
|
||||
this.currentContentCardPriority = 0
|
||||
this.currentContentCard = null
|
||||
this.pendingContentCards = []
|
||||
this.currentH5ExperienceOpen = false
|
||||
this.setState({
|
||||
pendingContentEntryVisible: false,
|
||||
pendingContentEntryText: '',
|
||||
})
|
||||
}
|
||||
|
||||
clearSessionTimerInterval(): void {
|
||||
@@ -1909,45 +2137,100 @@ export class MapEngine {
|
||||
const once = !!(options && options.once)
|
||||
const priority = options && typeof options.priority === 'number' ? options.priority : 0
|
||||
const contentKey = options && options.contentKey ? options.contentKey : ''
|
||||
|
||||
if (!autoPopup) {
|
||||
return
|
||||
const entry = {
|
||||
title,
|
||||
body,
|
||||
motionClass,
|
||||
contentKey,
|
||||
once,
|
||||
priority,
|
||||
autoPopup,
|
||||
h5Request: this.buildContentH5Request(contentKey, title, body, motionClass, once, priority, autoPopup),
|
||||
}
|
||||
|
||||
if (once && contentKey && this.shownContentCardKeys[contentKey]) {
|
||||
return
|
||||
}
|
||||
if (this.state.contentCardVisible && priority < this.currentContentCardPriority) {
|
||||
|
||||
if (!autoPopup) {
|
||||
this.enqueueContentCard(entry)
|
||||
return
|
||||
}
|
||||
|
||||
this.clearContentCardTimer()
|
||||
this.setState({
|
||||
contentCardVisible: true,
|
||||
contentCardTitle: title,
|
||||
contentCardBody: body,
|
||||
contentCardFxClass: motionClass,
|
||||
}, true)
|
||||
this.currentContentCardPriority = priority
|
||||
if (once && contentKey) {
|
||||
this.shownContentCardKeys[contentKey] = true
|
||||
if (this.currentH5ExperienceOpen) {
|
||||
this.enqueueContentCard(entry)
|
||||
return
|
||||
}
|
||||
this.contentCardTimer = setTimeout(() => {
|
||||
this.contentCardTimer = 0
|
||||
this.currentContentCardPriority = 0
|
||||
this.setState({
|
||||
contentCardVisible: false,
|
||||
contentCardFxClass: '',
|
||||
}, true)
|
||||
}, 2600) as unknown as number
|
||||
|
||||
if (this.state.contentCardVisible) {
|
||||
if (priority > this.currentContentCardPriority) {
|
||||
this.openContentCardEntry(entry)
|
||||
return
|
||||
}
|
||||
|
||||
this.enqueueContentCard(entry)
|
||||
return
|
||||
}
|
||||
|
||||
this.openContentCardEntry(entry)
|
||||
}
|
||||
|
||||
closeContentCard(): void {
|
||||
this.clearContentCardTimer()
|
||||
this.currentContentCardPriority = 0
|
||||
this.currentContentCard = null
|
||||
this.currentH5ExperienceOpen = false
|
||||
this.setState({
|
||||
contentCardVisible: false,
|
||||
contentCardFxClass: '',
|
||||
}, true)
|
||||
this.flushQueuedContentCards()
|
||||
}
|
||||
|
||||
openPendingContentCard(): void {
|
||||
if (!this.pendingContentCards.length) {
|
||||
return
|
||||
}
|
||||
|
||||
let candidateIndex = -1
|
||||
let candidatePriority = Number.NEGATIVE_INFINITY
|
||||
for (let index = 0; index < this.pendingContentCards.length; index += 1) {
|
||||
const item = this.pendingContentCards[index]
|
||||
if (item.autoPopup) {
|
||||
continue
|
||||
}
|
||||
if (item.priority > candidatePriority) {
|
||||
candidatePriority = item.priority
|
||||
candidateIndex = index
|
||||
}
|
||||
}
|
||||
|
||||
if (candidateIndex < 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const pending = this.pendingContentCards.splice(candidateIndex, 1)[0]
|
||||
this.openContentCardEntry({
|
||||
...pending,
|
||||
autoPopup: true,
|
||||
})
|
||||
}
|
||||
|
||||
handleH5ExperienceClosed(): void {
|
||||
this.currentH5ExperienceOpen = false
|
||||
this.currentContentCardPriority = 0
|
||||
this.currentContentCard = null
|
||||
this.flushQueuedContentCards()
|
||||
}
|
||||
|
||||
handleH5ExperienceFallback(fallback: H5ExperienceFallbackPayload): void {
|
||||
this.currentH5ExperienceOpen = false
|
||||
this.currentContentCardPriority = 0
|
||||
this.currentContentCard = null
|
||||
this.openContentCardEntry({
|
||||
...fallback,
|
||||
h5Request: null,
|
||||
})
|
||||
}
|
||||
|
||||
applyGameEffects(effects: GameEffect[]): string | null {
|
||||
@@ -2693,24 +2976,29 @@ export class MapEngine {
|
||||
}
|
||||
|
||||
handleMapTap(stageX: number, stageY: number): void {
|
||||
if (!this.gameRuntime.definition || !this.gameRuntime.state || this.gameRuntime.definition.mode !== 'score-o') {
|
||||
if (!this.gameRuntime.definition || !this.gameRuntime.state) {
|
||||
return
|
||||
}
|
||||
|
||||
const focusedControlId = this.findFocusableControlAt(stageX, stageY)
|
||||
if (focusedControlId === undefined) {
|
||||
return
|
||||
if (this.gameRuntime.definition.mode === 'score-o') {
|
||||
const focusedControlId = this.findFocusableControlAt(stageX, stageY)
|
||||
if (focusedControlId !== undefined) {
|
||||
const gameResult = this.gameRuntime.dispatch({
|
||||
type: 'control_focused',
|
||||
at: Date.now(),
|
||||
controlId: focusedControlId,
|
||||
})
|
||||
this.commitGameResult(
|
||||
gameResult,
|
||||
focusedControlId ? `已选择目标点 (${this.buildVersion})` : `已取消目标点选择 (${this.buildVersion})`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const gameResult = this.gameRuntime.dispatch({
|
||||
type: 'control_focused',
|
||||
at: Date.now(),
|
||||
controlId: focusedControlId,
|
||||
})
|
||||
this.commitGameResult(
|
||||
gameResult,
|
||||
focusedControlId ? `已选择目标点 (${this.buildVersion})` : `已取消目标点选择 (${this.buildVersion})`,
|
||||
)
|
||||
const contentControlId = this.findContentControlAt(stageX, stageY)
|
||||
if (contentControlId) {
|
||||
this.openControlClickContent(contentControlId)
|
||||
}
|
||||
}
|
||||
|
||||
findFocusableControlAt(stageX: number, stageY: number): string | null | undefined {
|
||||
@@ -2749,6 +3037,134 @@ export class MapEngine {
|
||||
return matchedControlId === this.gamePresentation.map.focusedControlId ? null : matchedControlId
|
||||
}
|
||||
|
||||
findContentControlAt(stageX: number, stageY: number): string | undefined {
|
||||
if (!this.gameRuntime.definition || !this.courseData || !this.state.stageWidth || !this.state.stageHeight) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
let matchedControlId: string | undefined
|
||||
let matchedDistance = Number.POSITIVE_INFINITY
|
||||
let matchedPriority = Number.NEGATIVE_INFINITY
|
||||
const hitRadiusPx = Math.max(28, this.getControlHitRadiusPx())
|
||||
|
||||
for (const control of this.gameRuntime.definition.controls) {
|
||||
if (
|
||||
!control.displayContent
|
||||
|| (
|
||||
!control.displayContent.clickTitle
|
||||
&& !control.displayContent.clickBody
|
||||
&& !(control.displayContent.clickExperience && control.displayContent.clickExperience.type === 'h5')
|
||||
&& !(control.displayContent.contentExperience && control.displayContent.contentExperience.type === 'h5')
|
||||
)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
if (!this.isControlTapContentVisible(control)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const screenPoint = this.getControlScreenPoint(control.id)
|
||||
if (!screenPoint) {
|
||||
continue
|
||||
}
|
||||
|
||||
const distancePx = Math.sqrt(
|
||||
Math.pow(screenPoint.x - stageX, 2)
|
||||
+ Math.pow(screenPoint.y - stageY, 2),
|
||||
)
|
||||
if (distancePx > hitRadiusPx) {
|
||||
continue
|
||||
}
|
||||
|
||||
const controlPriority = this.getControlTapContentPriority(control)
|
||||
const sameDistance = Math.abs(distancePx - matchedDistance) <= 2
|
||||
if (
|
||||
distancePx < matchedDistance
|
||||
|| (sameDistance && controlPriority > matchedPriority)
|
||||
) {
|
||||
matchedDistance = distancePx
|
||||
matchedPriority = controlPriority
|
||||
matchedControlId = control.id
|
||||
}
|
||||
}
|
||||
|
||||
return matchedControlId
|
||||
}
|
||||
|
||||
getControlTapContentPriority(control: { kind: 'start' | 'control' | 'finish'; id: string }): number {
|
||||
if (!this.gameRuntime.state || !this.gamePresentation.map) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const currentTargetControlId = this.gameRuntime.state.currentTargetControlId
|
||||
const completedControlIds = this.gameRuntime.state.completedControlIds
|
||||
|
||||
if (currentTargetControlId === control.id) {
|
||||
return 100
|
||||
}
|
||||
|
||||
if (control.kind === 'start') {
|
||||
return completedControlIds.includes(control.id) ? 10 : 90
|
||||
}
|
||||
|
||||
if (control.kind === 'finish') {
|
||||
return completedControlIds.includes(control.id)
|
||||
? 80
|
||||
: (this.gamePresentation.map.completedStart ? 85 : 5)
|
||||
}
|
||||
|
||||
return completedControlIds.includes(control.id) ? 40 : 60
|
||||
}
|
||||
|
||||
isControlTapContentVisible(control: { kind: 'start' | 'control' | 'finish'; sequence: number | null; id: string }): boolean {
|
||||
if (this.gamePresentation.map.revealFullCourse) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (control.kind === 'start') {
|
||||
return this.gamePresentation.map.activeStart || this.gamePresentation.map.completedStart
|
||||
}
|
||||
|
||||
if (control.kind === 'finish') {
|
||||
return this.gamePresentation.map.activeFinish || this.gamePresentation.map.focusedFinish || this.gamePresentation.map.completedFinish
|
||||
}
|
||||
|
||||
if (control.sequence === null) {
|
||||
return false
|
||||
}
|
||||
|
||||
const readyControlSequences = this.resolveReadyControlSequences()
|
||||
return this.gamePresentation.map.activeControlSequences.includes(control.sequence)
|
||||
|| this.gamePresentation.map.completedControlSequences.includes(control.sequence)
|
||||
|| this.gamePresentation.map.skippedControlSequences.includes(control.sequence)
|
||||
|| this.gamePresentation.map.focusedControlSequences.includes(control.sequence)
|
||||
|| readyControlSequences.includes(control.sequence)
|
||||
}
|
||||
|
||||
openControlClickContent(controlId: string): void {
|
||||
if (!this.gameRuntime.definition) {
|
||||
return
|
||||
}
|
||||
|
||||
const control = this.gameRuntime.definition.controls.find((item) => item.id === controlId)
|
||||
if (!control || !control.displayContent) {
|
||||
return
|
||||
}
|
||||
|
||||
const title = control.displayContent.clickTitle || control.displayContent.title || control.label || '内容体验'
|
||||
const body = control.displayContent.clickBody || control.displayContent.body || ''
|
||||
if (!title && !body) {
|
||||
return
|
||||
}
|
||||
|
||||
this.showContentCard(title, body, 'game-content-card--fx-pop', {
|
||||
contentKey: `${control.id}:click`,
|
||||
autoPopup: true,
|
||||
once: false,
|
||||
priority: control.displayContent.priority,
|
||||
})
|
||||
}
|
||||
|
||||
getControlHitRadiusPx(): number {
|
||||
if (!this.state.tileSizePx) {
|
||||
return 28
|
||||
|
||||
Reference in New Issue
Block a user