forked from nope5166/AtomCraft-2.28
598 lines
18 KiB
C#
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;
|
|
}
|
|
} |