Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>Fractal Farm Frenzy - Fixed</title>
- <style>
- @import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600&display=swap');
- * {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
- }
- body {
- font-family: 'Fredoka', cursive;
- background: linear-gradient(180deg, #87CEEB 0%, #98D98E 40%, #8B7355 100%);
- height: 100vh;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- align-items: center;
- color: #3a2317;
- padding: 10px;
- }
- #gameHeader {
- background: rgba(255, 255, 255, 0.95);
- border-radius: 20px;
- padding: 15px 30px;
- margin: 15px 0;
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
- backdrop-filter: blur(10px);
- display: flex;
- gap: 30px;
- align-items: center;
- z-index: 10;
- animation: slideDown 0.5s ease-out;
- flex-wrap: wrap;
- justify-content: center;
- max-width: 95%;
- }
- @keyframes slideDown {
- from {
- transform: translateY(-100px);
- opacity: 0;
- }
- to {
- transform: translateY(0);
- opacity: 1;
- }
- }
- .stat {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 5px;
- min-width: 80px;
- }
- .stat-label {
- font-size: 12px;
- color: #6b5d54;
- text-transform: uppercase;
- letter-spacing: 1px;
- }
- .stat-value {
- font-size: 24px;
- font-weight: 600;
- color: #3a2317;
- }
- #gameContainer {
- position: relative;
- width: 100%;
- max-width: 800px;
- display: flex;
- justify-content: center;
- }
- #gameCanvas {
- background: radial-gradient(circle at 50% 50%, #f5e6d3 0%, #d4b896 100%);
- border-radius: 20px;
- box-shadow: 0 15px 40px rgba(0, 0, 0, 0.2);
- cursor: crosshair;
- transition: transform 0.3s ease;
- max-width: 100%;
- }
- #gameCanvas:hover {
- transform: scale(1.01);
- }
- #controls {
- background: rgba(255, 255, 255, 0.9);
- border-radius: 15px;
- padding: 15px;
- margin: 15px 0;
- display: flex;
- gap: 10px;
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
- animation: slideUp 0.5s ease-out;
- flex-wrap: wrap;
- justify-content: center;
- max-width: 95%;
- }
- @keyframes slideUp {
- from {
- transform: translateY(100px);
- opacity: 0;
- }
- to {
- transform: translateY(0);
- opacity: 1;
- }
- }
- button {
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
- color: white;
- border: none;
- padding: 12px 20px;
- border-radius: 10px;
- font-size: 16px;
- font-weight: 600;
- cursor: pointer;
- transition: all 0.3s ease;
- box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
- font-family: 'Fredoka', cursive;
- min-width: 120px;
- }
- button:hover {
- transform: translateY(-2px);
- box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
- }
- button:active {
- transform: scale(0.95);
- }
- button.selected {
- transform: scale(1.05);
- box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.8), 0 6px 20px rgba(102, 126, 234, 0.6);
- }
- button.seed-btn {
- background: linear-gradient(135deg, #84fab0 0%, #8fd3f4 100%);
- }
- button.prune-btn {
- background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
- }
- button.harvest-btn {
- background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
- }
- #tooltip {
- position: absolute;
- background: rgba(0, 0, 0, 0.8);
- color: white;
- padding: 8px 12px;
- border-radius: 8px;
- font-size: 14px;
- pointer-events: none;
- display: none;
- z-index: 1000;
- animation: fadeIn 0.2s ease;
- max-width: 200px;
- text-align: center;
- }
- @keyframes fadeIn {
- from { opacity: 0; }
- to { opacity: 1; }
- }
- .warning {
- position: absolute;
- top: 20px;
- left: 50%;
- transform: translateX(-50%);
- background: rgba(255, 0, 0, 0.9);
- color: white;
- padding: 15px 30px;
- border-radius: 15px;
- font-size: 20px;
- font-weight: 600;
- display: none;
- z-index: 100;
- animation: pulse 0.8s ease infinite;
- text-align: center;
- }
- @keyframes pulse {
- 0%, 100% { transform: translateX(-50%) scale(1); }
- 50% { transform: translateX(-50%) scale(1.05); }
- }
- .particle {
- position: absolute;
- width: 4px;
- height: 4px;
- background: radial-gradient(circle, #ffeb3b 0%, transparent 70%);
- pointer-events: none;
- animation: float 2s ease-out forwards;
- }
- @keyframes float {
- to {
- transform: translateY(-100px) translateX(var(--drift));
- opacity: 0;
- }
- }
- #gameOver {
- position: absolute;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- background: white;
- padding: 40px;
- border-radius: 20px;
- text-align: center;
- display: none;
- z-index: 200;
- box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
- width: 90%;
- max-width: 400px;
- }
- #gameOver h2 {
- color: #3a2317;
- margin-bottom: 20px;
- font-size: 32px;
- }
- #gameOver p {
- color: #6b5d54;
- margin-bottom: 20px;
- font-size: 18px;
- }
- .growth-indicator {
- position: absolute;
- width: 30px;
- height: 30px;
- border: 3px solid #4caf50;
- border-radius: 50%;
- pointer-events: none;
- animation: growthPulse 1s ease-out forwards;
- }
- @keyframes growthPulse {
- to {
- transform: scale(2);
- opacity: 0;
- }
- }
- .instructions {
- background: rgba(255, 255, 255, 0.9);
- border-radius: 15px;
- padding: 15px;
- margin: 10px 0;
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
- text-align: center;
- max-width: 95%;
- }
- .instructions p {
- margin: 5px 0;
- color: #3a2317;
- font-size: 14px;
- }
- @media (max-width: 600px) {
- #gameHeader {
- gap: 15px;
- padding: 10px 15px;
- }
- .stat {
- min-width: 70px;
- }
- .stat-value {
- font-size: 20px;
- }
- button {
- padding: 10px 15px;
- font-size: 14px;
- min-width: 100px;
- }
- #controls {
- gap: 8px;
- }
- }
- </style>
- </head>
- <body>
- <h1>Fractal Farm Frenzy</h1>
- <div class="instructions">
- <p>🌱 Plant seeds, ✂️ prune overgrowth, and 🌾 harvest mature plants!</p>
- <p>Keep your stability above 0% to avoid game over.</p>
- </div>
- <div id="gameHeader">
- <div class="stat">
- <div class="stat-label">Seeds</div>
- <div class="stat-value" id="seedCount">5</div>
- </div>
- <div class="stat">
- <div class="stat-label">Harvest</div>
- <div class="stat-value" id="harvestCount">0</div>
- </div>
- <div class="stat">
- <div class="stat-label">Growth</div>
- <div class="stat-value" id="growthLevel">0%</div>
- </div>
- <div class="stat">
- <div class="stat-label">Stability</div>
- <div class="stat-value" id="stability">100%</div>
- </div>
- </div>
- <div id="gameContainer">
- <canvas id="gameCanvas" width="800" height="500"></canvas>
- <div class="warning" id="warning">⚠️ OVERGROWTH WARNING ⚠️</div>
- <div id="gameOver">
- <h2>Farm Consumed!</h2>
- <p>Your fractals grew out of control!</p>
- <p>Final Harvest: <span id="finalScore">0</span></p>
- <button id="gameOverReset">Try Again</button>
- </div>
- </div>
- <div id="controls">
- <button class="seed-btn selected" id="plantBtn">🌱 Plant Seed</button>
- <button class="prune-btn" id="pruneBtn">✂️ Prune</button>
- <button class="harvest-btn" id="harvestBtn">🌾 Harvest</button>
- <button id="resetBtn">🔄 Reset Farm</button>
- </div>
- <div id="tooltip"></div>
- <script>
- class FractalPlant {
- constructor(x, y, type = 'fern') {
- this.x = x;
- this.y = y;
- this.type = type;
- this.age = 0;
- this.maxDepth = 3;
- this.branches = [];
- this.growthRate = 0.01 + Math.random() * 0.02; // Reduced growth rate
- this.color = this.generateColor();
- this.angle = -Math.PI / 2;
- this.length = 20;
- this.thickness = 8;
- this.pruned = false;
- this.harvestable = false;
- this.energy = 1;
- this.lastPruneTime = 0;
- }
- generateColor() {
- const hue = 80 + Math.random() * 40; // Green to yellow range
- return `hsl(${hue}, 70%, 45%)`;
- }
- grow() {
- if (this.pruned) return 0;
- this.age += this.growthRate;
- if (this.age > 0.5 && this.branches.length < this.maxDepth * 2) {
- if (Math.random() < 0.008) { // Reduced branch generation rate
- this.branches.push({
- angle: this.angle + (Math.random() - 0.5) * Math.PI / 3,
- length: this.length * 0.7,
- thickness: this.thickness * 0.6,
- branches: [],
- age: 0
- });
- }
- }
- if (this.age > 1) {
- this.harvestable = true;
- }
- // Recursive growth for branches
- let totalGrowth = this.age;
- this.branches.forEach(branch => {
- branch.age = Math.min(branch.age + this.growthRate * 0.8, 1); // Slower branch growth
- totalGrowth += branch.age;
- if (branch.branches.length < 2 && Math.random() < 0.004) { // Reduced sub-branch generation
- branch.branches.push({
- angle: branch.angle + (Math.random() - 0.5) * Math.PI / 4,
- length: branch.length * 0.7,
- thickness: branch.thickness * 0.6,
- branches: [],
- age: 0
- });
- }
- branch.branches.forEach(subbranch => {
- subbranch.age = Math.min(subbranch.age + this.growthRate * 0.4, 1); // Even slower sub-branch growth
- totalGrowth += subbranch.age;
- });
- });
- return totalGrowth;
- }
- prune() {
- const now = Date.now();
- if (now - this.lastPruneTime < 1000) return false; // Prevent rapid pruning
- if (this.branches.length > 0) {
- this.branches.pop();
- this.pruned = true;
- this.lastPruneTime = now;
- setTimeout(() => this.pruned = false, 1500);
- return true;
- }
- return false;
- }
- harvest() {
- if (!this.harvestable) return 0;
- let harvestYield = Math.floor(this.age * 8 + this.branches.length * 4); // Reduced yield
- this.branches.forEach(branch => {
- harvestYield += Math.floor(branch.age * 2);
- branch.branches.forEach(subbranch => {
- harvestYield += Math.floor(subbranch.age * 1);
- });
- });
- return harvestYield;
- }
- draw(ctx) {
- ctx.save();
- ctx.translate(this.x, this.y);
- // Draw main stem
- ctx.strokeStyle = this.color;
- ctx.lineWidth = this.thickness * this.age;
- ctx.lineCap = 'round';
- ctx.beginPath();
- ctx.moveTo(0, 0);
- const endX = Math.cos(this.angle) * this.length * this.age;
- const endY = Math.sin(this.angle) * this.length * this.age;
- ctx.lineTo(endX, endY);
- ctx.stroke();
- // Draw branches recursively
- this.drawBranches(ctx, endX, endY, this.branches, 1);
- // Draw flowers/fruits if harvestable
- if (this.harvestable) {
- this.branches.forEach((branch, i) => {
- if (branch.age > 0.8) {
- const bx = endX + Math.cos(branch.angle) * branch.length * branch.age;
- const by = endY + Math.sin(branch.angle) * branch.length * branch.age;
- ctx.fillStyle = `hsl(${30 + i * 30}, 80%, 60%)`;
- ctx.beginPath();
- ctx.arc(bx, by, 5 + Math.sin(Date.now() * 0.001 + i) * 2, 0, Math.PI * 2);
- ctx.fill();
- }
- });
- }
- // Draw highlight if plant is selected
- if (this.pruned) {
- ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
- ctx.beginPath();
- ctx.arc(0, 0, 25, 0, Math.PI * 2);
- ctx.fill();
- }
- ctx.restore();
- }
- drawBranches(ctx, x, y, branches, depth) {
- branches.forEach(branch => {
- const endX = x + Math.cos(branch.angle) * branch.length * branch.age;
- const endY = y + Math.sin(branch.angle) * branch.length * branch.age;
- ctx.strokeStyle = this.color;
- ctx.lineWidth = branch.thickness * branch.age;
- ctx.beginPath();
- ctx.moveTo(x, y);
- ctx.lineTo(endX, endY);
- ctx.stroke();
- if (branch.branches.length > 0 && depth < 3) {
- this.drawBranches(ctx, endX, endY, branch.branches, depth + 1);
- }
- });
- }
- }
- class FractalFarmGame {
- constructor() {
- this.canvas = document.getElementById('gameCanvas');
- this.ctx = this.canvas.getContext('2d');
- this.plants = [];
- this.seeds = 5;
- this.harvest = 0;
- this.mode = 'plant';
- this.stability = 100;
- this.totalGrowth = 0;
- this.maxGrowth = 150; // Increased max growth threshold
- this.gameOver = false;
- this.lastUpdateTime = 0;
- this.updateInterval = 1000 / 30; // 30 FPS
- this.init();
- }
- init() {
- this.canvas.addEventListener('click', this.handleClick.bind(this));
- this.canvas.addEventListener('mousemove', this.handleMouseMove.bind(this));
- this.gameLoop();
- }
- handleClick(e) {
- if (this.gameOver) return;
- const rect = this.canvas.getBoundingClientRect();
- const x = e.clientX - rect.left;
- const y = e.clientY - rect.top;
- switch(this.mode) {
- case 'plant':
- this.plantSeed(x, y);
- break;
- case 'prune':
- this.prunePlant(x, y);
- break;
- case 'harvest':
- this.harvestPlant(x, y);
- break;
- }
- this.createParticles(x, y);
- }
- handleMouseMove(e) {
- const rect = this.canvas.getBoundingClientRect();
- const x = e.clientX - rect.left;
- const y = e.clientY - rect.top;
- const tooltip = document.getElementById('tooltip');
- const plant = this.getPlantAt(x, y);
- if (plant) {
- tooltip.style.display = 'block';
- tooltip.style.left = e.clientX + 10 + 'px';
- tooltip.style.top = e.clientY - 30 + 'px';
- if (this.mode === 'harvest' && plant.harvestable) {
- tooltip.textContent = `Ready to harvest! Yield: ~${Math.floor(plant.age * 8 + plant.branches.length * 4)}`;
- } else if (this.mode === 'harvest' && !plant.harvestable) {
- tooltip.textContent = `Not ready yet. Growth: ${Math.floor(plant.age * 100)}%`;
- } else if (this.mode === 'prune') {
- tooltip.textContent = `Branches: ${plant.branches.length}/${plant.maxDepth * 2}`;
- } else {
- tooltip.textContent = `Growth: ${Math.floor(plant.age * 100)}%`;
- }
- } else {
- tooltip.style.display = 'none';
- }
- }
- plantSeed(x, y) {
- if (this.seeds <= 0) {
- this.showTemporaryTooltip("No seeds left! Harvest plants to get more.");
- return;
- }
- // Check if position is valid (not too close to other plants)
- const tooClose = this.plants.some(plant => {
- const dist = Math.hypot(plant.x - x, plant.y - y);
- return dist < 50;
- });
- if (!tooClose) {
- this.plants.push(new FractalPlant(x, y));
- this.seeds--;
- this.updateUI();
- // Show growth indicator
- this.showGrowthIndicator(x, y);
- } else {
- this.showTemporaryTooltip("Too close to another plant!");
- }
- }
- showTemporaryTooltip(message) {
- const tooltip = document.getElementById('tooltip');
- tooltip.textContent = message;
- tooltip.style.display = 'block';
- tooltip.style.left = '50%';
- tooltip.style.top = '50%';
- tooltip.style.transform = 'translate(-50%, -50%)';
- setTimeout(() => {
- tooltip.style.display = 'none';
- tooltip.style.transform = '';
- }, 2000);
- }
- showGrowthIndicator(x, y) {
- const indicator = document.createElement('div');
- indicator.className = 'growth-indicator';
- indicator.style.left = x + this.canvas.offsetLeft + 'px';
- indicator.style.top = y + this.canvas.offsetTop + 'px';
- document.body.appendChild(indicator);
- setTimeout(() => indicator.remove(), 1000);
- }
- prunePlant(x, y) {
- const plant = this.getPlantAt(x, y);
- if (plant && plant.prune()) {
- this.stability = Math.min(100, this.stability + 8); // Increased stability gain from pruning
- this.updateUI();
- this.createParticles(x, y, '#ff9800');
- } else if (plant) {
- this.showTemporaryTooltip("No branches to prune!");
- }
- }
- harvestPlant(x, y) {
- const plant = this.getPlantAt(x, y);
- if (plant && plant.harvestable) {
- const harvestYield = plant.harvest();
- this.harvest += harvestYield;
- this.seeds += Math.floor(harvestYield / 8); // Adjusted seed yield
- // Remove plant after harvest
- const index = this.plants.indexOf(plant);
- this.plants.splice(index, 1);
- this.updateUI();
- this.createParticles(x, y, '#4caf50');
- } else if (plant) {
- this.showTemporaryTooltip("Not ready for harvest yet!");
- }
- }
- getPlantAt(x, y) {
- return this.plants.find(plant => {
- const dist = Math.hypot(plant.x - x, plant.y - y);
- return dist < 30;
- });
- }
- createParticles(x, y, color = '#ffeb3b') {
- for (let i = 0; i < 8; i++) {
- const particle = document.createElement('div');
- particle.className = 'particle';
- particle.style.left = x + this.canvas.offsetLeft + 'px';
- particle.style.top = y + this.canvas.offsetTop + 'px';
- particle.style.setProperty('--drift', (Math.random() - 0.5) * 100 + 'px');
- particle.style.background = `radial-gradient(circle, ${color} 0%, transparent 70%)`;
- document.body.appendChild(particle);
- setTimeout(() => particle.remove(), 2000);
- }
- }
- setMode(mode) {
- this.mode = mode;
- // Update button styles
- document.getElementById('plantBtn').classList.toggle('selected', mode === 'plant');
- document.getElementById('pruneBtn').classList.toggle('selected', mode === 'prune');
- document.getElementById('harvestBtn').classList.toggle('selected', mode === 'harvest');
- // Update cursor
- if (mode === 'plant') {
- this.canvas.style.cursor = 'crosshair';
- } else if (mode === 'prune') {
- this.canvas.style.cursor = 'grab';
- } else if (mode === 'harvest') {
- this.canvas.style.cursor = 'pointer';
- }
- }
- update(timestamp) {
- if (this.gameOver) return;
- // Throttle updates to improve performance
- if (!this.lastUpdateTime || timestamp - this.lastUpdateTime > this.updateInterval) {
- this.lastUpdateTime = timestamp;
- this.totalGrowth = 0;
- this.plants.forEach(plant => {
- this.totalGrowth += plant.grow();
- });
- // Calculate stability based on growth
- const growthRatio = this.totalGrowth / this.maxGrowth;
- this.stability = Math.max(0, 100 - growthRatio * 100);
- // Warning system
- const warning = document.getElementById('warning');
- if (this.stability < 30) {
- warning.style.display = 'block';
- } else {
- warning.style.display = 'none';
- }
- // Game over check
- if (this.stability <= 0) {
- this.endGame();
- }
- // Passive seed generation
- if (Math.random() < 0.002 && this.plants.length > 0) {
- this.seeds++;
- this.updateUI();
- }
- this.updateUI();
- }
- }
- render() {
- // Clear canvas
- this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
- // Draw grid
- this.ctx.strokeStyle = 'rgba(139, 115, 85, 0.15)';
- this.ctx.lineWidth = 1;
- for (let i = 0; i < this.canvas.width; i += 50) {
- this.ctx.beginPath();
- this.ctx.moveTo(i, 0);
- this.ctx.lineTo(i, this.canvas.height);
- this.ctx.stroke();
- }
- for (let i = 0; i < this.canvas.height; i += 50) {
- this.ctx.beginPath();
- this.ctx.moveTo(0, i);
- this.ctx.lineTo(this.canvas.width, i);
- this.ctx.stroke();
- }
- // Draw plants
- this.plants.forEach(plant => plant.draw(this.ctx));
- }
- updateUI() {
- document.getElementById('seedCount').textContent = this.seeds;
- document.getElementById('harvestCount').textContent = this.harvest;
- document.getElementById('growthLevel').textContent = Math.floor(this.totalGrowth) + '%';
- document.getElementById('stability').textContent = Math.floor(this.stability) + '%';
- // Color code stability
- const stabilityEl = document.getElementById('stability');
- if (this.stability > 70) {
- stabilityEl.style.color = '#4caf50';
- } else if (this.stability > 30) {
- stabilityEl.style.color = '#ff9800';
- } else {
- stabilityEl.style.color = '#f44336';
- }
- }
- endGame() {
- this.gameOver = true;
- document.getElementById('finalScore').textContent = this.harvest;
- document.getElementById('gameOver').style.display = 'block';
- }
- reset() {
- this.plants = [];
- this.seeds = 5;
- this.harvest = 0;
- this.stability = 100;
- this.totalGrowth = 0;
- this.gameOver = false;
- this.setMode('plant');
- document.getElementById('gameOver').style.display = 'none';
- document.getElementById('warning').style.display = 'none';
- this.updateUI();
- }
- gameLoop(timestamp) {
- this.update(timestamp);
- this.render();
- requestAnimationFrame((ts) => this.gameLoop(ts));
- }
- }
- // Initialize game
- let game;
- window.addEventListener('DOMContentLoaded', () => {
- game = new FractalFarmGame();
- // Set up button event listeners
- document.getElementById('plantBtn').addEventListener('click', () => game.setMode('plant'));
- document.getElementById('pruneBtn').addEventListener('click', () => game.setMode('prune'));
- document.getElementById('harvestBtn').addEventListener('click', () => game.setMode('harvest'));
- document.getElementById('resetBtn').addEventListener('click', () => game.reset());
- document.getElementById('gameOverReset').addEventListener('click', () => game.reset());
- });
- </script>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment