using UnityEngine; using System.Collections.Generic; using System.Collections; using System.Diagnostics.PerformanceData; using UnityEngine.UI; using TMPro; public class Atom : MonoBehaviour { public TextMeshProUGUI counterText; private int currentPro = 0; private int currentNeu = 0; private int currentEle = 0; private int targetPro = 0; private int targetNeu = 0; private int targetEle = 0; private string elementName; public string elementSymbol; public int atomicNumber; public float atomicWeight; public int protonCount; public Color protonColor; public int neutronCount; public Color neutronColor; public int[] electronConfiguration; public float electronShellSpacing = 0.5f; public Color electronColor; public bool spinElectrons = true; public bool freezeNucleusMovementAfter5Seconds = true; List shells = new List(); Transform nucleus; private float electronFirstShellSpacing; private Vector3 initialRotation; private Transform latestElectron; public GameObject carbonSign; public GameObject lithiumSign; public GameObject hydrogenSign; public void Start() { carbonSign.SetActive(false); lithiumSign.SetActive(false); hydrogenSign.SetActive(false); // Save desired rotation initialRotation = transform.localEulerAngles; // Set rotation to zero to configure Atom and then put desired rotation transform.localEulerAngles = Vector3.zero; electronFirstShellSpacing = 0.26f; //Assign Nucleus GameObject nucleus = transform.GetChild(0); //Nucleons int pc = protonCount; int nc = neutronCount; float scaleCount = 0.2f; // generateProton(transform.position); // pc -= 1; for (int i = 1; i <= nc + pc; i++) { int nucleonsToCreate = int.Parse((Mathf.Pow(2f, i - 1f) * 5f).ToString()); if (nc + pc >= nucleonsToCreate) { string s = createNucleons(nucleonsToCreate, scaleCount, pc, nc); scaleCount += 0.2f; pc -= int.Parse(s.Split(',')[0]); nc -= int.Parse(s.Split(',')[1]); } else { string s = createNucleons(pc + nc, scaleCount, pc, nc); scaleCount += 0.2f; pc -= int.Parse(s.Split(',')[0]); nc -= int.Parse(s.Split(',')[1]); } } //Electrons GameObject[] shellsGO = generateElectronShells(); for (int loop = 0; loop < electronConfiguration.Length; loop++) { int numPoints = electronConfiguration[loop]; for (int pointNum = 0; pointNum < numPoints; pointNum++) { float i = (float)(pointNum * 1.0) / numPoints; float angle = i * Mathf.PI * 2; float x = transform.localPosition.x + (Mathf.Sin(angle) * (3 * (loop + 1))); float z = transform.localPosition.z + (Mathf.Cos(angle) * (3 * (loop + 1))); Vector3 pos = new Vector3(x, transform.localPosition.y, z); generateElectron(pos, electronFirstShellSpacing + (electronShellSpacing * loop), loop + 1, shellsGO[loop]); atomicNumber += 1; } } SetAtomToInitialRotation(); //CHECK IF AN ATOM IS COMPLETED CheckIfCompleteAtom(); } void CheckIfCompleteAtom() { Debug.Log("Current particels number: currentPro=" + currentPro + " currentNeu=" + currentNeu + " currentEle=" + currentEle); if (elementName == "Carbon" && currentPro == 6 && currentNeu == 6 && currentEle == 6) { Debug.Log("You have built a Carbon atom!"); carbonSign.SetActive(true); } else if (elementName == "Lithium" && currentPro == 3 && currentNeu == 4 && currentEle == 3) { Debug.Log("You have built a Lithium atom!"); lithiumSign.SetActive(true); } else if (elementName == "Hydrogen" && currentPro == 1 && currentNeu == 0 && currentEle == 1) { Debug.Log("You have built a Hydrogen atom!"); hydrogenSign.SetActive(true); } } public void SetElementName(string elementName){ hydrogenSign.SetActive(false); lithiumSign.SetActive(false); carbonSign.SetActive(false); // resetting the atom foreach (GameObject shell in shells) { //destroy the shells and the electrons Destroy(shell); } foreach (Transform child in nucleus.transform) { // Destroy each child (neutron and proton) Destroy(child.gameObject); } electronConfiguration = null; //set the counter back to 0 currentPro = 0; currentNeu = 0; currentEle = 0; this.elementName = elementName; Debug.Log("New atom = " + elementName); if(elementName == "Hydrogen") { targetPro = 1; targetNeu = 0; targetEle = 1; } if (elementName == "Lithium") { targetPro = 3; targetNeu = 4; targetEle = 3; } if (elementName == "Carbon") { targetPro = 6; targetNeu = 6; targetEle = 6; } UpdateCounterText(); } string createNucleons(int nPoints, float scale, int pcount, int ncount) { int npc = 0; int nnc = 0; float fPoints = (float)nPoints; Vector3[] points = new Vector3[nPoints]; float inc = Mathf.PI * (3 - Mathf.Sqrt(5)); float off = 2 / fPoints; for (int k = 0; k < nPoints; k++) { float y = k * off - 1 + (off / 2); float r = Mathf.Sqrt(1 - y * y); float phi = k * inc; points[k] = new Vector3(Mathf.Cos(phi) * r, y, Mathf.Sin(phi) * r); } foreach (Vector3 point in points) { if (pcount > 0 && ncount > 0) { int borc = Random.Range(1, 10); if (borc > 5 && pcount > 0) { GameObject outerSphere = generateProton(transform.position); outerSphere.transform.position += point * scale; npc += 1; pcount -= 1; } else if (borc < 6 && ncount > 0) { GameObject outerSphere = generateNeutron(transform.position); outerSphere.transform.position += point * scale; nnc += 1; ncount -= 1; } } else if (pcount > 0 && ncount == 0) { GameObject outerSphere = generateProton(transform.position); outerSphere.transform.position += point * scale; npc += 1; pcount -= 1; } else if (pcount == 0 && ncount > 0) { GameObject outerSphere = generateNeutron(transform.position); outerSphere.transform.position += point * scale; nnc += 1; ncount -= 1; } } return npc + "," + nnc; } public void AddParticel(string particle) { //return rotation to zero transform.localEulerAngles = Vector3.zero; int nc = 0; int pc = 0; Debug.Log("Adding " + particle); if (particle == "electron") { AddElectron(); } else { if (particle == "proton") pc = 1; else if (particle == "neutron") nc = 1; float scaleCount = 0.2f; for (int i = 1; i <= nc + pc; i++) { int nucleonsToCreate = int.Parse((Mathf.Pow(2f, i - 1f) * 5f).ToString()); if (nc + pc >= nucleonsToCreate) { string s = createNucleons(nucleonsToCreate, scaleCount, pc, nc); scaleCount += 0.2f; pc -= int.Parse(s.Split(',')[0]); nc -= int.Parse(s.Split(',')[1]); } else { string s = createNucleons(pc + nc, scaleCount, pc, nc); scaleCount += 0.2f; pc -= int.Parse(s.Split(',')[0]); nc -= int.Parse(s.Split(',')[1]); } } } SetAtomToInitialRotation(); CheckIfCompleteAtom(); UpdateCounterText(); } private void AddElectron() { foreach (GameObject shell in shells) { Destroy(shell); } shells.Clear(); Debug.Log(electronConfiguration + " "); if (electronConfiguration == null || electronConfiguration.Length == 0) { electronConfiguration = new int[] { 1 }; } else { if (IsShellFull(electronConfiguration.Length, electronConfiguration[electronConfiguration.Length - 1])) { int[] newConfig = new int[electronConfiguration.Length + 1]; for (int i = 0; i < electronConfiguration.Length; i++) { newConfig[i] = electronConfiguration[i]; } newConfig[electronConfiguration.Length] = 1; electronConfiguration = newConfig; Debug.Log("Shell full -- New electron configuration: " + newConfig); } else { electronConfiguration[electronConfiguration.Length - 1]++; } } GameObject[] shellsGO = generateElectronShells(); for (int loop = 0; loop < electronConfiguration.Length; loop++) { int numPoints = electronConfiguration[loop]; for (int pointNum = 0; pointNum < numPoints; pointNum++) { float i = (float)(pointNum * 1.0) / numPoints; float angle = i * Mathf.PI * 2; float x = transform.localPosition.x + (Mathf.Sin(angle) * (3 * (loop + 1))); float z = transform.localPosition.z + (Mathf.Cos(angle) * (3 * (loop + 1))); Vector3 pos = new Vector3(x, transform.localPosition.y, z); generateElectron(pos, electronFirstShellSpacing + (electronShellSpacing * loop), loop + 1, shellsGO[loop]); atomicNumber += 1; } } currentEle++; Debug.Log("Current electrons = " + currentEle); } void SetAtomToInitialRotation() { transform.localEulerAngles = initialRotation; } bool IsShellFull(int shellNumber, int numElectrons) { // Calculate the maximum capacity of the given shell int maxCapacity = 2 * shellNumber * shellNumber; // Compare the number of electrons with the maximum capacity return numElectrons == maxCapacity; } bool prevSpinElectrons = true; public void Update() { // Vector3 currentRotation = transform.eulerAngles; // float clampedYRotation = Mathf.Clamp(currentRotation.y, -90f, 90f); // transform.eulerAngles = new Vector3(0f, clampedYRotation, currentRotation.z); if (spinElectrons && !prevSpinElectrons) { foreach (GameObject e in FindObjectsOfType(typeof(GameObject))) { if (e.name == "Electron") { e.GetComponent().enabled = true; prevSpinElectrons = spinElectrons; } } } else if (!spinElectrons && prevSpinElectrons) { foreach (GameObject e in FindObjectsOfType(typeof(GameObject))) { if (e.name == "Electron") { e.GetComponent().enabled = false; prevSpinElectrons = spinElectrons; } } } // 在这里添加代码以更新原子的protons、neutrons和electrons的数量 // 例如,您可以在碰撞或其他事件中增加或减少这些数量 } public void drawCircle(float radius, LineRenderer lr) { lr.positionCount = 361; lr.useWorldSpace = false; lr.startWidth = lr.endWidth = 0.01f; lr.materials[0] = new Material(Shader.Find("Diffuse")); lr.materials[0].SetColor("_Color", new Color32(128, 223, 255, 0)); float x, y = 0, z, angle = 0; for (int i = 0; i < 361; i++) { x = Mathf.Sin(Mathf.Deg2Rad * angle) * radius; z = Mathf.Cos(Mathf.Deg2Rad * angle) * radius; lr.SetPosition(i, new Vector3(x, y, z)); angle += 1; } } public GameObject generateProton(Vector3 pos) { GameObject proton = GameObject.CreatePrimitive(PrimitiveType.Sphere); proton.name = "Proton"; proton.transform.position = pos; proton.AddComponent().useGravity = false; Renderer renderer = proton.GetComponent(); Material material = new Material(Shader.Find("Universal Render Pipeline/Lit")); material.color = protonColor; renderer.material = material; Nucleon n = proton.AddComponent(); proton.transform.SetParent(nucleus); proton.transform.localScale = new Vector3(0.25f, 0.25f, 0.25f); if(currentPro == 0 && currentNeu == 0) n.firstNucleon = true; currentPro++; return proton; } public GameObject generateNeutron(Vector3 pos) { GameObject neutron = GameObject.CreatePrimitive(PrimitiveType.Sphere); neutron.name = "Neutron"; neutron.transform.position = pos; neutron.AddComponent().useGravity = false; Renderer renderer = neutron.GetComponent(); Material material = new Material(Shader.Find("Universal Render Pipeline/Lit")); material.color = neutronColor; renderer.material = material; neutron.GetComponent().material.SetColor("_Color", neutronColor); Nucleon n = neutron.AddComponent(); if(currentPro == 0 && currentNeu == 0) n.firstNucleon = true; neutron.transform.SetParent(nucleus); neutron.transform.localScale = new Vector3(0.25f, 0.25f, 0.25f); currentNeu++; return neutron; } public GameObject[] generateElectronShells() { for (int loop = 0; loop < electronConfiguration.Length; loop++) { GameObject shell = new GameObject(); shell.name = "Shell " + (loop + 1); shell.transform.parent = transform; shell.transform.localPosition = nucleus.localPosition; shell.transform.localRotation = transform.localRotation; // Vector3 currentRotation = shell.transform.eulerAngles; // shell.transform.eulerAngles = new Vector3(-45f, currentRotation.y, currentRotation.z); LineRenderer lr = shell.AddComponent(); drawCircle(electronFirstShellSpacing + (electronShellSpacing * loop), lr); shells.Add(shell); } return shells.ToArray(); } public void generateElectron(Vector3 pos, float r, int shell, GameObject shellGO) { GameObject electron = GameObject.CreatePrimitive(PrimitiveType.Sphere); // Save the object of the latest instantiated electron latestElectron = electron.transform; electron.name = "Electron"; electron.transform.localScale = new Vector3(0.08f, 0.08f, 0.08f); electron.transform.parent = shellGO.transform; electron.transform.position = pos; Renderer renderer = electron.GetComponent(); Material material = new Material(Shader.Find("Universal Render Pipeline/Lit")); material.color = electronColor; renderer.material = material; Destroy(electron.GetComponent()); Electron e = electron.AddComponent(); e.radius = r; e.centre = transform; e.rotationSpeed = 80 + (10 * shell); } public Vector3 getLatestElectronPosition() { if (latestElectron != null) return latestElectron.position; else return transform.position; } public Vector3 getNucleusPosition() { return transform.position; } public Vector3 getShellPosition() { if (IsShellFull(electronConfiguration.Length, electronConfiguration[electronConfiguration.Length - 1])) { float x = transform.position.x + (Mathf.Sin(0) * (3 * (electronConfiguration.Length + 1))); float z = transform.position.z + (Mathf.Cos(0) * (3 * (electronConfiguration.Length + 1))); Vector3 result = new Vector3(x, transform.position.y, z); float radius = electronFirstShellSpacing + (electronShellSpacing * (electronConfiguration.Length)); return (result - transform.position).normalized * radius + transform.position; } else { float x = transform.position.x + (Mathf.Sin(0) * (3 * (electronConfiguration.Length))); float z = transform.position.z + (Mathf.Cos(0) * (3 * (electronConfiguration.Length))); Vector3 result = new Vector3(x, transform.position.y, z); float radius = electronFirstShellSpacing + (electronShellSpacing * (electronConfiguration.Length)); float radius2 = electronFirstShellSpacing + (electronShellSpacing * (electronConfiguration.Length - 1)); Debug.Log("Radius1 = " + radius + "; Radius2 = " + radius2); return (result - transform.position).normalized * radius + transform.position; } } void UpdateCounterText() { // 将当前的proton、neutron和electron数量显示在UI文本中 counterText.text = elementName + "\nProton: " + currentPro.ToString() + "/" + targetPro + "\nNeutron: " + currentNeu.ToString() + "/" + targetNeu + "\nElectron: " + currentEle.ToString() + "/" + targetEle; } }