John Geschrieben 7. November 2017 Melden Share Geschrieben 7. November 2017 Heyo , ich wollte hier ein Thread erstellen in dem es darum geht kleine aber feine Tricks zu Listen die man jeweils beim Programmieren oftmals nicht im Kopf hat und benutzen kann um smarten Code zu schreiben Index Basics Der If-Else Terminator Extract If-Condition in Methods Simple Namings: Keine Type Beschreibung oder Falsch Information Das Zwiebel-Prinzip / News-Paper #1. Der If-Else Terminator Source-Code: Before: //... [SerializeField] private GameObject _obj1; [SerializeField] private GameObject _obj2; [SerializeField] private GameObject _obj3; [SerializeField] private GameObject _obj4; //... if (_obj1.activeSelf) { _obj1.SetActive(false); } if (_obj2.activeSelf) { _obj2.SetActive(false); } if (_obj3.activeSelf) { _obj3.SetActive(false); } if (_obj4.activeSelf) { _obj4.SetActive(false); } //... After: //... [SerializeField] private GameObject _obj1; [SerializeField] private GameObject _obj2; [SerializeField] private GameObject _obj3; [SerializeField] private GameObject _obj4; //... var objs = new GameObject[] {_obj1, _obj2, _obj3, _obj4}; foreach (var obj in objs) { if (obj.activeSelf) { obj.SetActive(false); } } //... Detail-Erklärung: Oftmals besitzt man eine feste Anzahl an Variablen die man gerne ändern möchte. Nicht immer sind die in einem Array und darum passiert es schnell das man eine endlose "if-else"-Abfrage hat in dem man jeweils die Variable überprüft und dan eine action ausführt. Da können sich schnell Fehler einschleichen oder das ändern bzw. hinzufügen neue Sachen ist oftmals sehr mühselig. Tipp: Erstellt einen temporären Array in dem ihr alle Objects zusammenfasst und lässt anschließend ein For-/-each-Loop rüber laufen und tada ihr hab alles zusammengefasst und müsst nur noch in diesem Abschnitt was ab ändern und es wird sofort auf alle Objects übernommen. So seid ihr auf der sicheren Seite was Änderungen angeht. Mfg. -John Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 7. November 2017 Melden Share Geschrieben 7. November 2017 Schönes Beispiel für eine solche Nutzung, wobei man im Beispiel eigentlich auch gleich schreiben kann: //... [SerializeField] private GameObject[] _allObjects = new GameObject[3]; //... foreach (GameObject obj in _allObjects) { if (obj.activeSelf) obj.SetActive(false); } Das geht natürlich nur bedingt, wenn du eine externe Klasse einbinden musst, die Variablen bereits einzeln übergibt. Aber wenn Variablen eh keine Aussagekraft besitzen (z.b. "Image1", "Image2" etc), dann würde ich sie gleich in ein Array packen. 1 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Life Is Good Geschrieben 7. November 2017 Melden Share Geschrieben 7. November 2017 Gekürzt //... using System.Linq; //... [SerializeField] private GameObject[] gameObjects; //... gameObjects.ToList().ForEach(go => { if (go.activeSelf) go.SetActive(false); }); //... Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
John Geschrieben 7. November 2017 Autor Melden Share Geschrieben 7. November 2017 @Zer0Cool & LifeIsGood ihr hab völlig recht in fall das man von dem gleichen Object eine Collection besitzt sollte man auf ein Array zurückgreifen und das jeweils mit eine SerializeField versehen wird. Aber ich gibt auch fälle wo man keine Collection jeweils davon besitzen möchte Aber der beste Hinweis ist wie @Zer0Cool gesagt hat "item01, item02, item3..." wen das auftaucht sollte man darüber nachdenken eine Collection zu machen. Ich habe nochmal ein Beispiel erstellt um es besser zu erklären //... [SerializeField] private int _goldAmount; [SerializeField] private int _diamontAmount; [SerializeField] private int _rubyAmount; [SerializeField] private int _perlAmount; //... var amounts = new int[] {_goldAmount, _diamontAmount, _rubyAmount, _perlAmount}; foreach (var amount in amounts) { if(amount < 0) { signal.Publish<NegativAmountEvent>(); } } //... In der Klasse selbst hat man jeweils noch andere Provider oder Behaviours die direkt mit den Variable z.b. individuell arbeiten. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
John Geschrieben 8. November 2017 Autor Melden Share Geschrieben 8. November 2017 #2. Extract If-Condition in Methods Before: //... private void OnRequestJoinSession() { if (_playerData.HasEquipKey && _playerData.EquipKeyId == _sessionData.RequiredKeyId && _playerData.Level > _sessionData.RequiredPlayerLevel) { //JoinSession... } } //... After: //... private void OnRequestJoinSession() { if (IsPlayerValid()) { //JoinSession... } } private bool IsPlayerValid() { return _playerData.HasEquipKey && _playerData.EquipKeyId == _sessionData.RequiredKeyId && _playerData.Level > _sessionData.RequiredPlayerLevel; } //... Detail-Erklärung: Ich habe schon oft erlebt das man meistens eine If-Condition hat die ein wenig mehr Logik erfordert. Oftmals schleichen sich hier schnell Fehler ein oder das lesen dieser Condition ist meistens mühselig. Für diese Fälle ist es praktisch diese in eine separate Methode zu verlagern um einerseits den Lesefluss zu erleichtern und auf der anderen Seite Fehler vorzubeugen. Falls man in seiner Klasse zum Beispiel öfters diese Condition überprüfen muss lohnt es sich auf jedenfalls diese in eine separate Methode zu Verlagen. Tipp: Ich benutze die Faustregel oft falls ich eine Condition habe die mehr als ein State überprüft verlagere ich diese in eine andere Methode. Oftmals macht es auch Sinn selbst bei eine Condition diese in einer separaten Methode zu verlagern z.B. bei größeren Überprüfungen. Es erleichtert das ab ändern später falls sich die Condition ändert und verbessert den Lesefluss des source-codes Zusatz-Beispiel: //... private bool IsNumberNotZero() { return int.Parse(_uiText.text) != 0; } //... 1 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Zer0Cool Geschrieben 8. November 2017 Melden Share Geschrieben 8. November 2017 Find ich gut, ein andere Methode wäre sehr konsequent auf die Bezeichner zu achten und den Klassen der Objekte selbst Methoden für die Prüfung an die Hand zu geben: private void OnRequestJoinSession() { if (m_currentPlayerData.HasEquipKey() && m_currentPlayerData.EquipKeyIdEquals(m_CurrentSessionData.RequiredKeyId) && m_currentSessionData.CheckRequiredPlayerLevel(m_currentPlayerData.Level)) { //JoinSession... } } 1 Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
John Geschrieben 8. November 2017 Autor Melden Share Geschrieben 8. November 2017 @Zer0Cool Du hast völlig recht das wäre der Ideal Fall. Die jeweilige evaluierung in die Klassen (bzw. Model ) selbst zu verfrachten Super punkt nochmal den du mit dem Example hervorgebracht hast. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
John Geschrieben 9. November 2017 Autor Melden Share Geschrieben 9. November 2017 #3. Simple Namings: Keine Type Beschreibung oder Falsch Information Before: //... private GameObject[] _unitList; //... private List<int> _scores; //... private GameObject _player01; //... private GameObject _player02; //... After: //... private GameObject[] _units; //... private List<int> _lastScoreCollection; //... private PlayerContainer _playerContainer; //... Detail-Erklärung: Ein richtiger Variablen-Name zu finden kann oftmals eine riesige Hürde sein und dann passiert es sehr schnell das man seinen Variablen-Name verkompliziert. Doch wie kann man dagegen angehen und welchen Trick gibt es für eine schnellere Findung von Variablen-Namen. Oftmals hilft es sogar wie im Falle von den units statt "-List" hinschreibt könnte man das ganze einfach sauber gestellten in dem man den Namen unit in die Mehrzahl verwandet units damit hat man schon Information geben das es sich hier nicht um eine einzelne Unit, sondern um eine Ansammlung von Units handelt. In dem Falle von scores ist es zwar jetzt nicht aussagekräftig nur ein "-s" dran zu hängen. Hier kann man auch auf Hilf Wörter zurückgreifen die das ganze mehr unterstreichen. Wie zum Beispiel "-Collection" das gibt darüber Auskunft das die letzte Score Zusammen Collected werden und man mit Hilfe dieser die letzte Score sich holen kann. Wichtiger Hinweis: Sicherlich wird sich jetzt der ein oder andere fragen: Was jetzt ein Unterschied macht wen ich „List“ hinschreibe anstatt von einer Collection? Es könnte schnell dazu führen das andere Leser oder man selbst verwirrt ist. Falls man jeweils mit dieser variable arbeitet und diese aus besonderen Gründen von einer List<int> in ein Array von int’s ändern müsste könnte der Leser erwarten, dass er eine Liste bekommt. Darum ist es ideal wen man einen Namen nimmt der jetzt nicht auf einen Typen zurückschließt lässt. Container ist ebenfalls ein oftmals Benutzer Name den einen öfters über den Weg läuft. Falls man zum Beispiel mehrere Spieler besitzt und diese gerne zusammenfassen will kann man dafür sogar eine extra Klasse anfertigen die diese hält und verwaltet. Ich benutze gerne den Namen Container wen ich in dieser Klasse eine Ansammlung von verschieden Typen habe. Bei einer Collection erwarte ich jeweils eine Ansammlung exakt nur vom einem Typen und nichts Anderes. Im Gegenteil zu einem Container wo ich alles reinpacken kann und diese dort auf eine bestimmte Zeit lagern kann. Tipp: Oftmals sollte man variablen nicht verkomplizieren nur, weil sie cool klingen oder glatt unnötige Information liefern wie z.B. den Typen den in den Namen reinschreiben das ist total überflüssig da fast jede der IDE bereits diesen Job übernehmen und dadurch nur mehr Verwirrung gestiftet werden kann. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
John Geschrieben 13. November 2017 Autor Melden Share Geschrieben 13. November 2017 #4. Das Zwiebel-Prinzip / News-Paper Before: //... private void OnGUI() { EditorGUILayout.HelpBox(_infoMessage, MessageType.Info); _displayAdvancedSettings = EditorGUILayout.Foldout(_displayAdvancedSettings, "Advance Settings:"); if (_displayAdvancedSettings) { _customizeXValue = EditorGUILayout.IntField(_customizeXValue, "Important Value"); _selectedColor = EditorGUILayout.ColorField("Selected Color", _selectedColor); _customizeYValue = EditorGUILayout.FloatField(_customizeYValue, "Important Value"); } if (GUILayout.Button("Execute... Something")) { ExecuteCalculation(); } GUILayout.Label("Process Time" + _processTime); } //... After: //... private void OnGUI() { DrawHelperHeader(); DrawSettingsActivator(); if (_displayAdvancedSettings) { DrawAdvancedSettings(); } DrawExecuteArea(); } private void DrawHelperHeader() { EditorGUILayout.HelpBox(_infoMessage, MessageType.Info); } private void DrawSettingsActivator() { _displayAdvancedSettings = EditorGUILayout.Foldout(_displayAdvancedSettings, "Advance Settings:"); } private void DrawAdvancedSettings() { _customizeXValue = EditorGUILayout.IntField(_customizeXValue, "Important Value"); _selectedColor = EditorGUILayout.ColorField("Selected Color", _selectedColor); _customizeYValue = EditorGUILayout.FloatField(_customizeYValue, "Important Value"); } private void DrawExecuteArea() { if (GUILayout.Button("Execute... Something")) { ExecuteCalculation(); } GUILayout.Label("Process Time" + _processTime); } //... Detail-Erklärung: Der Aufbau einer Kasse und deren Struktur ist ein wichtiger Bestandteil der oftmals in Vergessenheit gerat. Eine geordnete und saubere Klasse ist das fundamental für einen guten Lesefluss und Verständnis für eine Klasse. Doch wie sieht eine saubere Struktur eigentlich aus? Ein seltsames Phänomen das mir immer über den Weg läuft ist das öfters in der "OnGUI", "Update", "Start"... MonoBehaviour-Klassen auftreten. Dort wird oftmals alles was man möchtet in diese Methode reingeschrieben. Hier ist es von enormen Vorteil dieses in unterschiedliche Methoden zu Verlagen, da falls man Änderungen vornehmen will sich nicht erst durch den gewaltigen GUI-Code durchkämpfen muss, sondern man schaut sich jeweils einmal die OnGUI-Klasse an wo jeweils das UI-Behaviour beschrieben wird und springt dann anschließend in die jeweilige Methode in der man eine Änderung vornehmen will. Man erspart sich Zeit und erleichtert das Lesen und das Verständnis von Methoden. Diese Concept kann man auch jeweils für seinen Klassen-Aufbau anwenden. //... public class ... { //Public-Variablen //...(static, const,...) //Private-Variablen //...(static, const,...) //Constructor //...(init, setup) //Public-Methoden //...(static, override, virtual,...) //Private-Methoden //...(static, override, virtual,...) //Destructor //...(cleanup, destory) } //... Oftmals wird auch der Vergleich vom Zeitung-Lesen genommen. Das man jeweils seine Header hat darunter folgen die Header2 danach folgt Letzt endlich der Artikel-Content. So kann man schon vorab abklären was einem gefällt bzw. was man sucht und dann zu dem jeweiligen Artikel-Content schneller navigieren ohne von Anfang sich durch jeden Artikel Content zu kämpfen bis man zu seiner passenden Stelle trifft. Tipp: Ich verfolge stets das Ziel den Leser meiner Klasse Oberhalb meiner Klasse darüber Aufzuklären was in dieser Klasse passiert und unterhalb findet er jeweils die tatsächliche Implementierung. //... // Top public bool IsObjectInRange(object obj) { return _playerRange < GetPlayerDistanceFromTarget(obj); } // Bottom private float GetPlayerDistanceFromTarget(object obj) { return Vector3.Distance(_playerObj, obj); } //... Eine weitere Faustregel die man verfolgen kann in Public-Methoden beschreibe ich nur jeweils das Ausgeführte Behaviour das ich tatsächlich in den Private-Methoden ausführe. So bekomme ich schneller einen Überblick und Verständnis der Klasse. Wen ich von außen in diese Klasse springe und falls mich wirklich die Implementierung interessiert spring ich jeweils dann ein schritt tiefer zu den Private-Methoden. Zitieren Link zu diesem Kommentar Auf anderen Seiten teilen More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.