added mascot clicking
This commit is contained in:
127
src/App.tsx
127
src/App.tsx
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useState, useRef } from 'react';
|
||||
import { usePartyKit } from './hooks/usePartyKit';
|
||||
import { ClickButton } from './components/ClickButton';
|
||||
import { Counter } from './components/Counter';
|
||||
@@ -9,16 +9,21 @@ import { Background } from './components/Background';
|
||||
import { MILESTONES } from './config/milestones';
|
||||
import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/clerk-react';
|
||||
import { useAuth } from '@clerk/clerk-react';
|
||||
import { ClickableMascot } from './components/ClickableMascot'; // Import ClickableMascot component
|
||||
import { ClickableMascot as ClickableMascotType, Upgrade } from './types'; // Import ClickableMascotType and Upgrade
|
||||
import { UPGRADES } from './config/upgrades'; // Import UPGRADES for upgrade config
|
||||
|
||||
function App() {
|
||||
const { isSignedIn, isLoaded } = useAuth();
|
||||
const { gameState, sendClick, purchaseUpgrade, userId } = usePartyKit();
|
||||
const { gameState, sendClick, purchaseUpgrade, userId, sendMascotClickBonus } = usePartyKit(); // Renamed sendShoominionClickBonus
|
||||
const [celebrationMessage, setCelebrationMessage] = useState<string | null>(null);
|
||||
const [previousMilestones, setPreviousMilestones] = useState<Record<string, boolean>>({});
|
||||
const [mascotEntities, setMascotEntities] = useState<ClickableMascotType[]>([]);
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
// Effect for milestone celebrations
|
||||
useEffect(() => {
|
||||
if (gameState) {
|
||||
// Check for new milestones
|
||||
const newMilestones = Object.keys(gameState.milestones).filter(
|
||||
(milestoneId) =>
|
||||
gameState.milestones[milestoneId] &&
|
||||
@@ -37,6 +42,103 @@ function App() {
|
||||
}
|
||||
}, [gameState, previousMilestones]);
|
||||
|
||||
// Effect for spawning mascots
|
||||
useEffect(() => {
|
||||
if (!gameState) return;
|
||||
|
||||
const friendBoostUpgrade = UPGRADES.find(u => u.id === 'friendBoost') as Upgrade | undefined;
|
||||
const ownedFriendBoost = gameState.upgrades['friendBoost']?.owned || 0;
|
||||
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
|
||||
if (ownedFriendBoost > 0 && friendBoostUpgrade && friendBoostUpgrade.mascotTiers) {
|
||||
const baseInterval = 10000; // Increased base interval for less frequent spawns
|
||||
const minInterval = 1000; // Increased min interval
|
||||
const interval = Math.max(minInterval, baseInterval / (1 + ownedFriendBoost * 0.2)); // Adjusted scaling
|
||||
|
||||
const currentMascotTiers = friendBoostUpgrade.mascotTiers; // Ensure mascotTiers is not undefined
|
||||
|
||||
const spawnMascot = () => {
|
||||
const buttonContainer = document.getElementById('click-button-container');
|
||||
if (!buttonContainer) {
|
||||
console.warn('Click button container not found!');
|
||||
timeoutRef.current = setTimeout(spawnMascot, 1000); // Retry after 1 second
|
||||
return;
|
||||
}
|
||||
|
||||
const rect = buttonContainer.getBoundingClientRect();
|
||||
const spawnAreaPadding = 150;
|
||||
const minX = rect.left - spawnAreaPadding;
|
||||
const maxX = rect.right + spawnAreaPadding;
|
||||
const minY = rect.top - spawnAreaPadding;
|
||||
const maxY = rect.bottom + spawnAreaPadding;
|
||||
|
||||
const viewportWidth = window.innerWidth;
|
||||
const viewportHeight = window.innerHeight;
|
||||
|
||||
const randomX = Math.max(0, Math.min(viewportWidth, minX + Math.random() * (maxX - minX)));
|
||||
const randomY = Math.max(0, Math.min(viewportHeight, minY + Math.random() * (maxY - minY)));
|
||||
|
||||
// Filter available mascots based on ownedFriendBoost level
|
||||
const availableMascots = currentMascotTiers.filter(
|
||||
(tier) => ownedFriendBoost >= tier.level
|
||||
);
|
||||
|
||||
if (availableMascots.length === 0) {
|
||||
console.warn('No mascots available to spawn for current friendBoost level.');
|
||||
timeoutRef.current = setTimeout(spawnMascot, interval);
|
||||
return;
|
||||
}
|
||||
|
||||
// Weighted random selection based on rarity
|
||||
const totalRarity = availableMascots.reduce((sum, tier) => sum + tier.rarity, 0);
|
||||
let randomWeight = Math.random() * totalRarity;
|
||||
let selectedMascotTier = availableMascots[0]; // Default to first available
|
||||
|
||||
for (const tier of availableMascots) {
|
||||
randomWeight -= tier.rarity;
|
||||
if (randomWeight <= 0) {
|
||||
selectedMascotTier = tier;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const newMascot: ClickableMascotType = {
|
||||
id: `mascot-${Date.now()}-${Math.random()}`,
|
||||
x: randomX,
|
||||
y: randomY,
|
||||
multiplierBonus: selectedMascotTier.multiplier,
|
||||
imageSrc: selectedMascotTier.imageSrc,
|
||||
};
|
||||
|
||||
setMascotEntities((prev) => [...prev, newMascot]);
|
||||
|
||||
timeoutRef.current = setTimeout(spawnMascot, interval);
|
||||
};
|
||||
|
||||
spawnMascot(); // Start the first spawn
|
||||
} else {
|
||||
setMascotEntities([]); // Clear all mascots if friendBoost is 0
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (timeoutRef.current) {
|
||||
clearTimeout(timeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, [gameState?.upgrades['friendBoost']?.owned, gameState]);
|
||||
|
||||
const handleMascotClick = (id: string, multiplierBonus: number) => { // Renamed handler
|
||||
sendMascotClickBonus(multiplierBonus); // Renamed function call
|
||||
setMascotEntities((prev) => prev.filter((m) => m.id !== id)); // Update state variable
|
||||
};
|
||||
|
||||
const handleMascotRemove = (id: string) => { // Renamed handler
|
||||
setMascotEntities((prev) => prev.filter((m) => m.id !== id)); // Update state variable
|
||||
};
|
||||
|
||||
if (!isLoaded || !gameState) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-purple-900 to-pink-900">
|
||||
@@ -49,6 +151,8 @@ function App() {
|
||||
|
||||
// Only calculate userClicks if userId is defined (i.e., user is signed in)
|
||||
const userClicks = isSignedIn && userId ? gameState.users[userId]?.clicks || 0 : 0;
|
||||
const userBonusMultiplier = isSignedIn && userId ? gameState.users[userId]?.bonusMultiplier || 1 : 1;
|
||||
const effectiveClickMultiplier = gameState.clickMultiplier * userBonusMultiplier;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen relative overflow-x-hidden">
|
||||
@@ -82,12 +186,25 @@ function App() {
|
||||
{/* Main Content */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
{/* Left Column - Click Button */}
|
||||
<div className="lg:col-span-1 flex flex-col items-center justify-center">
|
||||
<div id="click-button-container" className="lg:col-span-1 flex flex-col items-center justify-center relative"> {/* Added id and relative positioning */}
|
||||
<ClickButton
|
||||
onClick={sendClick}
|
||||
imageUrl={gameState.currentClickImage}
|
||||
clickMultiplier={gameState.clickMultiplier}
|
||||
clickMultiplier={effectiveClickMultiplier}
|
||||
/>
|
||||
{/* Render Mascots */}
|
||||
{mascotEntities.map((mascot: ClickableMascotType) => (
|
||||
<ClickableMascot
|
||||
key={mascot.id}
|
||||
id={mascot.id}
|
||||
x={mascot.x}
|
||||
y={mascot.y}
|
||||
multiplierBonus={mascot.multiplierBonus}
|
||||
imageSrc={mascot.imageSrc}
|
||||
onClick={handleMascotClick}
|
||||
onRemove={handleMascotRemove}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Middle Column - Upgrades */}
|
||||
|
||||
Reference in New Issue
Block a user