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)

  1. 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.
    • 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".

    Ya tienes los "bloques de construcción" visuales para tu átomo.

Fase 2: Estructura del Átomo (GameObjects y Scripts Iniciales)

Vamos a crear una estructura jerárquica para organizar el átomo.

  1. 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ámalo AtomManager.
    • Arrastra el script AtomManager al GameObject "AtomController".
  2. 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.
  3. 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.

  1. 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
    }
  2. 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.

Fase 4: El Script AtomManager (Lógica Principal)

Este script será el cerebro.

  1. 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
    
                //
⚠️ **GitHub.com Fallback** ⚠️