Otros2 - santig005/Distributed-Systems-gRPC GitHub Wiki
¡Absolutamente! ¡Me encanta la idea! Un átomo interactivo en Unity es un proyecto fantástico para aprender y demostrar conceptos de computación gráfica. Y sí, hacerlo componentizable es la clave en Unity para que sea flexible y escalable.
¡Manos a la obra, futuro maestro del átomo digital! Aquí va una guía paso a paso con la estructura base:
Fase 1: Preparación de Assets (Partículas)
-
Creación de las Partículas Base (Prefabs):
-
Proton:
- En Unity, crea un nuevo objeto 3D:
GameObject > 3D Object > Sphere
. - Renómbralo a "Proton".
- Crea un nuevo Material (
Create > Material
en la ventana de Proyecto). Llama al material "ProtonMaterial". - Asígnale un color (ej. rojo brillante) al
Albedo
del "ProtonMaterial". - Arrastra "ProtonMaterial" sobre el objeto "Proton" en la escena.
- Ajusta su
Scale
si es necesario (ej.0.2, 0.2, 0.2
). - Arrastra el objeto "Proton" desde la Jerarquía a tu ventana de Proyecto para crear un Prefab. Elimina el "Proton" de la escena.
- En Unity, crea un nuevo objeto 3D:
-
Neutron:
- Repite el proceso para el "Neutron". Usa un color diferente (ej. azul o gris). Crea "NeutronMaterial". Escala similar. Crea el Prefab "Neutron".
-
Electron:
- Repite el proceso para el "Electron". Usa un color diferente (ej. amarillo o verde). Crea "ElectronMaterial". Hazlo un poco más pequeño que los protones/neutrones (ej.
0.1, 0.1, 0.1
). Crea el Prefab "Electron".
- Repite el proceso para el "Electron". Usa un color diferente (ej. amarillo o verde). Crea "ElectronMaterial". Hazlo un poco más pequeño que los protones/neutrones (ej.
Ya tienes los "bloques de construcción" visuales para tu átomo.
-
Proton:
Fase 2: Estructura del Átomo (GameObjects y Scripts Iniciales)
Vamos a crear una estructura jerárquica para organizar el átomo.
-
El Contenedor Principal del Átomo:
- Crea un Empty GameObject:
GameObject > Create Empty
. - Renómbralo a "AtomController". Este será el objeto principal que gestionará todo el átomo.
- Crea un nuevo script C#:
Create > C# Script
en la ventana de Proyecto. LlámaloAtomManager
. - Arrastra el script
AtomManager
al GameObject "AtomController".
- Crea un Empty GameObject:
-
El Núcleo:
- Dentro de "AtomController", crea otro Empty GameObject.
- Renómbralo a "Nucleus". Este GameObject será el padre de todos los protones y neutrones. Su posición será el centro del átomo.
-
Los Contenedores de Órbitas (para Electrones):
- Dentro de "AtomController" (al mismo nivel que "Nucleus"), crea un Empty GameObject.
- Renómbralo a "ElectronOrbitsContainer". Este contendrá los "caminos" de los electrones.
Tu jerarquía debería verse así:
AtomController (con script AtomManager) ├── Nucleus └── ElectronOrbitsContainer
Fase 3: Definiendo los Datos del Átomo (ScriptableObjects)
Para cambiar fácilmente entre átomos, usaremos ScriptableObjects
. Son contenedores de datos que viven en tu proyecto.
-
Crear el ScriptableObject
AtomData
:- Crea un nuevo C# Script llamado
AtomData
. - Reemplaza su contenido con esto:
using UnityEngine; [CreateAssetMenu(fileName = "NewAtomData", menuName = "Atom/Atom Data", order = 1)] public class AtomData : ScriptableObject { public string atomName = "Hydrogen"; public int protons = 1; public int neutrons = 0; public int electrons = 1; // Podríamos añadir más info aquí luego, como configuración de capas de electrones // public int[] electronShells; // Ejemplo: [2, 8, 1] para Sodio }
- Crea un nuevo C# Script llamado
-
Crear Instancias de
AtomData
:- En la ventana de Proyecto, haz clic derecho:
Create > Atom > Atom Data
. - Crea algunos:
-
HydrogenData
: Protons=1, Neutrons=0, Electrons=1 -
HeliumData
: Protons=2, Neutrons=2, Electrons=2 -
LithiumData
: Protons=3, Neutrons=4, Electrons=3 -
CarbonData
: Protons=6, Neutrons=6, Electrons=6
-
- Rellena los valores de cada uno en el Inspector.
- En la ventana de Proyecto, haz clic derecho:
Fase 4: El Script AtomManager
(Lógica Principal)
Este script será el cerebro.
-
Variables Iniciales en
AtomManager.cs
:using UnityEngine; using System.Collections.Generic; // Necesario para Listas public class AtomManager : MonoBehaviour { [Header("Particle Prefabs")] public GameObject protonPrefab; public GameObject neutronPrefab; public GameObject electronPrefab; [Header("Atom Configuration")] public List<AtomData> atomPresets = new List<AtomData>(); // Para asignar tus ScriptableObjects public int currentAtomIndex = 0; private AtomData currentAtomData; [Header("References")] public Transform nucleusParent; // Asigna el GameObject "Nucleus" aquí public Transform electronOrbitsParent; // Asigna "ElectronOrbitsContainer" [Header("Orbit Settings")] public float baseOrbitSpeed = 10f; public float orbitSpeedMultiplier = 1f; public float orbitRadiusStep = 0.5f; // Cuánto aumenta el radio por cada "capa" public float particleSpacingInNucleus = 0.25f; // Espacio entre protones/neutrones // Guardaremos referencias a los objetos instanciados para poder limpiarlos private List<GameObject> instantiatedProtons = new List<GameObject>(); private List<GameObject> instantiatedNeutrons = new List<GameObject>(); private List<GameObject> instantiatedElectronsAndOrbits = new List<GameObject>(); // Para los electrones y sus pivotes de órbita void Start() { if (atomPresets.Count > 0) { LoadAtom(currentAtomIndex); } else { Debug.LogError("No Atom Presets defined in AtomManager!"); } } void Update() { HandleInput(); UpdateElectronOrbits(); } void HandleInput() { // Cambiar de átomo (ej. flechas izquierda/derecha) if (Input.GetKeyDown(KeyCode.RightArrow)) { currentAtomIndex = (currentAtomIndex + 1) % atomPresets.Count; LoadAtom(currentAtomIndex); } if (Input.GetKeyDown(KeyCode.LeftArrow)) { currentAtomIndex--; if (currentAtomIndex < 0) currentAtomIndex = atomPresets.Count - 1; LoadAtom(currentAtomIndex); } // Controlar velocidad de electrones (ej. teclas + y -) if (Input.GetKeyDown(KeyCode.Plus) || Input.GetKeyDown(KeyCode.KeypadPlus)) { orbitSpeedMultiplier += 0.1f; } if (Input.GetKeyDown(KeyCode.Minus) || Input.GetKeyDown(KeyCode.KeypadMinus)) { orbitSpeedMultiplier = Mathf.Max(0.1f, orbitSpeedMultiplier - 0.1f); // No permitir velocidad negativa o cero } } public void LoadAtom(int atomIndex) { if (atomIndex < 0 || atomIndex >= atomPresets.Count) { Debug.LogError("Invalid atom index: " + atomIndex); return; } currentAtomData = atomPresets[atomIndex]; Debug.Log("Loading Atom: " + currentAtomData.atomName); ClearCurrentAtom(); BuildNucleus(); BuildElectronShells(); } void ClearCurrentAtom() { foreach (GameObject p in instantiatedProtons) Destroy(p); instantiatedProtons.Clear(); foreach (GameObject n in instantiatedNeutrons) Destroy(n); instantiatedNeutrons.Clear(); foreach (GameObject eo in instantiatedElectronsAndOrbits) Destroy(eo); // Esto incluye el pivote y el electrón instantiatedElectronsAndOrbits.Clear(); } void BuildNucleus() { // Estrategia simple: colocarlos aleatoriamente cerca del centro del núcleo // Para una representación más "esférica", se necesitaría un algoritmo de empaquetamiento de esferas. for (int i = 0; i < currentAtomData.protons; i++) { Vector3 position = Random.insideUnitSphere * particleSpacingInNucleus * Mathf.Pow(currentAtomData.protons + currentAtomData.neutrons, 1f/3f); // Escala con el tamaño del núcleo GameObject proton = Instantiate(protonPrefab, nucleusParent); proton.transform.localPosition = position; instantiatedProtons.Add(proton); } for (int i = 0; i < currentAtomData.neutrons; i++) { Vector3 position = Random.insideUnitSphere * particleSpacingInNucleus * Mathf.Pow(currentAtomData.protons + currentAtomData.neutrons, 1f/3f); GameObject neutron = Instantiate(neutronPrefab, nucleusParent); neutron.transform.localPosition = position; instantiatedNeutrons.Add(neutron); } } void BuildElectronShells() { // Distribución simple de electrones. Una real es mucho más compleja (orbitales s, p, d, f). // Aquí, los distribuimos en "capas" concéntricas. int electronsPlaced = 0; int shellNumber = 1; // Empezamos con la primera capa/órbita // Podríamos usar la info de electronShells de AtomData si la implementamos // Por ahora, una distribución simple: hasta 2 en la primera, hasta 8 en la segunda, etc. // O simplemente distribuirlos equitativamente en unas pocas órbitas. // Vamos con una distribución simple para empezar: float currentOrbitRadius = 1.5f; // Radio base de la primera órbita int electronsInThisOrbit = 0; int maxElectronsInShell = 2; // Simplificación: 2 en la primera, luego 8... for (int i = 0; i < currentAtomData.electrons; i++) { // Crea un pivote para la órbita del electrón GameObject orbitPivot = new GameObject("ElectronOrbitPivot_" + i); orbitPivot.transform.SetParent(electronOrbitsParent); orbitPivot.transform.localPosition = Vector3.zero; // Centrado en el AtomController //