narejeno
This commit is contained in:
491
src/systems/BreedingUISystem.js
Normal file
491
src/systems/BreedingUISystem.js
Normal file
@@ -0,0 +1,491 @@
|
||||
/**
|
||||
* BREEDING UI SYSTEM
|
||||
* Visual family tree and genetics display for animal breeding
|
||||
*/
|
||||
class BreedingUISystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
this.enabled = true;
|
||||
|
||||
// UI elements
|
||||
this.container = null;
|
||||
this.familyTreeView = null;
|
||||
this.geneticsPanel = null;
|
||||
this.isVisible = false;
|
||||
|
||||
// Selected animal
|
||||
this.selectedAnimal = null;
|
||||
|
||||
// Family tree data
|
||||
this.familyTree = new Map();
|
||||
|
||||
// UI settings
|
||||
this.settings = {
|
||||
nodeWidth: 80,
|
||||
nodeHeight: 60,
|
||||
horizontalSpacing: 100,
|
||||
verticalSpacing: 80,
|
||||
maxGenerations: 5
|
||||
};
|
||||
|
||||
this.init();
|
||||
console.log('✅ Breeding UI System initialized');
|
||||
}
|
||||
|
||||
init() {
|
||||
this.createUI();
|
||||
console.log('🌳 Family tree UI ready');
|
||||
}
|
||||
|
||||
// ========== UI CREATION ==========
|
||||
|
||||
createUI() {
|
||||
// Main container (hidden by default)
|
||||
this.container = this.scene.add.container(0, 0);
|
||||
this.container.setDepth(1000);
|
||||
this.container.setVisible(false);
|
||||
|
||||
// Background overlay
|
||||
const overlay = this.scene.add.rectangle(
|
||||
this.scene.cameras.main.width / 2,
|
||||
this.scene.cameras.main.height / 2,
|
||||
this.scene.cameras.main.width,
|
||||
this.scene.cameras.main.height,
|
||||
0x000000,
|
||||
0.8
|
||||
);
|
||||
overlay.setInteractive();
|
||||
overlay.on('pointerdown', () => this.hide());
|
||||
this.container.add(overlay);
|
||||
|
||||
// Panel background
|
||||
const panelWidth = 800;
|
||||
const panelHeight = 600;
|
||||
const panelX = this.scene.cameras.main.width / 2;
|
||||
const panelY = this.scene.cameras.main.height / 2;
|
||||
|
||||
const panel = this.scene.add.rectangle(
|
||||
panelX, panelY,
|
||||
panelWidth, panelHeight,
|
||||
0x2a2a2a
|
||||
);
|
||||
panel.setStrokeStyle(2, 0x4a4a4a);
|
||||
this.container.add(panel);
|
||||
|
||||
// Title
|
||||
const title = this.scene.add.text(
|
||||
panelX, panelY - panelHeight / 2 + 30,
|
||||
'Family Tree & Genetics',
|
||||
{
|
||||
fontSize: '24px',
|
||||
fontStyle: 'bold',
|
||||
color: '#ffffff'
|
||||
}
|
||||
);
|
||||
title.setOrigin(0.5);
|
||||
this.container.add(title);
|
||||
|
||||
// Close button
|
||||
const closeBtn = this.scene.add.text(
|
||||
panelX + panelWidth / 2 - 30,
|
||||
panelY - panelHeight / 2 + 30,
|
||||
'✕',
|
||||
{
|
||||
fontSize: '32px',
|
||||
color: '#ff4444'
|
||||
}
|
||||
);
|
||||
closeBtn.setOrigin(0.5);
|
||||
closeBtn.setInteractive({ useHandCursor: true });
|
||||
closeBtn.on('pointerdown', () => this.hide());
|
||||
this.container.add(closeBtn);
|
||||
|
||||
// Family tree view area
|
||||
this.familyTreeView = this.scene.add.container(panelX - 300, panelY);
|
||||
this.container.add(this.familyTreeView);
|
||||
|
||||
// Genetics panel
|
||||
this.geneticsPanel = this.scene.add.container(panelX + 200, panelY);
|
||||
this.container.add(this.geneticsPanel);
|
||||
}
|
||||
|
||||
// ========== SHOW/HIDE ==========
|
||||
|
||||
show(animalId) {
|
||||
if (!this.scene.animalBreeding) {
|
||||
console.log('❌ Animal Breeding System not found');
|
||||
return;
|
||||
}
|
||||
|
||||
const animal = this.scene.animalBreeding.animals.get(animalId);
|
||||
if (!animal) {
|
||||
console.log('❌ Animal not found');
|
||||
return;
|
||||
}
|
||||
|
||||
this.selectedAnimal = animal;
|
||||
this.buildFamilyTree(animal);
|
||||
this.displayGeneticsInfo(animal);
|
||||
|
||||
this.container.setVisible(true);
|
||||
this.isVisible = true;
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.container.setVisible(false);
|
||||
this.isVisible = false;
|
||||
this.selectedAnimal = null;
|
||||
}
|
||||
|
||||
// ========== FAMILY TREE ==========
|
||||
|
||||
buildFamilyTree(animal) {
|
||||
// Clear previous tree
|
||||
this.familyTreeView.removeAll(true);
|
||||
|
||||
// Build tree structure
|
||||
const tree = this.generateTreeStructure(animal);
|
||||
|
||||
// Render tree
|
||||
this.renderTree(tree, 0, 0, 0);
|
||||
}
|
||||
|
||||
generateTreeStructure(animal, generation = 0) {
|
||||
if (generation >= this.settings.maxGenerations) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const node = {
|
||||
animal,
|
||||
generation,
|
||||
parents: []
|
||||
};
|
||||
|
||||
// Get parents (if stored)
|
||||
if (animal.parents) {
|
||||
node.parents = animal.parents.map(parentId => {
|
||||
const parent = this.scene.animalBreeding.animals.get(parentId);
|
||||
return parent ? this.generateTreeStructure(parent, generation + 1) : null;
|
||||
}).filter(p => p !== null);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
renderTree(node, x, y, generation) {
|
||||
if (!node) return;
|
||||
|
||||
const settings = this.settings;
|
||||
|
||||
// Draw node
|
||||
this.drawAnimalNode(node.animal, x, y);
|
||||
|
||||
// Draw parents
|
||||
if (node.parents.length > 0) {
|
||||
const parentY = y - settings.verticalSpacing;
|
||||
const parentSpacing = settings.horizontalSpacing;
|
||||
|
||||
node.parents.forEach((parent, index) => {
|
||||
const parentX = x + (index - 0.5) * parentSpacing;
|
||||
|
||||
// Draw connection line
|
||||
const line = this.scene.add.line(
|
||||
0, 0,
|
||||
x, y - settings.nodeHeight / 2,
|
||||
parentX, parentY + settings.nodeHeight / 2,
|
||||
0x888888
|
||||
);
|
||||
line.setLineWidth(2);
|
||||
this.familyTreeView.add(line);
|
||||
|
||||
// Render parent node
|
||||
this.renderTree(parent, parentX, parentY, generation + 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
drawAnimalNode(animal, x, y) {
|
||||
const settings = this.settings;
|
||||
|
||||
// Node background
|
||||
const nodeColor = this.getNodeColor(animal);
|
||||
const node = this.scene.add.rectangle(
|
||||
x, y,
|
||||
settings.nodeWidth,
|
||||
settings.nodeHeight,
|
||||
nodeColor
|
||||
);
|
||||
node.setStrokeStyle(2, 0xffffff);
|
||||
this.familyTreeView.add(node);
|
||||
|
||||
// Animal icon/emoji
|
||||
const icon = this.getAnimalIcon(animal.species);
|
||||
const iconText = this.scene.add.text(x, y - 10, icon, {
|
||||
fontSize: '24px'
|
||||
});
|
||||
iconText.setOrigin(0.5);
|
||||
this.familyTreeView.add(iconText);
|
||||
|
||||
// Animal name/gender
|
||||
const genderSymbol = animal.gender === 'male' ? '♂' : '♀';
|
||||
const nameText = this.scene.add.text(
|
||||
x, y + 15,
|
||||
`${genderSymbol} ${animal.species}`,
|
||||
{
|
||||
fontSize: '10px',
|
||||
color: '#ffffff'
|
||||
}
|
||||
);
|
||||
nameText.setOrigin(0.5);
|
||||
this.familyTreeView.add(nameText);
|
||||
|
||||
// Mutation indicator
|
||||
if (animal.genetics.mutation) {
|
||||
const mutationBadge = this.scene.add.text(
|
||||
x + settings.nodeWidth / 2 - 5,
|
||||
y - settings.nodeHeight / 2 + 5,
|
||||
'⭐',
|
||||
{ fontSize: '12px' }
|
||||
);
|
||||
mutationBadge.setOrigin(0.5);
|
||||
this.familyTreeView.add(mutationBadge);
|
||||
}
|
||||
|
||||
// Make interactive
|
||||
node.setInteractive({ useHandCursor: true });
|
||||
node.on('pointerdown', () => {
|
||||
this.selectedAnimal = animal;
|
||||
this.displayGeneticsInfo(animal);
|
||||
});
|
||||
}
|
||||
|
||||
getNodeColor(animal) {
|
||||
// Color based on genetics
|
||||
const colorMap = {
|
||||
brown: 0x8B4513,
|
||||
black: 0x000000,
|
||||
white: 0xFFFFFF,
|
||||
golden: 0xFFD700,
|
||||
rainbow: 0xFF00FF
|
||||
};
|
||||
|
||||
return colorMap[animal.genetics.color] || 0x888888;
|
||||
}
|
||||
|
||||
getAnimalIcon(species) {
|
||||
const icons = {
|
||||
sheep: '🐑',
|
||||
cow: '🐄',
|
||||
chicken: '🐔',
|
||||
pig: '🐷',
|
||||
horse: '🐴'
|
||||
};
|
||||
|
||||
return icons[species] || '🐾';
|
||||
}
|
||||
|
||||
// ========== GENETICS PANEL ==========
|
||||
|
||||
displayGeneticsInfo(animal) {
|
||||
// Clear previous info
|
||||
this.geneticsPanel.removeAll(true);
|
||||
|
||||
let yOffset = -200;
|
||||
|
||||
// Title
|
||||
const title = this.scene.add.text(0, yOffset, 'Genetics Info', {
|
||||
fontSize: '18px',
|
||||
fontStyle: 'bold',
|
||||
color: '#ffffff'
|
||||
});
|
||||
title.setOrigin(0.5);
|
||||
this.geneticsPanel.add(title);
|
||||
yOffset += 40;
|
||||
|
||||
// Animal info
|
||||
const info = [
|
||||
`Species: ${animal.species}`,
|
||||
`Gender: ${animal.gender}`,
|
||||
`Age: ${Math.floor(animal.age)} days`,
|
||||
`Stage: ${animal.stage}`,
|
||||
'',
|
||||
'--- Genetics ---',
|
||||
`Color: ${animal.genetics.color}`,
|
||||
`Size: ${animal.genetics.size}`,
|
||||
`Speed: ${animal.genetics.speed}`,
|
||||
`Production: ${animal.genetics.production}`
|
||||
];
|
||||
|
||||
// Mutation info
|
||||
if (animal.genetics.mutation) {
|
||||
info.push('', '--- Mutation ---');
|
||||
info.push(`Type: ${animal.genetics.mutation}`);
|
||||
info.push('⭐ RARE MUTATION!');
|
||||
}
|
||||
|
||||
// Breeding info
|
||||
if (animal.pregnant) {
|
||||
info.push('', '--- Breeding ---');
|
||||
info.push(`Pregnant: ${Math.floor(animal.gestationProgress * 100)}%`);
|
||||
}
|
||||
|
||||
// Display all info
|
||||
info.forEach(line => {
|
||||
const text = this.scene.add.text(0, yOffset, line, {
|
||||
fontSize: '14px',
|
||||
color: line.includes('---') ? '#ffff00' : '#ffffff'
|
||||
});
|
||||
text.setOrigin(0.5);
|
||||
this.geneticsPanel.add(text);
|
||||
yOffset += 20;
|
||||
});
|
||||
|
||||
// DNA Helix Animation
|
||||
if (animal.genetics.mutation) {
|
||||
this.addDNAHelixAnimation(0, yOffset + 50);
|
||||
}
|
||||
}
|
||||
|
||||
addDNAHelixAnimation(x, y) {
|
||||
// Create mini DNA helix
|
||||
const helix = this.scene.add.container(x, y);
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const yPos = i * 5 - 25;
|
||||
const angle = (i / 10) * Math.PI * 2;
|
||||
|
||||
const x1 = Math.cos(angle) * 10;
|
||||
const x2 = Math.cos(angle + Math.PI) * 10;
|
||||
|
||||
const dot1 = this.scene.add.circle(x1, yPos, 2, 0x00ff00);
|
||||
const dot2 = this.scene.add.circle(x2, yPos, 2, 0x00ffff);
|
||||
|
||||
helix.add(dot1);
|
||||
helix.add(dot2);
|
||||
}
|
||||
|
||||
// Rotate animation
|
||||
this.scene.tweens.add({
|
||||
targets: helix,
|
||||
rotation: Math.PI * 2,
|
||||
duration: 3000,
|
||||
repeat: -1,
|
||||
ease: 'Linear'
|
||||
});
|
||||
|
||||
this.geneticsPanel.add(helix);
|
||||
}
|
||||
|
||||
// ========== BREEDING PREDICTION ==========
|
||||
|
||||
showBreedingPrediction(animal1, animal2) {
|
||||
if (!animal1 || !animal2) return;
|
||||
|
||||
// Predict offspring genetics
|
||||
const prediction = this.predictOffspring(animal1, animal2);
|
||||
|
||||
// Show in UI
|
||||
this.displayPrediction(prediction);
|
||||
}
|
||||
|
||||
predictOffspring(parent1, parent2) {
|
||||
// Simulate genetics inheritance
|
||||
const prediction = {
|
||||
possibleColors: this.predictColor(parent1, parent2),
|
||||
possibleSizes: this.predictTrait(parent1.genetics.size, parent2.genetics.size),
|
||||
possibleSpeeds: this.predictTrait(parent1.genetics.speed, parent2.genetics.speed),
|
||||
mutationChance: 0.05 // 5%
|
||||
};
|
||||
|
||||
return prediction;
|
||||
}
|
||||
|
||||
predictColor(p1, p2) {
|
||||
const colors = [p1.genetics.color, p2.genetics.color];
|
||||
|
||||
// Add dominant/recessive logic
|
||||
const dominant = ['brown', 'black'];
|
||||
const recessive = ['white', 'golden'];
|
||||
|
||||
if (dominant.includes(p1.genetics.color)) {
|
||||
return [p1.genetics.color];
|
||||
}
|
||||
if (dominant.includes(p2.genetics.color)) {
|
||||
return [p2.genetics.color];
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
predictTrait(trait1, trait2) {
|
||||
return [trait1, trait2];
|
||||
}
|
||||
|
||||
displayPrediction(prediction) {
|
||||
// Clear genetics panel
|
||||
this.geneticsPanel.removeAll(true);
|
||||
|
||||
let yOffset = -200;
|
||||
|
||||
const title = this.scene.add.text(0, yOffset, 'Breeding Prediction', {
|
||||
fontSize: '18px',
|
||||
fontStyle: 'bold',
|
||||
color: '#ffff00'
|
||||
});
|
||||
title.setOrigin(0.5);
|
||||
this.geneticsPanel.add(title);
|
||||
yOffset += 40;
|
||||
|
||||
// Display predictions
|
||||
const info = [
|
||||
'Possible Offspring:',
|
||||
'',
|
||||
`Colors: ${prediction.possibleColors.join(', ')}`,
|
||||
`Sizes: ${prediction.possibleSizes.join(', ')}`,
|
||||
`Speeds: ${prediction.possibleSpeeds.join(', ')}`,
|
||||
'',
|
||||
`Mutation Chance: ${prediction.mutationChance * 100}%`
|
||||
];
|
||||
|
||||
info.forEach(line => {
|
||||
const text = this.scene.add.text(0, yOffset, line, {
|
||||
fontSize: '14px',
|
||||
color: '#ffffff'
|
||||
});
|
||||
text.setOrigin(0.5);
|
||||
this.geneticsPanel.add(text);
|
||||
yOffset += 20;
|
||||
});
|
||||
}
|
||||
|
||||
// ========== KEYBOARD SHORTCUT ==========
|
||||
|
||||
setupKeyboard() {
|
||||
// Press 'F' to open family tree for selected animal
|
||||
this.scene.input.keyboard.on('keydown-F', () => {
|
||||
if (this.selectedAnimal) {
|
||||
if (this.isVisible) {
|
||||
this.hide();
|
||||
} else {
|
||||
this.show(this.selectedAnimal.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ========== UPDATE ==========
|
||||
|
||||
update(delta) {
|
||||
// Update animations if visible
|
||||
if (this.isVisible) {
|
||||
// Any dynamic updates here
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.container) {
|
||||
this.container.destroy();
|
||||
}
|
||||
console.log('🌳 Breeding UI System destroyed');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user