🎯 Kickstarter Demo Prep - Systems Ready
✅ NEW SYSTEMS: - CropGrowthSeasonSystem.js (8 growth stages + 4 seasons) - Asset generation manifest (113 sprites defined) 📋 ALREADY IMPLEMENTED: - Bug Catching System (50+ bugs, 3 net tiers) ✅ - Tool System (6 tiers, durability, repair) ✅ - Time/Season System (automatic season changes) ✅ 📝 READY FOR GENERATION: - 24 bug sprites (Common to Legendary) - 63 tool sprites (10 types × 6 tiers + enchanted) - 6 Ivan NPC sprites - 8 Blacksmith building sprites - 6 Repair Bench & UI sprites - 3 missing crop sprites (pumpkin winter) - 3 item icons (wood, stone, bread) ⏰ Awaiting API quota reset: 01:19 CET 🎯 Next: Generate all 113 assets → Integration → Build complete
This commit is contained in:
342
src/systems/CropGrowthSeasonSystem.js
Normal file
342
src/systems/CropGrowthSeasonSystem.js
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* CROP GROWTH & SEASON SYSTEM
|
||||
* Manages dynamic crop growth through 8 stages + 4 seasonal variations
|
||||
* Integrates with Faza 1 crop sprites (corn, tomatoes, carrots, potatoes, lettuce, pumpkin)
|
||||
*/
|
||||
|
||||
class CropGrowthSeasonSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
|
||||
// Growth system constants
|
||||
this.GROWTH_STAGES = 8;
|
||||
this.SEASONS = ['spring', 'summer', 'fall', 'winter'];
|
||||
|
||||
// Active crops in world
|
||||
this.crops = new Map(); // cropId -> {type, stage, season, sprite, growthTimer}
|
||||
|
||||
// Growth rates (minutes per stage in real time)
|
||||
this.growthRates = {
|
||||
corn: 5,
|
||||
tomatoes: 4,
|
||||
carrots: 3,
|
||||
potatoes: 4,
|
||||
lettuce: 2,
|
||||
pumpkin: 6
|
||||
};
|
||||
|
||||
// Seasonal color tints (applied to environment, NOT crops)
|
||||
this.seasonalTints = {
|
||||
spring: 0x8BC34A, // Fresh green
|
||||
summer: 0xFFC107, // Bright yellow-gold
|
||||
fall: 0xFF9800, // Orange-amber
|
||||
winter: 0x2196F3 // Cool blue
|
||||
};
|
||||
|
||||
// Current season (synced with TimeSystem)
|
||||
this.currentSeason = 'spring';
|
||||
|
||||
// Environment layer (sky/ambient tint)
|
||||
this.environmentTint = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize system
|
||||
*/
|
||||
init() {
|
||||
// Create environment tint overlay
|
||||
this.createEnvironmentTint();
|
||||
|
||||
// Subscribe to season changes from TimeSystem
|
||||
if (this.scene.time_system) {
|
||||
this.scene.events.on('seasonChanged', this.onSeasonChange, this);
|
||||
}
|
||||
|
||||
console.log('🌱 CropGrowthSeasonSystem initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create environment tint overlay for seasonal color shifts
|
||||
*/
|
||||
createEnvironmentTint() {
|
||||
// Create semi-transparent overlay
|
||||
const width = this.scene.cameras.main.width;
|
||||
const height = this.scene.cameras.main.height;
|
||||
|
||||
this.environmentTint = this.scene.add.rectangle(
|
||||
width / 2,
|
||||
height / 2,
|
||||
width * 2, // Make it larger to cover camera movement
|
||||
height * 2,
|
||||
this.seasonalTints[this.currentSeason],
|
||||
0.15 // 15% opacity
|
||||
);
|
||||
|
||||
this.environmentTint.setScrollFactor(1); // Moves with camera
|
||||
this.environmentTint.setDepth(1000); // Above most objects
|
||||
this.environmentTint.setBlendMode(Phaser.BlendModes.MULTIPLY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle season change
|
||||
*/
|
||||
onSeasonChange(newSeason) {
|
||||
console.log(`🍂 Season changing to: ${newSeason}`);
|
||||
this.currentSeason = newSeason;
|
||||
|
||||
// Animate environment tint transition
|
||||
if (this.environmentTint) {
|
||||
this.scene.tweens.add({
|
||||
targets: this.environmentTint,
|
||||
tint: this.seasonalTints[newSeason],
|
||||
duration: 2000,
|
||||
ease: 'Sine.easeInOut'
|
||||
});
|
||||
}
|
||||
|
||||
// Update all existing crops to new season sprites
|
||||
this.updateAllCropsForSeason(newSeason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plant a crop
|
||||
*/
|
||||
plantCrop(x, y, cropType) {
|
||||
const cropId = `crop_${Date.now()}_${Math.random()}`;
|
||||
|
||||
// Load sprite for current season, stage 1
|
||||
const spritePath = this.getCropSpritePath(cropType, this.currentSeason, 1);
|
||||
|
||||
// Create sprite
|
||||
const sprite = this.scene.add.sprite(x, y, spritePath);
|
||||
sprite.setDepth(2); // Above ground
|
||||
|
||||
// Store crop data
|
||||
this.crops.set(cropId, {
|
||||
id: cropId,
|
||||
type: cropType,
|
||||
stage: 1,
|
||||
season: this.currentSeason,
|
||||
sprite: sprite,
|
||||
growthTimer: 0,
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
|
||||
console.log(`🌱 Planted ${cropType} at ${x},${y}`);
|
||||
|
||||
return cropId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get crop sprite path based on type, season, and stage
|
||||
*/
|
||||
getCropSpritePath(cropType, season, stage) {
|
||||
// Path: assets/crops/faza1/{type}/{season}/stage{N}.png
|
||||
return `crops/faza1/${this.normalizeCropName(cropType)}/${season}/stage${stage}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize crop names to match folder structure
|
||||
*/
|
||||
normalizeCropName(cropType) {
|
||||
const nameMap = {
|
||||
'tomatoes': 'tomatoes',
|
||||
'tomato': 'tomatoes',
|
||||
'carrots': 'carrots',
|
||||
'carrot': 'carrots',
|
||||
'potatoes': 'potatos', // Note: folder is 'potatos' not 'potatoes'
|
||||
'potato': 'potatos',
|
||||
'lettuce': 'lettuces',
|
||||
'pumpkin': 'pumpkins',
|
||||
'corn': 'corn'
|
||||
};
|
||||
|
||||
return nameMap[cropType.toLowerCase()] || cropType.toLowerCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update crop growth (called every frame or fixed interval)
|
||||
*/
|
||||
update(deltaTime) {
|
||||
for (const [cropId, crop] of this.crops.entries()) {
|
||||
// Don't grow if already at max stage or dead
|
||||
if (crop.stage >= this.GROWTH_STAGES) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Increment growth timer
|
||||
crop.growthTimer += deltaTime / 1000; // Convert to seconds
|
||||
|
||||
// Check if it's time to advance stage
|
||||
const growthRate = this.growthRates[crop.type] || 5;
|
||||
const secondsPerStage = growthRate * 60; // Convert to seconds
|
||||
|
||||
if (crop.growthTimer >= secondsPerStage) {
|
||||
this.advanceCropStage(cropId);
|
||||
crop.growthTimer = 0; // Reset timer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Advance crop to next growth stage
|
||||
*/
|
||||
advanceCropStage(cropId) {
|
||||
const crop = this.crops.get(cropId);
|
||||
if (!crop) return;
|
||||
|
||||
// Advance stage
|
||||
crop.stage = Math.min(crop.stage + 1, this.GROWTH_STAGES);
|
||||
|
||||
// Update sprite
|
||||
const newSpritePath = this.getCropSpritePath(crop.type, crop.season, crop.stage);
|
||||
crop.sprite.setTexture(newSpritePath);
|
||||
|
||||
console.log(`🌾 ${crop.type} advanced to stage ${crop.stage}`);
|
||||
|
||||
// Special events
|
||||
if (crop.stage === 6) {
|
||||
// HARVEST READY
|
||||
this.scene.events.emit('cropReady', { cropId, crop });
|
||||
|
||||
// Add visual indicator (glow effect)
|
||||
this.addHarvestGlow(crop.sprite);
|
||||
}
|
||||
|
||||
if (crop.stage === 7) {
|
||||
console.warn(`⚠️ ${crop.type} is overripe! Harvest soon or it will die.`);
|
||||
}
|
||||
|
||||
if (crop.stage === 8) {
|
||||
console.log(`💀 ${crop.type} has died.`);
|
||||
// Crop is now dead (stage 8)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add glow effect to harvest-ready crops
|
||||
*/
|
||||
addHarvestGlow(sprite) {
|
||||
// Pulsing glow animation
|
||||
this.scene.tweens.add({
|
||||
targets: sprite,
|
||||
alpha: 0.7,
|
||||
duration: 800,
|
||||
yoyo: true,
|
||||
repeat: -1,
|
||||
ease: 'Sine.easeInOut'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Harvest a crop
|
||||
*/
|
||||
harvestCrop(cropId) {
|
||||
const crop = this.crops.get(cropId);
|
||||
if (!crop) return null;
|
||||
|
||||
// Can only harvest at stage 6 (perfect) or 5-7 (acceptable)
|
||||
if (crop.stage < 5 || crop.stage === 8) {
|
||||
console.warn(`Cannot harvest ${crop.type} at stage ${crop.stage}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Calculate yield based on stage
|
||||
let yield_quality = 1.0;
|
||||
if (crop.stage === 6) {
|
||||
yield_quality = 1.5; // Perfect harvest bonus
|
||||
} else if (crop.stage === 7) {
|
||||
yield_quality = 0.7; // Overripe penalty
|
||||
}
|
||||
|
||||
// Remove crop
|
||||
crop.sprite.destroy();
|
||||
this.crops.delete(cropId);
|
||||
|
||||
console.log(`✅ Harvested ${crop.type} with ${yield_quality}x quality`);
|
||||
|
||||
return {
|
||||
type: crop.type,
|
||||
quality: yield_quality,
|
||||
stage: crop.stage
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all crops when season changes
|
||||
*/
|
||||
updateAllCropsForSeason(newSeason) {
|
||||
for (const [cropId, crop] of this.crops.entries()) {
|
||||
crop.season = newSeason;
|
||||
|
||||
// Update sprite to new season
|
||||
const newSpritePath = this.getCropSpritePath(crop.type, newSeason, crop.stage);
|
||||
crop.sprite.setTexture(newSpritePath);
|
||||
}
|
||||
|
||||
console.log(`🍂 Updated ${this.crops.size} crops for ${newSeason}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get crop info
|
||||
*/
|
||||
getCropInfo(cropId) {
|
||||
return this.crops.get(cropId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save system state
|
||||
*/
|
||||
save() {
|
||||
const cropsData = [];
|
||||
|
||||
for (const [cropId, crop] of this.crops.entries()) {
|
||||
cropsData.push({
|
||||
id: cropId,
|
||||
type: crop.type,
|
||||
stage: crop.stage,
|
||||
season: crop.season,
|
||||
growthTimer: crop.growthTimer,
|
||||
x: crop.x,
|
||||
y: crop.y
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
currentSeason: this.currentSeason,
|
||||
crops: cropsData
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Load system state
|
||||
*/
|
||||
load(data) {
|
||||
if (data.currentSeason) {
|
||||
this.currentSeason = data.currentSeason;
|
||||
this.onSeasonChange(this.currentSeason);
|
||||
}
|
||||
|
||||
if (data.crops) {
|
||||
// Recreate crops
|
||||
for (const cropData of data.crops) {
|
||||
const spritePath = this.getCropSpritePath(cropData.type, cropData.season, cropData.stage);
|
||||
const sprite = this.scene.add.sprite(cropData.x, cropData.y, spritePath);
|
||||
sprite.setDepth(2);
|
||||
|
||||
this.crops.set(cropData.id, {
|
||||
...cropData,
|
||||
sprite: sprite
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`📂 Loaded ${this.crops.size} crops`);
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use in GameScene
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = CropGrowthSeasonSystem;
|
||||
}
|
||||
Reference in New Issue
Block a user