unity3d
अनुकूलन
खोज…
टिप्पणियों
- यदि संभव हो, तो आवश्यक नहीं होने पर ऑब्जेक्ट्स पर स्क्रिप्ट को अक्षम करें। उदाहरण के लिए यदि आपके पास एक शत्रु वस्तु पर एक स्क्रिप्ट है जो खिलाड़ी के लिए खोज और आग लगाता है तो इस स्क्रिप्ट को अक्षम करने पर विचार करें जब दुश्मन खिलाड़ी से बहुत दूर है।
फास्ट और कुशल चेक
अनावश्यक संचालन और विधि कॉल से बचें जहाँ भी आप कर सकते हैं, विशेष रूप से एक विधि में जिसे कई बार कहा जाता है, जैसे कि Update
।
दूरी / रेंज की जाँच
दूरी की तुलना करते समय magnitude
बजाय sqrMagnitude
उपयोग करें। यह अनावश्यक sqrt
संचालन से बचता है। ध्यान दें कि sqrMagnitude
का उपयोग करते sqrMagnitude
, दाहिने हाथ की तरफ भी चुकता होना चाहिए।
if ((target.position - transform.position).sqrMagnitude < minDistance * minDistance))
सीमा जाँच
ऑब्जेक्ट चौराहों की बारीकी से जाँच करके पता लगाया जा सकता है कि उनके Collider
/ Renderer
प्रतिच्छेदन सीमा है या नहीं। Bounds
संरचना भी एक सरल Intersects
विधि है जो यह निर्धारित दो सीमा एक दूसरे को काटना है कि क्या मदद करता है।
Bounds
भी वस्तुओं (देखें बीच वास्तविक (सतह पर सतह) दूरी के एक करीबी अनुमानित गणना करने के लिए हमें मदद Bounds.SqrDistance
)।
चेतावनियां
उत्तल वस्तुओं के लिए सीमा जाँच वास्तव में अच्छी तरह से काम करती है, लेकिन अवतल वस्तुओं पर सीमा जाँच वस्तु के आकार के आधार पर बहुत अधिक अशुद्धि हो सकती है।
Mesh.bounds
का उपयोग करने की अनुशंसा नहीं की जाती है क्योंकि यह स्थानीय स्थान सीमा देता है। इसके बजाय MeshRenderer.bounds
उपयोग करें।
कोरटाइन पावर
प्रयोग
यदि आपके पास लंबे समय तक चलने वाला ऑपरेशन है जो नॉट-थ्रेड-सेफ यूनिटी एपीआई पर निर्भर करता है, तो इसे कई फ्रेमों में विभाजित करने और अपने एप्लिकेशन को उत्तरदायी बनाए रखने के लिए कॉरटाइन्स का उपयोग करें।
Coroutines प्रत्येक क्रिया को हर फ्रेम में चलाने के बजाय महंगे कार्यों को करने में मदद करते हैं।
कई तख्ते पर लंबे समय तक चलने वाले मार्गों को विभाजित करना
कोराटाइन आपके एप्लिकेशन के फ्रैमरेट को बनाए रखने में मदद करने के लिए कई फ़्रेमों पर लंबे समय तक चलने वाले संचालन को वितरित करने में मदद करता है।
रूटीन को पेंट करने या उत्पन्न करने वाले रूटीन प्रक्रियात्मक रूप से या शोर उत्पन्न करते हैं, ऐसे उदाहरण हैं जिन्हें कोराटाइन उपचार की आवश्यकता हो सकती है।
for (int y = 0; y < heightmap.Height; y++)
{
for (int x = 0; x < heightmap.Width; x++)
{
// Generate pixel at (x, y)
// Assign pixel at (x, y)
// Process only 32768 pixels each frame
if ((y * heightmap.Height + x) % 32 * 1024) == 0)
yield return null; // Wait for next frame
}
}
उपरोक्त कोड उदाहरण को समझने में आसान है। उत्पादन कोड में प्रति-पिक्सेल चेक से बचने के लिए बेहतर है कि चेक करें कि कब
yield return
करना है (शायद यह हर 2-3 पंक्तियों में करें) और अग्रिम में लूप की लंबाई केfor
पूर्व-गणना करें।
महंगे कार्यों को कम बार करना
Coroutines आपको महंगी क्रियाओं को कम बार करने में मदद करती है, ताकि यह उतना बड़ा प्रदर्शन न हो जितना कि हर फ्रेम में किया जाएगा।
मैनुअल से सीधे निम्नलिखित उदाहरण लेते हुए:
private void ProximityCheck()
{
for (int i = 0; i < enemies.Length; i++)
{
if (Vector3.Distance(transform.position, enemies[i].transform.position) < dangerDistance)
return true;
}
return false;
}
private IEnumerator ProximityCheckCoroutine()
{
while(true)
{
ProximityCheck();
yield return new WaitForSeconds(.1f);
}
}
CullingGroup API का उपयोग करके निकटता परीक्षणों को और भी अधिक अनुकूलित किया जा सकता है ।
आम नुकसान
एक सामान्य गलती डेवलपर्स करियर के नतीजे या साइड इफेक्ट्स को कोरआउट के बाहर पहुंचा रहा है। जैसे ही yield return
स्टेटमेंट का सामना होता है और परिणाम या साइड इफेक्ट का प्रदर्शन नहीं किया जा सकता है, जैसे ही कॉलआउट वापस कॉल करने वाले पर नियंत्रण करता है। जहां coroutine बाहर परिणाम / पक्ष प्रभाव का उपयोग करने के गतिरोध उत्पन्न समस्याओं के लिए, जाँच इस जवाब ।
स्ट्रिंग्स
कोई यह तर्क दे सकता है कि विनम्र स्ट्रिंग की तुलना में एकता में अधिक संसाधन हॉग हैं, लेकिन इसे ठीक करने के लिए आसान पहलुओं में से एक है।
स्ट्रिंग ऑपरेशन कचरा निर्माण करते हैं
अधिकांश स्ट्रिंग ऑपरेशंस में छोटी मात्रा में कचरा बनता है, लेकिन अगर किसी एक अपडेट के दौरान कई बार उन ऑपरेशनों को कॉल किया जाता है, तो यह बंद हो जाता है। समय के साथ यह स्वचालित कचरा संग्रह को ट्रिगर करेगा, जिसके परिणामस्वरूप सीपीयू स्पाइक दिखाई दे सकता है।
अपने स्ट्रिंग ऑपरेशन कैश करें
निम्नलिखित उदाहरण पर विचार करें।
string[] StringKeys = new string[] {
"Key0",
"Key1",
"Key2"
};
void Update()
{
for (var i = 0; i < 3; i++)
{
// Cached, no garbage generated
Debug.Log(StringKeys[i]);
}
for (var i = 0; i < 3; i++)
{
// Not cached, garbage every cycle
Debug.Log("Key" + i);
}
// The most memory-efficient way is to not create a cache at all and use literals or constants.
// However, it is not necessarily the most readable or beautiful way.
Debug.Log("Key0");
Debug.Log("Key1");
Debug.Log("Key2");
}
यह मूर्खतापूर्ण और बेमानी लग सकता है, लेकिन यदि आप शेड्स के साथ काम कर रहे हैं, तो आप इन जैसी स्थितियों में भाग सकते हैं। चाबियों को कैच करने से फर्क पड़ेगा।
कृपया ध्यान दें कि स्ट्रिंग शाब्दिक और स्थिरांक कोई कचरा उत्पन्न नहीं करते हैं, क्योंकि वे प्रोग्राम स्टैक स्थान में सांख्यिकीय रूप से इंजेक्ट किए जाते हैं। यदि आप रन-टाइम पर स्ट्रेंथ जनरेट कर रहे हैं और हर बार उपरोक्त उदाहरण की तरह ही स्ट्रिंग्स जेनरेट करने की गारंटी दी जाती है, तो कैशिंग निश्चित रूप से मदद करेगा।
अन्य मामलों के लिए जहां उत्पन्न स्ट्रिंग प्रत्येक बार समान नहीं होती है, उन तारों को उत्पन्न करने के लिए कोई अन्य विकल्प नहीं है। इस प्रकार, मेमोरी स्पाइक हर बार मैन्युअल रूप से स्ट्रींग उत्पन्न करने के साथ आमतौर पर नगण्य होता है, जब तक कि एक बार में दसियों हज़ारों तार उत्पन्न न हों।
अधिकांश स्ट्रिंग ऑपरेशन डीबग संदेश हैं
डिबग संदेशों के लिए स्ट्रिंग संचालन करना, अर्थात। Debug.Log("Object Name: " + obj.name)
ठीक है और विकास के दौरान बचा नहीं जा सकता है। हालांकि, यह सुनिश्चित करना महत्वपूर्ण है कि अप्रासंगिक डिबग संदेश जारी उत्पाद में समाप्त न हों।
एक तरीका यह है कि अपने डीबग कॉल में सशर्त विशेषता का उपयोग करें। यह न केवल विधि कॉल को निकालता है, बल्कि सभी स्ट्रिंग ऑपरेशन भी इसमें जा रहा है।
using UnityEngine;
using System.Collections;
public class ConditionalDebugExample: MonoBehaviour
{
IEnumerator Start()
{
while(true)
{
// This message will pop up in Editor but not in builds
Log("Elapsed: " + Time.timeSinceLevelLoad);
yield return new WaitForSeconds(1f);
}
}
[System.Diagnostics.Conditional("UNITY_EDITOR")]
void Log(string Message)
{
Debug.Log(Message);
}
}
यह एक सरलीकृत उदाहरण है। आप कुछ समय के लिए और अधिक पूरी तरह से विकसित लॉगिंग दिनचर्या को डिजाइन करना चाहते हैं।
स्ट्रिंग तुलना
यह एक मामूली अनुकूलन है, लेकिन यह एक उल्लेख के लायक है। तार की तुलना थोड़ा अधिक शामिल है जो एक से अधिक सोच सकता है। सिस्टम सांस्कृतिक अंतर को डिफ़ॉल्ट रूप से ध्यान में रखने की कोशिश करेगा। आप इसके बजाय एक सरल बाइनरी तुलना का उपयोग करने का विकल्प चुन सकते हैं, जो तेजी से प्रदर्शन करता है।
// Faster string comparison
if (strA.Equals(strB, System.StringComparison.Ordinal)) {...}
// Compared to
if (strA == strB) {...}
// Less overhead
if (!string.IsNullOrEmpty(strA)) {...}
// Compared to
if (strA == "") {...}
// Faster lookups
Dictionary<string, int> myDic = new Dictionary<string, int>(System.StringComparer.Ordinal);
// Compared to
Dictionary<string, int> myDictionary = new Dictionary<string, int>();
कैश संदर्भ
विशेष रूप से अपडेट फ़ंक्शन में महंगी कॉल से बचने के लिए कैश संदर्भ। यह उपलब्ध होने पर इन संदर्भों को कैशिंग करके या उपलब्ध होने पर फिर से संदर्भ प्राप्त करने से बचने के लिए अशक्त / बूल फ्लैट के लिए उपलब्ध हो सकता है।
उदाहरण:
कैश घटक संदर्भ
परिवर्तन
void Update()
{
var renderer = GetComponent<Renderer>();
renderer.material.SetColor("_Color", Color.green);
}
सेवा
private Renderer myRenderer;
void Start()
{
myRenderer = GetComponent<Renderer>();
}
void Update()
{
myRenderer.material.SetColor("_Color", Color.green);
}
कैश ऑब्जेक्ट संदर्भ
परिवर्तन
void Update()
{
var enemy = GameObject.Find("enemy");
enemy.transform.LookAt(new Vector3(0,0,0));
}
सेवा
private Transform enemy;
void Start()
{
this.enemy = GameObject.Find("enemy").transform;
}
void Update()
{
enemy.LookAt(new Vector3(0, 0, 0));
}
इसके अलावा जहां संभव हो वहां मैथफ को कॉल जैसी महंगी कॉल करें।
स्ट्रिंग्स का उपयोग करके कॉल करने के तरीकों से बचें
स्ट्रिंग्स का उपयोग करके कॉलिंग विधियों से बचें जो विधियों को स्वीकार कर सकते हैं। यह दृष्टिकोण प्रतिबिंब का उपयोग करेगा जो विशेष रूप से अपडेट फ़ंक्शन में उपयोग किए जाने पर आपके गेम को धीमा कर सकता है।
उदाहरण:
//Avoid StartCoroutine with method name
this.StartCoroutine("SampleCoroutine");
//Instead use the method directly
this.StartCoroutine(this.SampleCoroutine());
//Avoid send message
var enemy = GameObject.Find("enemy");
enemy.SendMessage("Die");
//Instead make direct call
var enemy = GameObject.Find("enemy") as Enemy;
enemy.Die();
खाली एकता विधियों से बचें
खाली एकता विधियों से बचें। खराब प्रोग्रामिंग शैली होने के अलावा, रनटाइम स्क्रिप्टिंग में एक बहुत छोटा ओवरहेड शामिल है। कई उदाहरणों में, यह प्रदर्शन का निर्माण और प्रभावित कर सकता है।
void Update
{
}
void FixedUpdate
{
}