XTaylorSpenceX

Fractal Farm Frenzy

Sep 18th, 2025
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 30.22 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Fractal Farm Frenzy - Fixed</title>
  7.     <style>
  8.         @import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600&display=swap');
  9.        
  10.         * {
  11.             margin: 0;
  12.             padding: 0;
  13.             box-sizing: border-box;
  14.         }
  15.        
  16.         body {
  17.             font-family: 'Fredoka', cursive;
  18.             background: linear-gradient(180deg, #87CEEB 0%, #98D98E 40%, #8B7355 100%);
  19.             height: 100vh;
  20.             overflow: hidden;
  21.             display: flex;
  22.             flex-direction: column;
  23.             align-items: center;
  24.             color: #3a2317;
  25.             padding: 10px;
  26.         }
  27.        
  28.         #gameHeader {
  29.             background: rgba(255, 255, 255, 0.95);
  30.             border-radius: 20px;
  31.             padding: 15px 30px;
  32.             margin: 15px 0;
  33.             box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
  34.             backdrop-filter: blur(10px);
  35.             display: flex;
  36.             gap: 30px;
  37.             align-items: center;
  38.             z-index: 10;
  39.             animation: slideDown 0.5s ease-out;
  40.             flex-wrap: wrap;
  41.             justify-content: center;
  42.             max-width: 95%;
  43.         }
  44.        
  45.         @keyframes slideDown {
  46.             from {
  47.                 transform: translateY(-100px);
  48.                 opacity: 0;
  49.             }
  50.             to {
  51.                 transform: translateY(0);
  52.                 opacity: 1;
  53.             }
  54.         }
  55.        
  56.         .stat {
  57.             display: flex;
  58.             flex-direction: column;
  59.             align-items: center;
  60.             gap: 5px;
  61.             min-width: 80px;
  62.         }
  63.        
  64.         .stat-label {
  65.             font-size: 12px;
  66.             color: #6b5d54;
  67.             text-transform: uppercase;
  68.             letter-spacing: 1px;
  69.         }
  70.        
  71.         .stat-value {
  72.             font-size: 24px;
  73.             font-weight: 600;
  74.             color: #3a2317;
  75.         }
  76.        
  77.         #gameContainer {
  78.             position: relative;
  79.             width: 100%;
  80.             max-width: 800px;
  81.             display: flex;
  82.             justify-content: center;
  83.         }
  84.        
  85.         #gameCanvas {
  86.             background: radial-gradient(circle at 50% 50%, #f5e6d3 0%, #d4b896 100%);
  87.             border-radius: 20px;
  88.             box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2);
  89.             cursor: crosshair;
  90.             transition: transform 0.3s ease;
  91.             max-width: 100%;
  92.         }
  93.        
  94.         #gameCanvas:hover {
  95.             transform: scale(1.01);
  96.         }
  97.        
  98.         #controls {
  99.             background: rgba(255, 255, 255, 0.9);
  100.             border-radius: 15px;
  101.             padding: 15px;
  102.             margin: 15px 0;
  103.             display: flex;
  104.             gap: 10px;
  105.             box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
  106.             animation: slideUp 0.5s ease-out;
  107.             flex-wrap: wrap;
  108.             justify-content: center;
  109.             max-width: 95%;
  110.         }
  111.        
  112.         @keyframes slideUp {
  113.             from {
  114.                 transform: translateY(100px);
  115.                 opacity: 0;
  116.             }
  117.             to {
  118.                 transform: translateY(0);
  119.                 opacity: 1;
  120.             }
  121.         }
  122.        
  123.         button {
  124.             background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  125.             color: white;
  126.             border: none;
  127.             padding: 12px 20px;
  128.             border-radius: 10px;
  129.             font-size: 16px;
  130.             font-weight: 600;
  131.             cursor: pointer;
  132.             transition: all 0.3s ease;
  133.             box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
  134.             font-family: 'Fredoka', cursive;
  135.             min-width: 120px;
  136.         }
  137.        
  138.         button:hover {
  139.             transform: translateY(-2px);
  140.             box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
  141.         }
  142.        
  143.         button:active {
  144.             transform: scale(0.95);
  145.         }
  146.        
  147.         button.selected {
  148.             transform: scale(1.05);
  149.             box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.8), 0 6px 20px rgba(102, 126, 234, 0.6);
  150.         }
  151.        
  152.         button.seed-btn {
  153.             background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
  154.         }
  155.        
  156.         button.prune-btn {
  157.             background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
  158.         }
  159.        
  160.         button.harvest-btn {
  161.             background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  162.         }
  163.        
  164.         #tooltip {
  165.             position: absolute;
  166.             background: rgba(0, 0, 0, 0.8);
  167.             color: white;
  168.             padding: 8px 12px;
  169.             border-radius: 8px;
  170.             font-size: 14px;
  171.             pointer-events: none;
  172.             display: none;
  173.             z-index: 1000;
  174.             animation: fadeIn 0.2s ease;
  175.             max-width: 200px;
  176.             text-align: center;
  177.         }
  178.        
  179.         @keyframes fadeIn {
  180.             from { opacity: 0; }
  181.             to { opacity: 1; }
  182.         }
  183.        
  184.         .warning {
  185.             position: absolute;
  186.             top: 20px;
  187.             left: 50%;
  188.             transform: translateX(-50%);
  189.             background: rgba(255, 0, 0, 0.9);
  190.             color: white;
  191.             padding: 15px 30px;
  192.             border-radius: 15px;
  193.             font-size: 20px;
  194.             font-weight: 600;
  195.             display: none;
  196.             z-index: 100;
  197.             animation: pulse 0.8s ease infinite;
  198.             text-align: center;
  199.         }
  200.        
  201.         @keyframes pulse {
  202.             0%, 100% { transform: translateX(-50%) scale(1); }
  203.             50% { transform: translateX(-50%) scale(1.05); }
  204.         }
  205.        
  206.         .particle {
  207.             position: absolute;
  208.             width: 4px;
  209.             height: 4px;
  210.             background: radial-gradient(circle, #ffeb3b 0%, transparent 70%);
  211.             pointer-events: none;
  212.             animation: float 2s ease-out forwards;
  213.         }
  214.        
  215.         @keyframes float {
  216.             to {
  217.                 transform: translateY(-100px) translateX(var(--drift));
  218.                 opacity: 0;
  219.             }
  220.         }
  221.        
  222.         #gameOver {
  223.             position: absolute;
  224.             top: 50%;
  225.             left: 50%;
  226.             transform: translate(-50%, -50%);
  227.             background: white;
  228.             padding: 40px;
  229.             border-radius: 20px;
  230.             text-align: center;
  231.             display: none;
  232.             z-index: 200;
  233.             box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  234.             width: 90%;
  235.             max-width: 400px;
  236.         }
  237.        
  238.         #gameOver h2 {
  239.             color: #3a2317;
  240.             margin-bottom: 20px;
  241.             font-size: 32px;
  242.         }
  243.        
  244.         #gameOver p {
  245.             color: #6b5d54;
  246.             margin-bottom: 20px;
  247.             font-size: 18px;
  248.         }
  249.        
  250.         .growth-indicator {
  251.             position: absolute;
  252.             width: 30px;
  253.             height: 30px;
  254.             border: 3px solid #4caf50;
  255.             border-radius: 50%;
  256.             pointer-events: none;
  257.             animation: growthPulse 1s ease-out forwards;
  258.         }
  259.        
  260.         @keyframes growthPulse {
  261.             to {
  262.                 transform: scale(2);
  263.                 opacity: 0;
  264.             }
  265.         }
  266.        
  267.         .instructions {
  268.             background: rgba(255, 255, 255, 0.9);
  269.             border-radius: 15px;
  270.             padding: 15px;
  271.             margin: 10px 0;
  272.             box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
  273.             text-align: center;
  274.             max-width: 95%;
  275.         }
  276.        
  277.         .instructions p {
  278.             margin: 5px 0;
  279.             color: #3a2317;
  280.             font-size: 14px;
  281.         }
  282.        
  283.         @media (max-width: 600px) {
  284.             #gameHeader {
  285.                 gap: 15px;
  286.                 padding: 10px 15px;
  287.             }
  288.            
  289.             .stat {
  290.                 min-width: 70px;
  291.             }
  292.            
  293.             .stat-value {
  294.                 font-size: 20px;
  295.             }
  296.            
  297.             button {
  298.                 padding: 10px 15px;
  299.                 font-size: 14px;
  300.                 min-width: 100px;
  301.             }
  302.            
  303.             #controls {
  304.                 gap: 8px;
  305.             }
  306.         }
  307.     </style>
  308. </head>
  309. <body>
  310.     <h1>Fractal Farm Frenzy</h1>
  311.    
  312.     <div class="instructions">
  313.         <p>🌱 Plant seeds, ✂️ prune overgrowth, and 🌾 harvest mature plants!</p>
  314.         <p>Keep your stability above 0% to avoid game over.</p>
  315.     </div>
  316.    
  317.     <div id="gameHeader">
  318.         <div class="stat">
  319.             <div class="stat-label">Seeds</div>
  320.             <div class="stat-value" id="seedCount">5</div>
  321.         </div>
  322.         <div class="stat">
  323.             <div class="stat-label">Harvest</div>
  324.             <div class="stat-value" id="harvestCount">0</div>
  325.         </div>
  326.         <div class="stat">
  327.             <div class="stat-label">Growth</div>
  328.             <div class="stat-value" id="growthLevel">0%</div>
  329.         </div>
  330.         <div class="stat">
  331.             <div class="stat-label">Stability</div>
  332.             <div class="stat-value" id="stability">100%</div>
  333.         </div>
  334.     </div>
  335.    
  336.     <div id="gameContainer">
  337.         <canvas id="gameCanvas" width="800" height="500"></canvas>
  338.         <div class="warning" id="warning">⚠️ OVERGROWTH WARNING ⚠️</div>
  339.         <div id="gameOver">
  340.             <h2>Farm Consumed!</h2>
  341.             <p>Your fractals grew out of control!</p>
  342.             <p>Final Harvest: <span id="finalScore">0</span></p>
  343.             <button id="gameOverReset">Try Again</button>
  344.         </div>
  345.     </div>
  346.    
  347.     <div id="controls">
  348.         <button class="seed-btn selected" id="plantBtn">🌱 Plant Seed</button>
  349.         <button class="prune-btn" id="pruneBtn">✂️ Prune</button>
  350.         <button class="harvest-btn" id="harvestBtn">🌾 Harvest</button>
  351.         <button id="resetBtn">🔄 Reset Farm</button>
  352.     </div>
  353.    
  354.     <div id="tooltip"></div>
  355.    
  356.     <script>
  357.         class FractalPlant {
  358.             constructor(x, y, type = 'fern') {
  359.                 this.x = x;
  360.                 this.y = y;
  361.                 this.type = type;
  362.                 this.age = 0;
  363.                 this.maxDepth = 3;
  364.                 this.branches = [];
  365.                 this.growthRate = 0.01 + Math.random() * 0.02; // Reduced growth rate
  366.                 this.color = this.generateColor();
  367.                 this.angle = -Math.PI / 2;
  368.                 this.length = 20;
  369.                 this.thickness = 8;
  370.                 this.pruned = false;
  371.                 this.harvestable = false;
  372.                 this.energy = 1;
  373.                 this.lastPruneTime = 0;
  374.             }
  375.            
  376.             generateColor() {
  377.                 const hue = 80 + Math.random() * 40; // Green to yellow range
  378.                 return `hsl(${hue}, 70%, 45%)`;
  379.             }
  380.            
  381.             grow() {
  382.                 if (this.pruned) return 0;
  383.                
  384.                 this.age += this.growthRate;
  385.                
  386.                 if (this.age > 0.5 && this.branches.length < this.maxDepth * 2) {
  387.                    if (Math.random() < 0.008) { // Reduced branch generation rate
  388.                        this.branches.push({
  389.                            angle: this.angle + (Math.random() - 0.5) * Math.PI / 3,
  390.                            length: this.length * 0.7,
  391.                            thickness: this.thickness * 0.6,
  392.                            branches: [],
  393.                            age: 0
  394.                        });
  395.                     }
  396.                 }
  397.                
  398.                 if (this.age > 1) {
  399.                     this.harvestable = true;
  400.                 }
  401.                
  402.                 // Recursive growth for branches
  403.                 let totalGrowth = this.age;
  404.                 this.branches.forEach(branch => {
  405.                     branch.age = Math.min(branch.age + this.growthRate * 0.8, 1); // Slower branch growth
  406.                     totalGrowth += branch.age;
  407.                    
  408.                     if (branch.branches.length < 2 && Math.random() < 0.004) { // Reduced sub-branch generation
  409.                        branch.branches.push({
  410.                            angle: branch.angle + (Math.random() - 0.5) * Math.PI / 4,
  411.                            length: branch.length * 0.7,
  412.                            thickness: branch.thickness * 0.6,
  413.                            branches: [],
  414.                            age: 0
  415.                        });
  416.                    }
  417.                    
  418.                    branch.branches.forEach(subbranch => {
  419.                         subbranch.age = Math.min(subbranch.age + this.growthRate * 0.4, 1); // Even slower sub-branch growth
  420.                         totalGrowth += subbranch.age;
  421.                     });
  422.                 });
  423.                
  424.                 return totalGrowth;
  425.             }
  426.            
  427.             prune() {
  428.                 const now = Date.now();
  429.                 if (now - this.lastPruneTime < 1000) return false; // Prevent rapid pruning
  430.                
  431.                if (this.branches.length > 0) {
  432.                     this.branches.pop();
  433.                     this.pruned = true;
  434.                     this.lastPruneTime = now;
  435.                     setTimeout(() => this.pruned = false, 1500);
  436.                     return true;
  437.                 }
  438.                 return false;
  439.             }
  440.            
  441.             harvest() {
  442.                 if (!this.harvestable) return 0;
  443.                
  444.                 let harvestYield = Math.floor(this.age * 8 + this.branches.length * 4); // Reduced yield
  445.                 this.branches.forEach(branch => {
  446.                     harvestYield += Math.floor(branch.age * 2);
  447.                     branch.branches.forEach(subbranch => {
  448.                         harvestYield += Math.floor(subbranch.age * 1);
  449.                     });
  450.                 });
  451.                
  452.                 return harvestYield;
  453.             }
  454.            
  455.             draw(ctx) {
  456.                 ctx.save();
  457.                 ctx.translate(this.x, this.y);
  458.                
  459.                 // Draw main stem
  460.                 ctx.strokeStyle = this.color;
  461.                 ctx.lineWidth = this.thickness * this.age;
  462.                 ctx.lineCap = 'round';
  463.                 ctx.beginPath();
  464.                 ctx.moveTo(0, 0);
  465.                 const endX = Math.cos(this.angle) * this.length * this.age;
  466.                 const endY = Math.sin(this.angle) * this.length * this.age;
  467.                 ctx.lineTo(endX, endY);
  468.                 ctx.stroke();
  469.                
  470.                 // Draw branches recursively
  471.                 this.drawBranches(ctx, endX, endY, this.branches, 1);
  472.                
  473.                 // Draw flowers/fruits if harvestable
  474.                 if (this.harvestable) {
  475.                     this.branches.forEach((branch, i) => {
  476.                         if (branch.age > 0.8) {
  477.                             const bx = endX + Math.cos(branch.angle) * branch.length * branch.age;
  478.                             const by = endY + Math.sin(branch.angle) * branch.length * branch.age;
  479.                            
  480.                             ctx.fillStyle = `hsl(${30 + i * 30}, 80%, 60%)`;
  481.                             ctx.beginPath();
  482.                             ctx.arc(bx, by, 5 + Math.sin(Date.now() * 0.001 + i) * 2, 0, Math.PI * 2);
  483.                             ctx.fill();
  484.                         }
  485.                     });
  486.                 }
  487.                
  488.                 // Draw highlight if plant is selected
  489.                 if (this.pruned) {
  490.                     ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
  491.                     ctx.beginPath();
  492.                     ctx.arc(0, 0, 25, 0, Math.PI * 2);
  493.                     ctx.fill();
  494.                 }
  495.                
  496.                 ctx.restore();
  497.             }
  498.            
  499.             drawBranches(ctx, x, y, branches, depth) {
  500.                 branches.forEach(branch => {
  501.                     const endX = x + Math.cos(branch.angle) * branch.length * branch.age;
  502.                     const endY = y + Math.sin(branch.angle) * branch.length * branch.age;
  503.                    
  504.                     ctx.strokeStyle = this.color;
  505.                     ctx.lineWidth = branch.thickness * branch.age;
  506.                     ctx.beginPath();
  507.                     ctx.moveTo(x, y);
  508.                     ctx.lineTo(endX, endY);
  509.                     ctx.stroke();
  510.                    
  511.                     if (branch.branches.length > 0 && depth < 3) {
  512.                        this.drawBranches(ctx, endX, endY, branch.branches, depth + 1);
  513.                     }
  514.                 });
  515.             }
  516.         }
  517.        
  518.         class FractalFarmGame {
  519.             constructor() {
  520.                 this.canvas = document.getElementById('gameCanvas');
  521.                 this.ctx = this.canvas.getContext('2d');
  522.                 this.plants = [];
  523.                 this.seeds = 5;
  524.                 this.harvest = 0;
  525.                 this.mode = 'plant';
  526.                 this.stability = 100;
  527.                 this.totalGrowth = 0;
  528.                 this.maxGrowth = 150; // Increased max growth threshold
  529.                 this.gameOver = false;
  530.                 this.lastUpdateTime = 0;
  531.                 this.updateInterval = 1000 / 30; // 30 FPS
  532.                
  533.                 this.init();
  534.             }
  535.            
  536.             init() {
  537.                 this.canvas.addEventListener('click', this.handleClick.bind(this));
  538.                 this.canvas.addEventListener('mousemove', this.handleMouseMove.bind(this));
  539.                 this.gameLoop();
  540.             }
  541.            
  542.             handleClick(e) {
  543.                 if (this.gameOver) return;
  544.                
  545.                 const rect = this.canvas.getBoundingClientRect();
  546.                 const x = e.clientX - rect.left;
  547.                 const y = e.clientY - rect.top;
  548.                
  549.                 switch(this.mode) {
  550.                     case 'plant':
  551.                         this.plantSeed(x, y);
  552.                         break;
  553.                     case 'prune':
  554.                         this.prunePlant(x, y);
  555.                         break;
  556.                     case 'harvest':
  557.                         this.harvestPlant(x, y);
  558.                         break;
  559.                 }
  560.                
  561.                 this.createParticles(x, y);
  562.             }
  563.            
  564.             handleMouseMove(e) {
  565.                 const rect = this.canvas.getBoundingClientRect();
  566.                 const x = e.clientX - rect.left;
  567.                 const y = e.clientY - rect.top;
  568.                
  569.                 const tooltip = document.getElementById('tooltip');
  570.                 const plant = this.getPlantAt(x, y);
  571.                
  572.                 if (plant) {
  573.                     tooltip.style.display = 'block';
  574.                     tooltip.style.left = e.clientX + 10 + 'px';
  575.                     tooltip.style.top = e.clientY - 30 + 'px';
  576.                    
  577.                     if (this.mode === 'harvest' && plant.harvestable) {
  578.                        tooltip.textContent = `Ready to harvest! Yield: ~${Math.floor(plant.age * 8 + plant.branches.length * 4)}`;
  579.                     } else if (this.mode === 'harvest' && !plant.harvestable) {
  580.                        tooltip.textContent = `Not ready yet. Growth: ${Math.floor(plant.age * 100)}%`;
  581.                     } else if (this.mode === 'prune') {
  582.                         tooltip.textContent = `Branches: ${plant.branches.length}/${plant.maxDepth * 2}`;
  583.                     } else {
  584.                         tooltip.textContent = `Growth: ${Math.floor(plant.age * 100)}%`;
  585.                     }
  586.                 } else {
  587.                     tooltip.style.display = 'none';
  588.                 }
  589.             }
  590.            
  591.             plantSeed(x, y) {
  592.                 if (this.seeds <= 0) {
  593.                    this.showTemporaryTooltip("No seeds left! Harvest plants to get more.");
  594.                    return;
  595.                }
  596.                
  597.                // Check if position is valid (not too close to other plants)
  598.                const tooClose = this.plants.some(plant => {
  599.                     const dist = Math.hypot(plant.x - x, plant.y - y);
  600.                     return dist < 50;
  601.                });
  602.                
  603.                if (!tooClose) {
  604.                    this.plants.push(new FractalPlant(x, y));
  605.                    this.seeds--;
  606.                    this.updateUI();
  607.                    
  608.                    // Show growth indicator
  609.                    this.showGrowthIndicator(x, y);
  610.                } else {
  611.                    this.showTemporaryTooltip("Too close to another plant!");
  612.                }
  613.            }
  614.            
  615.            showTemporaryTooltip(message) {
  616.                const tooltip = document.getElementById('tooltip');
  617.                tooltip.textContent = message;
  618.                tooltip.style.display = 'block';
  619.                tooltip.style.left = '50%';
  620.                tooltip.style.top = '50%';
  621.                tooltip.style.transform = 'translate(-50%, -50%)';
  622.                
  623.                setTimeout(() => {
  624.                     tooltip.style.display = 'none';
  625.                     tooltip.style.transform = '';
  626.                 }, 2000);
  627.             }
  628.            
  629.             showGrowthIndicator(x, y) {
  630.                 const indicator = document.createElement('div');
  631.                 indicator.className = 'growth-indicator';
  632.                 indicator.style.left = x + this.canvas.offsetLeft + 'px';
  633.                 indicator.style.top = y + this.canvas.offsetTop + 'px';
  634.                 document.body.appendChild(indicator);
  635.                
  636.                 setTimeout(() => indicator.remove(), 1000);
  637.             }
  638.            
  639.             prunePlant(x, y) {
  640.                 const plant = this.getPlantAt(x, y);
  641.                 if (plant && plant.prune()) {
  642.                    this.stability = Math.min(100, this.stability + 8); // Increased stability gain from pruning
  643.                     this.updateUI();
  644.                     this.createParticles(x, y, '#ff9800');
  645.                 } else if (plant) {
  646.                     this.showTemporaryTooltip("No branches to prune!");
  647.                 }
  648.             }
  649.            
  650.             harvestPlant(x, y) {
  651.                 const plant = this.getPlantAt(x, y);
  652.                 if (plant && plant.harvestable) {
  653.                    const harvestYield = plant.harvest();
  654.                     this.harvest += harvestYield;
  655.                     this.seeds += Math.floor(harvestYield / 8); // Adjusted seed yield
  656.                    
  657.                     // Remove plant after harvest
  658.                     const index = this.plants.indexOf(plant);
  659.                     this.plants.splice(index, 1);
  660.                    
  661.                     this.updateUI();
  662.                     this.createParticles(x, y, '#4caf50');
  663.                 } else if (plant) {
  664.                     this.showTemporaryTooltip("Not ready for harvest yet!");
  665.                 }
  666.             }
  667.            
  668.             getPlantAt(x, y) {
  669.                 return this.plants.find(plant => {
  670.                     const dist = Math.hypot(plant.x - x, plant.y - y);
  671.                     return dist < 30;
  672.                });
  673.            }
  674.            
  675.            createParticles(x, y, color = '#ffeb3b') {
  676.                for (let i = 0; i < 8; i++) {
  677.                    const particle = document.createElement('div');
  678.                    particle.className = 'particle';
  679.                    particle.style.left = x + this.canvas.offsetLeft + 'px';
  680.                    particle.style.top = y + this.canvas.offsetTop + 'px';
  681.                    particle.style.setProperty('--drift', (Math.random() - 0.5) * 100 + 'px');
  682.                    particle.style.background = `radial-gradient(circle, ${color} 0%, transparent 70%)`;
  683.                    document.body.appendChild(particle);
  684.                    
  685.                    setTimeout(() => particle.remove(), 2000);
  686.                 }
  687.             }
  688.            
  689.             setMode(mode) {
  690.                 this.mode = mode;
  691.                
  692.                 // Update button styles
  693.                 document.getElementById('plantBtn').classList.toggle('selected', mode === 'plant');
  694.                 document.getElementById('pruneBtn').classList.toggle('selected', mode === 'prune');
  695.                 document.getElementById('harvestBtn').classList.toggle('selected', mode === 'harvest');
  696.                
  697.                 // Update cursor
  698.                 if (mode === 'plant') {
  699.                     this.canvas.style.cursor = 'crosshair';
  700.                 } else if (mode === 'prune') {
  701.                     this.canvas.style.cursor = 'grab';
  702.                 } else if (mode === 'harvest') {
  703.                     this.canvas.style.cursor = 'pointer';
  704.                 }
  705.             }
  706.            
  707.             update(timestamp) {
  708.                 if (this.gameOver) return;
  709.                
  710.                 // Throttle updates to improve performance
  711.                 if (!this.lastUpdateTime || timestamp - this.lastUpdateTime > this.updateInterval) {
  712.                     this.lastUpdateTime = timestamp;
  713.                    
  714.                     this.totalGrowth = 0;
  715.                     this.plants.forEach(plant => {
  716.                         this.totalGrowth += plant.grow();
  717.                     });
  718.                    
  719.                     // Calculate stability based on growth
  720.                     const growthRatio = this.totalGrowth / this.maxGrowth;
  721.                     this.stability = Math.max(0, 100 - growthRatio * 100);
  722.                    
  723.                     // Warning system
  724.                     const warning = document.getElementById('warning');
  725.                     if (this.stability < 30) {
  726.                        warning.style.display = 'block';
  727.                    } else {
  728.                        warning.style.display = 'none';
  729.                    }
  730.                    
  731.                    // Game over check
  732.                    if (this.stability <= 0) {
  733.                        this.endGame();
  734.                    }
  735.                    
  736.                    // Passive seed generation
  737.                    if (Math.random() < 0.002 && this.plants.length > 0) {
  738.                         this.seeds++;
  739.                         this.updateUI();
  740.                     }
  741.                    
  742.                     this.updateUI();
  743.                 }
  744.             }
  745.            
  746.             render() {
  747.                 // Clear canvas
  748.                 this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
  749.                
  750.                 // Draw grid
  751.                 this.ctx.strokeStyle = 'rgba(139, 115, 85, 0.15)';
  752.                 this.ctx.lineWidth = 1;
  753.                 for (let i = 0; i < this.canvas.width; i += 50) {
  754.                    this.ctx.beginPath();
  755.                    this.ctx.moveTo(i, 0);
  756.                    this.ctx.lineTo(i, this.canvas.height);
  757.                    this.ctx.stroke();
  758.                }
  759.                for (let i = 0; i < this.canvas.height; i += 50) {
  760.                    this.ctx.beginPath();
  761.                    this.ctx.moveTo(0, i);
  762.                    this.ctx.lineTo(this.canvas.width, i);
  763.                    this.ctx.stroke();
  764.                }
  765.                
  766.                // Draw plants
  767.                this.plants.forEach(plant => plant.draw(this.ctx));
  768.             }
  769.            
  770.             updateUI() {
  771.                 document.getElementById('seedCount').textContent = this.seeds;
  772.                 document.getElementById('harvestCount').textContent = this.harvest;
  773.                 document.getElementById('growthLevel').textContent = Math.floor(this.totalGrowth) + '%';
  774.                 document.getElementById('stability').textContent = Math.floor(this.stability) + '%';
  775.                
  776.                 // Color code stability
  777.                 const stabilityEl = document.getElementById('stability');
  778.                 if (this.stability > 70) {
  779.                     stabilityEl.style.color = '#4caf50';
  780.                 } else if (this.stability > 30) {
  781.                     stabilityEl.style.color = '#ff9800';
  782.                 } else {
  783.                     stabilityEl.style.color = '#f44336';
  784.                 }
  785.             }
  786.            
  787.             endGame() {
  788.                 this.gameOver = true;
  789.                 document.getElementById('finalScore').textContent = this.harvest;
  790.                 document.getElementById('gameOver').style.display = 'block';
  791.             }
  792.            
  793.             reset() {
  794.                 this.plants = [];
  795.                 this.seeds = 5;
  796.                 this.harvest = 0;
  797.                 this.stability = 100;
  798.                 this.totalGrowth = 0;
  799.                 this.gameOver = false;
  800.                 this.setMode('plant');
  801.                
  802.                 document.getElementById('gameOver').style.display = 'none';
  803.                 document.getElementById('warning').style.display = 'none';
  804.                
  805.                 this.updateUI();
  806.             }
  807.            
  808.             gameLoop(timestamp) {
  809.                 this.update(timestamp);
  810.                 this.render();
  811.                 requestAnimationFrame((ts) => this.gameLoop(ts));
  812.             }
  813.         }
  814.        
  815.         // Initialize game
  816.         let game;
  817.         window.addEventListener('DOMContentLoaded', () => {
  818.             game = new FractalFarmGame();
  819.            
  820.             // Set up button event listeners
  821.             document.getElementById('plantBtn').addEventListener('click', () => game.setMode('plant'));
  822.             document.getElementById('pruneBtn').addEventListener('click', () => game.setMode('prune'));
  823.             document.getElementById('harvestBtn').addEventListener('click', () => game.setMode('harvest'));
  824.             document.getElementById('resetBtn').addEventListener('click', () => game.reset());
  825.             document.getElementById('gameOverReset').addEventListener('click', () => game.reset());
  826.         });
  827.     </script>
  828. </body>
  829. </html>
  830.  
Advertisement
Add Comment
Please, Sign In to add comment