在MonoBehaviour.cpp中有这样一个Rebuild方法,它主要执行了CreateMonoScriptCache这样一个方法。
?
void MonoScript::Rebuild (ScriptingTypePtr klass)
{
......
m_ScriptCache = CreateMonoScriptCache (klass, m_IsEditorScript, this);
}
在CreateMonoScriptCache方法中,我们主要关注BuildMethodCache 和PopulateMethods方法。
MonoScriptCache* CreateMonoScriptCache (ScriptingTypePtr klass, bool isEditorScript, Object* errorContext)
{
......
BuildMethodCache (cache->methodCache, cache->klass, false);
PopulateMethods(*cache, cache->klass, errorContext);
......
return cache;
}
在BuildMethodCache方法中,通过调用
GetScriptingMethodRegistry().AllMethodsIn(klass, foundMethods, ScriptingMethodRegistry::kInstanceOnly);
将需要查找的方法放入到foundMethods这样的vector<ScriptingMethodPtr>列表中。
然后遍历这个列表,将<方法名,ScriptingMethodPtr 方法调用指针>插入到MethodCache&类型的 methods中。
static void BuildMethodCache (MethodCache& methods, ScriptingClassPtr klass, bool staticMethod)
{
AssertIf (klass == NULL);
std::vector<ScriptingMethodPtr> foundMethods;
GetScriptingMethodRegistry().AllMethodsIn(klass, foundMethods, ScriptingMethodRegistry::kInstanceOnly);
for (std::vector<ScriptingMethodPtr>::iterator methodIterator = foundMethods.begin(); methodIterator != foundMethods.end(); methodIterator++)
{
ScriptingMethodPtr method = *methodIterator;
std::string curName = scripting_method_get_name (method);
if (methods.find (curName.c_str()) != methods.end ())
continue;
methods.insert (std::make_pair (strcpy (new char[curName.length() + 1], curName.c_str()), method));
}
}
?注意关注到MonoScriptCache中的一个枚举
enum { kUpdate = 0, kLateUpdate, kFixedUpdate, kAwake, kStart, kMain, kRenderObject, kAddToManager, kRemoveFromManager, kRemoveFromManagerInternal, kCoroutineStart, kCoroutineMain, kRenderImageFilter, kDrawGizmos, kGUI, kValidateProperties, kSerializeNetView, kNetworkInstantiate, kOnDestroy, kAudioFilterRead, kMethodCount };
在PopulateMethods方法中,通过遍历枚举kMethodCount次,根据方法名kMethodNames数组拿到方法名,通过调用FindMethod方法,传入方法名,查找到对应的ScriptingMethodPtr这样类型的方法指针,进而建立起了从前文中的<方法名,ScriptingMethodPtr 方法调用指针>到<下标索引,ScriptingMethodPtr 方法调用指针>。
static void PopulateMethods(MonoScriptCache& cache, MonoClass* klass, Object* errorContext)
{
......
for (int i=0;i<MonoScriptCache::kMethodCount;i++)
{
DebugAssertIf(kMethodNames[i] == NULL);
ScriptingMethodPtr method = FindMethod (cache, kMethodNames[i]);
......
cache.methods[i] = method;
}
......
}
当我们在调用Awake方法时,主要是在CallMethodIfAvailable 中传入方法的索引,获取到ScriptingMethodPtr这样一个方法指针,进而完成对它的调用。
void MonoBehaviour::SetupAwake ()
{
if (IsPlayingOrAllowExecuteInEditMode () && !m_DidAwake && GetInstance() && IsActive ())
{
m_DidAwake = true;
CallMethodIfAvailable (MonoScriptCache::kAwake);
}
}
inline void MonoBehaviour::CallMethodIfAvailable (int methodIndex)
{
AssertIf (methodIndex < 0 || methodIndex >= MonoScriptCache::kMethodCount);
ScriptingMethodPtr method = m_Methods[methodIndex];
if (method == SCRIPTING_NULL)
{
return;
}
AssertIf (GetInstance() == SCRIPTING_NULL);
AssertIf (!m_DidAwake);
if (!IsActive ())
return;
ScriptingInvocationNoArgs invocation(method);
invocation.objectInstanceIDContextForException = GetInstanceID();
invocation.object = GetInstance();
invocation.Invoke();
}
同理可得Start方法
inline void MonoBehaviour::Start ()
{
......
m_DidStart = true;
ScriptingMethodPtr method;
method = m_Methods[MonoScriptCache::kCoroutineMain];
if (method)
InvokeMethodOrCoroutineChecked (method, SCRIPTING_NULL);
method = m_Methods[MonoScriptCache::kCoroutineStart];
if (method)
InvokeMethodOrCoroutineChecked (method, SCRIPTING_NULL);
}
注意到几个Update方法
void MonoBehaviour::Update ()
{
CallUpdateMethod (MonoScriptCache::kUpdate);
}
void MonoBehaviour::LateUpdate ()
{
CallUpdateMethod (MonoScriptCache::kLateUpdate);
}
void MonoBehaviour::FixedUpdate ()
{
CallUpdateMethod (MonoScriptCache::kFixedUpdate);
}
void MonoBehaviour::CallUpdateMethod(int methodIndex)
{
AssertIf (!IsPlayingOrAllowExecuteInEditMode ());
AssertIf (!IsActive ());
AssertIf (!GetEnabled ());
ScriptingObjectPtr instance = GetInstance();
if (instance == SCRIPTING_NULL)
return;
// Ensure Start has been called
Start ();
// We might be getting destroyed in Start
if (!IsInstanceValid(instance))
return;
// Call Update
CallMethodIfAvailable (methodIndex);
}
而至于Unity的引擎层如何和高级语言脚本类关联上,主要是通过Mono运行时嵌入到应用中,提供这样的脚本运行机制。
|