chemie-spiel/app.js

170 lines
5.1 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'
}
];
// 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 });
}