IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> MonoBehaviour引擎源码剖析Awake、Start、Update等方法执行原理 -> 正文阅读

[C++知识库]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运行时嵌入到应用中,提供这样的脚本运行机制。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 11:43:10  更:2021-09-03 11:44:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 20:22:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计