HarmonyOS7应用《拼棋派对》实战:找茬图片缩放与点击坐标映射
看图找茬的页面可以把图片缩小、左右摆放或上下排列,但同一处差异必须始终点得中。若差异坐标写成某个屏幕的像素值,换一个窗口大小,圈出来的位置就会偏离实际物体。
《拼棋派对》把每处差异保存为图片中的百分比区域,点击时再把局部坐标转换到相同坐标系。本文结合风景主题的命中、重复点击和完成过程,分析显示尺寸、热区和结果反馈如何配合。环境为HarmonyOS7 API26模拟器,主应用1.0.19。
本文目录
差异区域跟随图片保存
主题数据保存original、changed两张图片与spots列表。每个spot包含x、y、size、mark与color。x和y是区域左上角百分比,size分别作为宽度与高度百分比,mark描述差异内容。
假设一个区域为x=20、y=30、size=10,它在横向覆盖图片20%—30%,纵向覆盖30%—40%。这里的“10”不是10像素,也不是独立于图片比例的正方形像素尺寸。
| 数据 | 用途 |
|---|---|
| original / changed | 对照原图与实际差异图 |
| spots | 固定差异区域与说明 |
| differenceFound | 每个区域是否已找到 |
| differenceMistakes | 未命中的点击次数 |
| differenceHintIndex | 当前提示位置 |
| differenceFeedback | 正确、错误、重复、提示或答案状态 |
难度为4、5或6处,differenceTarget取难度与主题实际差异数量的较小值。难度筛选的是前若干区域,后面的差异可能仍在图片上,却不属于本局目标。内容制作时需要让提示与本局范围一致。
显示尺寸决定坐标换算
页面原图与找茬图都使用ImageFit.Fill,图片外层维持主题宽高比。找茬图上方叠加透明点击层,与图片同宽同高,通过onAreaChange记录交互区域实际尺寸。
.onAreaChange((oldArea, newArea) => {
if (interactive) {
this.updateDifferenceSceneSize(
this.areaNumber(newArea.width),
this.areaNumber(newArea.height));
}
})
记录的是当前显示区域,不是原图文件分辨率。手机上下排布与宽屏左右排布改变尺寸后,换算继续使用最新width和height。缓存首次尺寸而不处理窗口变化,会让折叠或旋转后的热区偏移。
ImageFit.Fill在这个组合中让图片内容覆盖整个点击矩形。如果改成Contain并出现留白,必须先减去图片实际显示区域的偏移;如果改成Cover裁剪,又需要处理裁剪后的内容范围。改变objectFit不只是视觉调整,也会改变坐标映射前提。
从局部点击映射到百分比
点击事件提供相对于交互层的x和y,页面除以当前宽高再乘100。随后遍历本局spot,判断点是否位于该区域内。
const x = event.x / this.differenceSceneWidth * 100;
const y = event.y / this.differenceSceneHeight * 100;
const spots = this.currentSpotTheme().spots.slice(0, this.differenceTarget());
for (let index = 0; index < spots.length; index++) {
const spot = spots[index];
if (x >= spot.x && x <= spot.x + spot.size &&
y >= spot.y && y <= spot.y + spot.size) {
this.handleDifferenceTap(index);
return;
}
}
this.handleDifferenceTap(-1);
尺寸必须大于0,否则不能除法换算,当前会按未命中处理。多个区域重叠时,这个遍历返回第一个命中的区域,因此制作数据时应尽量避免重叠,或者明确重叠的优先策略。
显示标记和命中区域不是同样大小。项目用较小的圈标记spot中心,减少遮挡图片;命中则使用完整spot区域。不能看到圈比较小,就按圈的像素边界重写点击判断。
命中、误点与重复点击
handleDifferenceTap先检查是否结束,未开始时会启动。传入-1或不在本局范围的索引,误点数加一;已找到区域返回重复提示,不再次增加进度。
首次命中时克隆found数组,把对应项设为true,再重算找到的数量。它不直接无条件累加hits,所以重复点同一处不会凑够完成条件。
if (this.differenceFound[spotIndex]) {
this.differenceFeedback = 'repeat';
this.differenceLastSpot = spotIndex;
return;
}
const next = this.differenceFound.slice();
next[spotIndex] = true;
this.differenceFound = next;
this.differenceHits = this.differenceFoundCount();
进度由found数组推导,圈标记也读取同一个数组。让画面与统计共享来源,能减少“已经圈住了,计数没增加”或“分数增加了,圈没出现”的部分更新。
提示和答案走不同结算路径
提示找到第一个尚未完成的区域,只设置differenceHintIndex并显示说明,不把found改成true。玩家仍需要点击才能计入进度。
“显示答案”则把目标区域全部标出,设置finished并停止计时,但明确提示本局不计入胜利,也不调用正常完成战绩路径。正常找齐最后一处才调用finishSpotDifference,保存主题、数量、用时与误点数。
这两条路径的界面都可能显示全部圈,但业务含义不同。只凭截图里圈满了,不能判定玩家已经完成一局。验收要结合提示、战绩处理和实际点击过程。
模拟器操作与适配检查
本次使用风景主题、标准5处,开始后在找茬图内点一个无差异位置,观察误点反馈。再依次点击目标区域中心;第一处找到后重复点击,检查进度保持1/5。最后找齐五处,出现完成状态。
操作过程中图片可能从设置页进入聚焦布局,点击位置因此每次按当前图片边界重新计算。演示验证的是已显示图片的局部坐标换算,不是给所有窗口复用固定屏幕坐标。
若再补一轮折叠和旋转验收,应在变化后点击同一个百分比中心,观察标记仍覆盖相同物体;同时检查边缘目标是否被容器裁掉、原图与找茬图是否保持相同比例。本文本轮使用手机单屏,未把它当作全部设备形态已验证。
内容方面,差异图必须实际包含对应变化,热区也需要包住那个物体。坐标正确不能弥补图片内容错误。增加主题时,应先逐处对照两张原始资源,再检查缩小后的可辨认性,最后验证命中与完成路径。
源码入口:common/GameConfig.ets 的 SPOT_THEMES;pages/Index.ets 的 DifferenceImagePanel、handleDifferenceSceneTap、handleDifferenceTap、showDifferenceHint 与 revealDifferences。参考HarmonyOS官方文档。下一批从寻物和文字玩法继续扩展状态模型。
更多推荐
所有评论(0)