Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 3x 3x 3x 3x 3x 3x 3x 3x 3x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 5x 1x 5x 1x 5x 5x 5x 6x 6x 2x 1x 1x 2x 4x 4x 4x 4x 4x 6x 1x 1x 1x 6x 6x 1x 1x 1x 1x 1x 1x 1x 1x 6x | import { useEffect, useRef, useState, useCallback } from 'react';
import { Animated, Dimensions, Easing } from 'react-native';
const { width: SCREEN_WIDTH } = Dimensions.get('window');
// 游戏配置常量
const GRAVITY = 0.8;
const JUMP_FORCE = -12;
const GROUND_HEIGHT = 50;
const CAT_SIZE = 60;
const OBSTACLE_SIZE = 30;
const OBSTACLE_SPEED = 5;
const MIN_OBSTACLE_GAP = 200; // 最小障碍物间隔
export const useLoadingGame = (isPlaying: boolean, onGameOver: () => void) => {
// 游戏状态
const [score, setScore] = useState(0);
const [isGameOver, setIsGameOver] = useState(false);
// 动画值
const catY = useRef(new Animated.Value(0)).current;
const obstacleX = useRef(new Animated.Value(SCREEN_WIDTH)).current;
// 物理状态引用(用于实时计算)
const catVelocity = useRef(0);
const catYValue = useRef(0);
const obstacleXValue = useRef(SCREEN_WIDTH);
const gameLoopRef = useRef<number | null>(null);
const isJumping = useRef(false);
// 初始化监听器
useEffect(() => {
const catListener = catY.addListener(({ value }) => {
catYValue.current = value;
});
const obstacleListener = obstacleX.addListener(({ value }) => {
obstacleXValue.current = value;
});
return () => {
catY.removeListener(catListener);
obstacleX.removeListener(obstacleListener);
};
}, []);
// 游戏循环
useEffect(() => {
if (!isPlaying || isGameOver) {
if (gameLoopRef.current) {
cancelAnimationFrame(gameLoopRef.current);
gameLoopRef.current = null;
}
return;
}
const loop = () => {
// 1. 更新猫咪位置(重力)
if (catYValue.current > 0 || isJumping.current) {
catVelocity.current += GRAVITY;
const newY = catYValue.current + catVelocity.current;
if (newY >= 0) {
// 落地
catY.setValue(0);
catYValue.current = 0; // Manually update ref
catVelocity.current = 0;
isJumping.current = false;
} else {
// 空中
catY.setValue(newY);
catYValue.current = newY; // Manually update ref
}
}
// 2. 更新障碍物位置
let newObstacleX = obstacleXValue.current - OBSTACLE_SPEED;
if (newObstacleX < -OBSTACLE_SIZE) {
// 重置障碍物
newObstacleX = SCREEN_WIDTH + Math.random() * 200;
setScore((s) => s + 1);
}
obstacleX.setValue(newObstacleX);
obstacleXValue.current = newObstacleX; // Manually update ref
// 3. 碰撞检测
// 猫咪中心点 (50, SCREEN_HEIGHT - GROUND_HEIGHT - catY - CAT_SIZE/2)
// 障碍物中心点 (obstacleX + OBSTACLE_SIZE/2, SCREEN_HEIGHT - GROUND_HEIGHT - OBSTACLE_SIZE/2)
// 简化为矩形碰撞
// 猫咪区域:X: 20~20+CAT_SIZE, Y: catYValue.current (注意Y轴向上为负)
// 障碍物区域:X: obstacleXValue.current, Y: 0 (贴地)
// 这里的坐标系:catY是相对于地面的偏移(负数向上),obstacleX是屏幕横坐标
const catLeft = 20; // 猫咪固定在左侧
const catRight = 20 + CAT_SIZE - 20; // 减去一点碰撞宽容度
const catBottom = catYValue.current; // 0是地面
const obsLeft = obstacleXValue.current + 5;
const obsRight = obstacleXValue.current + OBSTACLE_SIZE - 5;
const obsTop = -OBSTACLE_SIZE + 10; // 障碍物高度
// 碰撞条件:水平重叠 且 垂直重叠
if (
catRight > obsLeft &&
catLeft < obsRight &&
catBottom > obsTop // 猫咪底部 低于 障碍物顶部 (注意都是负数或0)
) {
handleGameOver();
return;
}
gameLoopRef.current = requestAnimationFrame(loop);
};
gameLoopRef.current = requestAnimationFrame(loop);
return () => {
Eif (gameLoopRef.current) {
cancelAnimationFrame(gameLoopRef.current);
}
};
}, [isPlaying, isGameOver]);
const jump = () => {
Eif (!isJumping.current && !isGameOver) {
isJumping.current = true;
catVelocity.current = JUMP_FORCE;
}
};
const handleGameOver = () => {
setIsGameOver(true);
onGameOver();
};
const resetGame = useCallback(() => {
setIsGameOver(false);
setScore(0);
// 重置动画值
catY.setValue(0);
obstacleX.setValue(SCREEN_WIDTH);
// 关键:同时重置物理状态引用
catVelocity.current = 0;
catYValue.current = 0;
obstacleXValue.current = SCREEN_WIDTH;
isJumping.current = false;
}, []);
return {
catY,
obstacleX,
score,
isGameOver,
jump,
resetGame,
};
};
|