mirror of
https://github.com/mudabbir-ahmad/MAD-Treasure-Hunt.git
synced 2026-10-08 03:00:20 +00:00
Refactor map functionality: streamline cache visibility logic by removing proximity fallback for iOS, ensuring player must have heading to view caches, and simplify heading checks in player game hook
This commit is contained in:
1 parent
63c082bb8f
commit
4a5cc716db
3 files changed
+19
-46
No files matched your search
@@ -11,8 +11,9 @@ const PlayerMapView = ({userLocation, visibleCaches, heading, claimDistance}) =>
|
|||||||
|
|
||||||
if (!userLocation) return null;
|
if (!userLocation) return null;
|
||||||
|
|
||||||
const hasHeading = heading !== null && heading !== undefined;
|
const coneCoords = (heading !== null && heading !== undefined)
|
||||||
const coneCoords = hasHeading ? getFovCone(userLocation, heading) : null;
|
? getFovCone(userLocation, heading)
|
||||||
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MapView
|
<MapView
|
||||||
@@ -46,7 +47,7 @@ const PlayerMapView = ({userLocation, visibleCaches, heading, claimDistance}) =>
|
|||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
))}
|
))}
|
||||||
{/* FOV cone when heading is available */}
|
{/* FOV heading cone */}
|
||||||
{coneCoords && (
|
{coneCoords && (
|
||||||
<Polygon
|
<Polygon
|
||||||
coordinates={coneCoords}
|
coordinates={coneCoords}
|
||||||
@@ -55,15 +56,6 @@ const PlayerMapView = ({userLocation, visibleCaches, heading, claimDistance}) =>
|
|||||||
strokeWidth={1}
|
strokeWidth={1}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/* Proximity circle when heading is NOT available (iOS fallback) */}
|
|
||||||
{!hasHeading && claimDistance > 0 && (
|
|
||||||
<Circle
|
|
||||||
center={userLocation}
|
|
||||||
radius={claimDistance}
|
|
||||||
fillColor="rgba(66,133,244,0.12)"
|
|
||||||
strokeColor="rgba(66,133,244,0.40)"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</MapView>
|
</MapView>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {Platform, StyleSheet, View} from 'react-native';
|
|||||||
import MapView, {Circle, Marker, Polygon} from 'react-native-maps';
|
import MapView, {Circle, Marker, Polygon} from 'react-native-maps';
|
||||||
import * as Location from 'expo-location';
|
import * as Location from 'expo-location';
|
||||||
import Screen from '../layout/Screen';
|
import Screen from '../layout/Screen';
|
||||||
import {getFovCone, isInClaimCone, isWithinRadius} from '../../utils/geoMath';
|
import {getFovCone, isInClaimCone} from '../../utils/geoMath';
|
||||||
|
|
||||||
const DEFAULT_REGION = {latitude: 51.5074, longitude: -0.1278, latitudeDelta: 0.01, longitudeDelta: 0.01};
|
const DEFAULT_REGION = {latitude: 51.5074, longitude: -0.1278, latitudeDelta: 0.01, longitudeDelta: 0.01};
|
||||||
|
|
||||||
@@ -71,14 +71,10 @@ const ExpandedMapScreen = ({route}) => {
|
|||||||
? getFovCone(userLocation, heading)
|
? getFovCone(userLocation, heading)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
// For players — when heading is available use FOV cone, otherwise fall back
|
// For players — heading is required so the player must point their device
|
||||||
// to proximity-only so the expanded map works on iPhones without compass data
|
// towards a cache for it to appear (same logic as the main MapScreen)
|
||||||
const visiblePlayerCaches = (!isAdmin && userLocation)
|
const visiblePlayerCaches = (!isAdmin && userLocation && hasHeading)
|
||||||
? caches.filter((c) =>
|
? caches.filter((c) => isInClaimCone(heading, userLocation, c.coordinates, claimDistance))
|
||||||
hasHeading
|
|
||||||
? isInClaimCone(heading, userLocation, c.coordinates, claimDistance)
|
|
||||||
: isWithinRadius(userLocation, c.coordinates, claimDistance),
|
|
||||||
)
|
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -140,15 +136,6 @@ const ExpandedMapScreen = ({route}) => {
|
|||||||
strokeWidth={1}
|
strokeWidth={1}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/* Proximity circle when heading is unavailable (iOS fallback) */}
|
|
||||||
{!isAdmin && userLocation && !hasHeading && claimDistance > 0 && (
|
|
||||||
<Circle
|
|
||||||
center={userLocation}
|
|
||||||
radius={claimDistance}
|
|
||||||
fillColor="rgba(66,133,244,0.12)"
|
|
||||||
strokeColor="rgba(66,133,244,0.40)"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</MapView>
|
</MapView>
|
||||||
</View>
|
</View>
|
||||||
</Screen>
|
</Screen>
|
||||||
|
|||||||
+10
-16
@@ -1,5 +1,5 @@
|
|||||||
import {useEffect, useRef, useState} from 'react';
|
import {useEffect, useRef, useState} from 'react';
|
||||||
import {isInClaimCone, isWithinRadius} from '../utils/geoMath';
|
import {isInClaimCone} from '../utils/geoMath';
|
||||||
|
|
||||||
const usePlayerGame = (playerLocation, playerHeading, activeCaches, claimDistance) => {
|
const usePlayerGame = (playerLocation, playerHeading, activeCaches, claimDistance) => {
|
||||||
// State ----------------------
|
// State ----------------------
|
||||||
@@ -11,8 +11,9 @@ const usePlayerGame = (playerLocation, playerHeading, activeCaches, claimDistanc
|
|||||||
// Handlers -------------------
|
// Handlers -------------------
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// No location at all — clear everything
|
// Both location AND heading are required — the player must physically
|
||||||
if (!playerLocation) {
|
// point their device towards a cache to trigger the claim countdown
|
||||||
|
if (!playerLocation || playerHeading === null || playerHeading === undefined) {
|
||||||
if (prevIdsRef.current !== '') {
|
if (prevIdsRef.current !== '') {
|
||||||
prevIdsRef.current = '';
|
prevIdsRef.current = '';
|
||||||
setVisibleCaches([]);
|
setVisibleCaches([]);
|
||||||
@@ -21,24 +22,17 @@ const usePlayerGame = (playerLocation, playerHeading, activeCaches, claimDistanc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasHeading = playerHeading !== null && playerHeading !== undefined;
|
// Find all caches that fall inside the claim cone
|
||||||
|
const inCone = (activeCaches || []).filter((cache) =>
|
||||||
// When heading is available use the full FOV cone check.
|
isInClaimCone(playerHeading, playerLocation, cache.coordinates, claimDistance),
|
||||||
// When heading is NOT available (common on iOS / Apple Maps where the
|
|
||||||
// compass may be delayed or unavailable) fall back to proximity-only so
|
|
||||||
// iPhone users can still discover and claim caches within range.
|
|
||||||
const nearby = (activeCaches || []).filter((cache) =>
|
|
||||||
hasHeading
|
|
||||||
? isInClaimCone(playerHeading, playerLocation, cache.coordinates, claimDistance)
|
|
||||||
: isWithinRadius(playerLocation, cache.coordinates, claimDistance),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only update state when the set of visible caches actually changes
|
// Only update state when the set of visible caches actually changes
|
||||||
const newIds = nearby.map((c) => c.id).join(',');
|
const newIds = inCone.map((c) => c.id).join(',');
|
||||||
if (newIds !== prevIdsRef.current) {
|
if (newIds !== prevIdsRef.current) {
|
||||||
prevIdsRef.current = newIds;
|
prevIdsRef.current = newIds;
|
||||||
setVisibleCaches(nearby);
|
setVisibleCaches(inCone);
|
||||||
setIsClaiming(nearby.length > 0);
|
setIsClaiming(inCone.length > 0);
|
||||||
}
|
}
|
||||||
}, [playerLocation, playerHeading, activeCaches, claimDistance]);
|
}, [playerLocation, playerHeading, activeCaches, claimDistance]);
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user