185 lines
5.6 KiB
JavaScript
185 lines
5.6 KiB
JavaScript
const workspace = document.getElementById('workspace');
|
|
const spawnBtns = document.querySelectorAll('.spawn-btn');
|
|
|
|
let elementsOnDesk = [];
|
|
let draggingElement = null;
|
|
let offsetX = 0;
|
|
let offsetY = 0;
|
|
|
|
// Rezepturenbuch (die Formeln müssen genau den Kombinationen der Symbole entsprechen)
|
|
const recipes = [
|
|
{
|
|
ingredients: ['H', 'H', 'O'], // 2x Wasserstoff, 1x Sauerstoff
|
|
result: 'H₂O (Wasser)',
|
|
color: '#3498db'
|
|
},
|
|
{
|
|
ingredients: ['Cl', 'Na'], // 1x Natrium, 1x Chlor
|
|
result: 'NaCl (Kochsalz)',
|
|
color: '#ecf0f1'
|
|
},
|
|
{
|
|
ingredients: ['O', 'O'], // 2x Sauerstoff
|
|
result: 'O₂ (Sauerstoff-Molekül)',
|
|
color: '#bdc3c7'
|
|
},
|
|
{
|
|
ingredients: ['C', 'O', 'O'], // 1x Kohlenstoff, 2x Sauerstoff
|
|
result: 'CO₂ (Kohlendioxid)',
|
|
color: '#7f8c8d'
|
|
},
|
|
{
|
|
ingredients: ['C', 'H', 'H', 'H', 'H'], // 1x Kohlenstoff, 4x Wasserstoff
|
|
result: 'CH₄ (Methan)',
|
|
color: '#f39c12'
|
|
},
|
|
{
|
|
ingredients: ['N', 'H', 'H', 'H'], // 1x Stickstoff, 3x Wasserstoff
|
|
result: 'NH₃ (Ammoniak)',
|
|
color: '#9b59b6'
|
|
}
|
|
];
|
|
|
|
// Button-Klicks registrieren
|
|
spawnBtns.forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
spawnAtom(btn.dataset.element, btn.dataset.color);
|
|
});
|
|
});
|
|
|
|
function spawnAtom(symbol, color) {
|
|
const el = document.createElement('div');
|
|
el.classList.add('atom');
|
|
el.innerText = symbol;
|
|
el.dataset.symbol = symbol;
|
|
el.style.backgroundColor = color;
|
|
|
|
// Zufällige Position auf dem Tisch
|
|
const x = Math.random() * (workspace.clientWidth - 50);
|
|
const y = Math.random() * (workspace.clientHeight - 50);
|
|
|
|
el.style.left = x + 'px';
|
|
el.style.top = y + 'px';
|
|
|
|
makeDraggable(el);
|
|
workspace.appendChild(el);
|
|
elementsOnDesk.push(el);
|
|
}
|
|
|
|
function makeDraggable(el) {
|
|
el.addEventListener('mousedown', (e) => {
|
|
draggingElement = el;
|
|
const rect = el.getBoundingClientRect();
|
|
|
|
offsetX = e.clientX - rect.left;
|
|
offsetY = e.clientY - rect.top;
|
|
el.style.zIndex = 1000;
|
|
});
|
|
}
|
|
|
|
document.addEventListener('mousemove', (e) => {
|
|
if (draggingElement) {
|
|
const workspaceRect = workspace.getBoundingClientRect();
|
|
|
|
let newX = e.clientX - workspaceRect.left - offsetX;
|
|
let newY = e.clientY - workspaceRect.top - offsetY;
|
|
|
|
// Grenzen beachten
|
|
newX = Math.max(0, Math.min(newX, workspaceRect.width - draggingElement.offsetWidth));
|
|
newY = Math.max(0, Math.min(newY, workspaceRect.height - draggingElement.offsetHeight));
|
|
|
|
draggingElement.style.left = newX + 'px';
|
|
draggingElement.style.top = newY + 'px';
|
|
}
|
|
});
|
|
|
|
document.addEventListener('mouseup', () => {
|
|
if (draggingElement) {
|
|
draggingElement.style.zIndex = '';
|
|
checkForReactions();
|
|
draggingElement = null;
|
|
}
|
|
});
|
|
|
|
function checkForReactions() {
|
|
if (!draggingElement) return;
|
|
|
|
const rect1 = draggingElement.getBoundingClientRect();
|
|
|
|
// Finde alle Elemente, die sich berühren (inklusive des gezogenen Elements)
|
|
// Einfache Kollisionserkennung: Wir gruppieren alle Elemente, die nahe beieinander liegen.
|
|
let cluster = [draggingElement];
|
|
let added = true;
|
|
|
|
// Erweitere den Cluster iterativ, bis keine berührenden Elemente mehr gefunden werden
|
|
while(added) {
|
|
added = false;
|
|
for (let el of elementsOnDesk) {
|
|
if (cluster.includes(el)) continue;
|
|
|
|
// Prüfe Kollision mit irgendeinem Element im Cluster
|
|
let touches = cluster.some(cEl => {
|
|
const r1 = cEl.getBoundingClientRect();
|
|
const r2 = el.getBoundingClientRect();
|
|
return !(r1.right < r2.left ||
|
|
r1.left > r2.right ||
|
|
r1.bottom < r2.top ||
|
|
r1.top > r2.bottom);
|
|
});
|
|
|
|
if (touches) {
|
|
cluster.push(el);
|
|
added = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cluster.length > 1) {
|
|
const symbols = cluster.map(el => el.dataset.symbol).sort();
|
|
|
|
// Prüfe gegen alle Rezepte
|
|
for (const recipe of recipes) {
|
|
const recipeSymbols = [...recipe.ingredients].sort();
|
|
|
|
if (JSON.stringify(symbols) === JSON.stringify(recipeSymbols)) {
|
|
// REAKTION!
|
|
const midX = draggingElement.style.left;
|
|
const midY = draggingElement.style.top;
|
|
|
|
// Lösche alte Atome
|
|
cluster.forEach(el => {
|
|
if (workspace.contains(el)) {
|
|
workspace.removeChild(el);
|
|
}
|
|
elementsOnDesk = elementsOnDesk.filter(e => e !== el);
|
|
});
|
|
|
|
// Neues Molekül erstellen
|
|
createMolecule(recipe.result, recipe.color, midX, midY);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function createMolecule(name, color, x, y) {
|
|
const el = document.createElement('div');
|
|
el.classList.add('molecule');
|
|
el.innerText = name;
|
|
el.dataset.symbol = name; // Für diesen Prototyp können Moleküle noch nicht weiterreagieren
|
|
el.style.backgroundColor = color;
|
|
el.style.left = x;
|
|
el.style.top = y;
|
|
|
|
makeDraggable(el);
|
|
workspace.appendChild(el);
|
|
elementsOnDesk.push(el);
|
|
|
|
// Animation
|
|
el.animate([
|
|
{ transform: 'scale(0.5)' },
|
|
{ transform: 'scale(1.2)' },
|
|
{ transform: 'scale(1)' }
|
|
], { duration: 300 });
|
|
}
|