Session 3: Tree Variety System Complete

TREE VARIETIES IMPLEMENTED:
- Added 5 tree types: Cherry, Oak, Pine, Dead, Apple
- AI-generated PNG sprites with transparent backgrounds
- Random tree selection for natural diversity
- Growth scaling (0.4-0.6x for variety)

 VISUAL IMPROVEMENTS:
- 2.5D depth sorting (Y-position based)
- Proper shadows matching tree size
- Layered rendering for perspective

 TRANSPARENCY FIXES:
- Disabled automatic sprite processing
- User manually removed green screen backgrounds
- Fixed pink/red color preservation
- Trees now render with proper transparency

 TREE DISTRIBUTION:
- Reduced from ~78 to 10 trees (87% reduction)
- Removed corner forest clusters (too crowded)
- Sparse scattered placement across 100x100 map
- Wider spacing (8-15 tiles apart)
- Small tree sizes (0.35-0.7x scale, ~50% reduction)

 TECHNICAL CHANGES:
- PreloadScene: Added tree sprite loading
- PreloadScene: Disabled processAllTransparency()
- Flat2DTerrainSystem: PNG sprite rendering with fallback
- map2d_data.js: Sparse tree generation
- Green removal threshold: g > 180 (preserves pink/red)

 FILES MODIFIED:
- src/scenes/PreloadScene.js
- src/systems/Flat2DTerrainSystem.js
- data/map2d_data.js
- assets/sprites/tree_*.png (5 new sprites)
- docs/DNEVNIK.md (updated with user availability)

Session: 1.5h (23:28-00:48)
Date: 14-15.12.2024
This commit is contained in:
2025-12-15 00:49:06 +01:00
parent c5d6c01305
commit 344fbc307d
20 changed files with 272 additions and 85 deletions

View File

@@ -309,69 +309,259 @@ class Flat2DTerrainSystem {
}
if (sprite) {
// 🎨 2.5D DEPTH SORTING - Y position = depth!
// Objects lower on screen appear in front
sprite.setDepth(10 + worldY);
this.decorLayer.add(sprite);
}
}
createTree(x, y) {
// 🌸 PNG DISABLED - procedural is more reliable!
// if (this.scene.textures.exists('cesnjevo_drevo')) {
// const tree = this.scene.add.image(x, y, 'cesnjevo_drevo');
// const growthScale = Phaser.Math.FloatBetween(0.3, 0.7);
// tree.setScale(growthScale);
// tree.setOrigin(0.5, 0.9);
// const shadow = this.scene.add.ellipse(x, y + 10, 20 * growthScale, 6, 0x000000, 0.15);
// shadow.setDepth(tree.depth - 1);
// return tree;
// }
// 🌳 TREE VARIETY SYSTEM!
const treeTypes = ['cherry', 'oak', 'pine', 'dead', 'apple'];
const randomType = Phaser.Utils.Array.GetRandom(treeTypes);
// PROCEDURAL CHERRY BLOSSOM (RELIABLE!)
switch (randomType) {
case 'oak': return this.createOakTree(x, y);
case 'pine': return this.createPineTree(x, y);
case 'dead': return this.createDeadTree(x, y);
case 'apple': return this.createAppleTree(x, y);
default: return this.createCherryTree(x, y);
}
}
createCherryTree(x, y) {
// 🌸 PNG SPRITE!
if (this.scene.textures.exists('tree_cherry')) {
const tree = this.scene.add.image(x, y, 'tree_cherry');
const scale = Phaser.Math.FloatBetween(0.4, 0.6); // SMALLER! (was 0.8-1.2)
tree.setScale(scale);
tree.setOrigin(0.5, 0.85);
// Shadow
const shadow = this.scene.add.ellipse(x, y + 15, 30 * scale, 10, 0x000000, 0.2);
shadow.setDepth(tree.depth - 1);
return tree;
}
// FALLBACK: Procedural
return this.createProceduralCherryTree(x, y);
}
createProceduralCherryTree(x, y) {
// Old procedural code (backup)
const graphics = this.scene.add.graphics();
const growthScale = Phaser.Math.FloatBetween(0.8, 1.4); // BIGGER!
// DROP SHADOW (2D depth!) 🎨
graphics.fillStyle(0x000000, 0.15);
graphics.fillEllipse(x + 1, y + 24, 20, 6);
const heightOffset = -20 * growthScale;
const crownSize = 30 * growthScale; // MUCH BIGGER!
// TRUNK - simple rectangle
graphics.fillStyle(0x8B4513);
graphics.fillRect(x - 4, y + 6, 8, 18);
// Shadow (ellipse on ground)
graphics.fillStyle(0x000000, 0.2);
graphics.fillEllipse(x, y + 30, 40 * growthScale, 12); // Bigger shadow
// Trunk outline
graphics.lineStyle(1, 0x654321);
graphics.strokeRect(x - 4, y + 6, 8, 18);
// Trunk (with shading for volume)
const trunkW = 12 * growthScale; // Thicker
const trunkH = 30 * growthScale; // Taller
// CHERRY BLOSSOM CROWN - FLAT 2D TRIANGLE! 🌸
// Base pink triangle
// Dark side (right)
graphics.fillStyle(0x6D3F1A);
graphics.fillRect(x + trunkW / 4, y + 10 + heightOffset, trunkW / 2, trunkH);
// Light side (left)
graphics.fillStyle(0x8B5A2B);
graphics.fillRect(x - trunkW / 2, y + 10 + heightOffset, trunkW / 2, trunkH);
// CROWN - Layered circles for 2.5D!
const crownY = y - 10 * growthScale + heightOffset; // Higher crown
// Dark base (shadow underneath)
graphics.fillStyle(0xE75480);
graphics.fillCircle(x + 4 * growthScale, crownY + 4 * growthScale, crownSize);
// Main pink crown
graphics.fillStyle(0xFF69B4);
graphics.fillCircle(x, crownY, crownSize);
// Top highlight (light from top-left)
graphics.fillStyle(0xFFB6C1, 0.8);
graphics.fillCircle(x - 6 * growthScale, crownY - 6 * growthScale, crownSize * 0.6);
// Bright specular spot
graphics.fillStyle(0xFFFFFF, 0.5);
graphics.fillCircle(x - 8 * growthScale, crownY - 8 * growthScale, crownSize * 0.3);
return graphics;
}
createOakTree(x, y) {
// 🌲 PNG SPRITE!
if (this.scene.textures.exists('tree_oak')) {
const tree = this.scene.add.image(x, y, 'tree_oak');
const scale = Phaser.Math.FloatBetween(0.45, 0.65); // SMALLER!
tree.setScale(scale);
tree.setOrigin(0.5, 0.85);
const shadow = this.scene.add.ellipse(x, y + 15, 35 * scale, 12, 0x000000, 0.2);
shadow.setDepth(tree.depth - 1);
return tree;
}
// FALLBACK:
const graphics = this.scene.add.graphics();
const growthScale = Phaser.Math.FloatBetween(0.8, 1.4); // BIGGER!
// Shadow
graphics.fillStyle(0x000000, 0.15);
graphics.fillEllipse(x, y + 24, 25 * growthScale, 8);
// Thick trunk
graphics.fillStyle(0x654321);
graphics.fillRect(x - 5 * growthScale, y, 10 * growthScale, 24 * growthScale);
// Large round crown
graphics.fillStyle(0x228B22); // Forest green
graphics.fillCircle(x, y - 10 * growthScale, 18 * growthScale);
// Darker outline
graphics.lineStyle(2, 0x006400);
graphics.strokeCircle(x, y - 10 * growthScale, 18 * growthScale);
// Highlight
graphics.fillStyle(0x32CD32, 0.6);
graphics.fillCircle(x - 5 * growthScale, y - 15 * growthScale, 8 * growthScale);
return graphics;
}
createPineTree(x, y) {
// 🌲 PNG SPRITE!
if (this.scene.textures.exists('tree_pine')) {
const tree = this.scene.add.image(x, y, 'tree_pine');
const scale = Phaser.Math.FloatBetween(0.45, 0.7); // SMALLER!
tree.setScale(scale);
tree.setOrigin(0.5, 0.9); // Taller
const shadow = this.scene.add.ellipse(x, y + 20, 30 * scale, 10, 0x000000, 0.2);
shadow.setDepth(tree.depth - 1);
return tree;
}
// FALLBACK:
const graphics = this.scene.add.graphics();
const growthScale = Phaser.Math.FloatBetween(0.8, 1.5); // BIGGER (Pine taller)
// Shadow
graphics.fillStyle(0x000000, 0.15);
graphics.fillEllipse(x, y + 20, 15 * growthScale, 6);
// Trunk
graphics.fillStyle(0x8B4513);
graphics.fillRect(x - 3 * growthScale, y + 5, 6 * growthScale, 15 * growthScale);
// Stacked triangles (pine shape)
graphics.fillStyle(0x2F4F2F); // Dark green
// Bottom tier
graphics.fillTriangle(
x, y - 18, // Top point
x - 16, y + 8, // Bottom left
x + 16, y + 8 // Bottom right
x, y - 5 * growthScale,
x - 14 * growthScale, y + 10,
x + 14 * growthScale, y + 10
);
// Dark outline (2D cartoon style!)
graphics.lineStyle(2, 0xDB7093, 1.0);
graphics.strokeTriangle(
x, y - 18,
x - 16, y + 8,
x + 16, y + 8
// Middle tier
graphics.fillTriangle(
x, y - 15 * growthScale,
x - 10 * growthScale, y,
x + 10 * growthScale, y
);
// Inner lighter triangle (highlight)
graphics.fillStyle(0xFFB6C1);
// Top tier
graphics.fillTriangle(
x, y - 14,
x - 10, y + 4,
x + 10, y + 4
x, y - 25 * growthScale,
x - 7 * growthScale, y - 10 * growthScale,
x + 7 * growthScale, y - 10 * growthScale
);
// Top highlight (blossom peak!)
graphics.fillStyle(0xFFFFFF, 0.7);
graphics.fillTriangle(
x, y - 14,
x - 6, y - 4,
x + 6, y - 4
);
return graphics;
}
createDeadTree(x, y) {
// 💀 PNG SPRITE!
if (this.scene.textures.exists('tree_dead')) {
const tree = this.scene.add.image(x, y, 'tree_dead');
const scale = Phaser.Math.FloatBetween(0.35, 0.55); // SMALLER!
tree.setScale(scale);
tree.setOrigin(0.5, 0.85);
const shadow = this.scene.add.ellipse(x, y + 18, 28 * scale, 10, 0x000000, 0.3);
shadow.setDepth(tree.depth - 1);
return tree;
}
// FALLBACK:
const graphics = this.scene.add.graphics();
const growthScale = Phaser.Math.FloatBetween(0.7, 1.2); // BIGGER!
// Shadow
graphics.fillStyle(0x000000, 0.2);
graphics.fillEllipse(x, y + 20, 18 * growthScale, 6);
// Dark trunk
graphics.fillStyle(0x3D3D3D);
graphics.fillRect(x - 4 * growthScale, y, 8 * growthScale, 22 * growthScale);
// Branches (bare)
graphics.lineStyle(3 * growthScale, 0x2D2D2D);
graphics.beginPath();
graphics.moveTo(x, y - 5 * growthScale);
graphics.lineTo(x - 10 * growthScale, y - 15 * growthScale);
graphics.moveTo(x, y - 8 * growthScale);
graphics.lineTo(x + 12 * growthScale, y - 12 * growthScale);
graphics.strokePath();
return graphics;
}
createAppleTree(x, y) {
// 🍎 PNG SPRITE!
if (this.scene.textures.exists('tree_apple')) {
const tree = this.scene.add.image(x, y, 'tree_apple');
const scale = Phaser.Math.FloatBetween(0.4, 0.6); // SMALLER!
tree.setScale(scale);
tree.setOrigin(0.5, 0.85);
const shadow = this.scene.add.ellipse(x, y + 16, 32 * scale, 11, 0x000000, 0.2);
shadow.setDepth(tree.depth - 1);
return tree;
}
// FALLBACK:
const graphics = this.scene.add.graphics();
const growthScale = Phaser.Math.FloatBetween(0.8, 1.3); // BIGGER!
// Shadow
graphics.fillStyle(0x000000, 0.15);
graphics.fillEllipse(x, y + 22, 22 * growthScale, 7);
// Trunk
graphics.fillStyle(0x8B4513);
graphics.fillRect(x - 4 * growthScale, y + 2, 8 * growthScale, 20 * growthScale);
// Green crown
graphics.fillStyle(0x3CB371); // Medium sea green
graphics.fillCircle(x, y - 8 * growthScale, 16 * growthScale);
// Apples (red circles)
graphics.fillStyle(0xFF0000);
const applePositions = [
{ x: -8, y: -12 }, { x: 5, y: -10 }, { x: -3, y: -5 },
{ x: 8, y: -8 }, { x: 0, y: -15 }
];
applePositions.forEach(pos => {
graphics.fillCircle(
x + pos.x * growthScale,
y + pos.y * growthScale,
3 * growthScale
);
});
return graphics;
}