Advertisement
Guest User

Simple monster catcher game (tsx)

a guest
May 29th, 2025
8
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.39 KB | None | 0 0
  1. import React, { useState, useEffect } from 'react';
  2. import { Sparkles, Heart, Zap, Leaf, Droplets, Mountain } from 'lucide-react';
  3.  
  4. const MonsterCatcherGame = () => {
  5. const [currentMonster, setCurrentMonster] = useState(null);
  6. const [collection, setCollection] = useState([]);
  7. const [energy, setEnergy] = useState(100);
  8. const [catchMessage, setCatchMessage] = useState('');
  9. const [gameStats, setGameStats] = useState({ encountered: 0, caught: 0 });
  10.  
  11. const monsters = [
  12. { id: 1, name: 'Flamewyrm', type: 'Fire', rarity: 'Common', catchRate: 70, icon: '🔥', color: 'bg-red-500' },
  13. { id: 2, name: 'Aquafin', type: 'Water', rarity: 'Common', catchRate: 75, icon: '🌊', color: 'bg-blue-500' },
  14. { id: 3, name: 'Leafwhisper', type: 'Nature', rarity: 'Common', catchRate: 80, icon: '🌱', color: 'bg-green-500' },
  15. { id: 4, name: 'Thunderclaw', type: 'Electric', rarity: 'Uncommon', catchRate: 50, icon: '⚡', color: 'bg-yellow-500' },
  16. { id: 5, name: 'Crystalwing', type: 'Crystal', rarity: 'Uncommon', catchRate: 45, icon: '💎', color: 'bg-purple-500' },
  17. { id: 6, name: 'Shadowmist', type: 'Dark', rarity: 'Rare', catchRate: 30, icon: '🌙', color: 'bg-gray-700' },
  18. { id: 7, name: 'Sunburst', type: 'Light', rarity: 'Rare', catchRate: 25, icon: '☀️', color: 'bg-orange-400' },
  19. { id: 8, name: 'Voidkeeper', type: 'Void', rarity: 'Legendary', catchRate: 15, icon: '🌌', color: 'bg-black' },
  20. { id: 9, name: 'Starfall', type: 'Cosmic', rarity: 'Legendary', catchRate: 10, icon: '⭐', color: 'bg-indigo-600' },
  21. ];
  22.  
  23. const getTypeIcon = (type) => {
  24. const iconMap = {
  25. Fire: <Zap className="w-4 h-4" />,
  26. Water: <Droplets className="w-4 h-4" />,
  27. Nature: <Leaf className="w-4 h-4" />,
  28. Electric: <Zap className="w-4 h-4" />,
  29. Crystal: <Mountain className="w-4 h-4" />,
  30. Dark: <Heart className="w-4 h-4" />,
  31. Light: <Sparkles className="w-4 h-4" />,
  32. Void: <Heart className="w-4 h-4" />,
  33. Cosmic: <Sparkles className="w-4 h-4" />
  34. };
  35. return iconMap[type] || <Heart className="w-4 h-4" />;
  36. };
  37.  
  38. const getRarityColor = (rarity) => {
  39. const colorMap = {
  40. Common: 'border-gray-400 text-gray-600',
  41. Uncommon: 'border-green-400 text-green-600',
  42. Rare: 'border-blue-400 text-blue-600',
  43. Legendary: 'border-purple-400 text-purple-600'
  44. };
  45. return colorMap[rarity] || 'border-gray-400 text-gray-600';
  46. };
  47.  
  48. const searchForMonster = () => {
  49. if (energy < 10) {
  50. setCatchMessage("Not enough energy! Wait for it to regenerate.");
  51. return;
  52. }
  53.  
  54. setEnergy(prev => prev - 10);
  55. setGameStats(prev => ({ ...prev, encountered: prev.encountered + 1 }));
  56.  
  57. // Weighted random selection based on rarity
  58. const commonChance = 60;
  59. const uncommonChance = 25;
  60. const rareChance = 12;
  61. const legendaryChance = 3;
  62.  
  63. const roll = Math.random() * 100;
  64. let selectedRarity;
  65.  
  66. if (roll < legendaryChance) selectedRarity = 'Legendary';
  67. else if (roll < legendaryChance + rareChance) selectedRarity = 'Rare';
  68. else if (roll < legendaryChance + rareChance + uncommonChance) selectedRarity = 'Uncommon';
  69. else selectedRarity = 'Common';
  70.  
  71. const availableMonsters = monsters.filter(m => m.rarity === selectedRarity);
  72. const randomMonster = availableMonsters[Math.floor(Math.random() * availableMonsters.length)];
  73.  
  74. setCurrentMonster(randomMonster);
  75. setCatchMessage(`A wild ${randomMonster.name} appeared!`);
  76. };
  77.  
  78. const attemptCatch = () => {
  79. if (!currentMonster || energy < 5) {
  80. setCatchMessage("Not enough energy to attempt catch!");
  81. return;
  82. }
  83.  
  84. setEnergy(prev => prev - 5);
  85. const success = Math.random() * 100 < currentMonster.catchRate;
  86.  
  87. if (success) {
  88. const isAlreadyCaught = collection.some(m => m.id === currentMonster.id);
  89. if (!isAlreadyCaught) {
  90. setCollection(prev => [...prev, { ...currentMonster, caughtAt: new Date().toLocaleTimeString() }]);
  91. setGameStats(prev => ({ ...prev, caught: prev.caught + 1 }));
  92. setCatchMessage(`Success! You caught ${currentMonster.name}! Added to your collection.`);
  93. } else {
  94. setCatchMessage(`You caught ${currentMonster.name}, but you already have one in your collection.`);
  95. }
  96. } else {
  97. setCatchMessage(`${currentMonster.name} escaped! Try again or search for another monster.`);
  98. }
  99. };
  100.  
  101. // Energy regeneration
  102. useEffect(() => {
  103. const interval = setInterval(() => {
  104. setEnergy(prev => Math.min(100, prev + 2));
  105. }, 1000);
  106. return () => clearInterval(interval);
  107. }, []);
  108.  
  109. return (
  110. <div className="min-h-screen bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 p-4">
  111. <div className="max-w-4xl mx-auto">
  112. <h1 className="text-4xl font-bold text-white text-center mb-8 flex items-center justify-center gap-2">
  113. <Sparkles className="w-8 h-8" />
  114. Monster Catcher
  115. <Sparkles className="w-8 h-8" />
  116. </h1>
  117.  
  118. {/* Game Stats */}
  119. <div className="bg-white/10 backdrop-blur-sm rounded-lg p-4 mb-6">
  120. <div className="grid grid-cols-3 gap-4 text-center text-white">
  121. <div>
  122. <div className="text-2xl font-bold">{energy}</div>
  123. <div className="text-sm opacity-80">Energy</div>
  124. <div className="w-full bg-gray-700 rounded-full h-2 mt-1">
  125. <div
  126. className="bg-green-500 h-2 rounded-full transition-all duration-300"
  127. style={{ width: `${energy}%` }}
  128. ></div>
  129. </div>
  130. </div>
  131. <div>
  132. <div className="text-2xl font-bold">{gameStats.encountered}</div>
  133. <div className="text-sm opacity-80">Encountered</div>
  134. </div>
  135. <div>
  136. <div className="text-2xl font-bold">{collection.length}</div>
  137. <div className="text-sm opacity-80">Collected</div>
  138. </div>
  139. </div>
  140. </div>
  141.  
  142. {/* Current Monster */}
  143. <div className="bg-white/10 backdrop-blur-sm rounded-lg p-6 mb-6">
  144. {currentMonster ? (
  145. <div className="text-center">
  146. <div className="text-6xl mb-4">{currentMonster.icon}</div>
  147. <h2 className="text-2xl font-bold text-white mb-2">{currentMonster.name}</h2>
  148. <div className="flex items-center justify-center gap-2 mb-4">
  149. {getTypeIcon(currentMonster.type)}
  150. <span className="text-white">{currentMonster.type}</span>
  151. <span className={`px-2 py-1 rounded-full text-xs border ${getRarityColor(currentMonster.rarity)}`}>
  152. {currentMonster.rarity}
  153. </span>
  154. </div>
  155. <div className="text-white mb-4">
  156. Catch Rate: {currentMonster.catchRate}%
  157. </div>
  158. <button
  159. onClick={attemptCatch}
  160. disabled={energy < 5}
  161. className="bg-red-500 hover:bg-red-600 disabled:bg-gray-500 text-white px-6 py-2 rounded-lg font-bold transition-colors"
  162. >
  163. Throw Pokeball! (5 Energy)
  164. </button>
  165. </div>
  166. ) : (
  167. <div className="text-center text-white">
  168. <div className="text-6xl mb-4">🔍</div>
  169. <p>Search for monsters to begin your adventure!</p>
  170. </div>
  171. )}
  172. </div>
  173.  
  174. {/* Action Buttons */}
  175. <div className="text-center mb-6">
  176. <button
  177. onClick={searchForMonster}
  178. disabled={energy < 10}
  179. className="bg-blue-500 hover:bg-blue-600 disabled:bg-gray-500 text-white px-8 py-3 rounded-lg font-bold mr-4 transition-colors"
  180. >
  181. Search for Monster (10 Energy)
  182. </button>
  183. </div>
  184.  
  185. {/* Message */}
  186. {catchMessage && (
  187. <div className="bg-white/20 backdrop-blur-sm rounded-lg p-4 mb-6 text-center text-white">
  188. {catchMessage}
  189. </div>
  190. )}
  191.  
  192. {/* Collection */}
  193. <div className="bg-white/10 backdrop-blur-sm rounded-lg p-6">
  194. <h3 className="text-xl font-bold text-white mb-4">Your Collection ({collection.length}/9)</h3>
  195. {collection.length > 0 ? (
  196. <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  197. {collection.map((monster, index) => (
  198. <div key={index} className="bg-white/20 rounded-lg p-4 text-center">
  199. <div className="text-3xl mb-2">{monster.icon}</div>
  200. <div className="text-white font-bold">{monster.name}</div>
  201. <div className="text-sm text-white/80">{monster.type}</div>
  202. <div className={`text-xs px-2 py-1 rounded-full border ${getRarityColor(monster.rarity)} mt-2 inline-block`}>
  203. {monster.rarity}
  204. </div>
  205. <div className="text-xs text-white/60 mt-1">
  206. Caught at {monster.caughtAt}
  207. </div>
  208. </div>
  209. ))}
  210. </div>
  211. ) : (
  212. <div className="text-center text-white/60">
  213. Your collection is empty. Start catching monsters!
  214. </div>
  215. )}
  216. </div>
  217. </div>
  218. </div>
  219. );
  220. };
  221.  
  222. export default MonsterCatcherGame;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement