神经元代码



您好亲爱的GeekTimes社区!不久前,这里发表了一系列有关创建神经系统模型的文章。理解模型逻辑的最好方法是研究程序代码的实现。我不仅想更详细地传达我的想法,而且还希望向社区寻求帮助。我知道在GT读者中,在编写软件代码和您的经验方面有很多专业人士,知识可以帮助项目的发展。有时,有能力的建议或建议足以使解决此类非典型任务变得优雅而轻松。

内容周期
1. . 1.
2. . 2.
3. . 3.
4. ,
5.
6.
7.

开发环境是Unity3D,这是一种非常流行的游戏引擎。事实证明,这种环境非常方便且易于使用,无论是与编辑器一起使用,还是存在大量俄语参考文献,解释和评论。因此,我精通的编程技巧足以使用Unity3D实现我的想法。

这些计划不会改变开发环境,因为游戏引擎可以轻松解决可视化问题,这在现阶段非常重要。

对于那些由于疏忽,可能忽略语言语法和可能出现错误而转向代码的人,我深表歉意。当我开始这项工作时,计划中没有代码演示。我想检验一些假设。

该代码反映了创造性的搜索。在工作过程中,我面临另一个问题,该模型并不想像我想象的那样运行。白天,我会想到如何解决此问题的想法。在这些时刻,我会受到某种见识的启发。从工作中回来后,我急于进行更正,而忽略了代码中的所有规则,没有时间这样做了。以及这种情况发生的频率,这些见解并没有带来结果,也没有带来预期的结果。因此,该项目的工作继续进行,并感谢我妻子的耐心,这使我得以开展这项工作。在代码标准化的日常工作中,很难在家庭,工作,自己的拖延和懒惰之间找到时间。尽管仍然有一天必须这样做。

在我的工作中,我坚持使用了某种与众不同的神经元模型。像生物神经元一样,神经元模型可以与其他神经元的工作异步地起作用。来自接收器按键的信号(例如来自皮肤接收器的信号)可能不同步。因此,在第一个模型中,在定型思维的影响下,我区分了神经元中状态的某些阶段,该阶段持续了整个系统的一定数量的步骤(循环),并且系统的步骤在所有神经元中同步执行。这不能正常工作,而且非常不舒服。但是有必要以某种方式同步输入和输出信号,并正确评估它们。

在某个时候,一个想法出现了,一个互联网用户后来称其为“排水箱”。事实证明,“排水箱”模型出奇地准确,适用于生物神经元,它非常清楚地说明了求和机制,并且更易于实现。现在,模拟的神经元可以完全独立,就像真实的对象一样。



这个加法器模型是我所知道的最准确的生物神经元模型。要详细模拟胃细胞将需要非常大的处理能力,但是如果需要的话,该细胞所做的只是产生适当的酶或激素。在现代控制论中,将不可思议的计算属性归因于神经元非常普遍。

随后,将来自反射理论的一些机制和传出突触功率设置的方向定向的思想添加到求和模型中。由此产生的模型有可能创建一个理论基础,该理论基础非常简单地解释了神经系统中发生的许多过程和现象。反射机制,记忆和记忆巩固,神经元的自组织和专业化,小脑工作,情绪机制和思维都集中在一瓶中。

我不会无聊的。链接到GitHub存储库

例如,包含神经元素NeironScript.cs操作的主要逻辑的脚本代码(对不起,我的法语):

很多代码
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class NeironScript : MonoBehaviour {

	public GameObject prefabNeiron;          // 
	public GameObject prefabSinaps;          // 

	public int IndexNeiron = 0;              // 

	private int _TypeIndexNeiron = 0;        //  

	public int TypeIndexNeiron               //  
	{
		get { return _TypeIndexNeiron; }
		set {
			if (value == 0) 
				{ _TypeIndexNeiron = value;
				  gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 255, 0, 255);//, 
				}	
			if (value == 1) 
				{ _TypeIndexNeiron = value;
				gameObject.GetComponent<SpriteRenderer>().color = new Color32( 0, 255, 0, 255); //,  //
				}	
			if (value == 2) 
				{ _TypeIndexNeiron = value;
				gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 255, 255, 255);//,  
				}
			if (value == 3) 
				{ _TypeIndexNeiron = value;
				gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 255, 255, 255);//,  
				}
			}
	}
	//   0
	public float Adder = 0.0f; 										//

	public float MaxAdder = 30f;									//  

	public float DampferAdder = 1.0f; 								// 
	public float thresholdTop = 1.0f; 								//  
	public float AnswerTime = 0.1f;      							// 
	public float TimeRepose = 0f;       							//  

	public bool IgnoreInput = false; 								//  
	public List<GameObject> hitSinaps = new List<GameObject>();  	// 

	public GameObject Area; 										//

	private bool _ActionN;											//  
	
	public bool ActionN												//  
	{
		get { return _ActionN; }
		set 
		{
			_ActionN = value;
			if (Area != null)
			{
				gameObject.GetComponent<LineRenderer>().enabled = value; //  ..
                bool existAction = Area.GetComponent<AreaScript>().NeironActionList.Contains(gameObject); //existAction = true -       
				if (_ActionN && (!existAction)) Area.GetComponent<AreaScript>().NeironActionList.Add(gameObject); //    
				else Area.GetComponent<AreaScript>().NeironActionList.Remove(gameObject); //    
			}
		}
	}

	//   1 

	public float thresholdDown = -5.0f;			 		//  
	public float timeIgnore = 5.0f;   					//        
	public float bonusThreshold = 0f; 					//   
	public float DempferBonusThreshold = 1.0f; 			//   
	public float TimeEvaluation = 5.0f;					// 
	public int LimitRecurrence = 5; 					// 
	public float thresholdTopUp = 1.0f;					//   

	public bool TimeEvaluationBool = false;				// 
	public int LimitEvaluationInt = 0;					//     

	public float AdaptationTime = 0;                    // 
	public float thresholdAdapt = 1f;                   //  

	//   2

	public float MaxForceSinaps = 100f;
	private Vector3 VectorPattern; 						// 
	public Vector3 VectorTrend; 						// 

	public float Charge = 0.0f; 						//
	public float TimeCharge = 0.01f; 					//   

	private float changeAngle = 0f; 					//  

	public float FocusNeiron = 90f;						// 
	public bool FocusDinamic = true;                    //  
	public float StepFocus = 1f;						//  
	public float MaxFocus = 90f;						//  

	public float Plasticity = 1.0f; 					//
	public bool PlasticityDinamic = true; 				//   
	public float StepPlasticity = 0.01f;				// 
	public float BasicPlasticity = 1.0f;				//  (  )
	public bool NewNeironDinamic = true;				//   

	

	private float angleMin = 0f;

	private bool CorunPlasticRun = false;

	// END VAR

    private Vector3 noveltyVector = Vector3.zero;
    private float noveltyFactor = 0.1f;

	IEnumerator StartSummator (){
		IgnoreInput = true;  //   
		gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); // 
		ActionN = true; //    
		yield return new WaitForSeconds(AnswerTime); // 
		ActionN = false; 
		ExcitationTransfer (); // 
		yield return new WaitForSeconds(TimeRepose);// 
		IgnoreInput = false; //    
		TypeIndexNeiron = _TypeIndexNeiron; //   
	}

	IEnumerator repolarizationTime (){
		IgnoreInput = true; //   
		gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255);//  
		yield return new WaitForSeconds(timeIgnore);// 
		IgnoreInput = false;
		TypeIndexNeiron = _TypeIndexNeiron;//  
	}

	IEnumerator StartModule (){
        IgnoreInput = true; //   
		ActionN = true; // ,      
		gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255);// 
		yield return new WaitForSeconds(AnswerTime);// 
		ExcitationTransfer ();//    
		ActionN = false;//  
		yield return new WaitForSeconds(TimeRepose);// 
		IgnoreInput = false;//   
		TypeIndexNeiron = _TypeIndexNeiron;// 
		StartCoroutine ("EvaluationTime");//  
		if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");// ,     =0   
        //         
	}

	IEnumerator EvaluationTime(){ 
		TimeEvaluationBool = true;//   
		yield return new WaitForSeconds(TimeEvaluation);
		TimeEvaluationBool = false;//  
	}

	IEnumerator AdaptationVoid(){
		yield return new WaitForSeconds(AdaptationTime);//  
        if (thresholdTop > thresholdAdapt) thresholdTop--;// ,    
		if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");//  
	}

	IEnumerator NegativeRepolarization(){
		IgnoreInput = true; //   
		ActionN = true; //
        for (int i = 0; i < 16; i++)
        {  //  
			Charge = Area.GetComponent<AreaScript>().Spike2[i];
			if (Charge > 0) gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); //
			else gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255); //
			yield return new WaitForSeconds(TimeCharge); //  /
		}
		Charge = 0f;// 
		TypeIndexNeiron = _TypeIndexNeiron;// 
		ActionN = false;//
		IgnoreInput = false;//    
	}

	IEnumerator StartAssociative(){
		IgnoreInput = true;//  
		ActionN = true;//
        StartCoroutine("PositiveRepolarization"); //   
		yield return new WaitForSeconds(AnswerTime); 		//  
		Compass ();//  
	}

	IEnumerator StartWhite() {
        IgnoreInput = true;//  
        ActionN = true;//
        StartCoroutine("PositiveRepolarization");//   
		yield return new WaitForSeconds(AnswerTime); 		// 
		ExcitationTransfer ();//    
	}

	IEnumerator PositiveRepolarization(){
		for (int i = 0; i < 16; i++) {
            //  
			Charge = Area.GetComponent<AreaScript>().Spike1[i];
			if (Charge > 0) gameObject.GetComponent<SpriteRenderer>().color = new Color32(255, 0, 0, 255); //
			else gameObject.GetComponent<SpriteRenderer>().color = new Color32(0, 0, 255, 255); //
			yield return new WaitForSeconds(TimeCharge); //  
		}
		Charge = 0f; // 
		TypeIndexNeiron = _TypeIndexNeiron;// 
		ActionN = false;// 
		yield return new WaitForSeconds(TimeRepose);// 
		IgnoreInput = false;// 
		StartCoroutine ("EvaluationTime");// 
		if ((AdaptationTime > 0) && (thresholdTop > thresholdAdapt)) StartCoroutine ("AdaptationVoid");//
	}

	IEnumerator PlasticTimeCoruntine (Vector2 PT){//  
		CorunPlasticRun = true;//   
		float PlasticBuffer = Plasticity;//  
		Plasticity = PT.x;// 
		yield return new WaitForSeconds(PT.y);//  
		Plasticity = PlasticBuffer;//  
		CorunPlasticRun = false;//   
	}

	public void ActiveNeiron (){ //        
		if (!IgnoreInput)
		{
			if (TypeIndexNeiron == 0) StartCoroutine ("StartSummator");//  
			if (TypeIndexNeiron == 1) StartCoroutine ("StartModule");// 
			if (TypeIndexNeiron == 2) StartCoroutine ("StartAssociative");// ,    
			if (TypeIndexNeiron == 3) StartCoroutine ("StartWhite");//  
		}
	}

	private void Compass (){
		if (Area != null){ //    ,        
			VectorPattern = Vector3.zero; //  
            //  
			for (int i = 0; i < Area.GetComponent<AreaScript>().NeironActionList.Count; i++) { //   
				if (gameObject == Area.GetComponent<AreaScript> ().NeironActionList [i]) continue; //    
				Vector3 R = Area.GetComponent<AreaScript> ().NeironActionList [i].transform.position - transform.position;//  ,   
                //       
				VectorPattern += (Area.GetComponent<AreaScript> ().NeironActionList [i].GetComponent<NeironScript> ().Charge * R.normalized);//R.sqrMagnitude; .normalized   //sqrMagnitude;!!!!!!!!!(  )
			}

			if (VectorPattern.sqrMagnitude < 3f) VectorPattern = VectorTrend; //   ,    
			if (VectorPattern.sqrMagnitude == 0) VectorPattern = new Vector3(Random.Range(-1f, 1f), Random.Range(-1f, 1f), Random.Range(-1f, 1f)); 
            //   ( ),    ,    ,    - 

			VectorPattern.Normalize(); //   

            if (noveltyVector == Vector3.zero) noveltyVector = -VectorPattern; //  (   )    -    
			changeAngle = Vector3.Angle(VectorPattern, noveltyVector);//         

			if (Area != null) Area.SendMessage("MessageOriginality", changeAngle/180);//      

			VectorTrend = VectorPattern; // 
            noveltyVector = Vector3.Slerp(noveltyVector, VectorPattern, noveltyFactor);//  
            //      
            //        
            //   noveltyVector = VectorPattern,       (     )
            //       ,       
			gameObject.GetComponent<LineRenderer>().SetPosition(0, transform.position);//   
			gameObject.GetComponent<LineRenderer>().SetPosition(1, transform.position + VectorTrend * 6);

           
			if (PlasticityDinamic) {
				if (changeAngle < 10) Plasticity -= StepPlasticity; else Plasticity += StepPlasticity; // 
				if (Plasticity > 1) Plasticity = 1f;
				if (Plasticity < 0) Plasticity = 0f;
                //         
                //    ,         . 
                //..        ,       
			}

			if (FocusDinamic){
				if (changeAngle < 10) FocusNeiron -= StepFocus; else FocusNeiron = MaxFocus;
				if (FocusNeiron < 0) FocusNeiron = 0;
                //         .
                //        .
                //       .
                //   -     ,      
			}

            //  
			if (NewNeironDinamic){
                if (!Physics.CheckSphere(transform.position + VectorTrend * 5, 3f))
                {   //  -     3,
                    //     5   
                    //   
					if (Area.GetComponent<AreaScript>().Global) NewNeiron(); //    
					else 
					{
						if (Area.GetComponent<Collider>().bounds.Contains(transform.position + VectorTrend * 5)) NewNeiron(); //          
					}
				}

				//   
                Collider[] hitColliders = Physics.OverlapSphere(transform.position + VectorTrend * 5, 3f); //          
				foreach (Collider value in hitColliders) //    
				{
					if (value.tag == "Neiron") //  
					{
						bool EnableSinaps = false; //    
						foreach (GameObject sinapsValue in hitSinaps) //    
						{
							if (sinapsValue.GetComponent<SinapsScript>().NeironTarget == value.gameObject) {
								EnableSinaps = true; //   
								break; //  
							} 	
						}
						
						if (!EnableSinaps) { //   
							GameObject cSinaps = Instantiate(prefabSinaps, transform.position, transform.rotation) as GameObject;//   
							cSinaps.transform.parent = transform;
							cSinaps.GetComponent<SinapsScript>().NeironTarget = value.gameObject;
							cSinaps.GetComponent<SinapsScript>().Force = 0f;
							hitSinaps.Add(cSinaps);

						}

					}
				}
			}

			//        
			angleMin = 180f;
			if (hitSinaps.Count != 0) angleMin = Vector3.Angle(hitSinaps[0].GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
			foreach(GameObject ShershSinaps in hitSinaps)
			{
				float angleShersh = Vector3.Angle(ShershSinaps.GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
				if (angleShersh < angleMin) angleMin = angleShersh;
			}
           
			if (FocusNeiron < angleMin) FocusNeiron = angleMin;
            //      ,       .
            //        , 
            //        .

			//  
			foreach(GameObject SinapsCoeff in hitSinaps){
					if (SinapsCoeff.GetComponent<SinapsScript>().TypeSinaps == 0){
					    float angleSinaps = Vector3.Angle(SinapsCoeff.GetComponent<SinapsScript>().NeironTarget.transform.position - transform.position, VectorTrend);
					    if (angleSinaps <= FocusNeiron) SinapsCoeff.GetComponent<SinapsScript>().Force += MaxForceSinaps * Plasticity;
					    else SinapsCoeff.GetComponent<SinapsScript>().Force -= MaxForceSinaps * Plasticity;
					    SinapsCoeff.GetComponent<SinapsScript>().Force = Mathf.Clamp(SinapsCoeff.GetComponent<SinapsScript>().Force, 0, MaxForceSinaps);
				    }
			}
		}

		ExcitationTransfer ();//    
	}

	private void NewNeiron (){
		GameObject clone = Instantiate(prefabNeiron, transform.position + VectorTrend * 6, transform.rotation) as GameObject;
        /*  :        (   ),
         *      ,        
         *        ,     .
         *       ....
         * */
		if (Area != null) Area.GetComponent<AreaScript>().amount++;//     

		clone.GetComponent<NeironScript>().Plasticity = BasicPlasticity;//  
		clone.GetComponent<NeironScript>().ActionN = false;
		clone.GetComponent<NeironScript>().IgnoreInput = false;
		clone.GetComponent<NeironScript>().Adder = 0f;
		clone.GetComponent<NeironScript>().VectorTrend = Vector3.zero;
		clone.GetComponent<NeironScript>().Area = Area;
		clone.GetComponent<NeironScript>().TimeEvaluationBool = false;
		clone.GetComponent<NeironScript>().LimitEvaluationInt = 0;
		clone.GetComponent<NeironScript>().Charge = 0.0f; 
		clone.GetComponent<NeironScript>().FocusNeiron = MaxFocus;
		clone.GetComponent<NeironScript>().Plasticity =  BasicPlasticity;
		clone.GetComponent<NeironScript>().TypeIndexNeiron = 2;
        clone.GetComponent<NeironScript>().noveltyVector = Vector3.zero;
        clone.GetComponent<NeironScript>().VectorTrend = Vector3.zero;

		clone.GetComponent<LineRenderer>().SetPosition(0, clone.transform.position);
		clone.GetComponent<LineRenderer>().SetPosition(1, clone.transform.position);

		clone.SendMessage("StopNeiron"); //          ,   

		GameObject ManagerObj = GameObject.Find("Manager"); //... , Find   
		ManagerObj.GetComponent<ManagerScript>().EndIndexNeiron++;// 
		clone.GetComponent<NeironScript>().IndexNeiron = ManagerObj.GetComponent<ManagerScript>().EndIndexNeiron;//    
		clone.name = "Neiron" + clone.GetComponent<NeironScript>().IndexNeiron;//     

        foreach (GameObject sd in clone.GetComponent<NeironScript>().hitSinaps) Destroy(sd); //       ,     
		clone.GetComponent<NeironScript>().hitSinaps.Clear(); //   .  ..
	}

	void FixedUpdate(){ //      0.01


		if (!IgnoreInput) //    
		{
			if (TypeIndexNeiron == 0)  //    
			{
				if (Adder > thresholdTop) // 
				{
					StartCoroutine ("StartSummator"); 
				}
			}

			if (TypeIndexNeiron == 1) //  
			{
				if (Adder > thresholdTop + bonusThreshold) // 
				{
					
					if (TimeEvaluationBool) //  ?
					{                       
						LimitEvaluationInt++; // 
						StopCoroutine("EvaluationTime"); //    
						TimeEvaluationBool = false; //  
					}
					else LimitEvaluationInt = 0; //   

					if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; //         - 

					StopCoroutine ("AdaptationVoid");  // ,      
					StartCoroutine ("StartModule"); //    
					
				}

				if (Adder < thresholdDown) //    
				{
					if (Area != null) StartCoroutine ("repolarizationTime"); //   ,    
				}
			}

			if (TypeIndexNeiron == 2) // 
			{
				if (Adder > thresholdTop + bonusThreshold) //    :   
				{
					if (TimeEvaluationBool) //     
					{
						LimitEvaluationInt++; //  
						StopCoroutine("EvaluationTime");//  
						TimeEvaluationBool = false;
					}
					else LimitEvaluationInt = 0; //   ,  

					if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp; //      ,    

					StopCoroutine ("AdaptationVoid");// ,   ( -    )
					StartCoroutine ("StartAssociative"); //    
				}

				if (Adder < thresholdDown) //   
				{
					StartCoroutine ("NegativeRepolarization");  //  ()
				}
			}

			if (TypeIndexNeiron == 3) //  
			{
				if (Adder > thresholdTop + bonusThreshold)//   
				{
					if (TimeEvaluationBool)// ...
					{
						LimitEvaluationInt++;
						StopCoroutine("EvaluationTime");
						TimeEvaluationBool = false;
					}
					else LimitEvaluationInt = 0;

					if ((LimitEvaluationInt > LimitRecurrence) && (bonusThreshold == 0)) thresholdTop += thresholdTopUp;

					StopCoroutine ("AdaptationVoid");
					StartCoroutine ("StartWhite");  
				}

				if (Adder < thresholdDown)
				{
					StartCoroutine ("NegativeRepolarization");  
				}
			}

		}

        if (Mathf.Abs(Adder) <= DampferAdder) Adder = 0f; // 
		if (Adder > DampferAdder) Adder -= DampferAdder;
		if (Adder < -DampferAdder) Adder += DampferAdder;

        if (Mathf.Abs(bonusThreshold) <= DempferBonusThreshold) bonusThreshold = 0f; //  
		if (bonusThreshold > DempferBonusThreshold) bonusThreshold -= DempferBonusThreshold;
		if (bonusThreshold < -DempferBonusThreshold) bonusThreshold += DempferBonusThreshold;
	} 

	private void ExcitationTransfer () // 
	{
		foreach (GameObject value in hitSinaps) //   
		{
			int T = value.GetComponent<SinapsScript>().TypeSinaps; // 
			float F = value.GetComponent<SinapsScript>().Force; // 
			GameObject NT = value.GetComponent<SinapsScript>().NeironTarget;// 
			if (T == 0) NT.SendMessage("AddSummator", F);// 
			if (T == 1) NT.SendMessage("AddTActual", F);
			if (T == 2) NT.SendMessage("ActiveNeiron");
            if (T == 3) NT.SendMessage("AddSummator", F);
			value.GetComponent<SinapsScript>().GoAction = true;//  
		}
	}

	public void AddSummator (float Summ) //      
	{
		Adder += Summ;
		if (Adder > MaxAdder) Adder = MaxAdder;
        if (Adder < - MaxAdder) Adder = -MaxAdder;
	}

	public void AddTActual (float T)//  ,  
	{
		bonusThreshold += T;
		if (bonusThreshold + thresholdTop < 0f) bonusThreshold = - thresholdTop + 0.0001f;
	}

	public void StopNeiron(){//  ,     GameOject.SendMessage("StopNeiron") 
		StopAllCoroutines();
	}

	public void plasticSetTime (Vector2 plasticTime){
        //  , SendMessage     , Vectir2 -    
        //     
		if (!CorunPlasticRun) StartCoroutine("PlasticTimeCoruntine", plasticTime);
        if (TypeIndexNeiron == 2) thresholdTop = thresholdAdapt;
	}
}




神经元之间的通信是使用基于SendMessage的消息系统进行的,并且与状态更改相关的所有过程都在协程中进行。



在框图中,神经元的基本基础。 SendMessage(“ AddSummator”,F)-力为F的直接作用突触,将加法器的总和增加给定数。每0.01 s激活一次FixedUpdate()函数,其中加法器的调制器以设定的阻尼器/数字减小。并且还要检查加法器是否超过了阈值,如果超过了阈值,则会启动coruntin。在刚玉运行期间,将忽略外部信号的模式打开,但是加法器的阻尼器仍在继续,还有补充量的机会。 SendMessage(“ ActiveNeiron”)-接触突触(efaps),如果协程枪不在当前运行,它将启动协程,否则该信号将被忽略。

在此基础上,进一步增加了与细胞代谢(成瘾和适应)有关的机制,以及从Eric Kandel的工作中获得的调节系统。为了进行验证,我定向激励的定向传输的想法开始了这个项目。

许多人对该项目的源代码感兴趣,但不仅出于这个原因,我还发布了源代码。事实是,仍有大量工作要做,计划认真扩展功能和工具,创建一定的环境,使您可以方便地处理大量元素,进行结构化和组织化。我没有太多的编程经验,但是我敢肯定,GeekTimes社区中的很多人都可以就结构,方法和优化方面提出建议,以从质量上改善项目。我计划不更改开发环境,开发过程的经验对我很重要,而最终结果的美观性和到目前为止的Unity游戏引擎在这方面对我非常有帮助。

Source: https://habr.com/ru/post/zh-CN398867/


All Articles