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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user