返回 登录
0

Unity引擎内部之回调函数封装

开发者在使用Unity引擎做开发时,都是用脚本进行编程,通过Unity官方提供的帮助文档或者开发者提供的插件,可以非常快速的开发出一款小游戏。这也是Unity能够被广泛接受的原因。但是读者在使用的过程中,有没有想过引擎底层C++代码是如何跟C#脚本通信的?为什么使用C#脚本可以调用引擎封装好的C++实现的代码接口?下面我们会通过一系列技术文章给读者解密Unity引擎内部的实现原理。
在解密Unity源代码之前,读者首先要清楚C++的宏定义,因为引擎内部使用了非常多的宏定义。C#要调用C++的接口,就需要C++内部实现其需要调用的接口。当然笔者的本意是让读者了解一下Unity引擎内部的实现原理,所以并不会把所有的代码都展示出来,只会把一些核心的东西给读者展示,也是为了帮助读者了解Unity引擎内部的实现过程,更有助于帮助读者编写逻辑或者为学习其他引擎提供参考。
我们在使用Unity编程时,经常会使用一些触发函数比如:”OnTriggerEnter”,”OnTriggerExit”,”OnCollisionEnter”,”OnBecameVisible”,”OnPreRender”,”OnApplicationQuit”等函数回调接口,它是被封装在引擎的一个头文件中,通过消息传递的方式发送给C#脚本。引擎文件定义如下:

#ifndef MESSAGE_IDENTIFIER
#define MESSAGE_IDENTIFIER(n,p) const extern EXPORT_COREMODULE MessageIdentifier n
#endif

MESSAGE_IDENTIFIER(kEnterTrigger, ("OnTriggerEnter", MessageIdentifier::kSendToScripts, ClassID (Collider)));
MESSAGE_IDENTIFIER(kExitTrigger, ("OnTriggerExit", MessageIdentifier::kSendToScripts, ClassID (Collider)));
MESSAGE_IDENTIFIER(kStayTrigger, ("OnTriggerStay", MessageIdentifier::kSendToScripts, ClassID (Collider)));
MESSAGE_IDENTIFIER(kEnterContact, ("OnCollisionEnter", MessageIdentifier::kSendToScripts, ClassID (Collision)));
MESSAGE_IDENTIFIER(kExitContact, ("OnCollisionExit", MessageIdentifier::kSendToScripts, ClassID (Collision)));
MESSAGE_IDENTIFIER(kStayContact, ("OnCollisionStay", MessageIdentifier::kSendToScripts, ClassID (Collision)));
MESSAGE_IDENTIFIER(kCollisionEnter2D, ("OnCollisionEnter2D", MessageIdentifier::kSendToScripts, ClassID (Collision2D)));
MESSAGE_IDENTIFIER(kCollisionExit2D, ("OnCollisionExit2D", MessageIdentifier::kSendToScripts, ClassID (Collision2D)));
MESSAGE_IDENTIFIER(kCollisionStay2D, ("OnCollisionStay2D", MessageIdentifier::kSendToScripts, ClassID (Collision2D)));
MESSAGE_IDENTIFIER(kTriggerEnter2D, ("OnTriggerEnter2D", MessageIdentifier::kSendToScripts, ClassID (Collider2D)));
MESSAGE_IDENTIFIER(kTriggerExit2D, ("OnTriggerExit2D", MessageIdentifier::kSendToScripts, ClassID (Collider2D)));
MESSAGE_IDENTIFIER(kTriggerStay2D, ("OnTriggerStay2D", MessageIdentifier::kSendToScripts, ClassID (Collider2D)));
MESSAGE_IDENTIFIER(kJointBreak, ("OnJointBreak", MessageIdentifier::kSendToScripts, ClassID (float)));
MESSAGE_IDENTIFIER(kTransformChanged, ("OnTransformChanged", MessageIdentifier::kDontSendToScripts, ClassID (int)));
MESSAGE_IDENTIFIER(kParticleCollisionEvent, ("OnParticleCollision", MessageIdentifier::kSendToScripts, ClassID (GameObject)));
MESSAGE_IDENTIFIER(kDidModifyValidity, ("OnDidModifyMeshValidity", MessageIdentifier::kDontSendToScripts));
MESSAGE_IDENTIFIER(kDidDeleteMesh, ("OnDidModifyMeshDelete", MessageIdentifier::kDontSendToScripts, ClassID (Mesh)));
MESSAGE_IDENTIFIER(kDidModifyBounds, ("OnDidModifyMeshBounds", MessageIdentifier::kDontSendToScripts));
MESSAGE_IDENTIFIER(kDidModifyMesh, ("OnDidModifyMesh", MessageIdentifier::kDontSendToScripts));
MESSAGE_IDENTIFIER(kLayerChanged, ("OnLayersChanged", MessageIdentifier::kDontSendToScripts));
MESSAGE_IDENTIFIER(kDestroyedComponentNotification, ("OnDestroyedComponent", MessageIdentifier::kUseNotificationManager));
MESSAGE_IDENTIFIER(kDidAddComponent , ("OnDidAddComponent", MessageIdentifier::kDontSendToScripts, ClassID (Component)));
MESSAGE_IDENTIFIER(kBecameVisible, ("OnBecameVisible", MessageIdentifier::kSendToScripts));
MESSAGE_IDENTIFIER(kBecameInvisible, ("OnBecameInvisible", MessageIdentifier::kSendToScripts));
MESSAGE_IDENTIFIER(kOnWillRenderObject, ("OnWillRenderObject", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
MESSAGE_IDENTIFIER(kPreCull, ("OnPreCull", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
MESSAGE_IDENTIFIER(kPostRender, ("OnPostRender", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
MESSAGE_IDENTIFIER(kPreRender, ("OnPreRender", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
MESSAGE_IDENTIFIER(kControllerColliderHit, ("OnControllerColliderHit", MessageIdentifier::kSendToScripts, ClassID (MonoObject)));
MESSAGE_IDENTIFIER(kAnimatorMove, ("OnAnimatorMove", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled)));
MESSAGE_IDENTIFIER(kAnimatorMoveBuiltin, ("OnAnimatorMoveBuiltin", MessageIdentifier::kDontSendToScripts, ClassID(RootMotionData)));
MESSAGE_IDENTIFIER(kAnimatorIK, ("OnAnimatorIK", (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts|MessageIdentifier::kDontSendToDisabled), ClassID (int)));
MESSAGE_IDENTIFIER(kForceRecreateCollider, ("ForceRecreateCollider", MessageIdentifier::kDontSendToScripts));
MESSAGE_IDENTIFIER(kRecreateRigidBodyDependencies2D, ("RecreateRigidBodyDependencies2D", MessageIdentifier::kDontSendToScripts, ClassID (Rigidbody2D)));
MESSAGE_IDENTIFIER(kServerInitialized, ("OnServerInitialized", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkPlayer"));
MESSAGE_IDENTIFIER(kPlayerConnected, ("OnPlayerConnected", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkPlayer"));
MESSAGE_IDENTIFIER(kConnectedToServer, ("OnConnectedToServer", MessageIdentifier::kSendToScripts));
MESSAGE_IDENTIFIER(kPlayerDisconnected, ("OnPlayerDisconnected", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkPlayer"));
MESSAGE_IDENTIFIER(kDisconnectedFromServer, ("OnDisconnectedFromServer", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkDisconnection"));
MESSAGE_IDENTIFIER(kConnectionAttemptFailed, ("OnFailedToConnect", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkConnectionError"));
MESSAGE_IDENTIFIER(kMasterServerConnectionAttemptFailed, ("OnFailedToConnectToMasterServer", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkConnectionError"));
MESSAGE_IDENTIFIER(kDisconnectedFromMasterServer, ("OnDisconnectedFromMasterServer", MessageIdentifier::kSendToScripts, ClassID (int), "NetworkDisconnection"));
MESSAGE_IDENTIFIER(kMasterServerEvent, ("OnMasterServerEvent", MessageIdentifier::kSendToScripts, ClassID (int), "MasterServerEvent"));
MESSAGE_IDENTIFIER(kLevelWasLoaded, ("OnLevelWasLoaded", MessageIdentifier::kSendToScripts, ClassID (int)));
MESSAGE_IDENTIFIER(kPlayerPause, ("OnApplicationPause", MessageIdentifier::kSendToScripts, ClassID (bool)));
MESSAGE_IDENTIFIER(kPlayerFocus, ("OnApplicationFocus", MessageIdentifier::kSendToScripts, ClassID (bool)));
MESSAGE_IDENTIFIER(kPlayerQuit, ("OnApplicationQuit", MessageIdentifier::kSendToScripts));
MESSAGE_IDENTIFIER(kTerrainChanged, ("OnTerrainChanged", MessageIdentifier::kSendToScripts, ClassID (int), "TerrainChangedFlags"));  // Investigate getting rid of these
MESSAGE_IDENTIFIER(kSetLightmapIndex, ("SetLightmapIndex", MessageIdentifier::kSendToScripts, ClassID (int)));                       //
MESSAGE_IDENTIFIER(kShiftLightmapIndex, ("ShiftLightmapIndex", MessageIdentifier::kSendToScripts, ClassID (int)));                   //
MESSAGE_IDENTIFIER(kDidModifyAnimatorController, ("OnDidModifyAnimatorController", MessageIdentifier::kDontSendToScripts));
MESSAGE_IDENTIFIER(kDidModifyMotion, ("OnDidModifyMotion", MessageIdentifier::kDontSendToScripts));
MESSAGE_IDENTIFIER(kDidVelocityChange, ("OnDidVelocityChange", MessageIdentifier::kDontSendToDisabled, ClassID (Vector3f)));
MESSAGE_IDENTIFIER(kDidModifyAvatar, ("OnDidModifyAvatar", MessageIdentifier::kDontSendToScripts));

#if ENABLE_NEW_EVENT_SYSTEM

#ifndef SEND_TO_SCRIPTS
#define SEND_TO_SCRIPTS  (MessageIdentifier::Options)(MessageIdentifier::kSendToScripts | MessageIdentifier::kDontSendToDisabled)
#endif

MESSAGE_IDENTIFIER(kOnMouseEnterEvent,  ("OnMouseEnterEvent",   SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnMouseExitEvent,   ("OnMouseExitEvent",    SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnMouseMoveEvent,   ("OnMouseMoveEvent",    SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnPressEvent,       ("OnPressEvent",        SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnReleaseEvent,     ("OnReleaseEvent",      SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnDragEvent,        ("OnDragEvent",         SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnDropEvent,        ("OnDropEvent",         SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnDragEnterEvent,   ("OnDragEnterEvent",    SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnDragExitEvent,    ("OnDragExitEvent",     SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnClickEvent,       ("OnClickEvent",        SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnKeyEvent,         ("OnKeyEvent",          SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnSelectEvent,      ("OnSelectEvent",       SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnDeselectEvent,    ("OnDeselectEvent",     SEND_TO_SCRIPTS));
MESSAGE_IDENTIFIER(kOnScrollEvent,      ("OnScrollEvent",       SEND_TO_SCRIPTS));
//MESSAGE_IDENTIFIER(kOnShowTooltip,        ("OnShowTooltip",   SEND_TO_SCRIPTS));
//MESSAGE_IDENTIFIER(kOnHideTooltip,        ("OnHideTooltip",   SEND_TO_SCRIPTS));
#endif

引擎定义一般都喜欢做一个类的ID标识,Unity引擎也不例外,在上述代码中有ClassID函数,那它的定义是以枚举的方式定义的。代码如下所示:

#ifndef CLASSIDS_H_
#define CLASSIDS_H_

#define ClassID(x)                CLASS_##x
#define DefineClassID(x,classID)  ClassID(x) = classID,

// Runtime classIDs are kept intentionally small.
enum ClassIDType
{
DefineClassID (Undefined, -1)   
DefineClassID (Object, 0)
DefineClassID (GameObject, 1)
DefineClassID (Component, 2)
DefineClassID (LevelGameManager, 3)
DefineClassID (Transform, 4)
DefineClassID (TimeManager, 5)
DefineClassID (GlobalGameManager, 6)
DefineClassID (Behaviour, 8)
DefineClassID (GameManager, 9)
DefineClassID (AudioManager, 11)
DefineClassID (ParticleAnimator, 12)
DefineClassID (InputManager, 13)
DefineClassID (EllipsoidParticleEmitter, 15)
DefineClassID (Pipeline, 17)
DefineClassID (EditorExtension, 18)
DefineClassID (Physics2DSettings, 19)
DefineClassID (Camera, 20)
DefineClassID (Material, 21)
DefineClassID (MeshRenderer, 23)
DefineClassID (Renderer, 25)
DefineClassID (ParticleRenderer, 26)
DefineClassID (Texture, 27)
DefineClassID (Texture2D, 28)
DefineClassID (SceneSettings, 29)
DefineClassID (GraphicsSettings, 30)
DefineClassID (MeshFilter, 33)
DefineClassID (OcclusionPortal, 41)
DefineClassID (Mesh, 43)
DefineClassID (Skybox, 45)
DefineClassID (QualitySettings, 47)
DefineClassID (Shader, 48)
DefineClassID (TextAsset, 49)
DefineClassID (Rigidbody2D, 50)
DefineClassID (Physics2DManager, 51)
DefineClassID (Collider2D, 53)
DefineClassID (Rigidbody, 54)
DefineClassID (PhysicsManager, 55)
DefineClassID (Collider, 56)
DefineClassID (Joint, 57)
DefineClassID (CircleCollider2D, 58)
DefineClassID (HingeJoint, 59)
DefineClassID (PolygonCollider2D, 60)
DefineClassID (BoxCollider2D, 61)
DefineClassID (PhysicsMaterial2D, 62)
DefineClassID (MeshCollider, 64)
DefineClassID (BoxCollider, 65)
DefineClassID (SpriteCollider2D, 66)
DefineClassID (EdgeCollider2D, 68)
DefineClassID (PolygonColliderBase2D, 69)
DefineClassID (ComputeShader, 72)
DefineClassID (AnimationClip, 74)
DefineClassID (ConstantForce, 75)
DefineClassID (WorldParticleCollider, 76)
DefineClassID (TagManager, 78)
DefineClassID (AudioListener, 81)
DefineClassID (AudioSource, 82)
DefineClassID (AudioClip, 83)
DefineClassID (RenderTexture, 84)
DefineClassID (MeshParticleEmitter, 87)
DefineClassID (ParticleEmitter, 88)
DefineClassID (Cubemap, 89)
DefineClassID (Avatar, 90)
DefineClassID (AnimatorController, 91)
DefineClassID (GUILayer, 92)
DefineClassID (RuntimeAnimatorController, 93)
DefineClassID (ScriptMapper, 94)
DefineClassID (Animator, 95)
DefineClassID (TrailRenderer, 96)
DefineClassID (DelayedCallManager, 98)
DefineClassID (TextMesh, 102)
DefineClassID (RenderSettings, 104)
DefineClassID (Light, 108)
DefineClassID (CGProgram, 109)
DefineClassID (BaseAnimationTrack, 110)
DefineClassID (Animation, 111)
DefineClassID (MonoBehaviour, 114)
DefineClassID (MonoScript, 115)
DefineClassID (MonoManager, 116)
DefineClassID (Texture3D, 117)
DefineClassID (NewAnimationTrack, 118)
DefineClassID (Projector, 119)
DefineClassID (LineRenderer, 120)
DefineClassID (Flare, 121)
DefineClassID (Halo, 122)
DefineClassID (LensFlare, 123)
DefineClassID (FlareLayer, 124)
DefineClassID (HaloLayer, 125)
DefineClassID (NavMeshLayers, 126)
DefineClassID (HaloManager, 127)
DefineClassID (Font, 128)
DefineClassID (PlayerSettings, 129)
DefineClassID (NamedObject, 130)
DefineClassID (GUITexture, 131)
DefineClassID (GUIText, 132)
DefineClassID (GUIElement, 133)
DefineClassID (PhysicMaterial, 134)
DefineClassID (SphereCollider, 135)
DefineClassID (CapsuleCollider, 136)
DefineClassID (SkinnedMeshRenderer, 137)
DefineClassID (FixedJoint, 138)
DefineClassID (RaycastCollider, 140)
DefineClassID (BuildSettings, 141)
DefineClassID (AssetBundle, 142)
DefineClassID (CharacterController, 143)
DefineClassID (CharacterJoint, 144)
DefineClassID (SpringJoint, 145)
DefineClassID (WheelCollider, 146)
DefineClassID (ResourceManager, 147)
DefineClassID (NetworkView, 148)
DefineClassID (NetworkManager, 149)
DefineClassID (PreloadData, 150)
DefineClassID (MovieTexture, 152)
DefineClassID (ConfigurableJoint, 153)
DefineClassID (TerrainCollider, 154)
DefineClassID (MasterServerInterface, 155)
DefineClassID (TerrainData, 156)
DefineClassID (LightmapSettings, 157)
DefineClassID (WebCamTexture, 158)
DefineClassID (EditorSettings, 159)
DefineClassID (InteractiveCloth, 160)
DefineClassID (ClothRenderer, 161)
DefineClassID (EditorUserSettings, 162)
DefineClassID (SkinnedCloth, 163)
DefineClassID (AudioReverbFilter, 164)
DefineClassID (AudioHighPassFilter, 165)
DefineClassID (AudioChorusFilter, 166)
DefineClassID (AudioReverbZone, 167)
DefineClassID (AudioEchoFilter, 168)
DefineClassID (AudioLowPassFilter, 169)
DefineClassID (AudioDistortionFilter, 170)
DefineClassID (AudioBehaviour, 180)
DefineClassID (AudioFilter, 181)
DefineClassID (WindZone, 182)
DefineClassID (Cloth, 183)
DefineClassID (SubstanceArchive, 184)
DefineClassID (ProceduralMaterial, 185)
DefineClassID (ProceduralTexture, 186)
DefineClassID (OffMeshLink, 191)
DefineClassID (OcclusionArea, 192)
DefineClassID (Tree, 193)
DefineClassID (NavMesh, 194)
DefineClassID (NavMeshAgent, 195)
DefineClassID (NavMeshSettings, 196)
DefineClassID (LightProbes, 197)
DefineClassID (ParticleSystem, 198)
DefineClassID (ParticleSystemRenderer, 199)
DefineClassID (LODGroup, 205)
DefineClassID (BlendTree, 206)
DefineClassID (Motion, 207)
DefineClassID (NavMeshObstacle, 208)
DefineClassID (TerrainInstance, 210)

DefineClassID (SpriteRenderer, 212)
DefineClassID (Sprite, 213)
DefineClassID (CachedSpriteAtlas, 214)

DefineClassID (LightProbeGroup, 220)
DefineClassID (AnimatorOverrideController, 221)

DefineClassID (Joint2D, 230)
DefineClassID (SpringJoint2D, 231)
DefineClassID (DistanceJoint2D, 232)
DefineClassID (HingeJoint2D, 233)
DefineClassID (SliderJoint2D, 234)
// Reserved 235-238 for new joints.
//DefineClassID (WheelJoint2D, 235)
//DefineClassID (FrictionJoint2D, 236)
//DefineClassID (PulleyJoint2D, 237)
//DefineClassID (GearJoint2D, 238)

kLargestRuntimeClassID,

DefineClassID (SmallestEditorClassID, 1000)
DefineClassID (Prefab, 1001)
DefineClassID (EditorExtensionImpl, 1002)
DefineClassID (AssetImporter, 1003)
DefineClassID (AssetDatabase, 1004)
DefineClassID (Mesh3DSImporter, 1005)
DefineClassID (TextureImporter, 1006)
DefineClassID (ShaderImporter, 1007)
DefineClassID (ComputeShaderImporter, 1008)
DefineClassID (AvatarMask, 1011)
DefineClassID (AudioImporter, 1020)
DefineClassID (HierarchyState, 1026)
DefineClassID (GUIDSerializer, 1027)
DefineClassID (AssetMetaData, 1028)
DefineClassID (DefaultAsset, 1029)
DefineClassID (DefaultImporter, 1030)
DefineClassID (TextScriptImporter, 1031)
DefineClassID (SceneAsset, 1032)
DefineClassID (NativeFormatImporter, 1034)
DefineClassID (MonoImporter, 1035)
DefineClassID (AssetServerCache, 1037)
DefineClassID (LibraryAssetImporter, 1038)
DefineClassID (ModelImporter, 1040)
DefineClassID (FBXImporter, 1041)
DefineClassID (TrueTypeFontImporter, 1042)
DefineClassID (MovieImporter, 1044)
DefineClassID (EditorBuildSettings, 1045)
DefineClassID (DDSImporter, 1046)
DefineClassID (InspectorExpandedState, 1048)
DefineClassID (AnnotationManager, 1049)
DefineClassID (MonoAssemblyImporter, 1050)
DefineClassID (EditorUserBuildSettings, 1051)
DefineClassID (PVRImporter, 1052)
DefineClassID (Transition, 1101)
DefineClassID (State, 1102)
DefineClassID (HumanTemplate, 1105)
DefineClassID (StateMachine, 1107)
DefineClassID (PreviewAssetType, 1108)
DefineClassID (SubstanceImporter, 1112)

kLargestEditorClassID,

kClassIdOutOfHierarchy = 100000,

DefineClassID (int, kClassIdOutOfHierarchy)
DefineClassID (bool, kClassIdOutOfHierarchy + 1)
DefineClassID (float, kClassIdOutOfHierarchy + 2)
DefineClassID (MonoObject, kClassIdOutOfHierarchy + 3)
DefineClassID (Collision, kClassIdOutOfHierarchy + 4)
DefineClassID (Vector3f, kClassIdOutOfHierarchy + 5)
DefineClassID (RootMotionData, kClassIdOutOfHierarchy + 6)
DefineClassID (Collision2D, kClassIdOutOfHierarchy + 7)
};

//make sure people dont accidentally define classids in other files:
#undef DefineClassID

#endif

类文件中定义了两个宏,以上就是关于引擎内部的回调函数封装。是不是并没有想象的那么难?学习引擎编程的思想是很重要的。

笔者简介:姜雪伟个人主页

评论