mirror of
https://github.com/mudabbir-ahmad/MAD-Treasure-Hunt.git
synced 2026-10-08 03:00:20 +00:00
Refactor map components: streamline player cache marker rendering and update claim logic to use selected cache ID for triggering countdown.
This commit is contained in:
1 parent
e60c6181f1
commit
fc378ae016
4 files changed
+47
-51
No files matched your search
@@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import {Platform, StyleSheet, View} from 'react-native';
|
||||
import MapView, {Circle, Marker, Polygon} from 'react-native-maps';
|
||||
import MapView, {Marker, Polygon} from 'react-native-maps';
|
||||
import {getFovCone} from '../../utils/geoMath';
|
||||
|
||||
const PlayerMapView = ({userLocation, visibleCaches, heading, claimDistance}) => {
|
||||
const PlayerMapView = ({userLocation, visibleCaches, heading}) => {
|
||||
// Initialisation -------------
|
||||
// State ----------------------
|
||||
// Handlers -------------------
|
||||
@@ -26,27 +26,21 @@ const PlayerMapView = ({userLocation, visibleCaches, heading, claimDistance}) =>
|
||||
pitchEnabled={false}
|
||||
showsUserLocation
|
||||
>
|
||||
{/* Cache markers — uses a custom View instead of pinColor so the
|
||||
marker renders identically on Apple Maps (iOS) and Google Maps */}
|
||||
{/* Cache pin markers — appear temporarily when the cache is in the FOV
|
||||
cone AND within claim distance. Uses a custom View so the pin
|
||||
renders identically on iOS (Google Maps) and Android */}
|
||||
{(visibleCaches || []).map((cache) => (
|
||||
<React.Fragment key={cache.id}>
|
||||
<Marker
|
||||
coordinate={cache.coordinates}
|
||||
title={cache.clue}
|
||||
anchor={{x: 0.5, y: 0.5}}
|
||||
tracksViewChanges={Platform.OS === 'ios'}
|
||||
>
|
||||
<View style={styles.markerOuter}>
|
||||
<View style={styles.markerInner} />
|
||||
</View>
|
||||
</Marker>
|
||||
<Circle
|
||||
center={cache.coordinates}
|
||||
radius={claimDistance}
|
||||
fillColor="rgba(250, 204, 21, 0.20)"
|
||||
strokeColor="rgba(250, 204, 21, 0.90)"
|
||||
/>
|
||||
</React.Fragment>
|
||||
<Marker
|
||||
key={cache.id}
|
||||
coordinate={cache.coordinates}
|
||||
title={cache.clue}
|
||||
anchor={{x: 0.5, y: 0.5}}
|
||||
tracksViewChanges={Platform.OS === 'ios'}
|
||||
>
|
||||
<View style={styles.markerOuter}>
|
||||
<View style={styles.markerInner} />
|
||||
</View>
|
||||
</Marker>
|
||||
))}
|
||||
{/* FOV heading cone */}
|
||||
{coneCoords && (
|
||||
|
||||
@@ -107,26 +107,19 @@ const ExpandedMapScreen = ({route}) => {
|
||||
/>
|
||||
</React.Fragment>
|
||||
))}
|
||||
{/* Players — custom View markers for Apple Maps compatibility */}
|
||||
{/* Players — pin markers appear when cache is in FOV cone + within range */}
|
||||
{!isAdmin && visiblePlayerCaches.map((cache) => (
|
||||
<React.Fragment key={cache.id}>
|
||||
<Marker
|
||||
coordinate={cache.coordinates}
|
||||
title={cache.clue}
|
||||
anchor={{x: 0.5, y: 0.5}}
|
||||
tracksViewChanges={Platform.OS === 'ios'}
|
||||
>
|
||||
<View style={styles.cacheMarkerOuter}>
|
||||
<View style={styles.cacheMarkerInner} />
|
||||
</View>
|
||||
</Marker>
|
||||
<Circle
|
||||
center={cache.coordinates}
|
||||
radius={claimDistance}
|
||||
fillColor="rgba(250, 204, 21, 0.20)"
|
||||
strokeColor="rgba(250, 204, 21, 0.90)"
|
||||
/>
|
||||
</React.Fragment>
|
||||
<Marker
|
||||
key={cache.id}
|
||||
coordinate={cache.coordinates}
|
||||
title={cache.clue}
|
||||
anchor={{x: 0.5, y: 0.5}}
|
||||
tracksViewChanges={Platform.OS === 'ios'}
|
||||
>
|
||||
<View style={styles.cacheMarkerOuter}>
|
||||
<View style={styles.cacheMarkerInner} />
|
||||
</View>
|
||||
</Marker>
|
||||
))}
|
||||
{/* Heading FOV cone */}
|
||||
{coneCoords && (
|
||||
|
||||
@@ -73,12 +73,14 @@ const MapScreen = ({navigation}) => {
|
||||
});
|
||||
}, [cacheRecords, isPlayer, session.currentTid, session.currentUid, EMPTY_CACHES]);
|
||||
|
||||
// When requiresTeam is true pass null/empty so usePlayerGame is inert
|
||||
// When requiresTeam is true pass null/empty so usePlayerGame is inert.
|
||||
// selectedCacheId is the 5th param — only that cache can trigger the claim countdown.
|
||||
const {visibleCaches, isClaiming, setIsClaiming} = usePlayerGame(
|
||||
(isPlayer && !requiresTeam) ? userLocation : null,
|
||||
(isPlayer && !requiresTeam) ? heading : null,
|
||||
requiresTeam ? EMPTY_CACHES : activeCachesForPlayer,
|
||||
claimDistance,
|
||||
selectedCacheId,
|
||||
);
|
||||
|
||||
const mapRegion = userLocation
|
||||
@@ -521,8 +523,8 @@ const MapScreen = ({navigation}) => {
|
||||
);
|
||||
}
|
||||
|
||||
// Player in game — use the first visible cache for the claim timer
|
||||
const claimTarget = visibleCaches.length > 0 ? visibleCaches[0] : null;
|
||||
// Player in game — the claim target is the selected cache (only it can trigger the countdown)
|
||||
const claimTarget = visibleCaches.find((c) => c.id === selectedCacheId) || null;
|
||||
|
||||
return (
|
||||
<Screen style={styles.containerMap}>
|
||||
@@ -534,7 +536,6 @@ const MapScreen = ({navigation}) => {
|
||||
userLocation={userLocation}
|
||||
visibleCaches={visibleCaches}
|
||||
heading={heading}
|
||||
claimDistance={claimDistance}
|
||||
/>
|
||||
<Pressable style={styles.expandButton} onPress={handleExpandMap}>
|
||||
<Text style={styles.expandIcon}>⛶</Text>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {useEffect, useRef, useState} from 'react';
|
||||
import {isInClaimCone} from '../utils/geoMath';
|
||||
|
||||
const usePlayerGame = (playerLocation, playerHeading, activeCaches, claimDistance) => {
|
||||
const usePlayerGame = (playerLocation, playerHeading, activeCaches, claimDistance, selectedCacheId) => {
|
||||
// State ----------------------
|
||||
|
||||
const [visibleCaches, setVisibleCaches] = useState([]);
|
||||
@@ -10,19 +10,16 @@ const usePlayerGame = (playerLocation, playerHeading, activeCaches, claimDistanc
|
||||
|
||||
// Handlers -------------------
|
||||
|
||||
// Determine which caches fall inside the FOV claim cone
|
||||
useEffect(() => {
|
||||
// Both location AND heading are required — the player must physically
|
||||
// point their device towards a cache to trigger the claim countdown
|
||||
if (!playerLocation || playerHeading === null || playerHeading === undefined) {
|
||||
if (prevIdsRef.current !== '') {
|
||||
prevIdsRef.current = '';
|
||||
setVisibleCaches([]);
|
||||
setIsClaiming(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Find all caches that fall inside the claim cone
|
||||
const inCone = (activeCaches || []).filter((cache) =>
|
||||
isInClaimCone(playerHeading, playerLocation, cache.coordinates, claimDistance),
|
||||
);
|
||||
@@ -32,10 +29,21 @@ const usePlayerGame = (playerLocation, playerHeading, activeCaches, claimDistanc
|
||||
if (newIds !== prevIdsRef.current) {
|
||||
prevIdsRef.current = newIds;
|
||||
setVisibleCaches(inCone);
|
||||
setIsClaiming(inCone.length > 0);
|
||||
}
|
||||
}, [playerLocation, playerHeading, activeCaches, claimDistance]);
|
||||
|
||||
// Claiming requires ALL four criteria:
|
||||
// 1. Cache not already claimed by player's team (handled by activeCaches filter)
|
||||
// 2. Cache within claim distance (handled by isInClaimCone)
|
||||
// 3. Player looking at the cache (in FOV cone) (handled by isInClaimCone)
|
||||
// 4. Cache is the one currently selected in list (checked here)
|
||||
useEffect(() => {
|
||||
const canClaim = Boolean(
|
||||
selectedCacheId && visibleCaches.some((c) => c.id === selectedCacheId),
|
||||
);
|
||||
setIsClaiming(canClaim);
|
||||
}, [visibleCaches, selectedCacheId]);
|
||||
|
||||
// Return ---------------------
|
||||
|
||||
return {visibleCaches, isClaiming, setIsClaiming};
|
||||
|
||||
Reference in new issue
Block a user