MonoBehaviour引擎源码剖析Awake、Start、Update等方法执行原理

在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运行时嵌入到应用中,提供这样的脚本运行机制。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值