sbertaccini e33cf800ae fixes
2024-03-19 19:46:31 +01:00

598 lines
18 KiB
C#

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<GameObject> shells = new List<GameObject>();
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<Electron>().enabled = true;
prevSpinElectrons = spinElectrons;
}
}
}
else if (!spinElectrons && prevSpinElectrons)
{
foreach (GameObject e in FindObjectsOfType(typeof(GameObject)))
{
if (e.name == "Electron")
{
e.GetComponent<Electron>().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<Rigidbody>().useGravity = false;
Renderer renderer = proton.GetComponent<Renderer>();
Material material = new Material(Shader.Find("Universal Render Pipeline/Lit"));
material.color = protonColor;
renderer.material = material;
Nucleon n = proton.AddComponent<Nucleon>();
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<Rigidbody>().useGravity = false;
Renderer renderer = neutron.GetComponent<Renderer>();
Material material = new Material(Shader.Find("Universal Render Pipeline/Lit"));
material.color = neutronColor;
renderer.material = material;
neutron.GetComponent<Renderer>().material.SetColor("_Color", neutronColor);
Nucleon n = neutron.AddComponent<Nucleon>();
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<LineRenderer>();
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<Renderer>();
Material material = new Material(Shader.Find("Universal Render Pipeline/Lit"));
material.color = electronColor;
renderer.material = material;
Destroy(electron.GetComponent<SphereCollider>());
Electron e = electron.AddComponent<Electron>();
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;
}
}