492 lines
14 KiB
JavaScript
492 lines
14 KiB
JavaScript
/**
|
|
* 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');
|
|
}
|
|
}
|