Commit f807008f authored by 董政锦's avatar 董政锦

style: game3 的 h5 样式马位置、道具位置、道具碰到位置、苹果蒙层宽度调整;

parent f8b7ee46
......@@ -193,14 +193,18 @@ defineExpose({
}
.modal-container {
position: absolute;
inset: 0;
/* position:fixed + 显式 100vw/100vh 确保在 iOS Safari 中全屏蒙层,
避免因父级 overflow:hidden / transform:scale 导致 inset:0 计算异常 */
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.6);
/* pointer-events: none; */
}
.game-rule-fade-enter-active,
......
This diff is collapsed.
......@@ -26,8 +26,26 @@ const HORSE_BOTTOM_PCT = 19.11;
const ITEM_SIZE = 80;
const GAME_DURATION = 60;
const LEFT_LANE_X = 170;
const RIGHT_LANE_X = 470;
// 设计基准跑道 X 位置(750px 设计稿下的值,窄屏设备上会自动居中偏移)
const DESIGN_LEFT_LANE_X = 150;
const DESIGN_RIGHT_LANE_X = 500;
// 运行时根据视口计算的真实 X 位置(适配不同屏幕宽度)
const leftLaneX = ref(DESIGN_LEFT_LANE_X);
const rightLaneX = ref(DESIGN_RIGHT_LANE_X);
/** 按视口宽度计算 750px 设计区域在 content-bg 中的居中偏移 */
const updateLanePositions = () => {
const vw = window.visualViewport?.width ?? window.innerWidth;
const vh = window.visualViewport?.height ?? window.innerHeight;
// MobileStage contain 模式下 scale = min(scaleX, scaleY),手机通常由高度决定
const scaleY = vh / 1624;
if (!scaleY || scaleY <= 0) return;
const stageViewportWidth = vw / scaleY;
const offset = Math.max(0, (stageViewportWidth - 750) / 2);
leftLaneX.value = DESIGN_LEFT_LANE_X + offset;
rightLaneX.value = DESIGN_RIGHT_LANE_X + offset;
};
// ========== 马帧 ==========
const HORSE_FRAME_COUNT = 21;
......@@ -63,20 +81,20 @@ preloadFrames(bomFrames);
const horseLane = ref<'left' | 'right'>('left');
const horseFrameIndex = ref(0);
const horseX = ref(LEFT_LANE_X);
const horseTargetX = ref(LEFT_LANE_X);
const horseX = ref(leftLaneX.value);
const horseTargetX = ref(leftLaneX.value);
const switchToLeft = () => {
if (horseLane.value !== 'left') {
horseLane.value = 'left';
horseTargetX.value = LEFT_LANE_X;
horseTargetX.value = leftLaneX.value;
}
};
const switchToRight = () => {
if (horseLane.value !== 'right') {
horseLane.value = 'right';
horseTargetX.value = RIGHT_LANE_X;
horseTargetX.value = rightLaneX.value;
}
};
......@@ -183,7 +201,7 @@ function generateNewItem() {
if (!props.isDivDescVisible) return;
const seed = Date.now() + itemIdCounter;
const kind: ItemKind = seededRandom(seed) < 0.55 ? 'coin' : 'bomb';
const kind: ItemKind = seededRandom(seed) < 0.75 ? 'coin' : 'bomb';
// 概率分配车道,但避免与前一个同车道道具太近
let lane: 'left' | 'right' = seededRandom(seed + 1000) < 0.5 ? 'left' : 'right';
......@@ -244,7 +262,7 @@ const checkCollisions = () => {
for (const item of roadItems.value) {
if (item.collected || item.colliding) continue;
const itemX = item.lane === 'left' ? LEFT_LANE_X : RIGHT_LANE_X;
const itemX = item.lane === 'left' ? leftLaneX.value : rightLaneX.value;
// item.y 已经是屏幕坐标(content-bg 内),无需加 roadOffset
const itemCenterX = itemX + ITEM_SIZE / 2;
const itemCenterY = item.y + ITEM_SIZE / 2;
......@@ -278,7 +296,7 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
const frameDuration = 1000 / totalFrames;
// 碰撞动画(大幅放大尺寸,x 往右偏移让动画居中于视觉碰撞点)
effectAnims.value.push({ id: animId, kind: item.kind, frame: 0, x: x + 40, y });
effectAnims.value.push({ id: animId, kind: item.kind, frame: 0, x: x + 65, y });
let frameIdx = 0;
const tick = () => {
......@@ -297,7 +315,7 @@ const playCollectEffect = (item: RoadItem, x: number, y: number) => {
const effectId = ++scoreEffectIdSeq;
scoreEffects.value.push({
id: effectId,
x: x + ITEM_SIZE / 2,
x: x + ITEM_SIZE / 2 + 25,
y: y,
score: delta,
});
......@@ -377,6 +395,12 @@ const stopMainLoop = () => {
// ========== 生命周期 ==========
onMounted(() => {
window.addEventListener('keydown', handleKeydown);
window.addEventListener('resize', updateLanePositions);
window.visualViewport?.addEventListener('resize', updateLanePositions);
updateLanePositions();
// 初始化马匹在左侧跑道(使用计算后的实际 X 位置)
horseX.value = leftLaneX.value;
horseTargetX.value = leftLaneX.value;
nextTick(() => {
startRoadScroll();
startMainLoop();
......@@ -386,6 +410,8 @@ onMounted(() => {
onBeforeUnmount(() => {
window.removeEventListener('keydown', handleKeydown);
window.removeEventListener('resize', updateLanePositions);
window.visualViewport?.removeEventListener('resize', updateLanePositions);
stopRoadScroll();
stopMainLoop();
stopItemGen();
......@@ -405,6 +431,9 @@ watch(() => props.isDivDescVisible, (visible) => {
scoreEffects.value = [];
roadOffset.value = 0;
gameElapsed.value = 0;
updateLanePositions();
horseX.value = leftLaneX.value;
horseTargetX.value = leftLaneX.value;
startRoadScroll();
startMainLoop();
scheduleNextItem();
......@@ -582,18 +611,21 @@ watch(() => props.isDivDescVisible, (visible) => {
.road-item {
position: absolute;
width: 80px;
height: 80px;
/* width: 80px;
height: 80px; */
width: 77px;
height: 96px;
z-index: 5;
pointer-events: none;
}
.item-lane-left {
left: 170px;
/* 当 content-bg 宽于 750px 设计稿时,自动居中 750px 游戏区域 */
left: calc((var(--stage-viewport-width, 750px) - 750px) / 2 + 170px);
}
.item-lane-right {
left: 470px;
left: calc((var(--stage-viewport-width, 750px) - 750px) / 2 + 520px);
}
.effect-anim {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment