A repo recording my learning path in unity. The exploration is led by scene.
Scenes are categoried by the big part in Unity. Every scene includes the features of the specific part.
- Change the skybox (mat) via
Window / Rendering / Lighting / Environment
. We can also set the fog effect there. - Create simple 3d mesh via
+ / 3D Objects
. - Adjust mesh position, rotation, scale in Inspector View or directly in the scene view. Via
holding Ctrl
, we can move the object by grid. - Load material via dragging. If the surface type is
Transparent
, we can set the alpha channel to have transparent effect of mesh. - Duplicate the mesh via
Ctrl + D
. - Inspect the mesh in view via
Shift + F
. When inspecting an object, pressAlt(left) + Left click
to inspect aroung the object. - Align the mesh via
Shift + V
between two features, e.g. corner, of the target meshes. - Group mesh together via selecting and
+ / Group Empty Parent
. - Define mesh as Prefab via
dragging into Prefabs/
so as to be able to change parent mesh by change prefab child mesh. - Add physics to the mesh via
Add Component / Rigidbody
.Use Gravity
determine if the rigidbody is affected by the gravity force toward minus Y.Drag
act like a damping parameter, higher the value, higher the damping.Rigidbody
decides if the object is simulated by the unity physical engine and react to collision and forces.Is Kinematic
determine if the update() of the mesh is fully dependent on the script or animation. An object isStatic Collider
if the Gameobject has a collider but no rigidbody, which means it cannot be affected by any force (AddForce() is a method of Rigidbody). An object isRigidbody Collider
if the Gameobject has a collider and rigidbody withIs Kinematic
set as False, which means it is simulated by the defaule physicis engine. An object isKinematic Rigidbody Collider
if the Gameobject has a collider and rigidbody withIs Kinematic
set as True, which means it is not simulated by the defaule physicis engine with force and collision reaction, however since it still has a rigidbody component, we can addforce explicitly. - If
Is Trigger
in the collider is set as True, the gameobject will not collide and has collision reaction with other gameobejcts when the collider penetrates. The original collider region becomes a trigger, so that it is allowed to penetrates. From the code perspective, it reflects in the difference betweenOnCollisionXXX()
andOnTriggerXXX()
. - For parent GameObject with children components, use the collider of the child mesh with the rigidbody of the parent. But if we would not like the newly instantiated child mesh to affect the center of mass of the parent mesh, we can add rigidbody of the children which overrides that of parent so that will not affect the mass which is defined in rigidbody component of the parent.
- Add script to the object via
Add Component / New Script
. - One gameObject can have more than one collider. Currently, trial with one collider and one trigger does work.
- Create a new material via
right clicking parent folder in project view / Create / Material
. - Load texture image via
dragging the target image to Base Map
. The albedo color still affects. Physic Material
can be added to GameObject on its collider material, which is used to adjust friction and bouncing effects of colliding objects. For more details, clickhere.Friction
reflects to coefficient of friction,[0,1]
, which is further classified asstatic friction
anddynamic friction
.Bounciness
reflects to bouncy,[0,1]
. Both parameter has mode ofCombine
, which defines how the parameter of the two colliders are combined. The combination priority isAverage < Minimum < Multiply < Maximum
. The default setup forPhysic Material = None
is the default initialized setup.- Material can be emissive, the simplest emissive effect can be realized by choosing
Emission
for the material and define the light color and intensity. - We can get the material of the gameObject by
GetComponent<Renderer>().material
.
- Create
Direct Light
which creates the global light in the scene. The position of direct light will not affect the lighting effect while the angle define the global direction of light. - Create
Spot Light
which creates a cone light in the scene.Inner / Outer angle
defines the angle attenuation, which issaturate((d-cos(r_o))/(cos(r_i)-cos(r_o)), min=0, max=1)
.
- The sound of the scene is listened by
Audio Listener
. There could be one and only oneAudio Listener
in the scene. By default, it is within theMain Camera
. - Attach a sound affect to a game object via
Add Component / Audio Source
. Select the sound file inAudioClip
. MarkLoop
for continuous play'''. 2D / 3D effect is controlled bySpatial Blend
. In3D Sound Settings
, we can activateDoppler Level
and customize theVolume Rolloff
, which reflects the relationship between distance and ratio of volume. AudioClip
is the variable type of sound file.
- The camera follows the player in a third person manner by a script which update the position of the camera according to the position of a GameObject reference. The angle of camera is controlled by user's mouse.
- Object is controlled by the player through
Input
. Detailed introduction ofInput
can refer to Section:Script & API / Input. - Define behaviour that will be periodically happened as prefab. The prefab can store variables of its own.
- We can set the life time
t
of an objectobj
by implementingDestroy(obj, t)
inStart()
. - Instantiate new object relative to another object via
Instantiate(Object obj, Transform parent)
, in which case the bahaviour of prefab is also relative to its parent. - Implement the automatic shooting by explicit time counting,
InvokeRepeating()
,StartCoroutines()
that invokes the function to instantiate the bullet repeatedly. - Implement jump by applying force to the
Rigidbody
. We should get user input inUpdate()
and apply physics inFixedUpdate()
.
- Add
Animator
to GameObejct which point to ananimation controller
which defines the configuration and transition of meta animations andavatar
which defines the structure, e.g. the bone structure, of the character. - We can define animation state and their transitions in Animator Editor. One state is set as default state which serves as the first state when the animation starts.
- We can blend animation with
Blend Tree
which interpolates two or more animations via defined parameter. The specific blending method is defined byBlend Type
. In this scene, we blend idle, walk in 4 directions and run forward using2D Freeform Directional
.2D Freeform Directional
allows multiple animations in the same direction, e.g. in our case walk forward and run forward, while2D Simple Directional
does not allow such case.2D Freeform Cartesian
is best used when the parameter does not represent the direction. For more details, click here. - The transition has one attribute -
Has Exit Time
which determines if the previous animation plays to an end when the transition condition is satisfied. - The controller script can communicate with Animator by first
GetComponent<Animator>()
and use methods likeSetFloat()
to change the parameters in animator controller. - We can modify the structure and kinematics of the animator components by
OnAnimatorIK(int layerIndex)
. It should be noted that theIK Pass
option of the layer in animator controller should be chosen.
- The UI panel is realized by
Canvas
. - We can add text by
+ / UI / Text - TextMeshPro
and for other UI compenents similiarly.TextMeshPro
is an improvement of default text using a different rendering techniqueSDF
, which is based on the principle of rendering a Font Atlas at a high resolution. Resize the text will not lead to blur. Still, we can control the visual effect of text without recreating new font. We can combineRich Text
withTextMeshPro
. Even material, namedMaterial Preset
can be added to text to give it a special effect. For more details of the difference betweenTextMeshPro
and default text, click here Button - TextMeshPro
is a Button that usesText - TextMeshPro
, which is equivalent to create default button and replace text child withText - TextMeshPro
.- To use
TextMeshPro
in C#, addusing TMPro
. - We can anchor the text so that the position is relatively still with regard to the anchor position regardless of the size of the game window.
- We can make the text unaffected by the text box by choosing
Wrapping
as disable. - We can control the visibility of the text and other UI components by controlling their alive status.
- Button interaction can be defined through editor by
Button / OnClick()
, which receives a accessable (usually public) function as the behavior after being clicked. Additionally, we can define the click behavior throughbutton.onClick.AddListener()
which can bring us less limitation and really decide what function to be called. But remember to remove the listener afterwards. - Scene is managed by
SceneManager
, which stores the information as well as behavior of the scene.
- Include particle systems with different demo effect.
- Bloom post processing can be achieved by first adding
Volumn
component and addPostprocessing > Bloom
. - (TODO, more effects can be played with...)
- In a 2D template project, the camera is orthographic by default. The canvas is parallel to XY-Plane where the the width is measured in
X
and height is measured inY
. Since the camera is orthographic,Z
does not affect the size of a game object, however, affected the visibility among multiple objects. What's more, only when theZ coordinate
of an object is within the camera clipping planes will it be seen by camera. - We can alter the scene view between 2D and 3D via
2D Button
in the tool bar of scene view so as to visualize the depth of objects. - We can alter the scene view between perspective and isometric via the icon at right top beneath the coordinate icon, which cooresponds to the perspective camera and orthographic camera.
- The basic 2D object is called Sprite. We can define the specific sprite shape in
Sprite Renderer / Sprite
. We can addRigidbody 2D
alike what we do to 3D meshes. One thing different from 3D mesh is that, the collider is added to 3D mesh by default, but it's not the case in 2D case. Thus, we have to add collider with the specific shape type to the sprite with which we can useOnCollideXXX()
. ThePolygon Collider
provides the tight(est) bound.
-
The Script name has to be identical with the class name. (Automatically done via
Add Component / New Script
.) Therefore, script name, the same as the class name, is also a valid type in C# script, e.g., we can useGetComponent<ScriptName>()
to get the reference to the class object to get the public fields and use the public methods. -
MonoBehaviour: The base class from which every Unity script derives. For detailed API, click here
- Start(), Update(), ... are
Event Functions
in Unity. Running a Unity script executes a number of event functions in a predetermined order, for details click here. ThePhysics
, which containsOnTriggerXXX(), OnCollideXXX(), ...
is seperated fromGame Logic
, which containsUpdate(), LateUpdate(), ...
. Therefore, an GameObject withRigidBody
which gives physics can also be affected byUpdate()
. - Invoke a function
f
with time delayt
viaInvoke(f, t)
. Ift == 0
, just call the function directly. Other invoke related methods areInvokeRepeating(f,t,interval)
which invoking function repeatedly,IsInvoking(f)
which checks if a function is being invoked andCancelInvoke()
which cancel all invokes in this. *(However, for better performance and maintability, use Coroutines instead.) - Coroutine combines the function of
Invoke()
andInvokeRepeating()
with more flexibility. For instance,InvokeRepeating()
can only repeat the invoke with fixed time interval but Coroutine is able to dynamicaaly change the time interval.StartCoroutine(IEnumerator routine)
directly receives the function callroutine(...)
which returns an IEnumerator object in the formatyield return xxx;
. Specifically, we can yield returnWaitForSeconds(float timeInterval)
to allow the coroutine to resume on the first frame aftertimeInterval
seconds has passed. OnCollisionXXX(Collision collision)
is invoked whenever there is a penetration between collider and collider.OnCollisionEnter(Collision collision)
is invoked whenever there is a penetration between collider and trigger / trigger and trigger. For more details, click hereOnAnimatorIK(int layerIndex)
allows to update the kinematics of animation components, like bones, in a desired manner. It should be noted that theIK Pass
option of the layer in animator controller should be chosen.LateUpdate()
is the last invoked event function in the Game Logic part, which is invoked after the internal animation update. Thus we can use it to update the joint in animation as we desired.OnEnable()
is called when the object becomes enabled and active.OnDisable()
is called when the behaviour becomes disabled.- We detect the interaction between our mouse and collider with
OnMouseDown()
when we press the mouse while colliding,OnMouseUp()
when we release the mouse while colliding,OnMouseDrag()
when we keep pressing the mouse while colliding,OnMouseEnter()
when the mouse collider enters the object collider,OnMouseExit()
when the mouse collider exits the object collider,OnMouseOver()
when the mouse collider stays colliding with the object. They are detected simultanuously, i.e., we can conclude that whenOnMouseDrag()
is called,OnMouseOver()
must can called as well. These functions should be declared in the script which is the component of the target gameObject whose collider is what we want to interact with. Also, make sure the gameObject has its collider, whether trigger or not is not important.
- Start(), Update(), ... are
-
Object: Base class for all objects Unity can reference. Therefore, for static methods, we do not have to explicit write prefix
Object.
. For detailed API, click here.- Every object in unity can transfer to string via
ToString()
. - We can destroy an object
obj
with time delayt
viaDestroy(Object obj, float t = 0.0f)
. - We can instantiate an object
original
viaInstantiate(Object original)
. We can specify the parent oforiginal
viaTransform parent
parameter which is suppoted by some overloads, otherwiseoriginal
will not have parent. We can specifyVector3 position
andQuaternion rotation
in world coordinate, otherwiseoriginal
is instantiated as the default position and rotation of the mesh or prefab, either in world coordinate or parent coordinate. - We can find the first active object by
FindObjectOfType<T>
all objects of typeT
byFindObjectsOfType<T>
.
- Every object in unity can transfer to string via
-
GameObject: Base class for all entities in Unity Scenes. For detailed API, click here.
- We can find an GameObject by name via
Find(string name)
.name
with '/' can indicate a hierarchy path name. Note thatFind(string name)
returns exactly one GameObject, but Unity allows duplicate names for different GameObjects. So it would be better to give different absolute name to different GameObjects and we can organize the same kind of GameObjects with the same tag and fetch the list of them withFindGameObjectsWithTag(string tag)
. - We activate / deavtivate the GameObject by
SetActive(bool flag)
. A GameObject is active only when the it and all its direct and indirect parents are active, therefore activating a GameObject whose parents are inactivate will not actually active it.OnEnable()
orOnDisable()
are called as the GameObject receivedSetActive(true)
orSetActive(false)
. Activating / deactivating a GameObjetc is useful, e.g., when only one object is at most used occationally.
- We can find an GameObject by name via
-
Transform: Position, rotation and scale of an object. Transform follows the hierarchy of the scene. Every Transform can have at most one parent and several children. Transform is relative to the parent transform, which can be visualized by
Pivot Local Coordinate
. For detailed API, click here.- Get the parent by
transform.parent
. Get children number bychildCount
and get children bytransform
which is iterable, or byGetChild(int index)
. We can also get a child with its name byFind(string name)
. - To relationship between local and world coordinate is
transform.parent.localToWorldMatrix.MultiplyPoint3x4(transform.localPosition)) == transform.localToWorldMatrix.MultiplyPoint3x4(new Vector3(0.0f, 0.0f, 0.0f)) == transform.position
andtransform.parent.worldToLocalMatrix.MultiplyPoint3x4(transform.position)) == Matrix4x4.TRS(transform.localPosition, transform.localRotation, transform.localScale).MultiplyPoint3x4(new Vector3(0.0f, 0.0f, 0.0f))) == transform.localPosition
. The reason why we usetransform.parent.localToWorldMatrix
is becasuelocalPosition, localRotation (localEulerAngles), localScale
is all relative to the parent transform. ViaMatrix4x4.TRS(transform.localPosition, transform.localRotation, transform.localScale)
, we get the relative tranform between child and parent. position, rotation (eulerAngles), scale
store the information in the world coordinate.- Update either
eulerAngle (Vector3)
orrotation (Quaternion)
will make the object rotate and update the other one automatically. However, explicitly updatingeulerAngle (Vector3)
might result in Gimbal Lock.rotation (Quaternion)
, on the other hand, does not suffer from Gimbal Lock, but cannot rotate over 180 degree, (recall that quaternion rotates in the least distance, which means rotation over 180 degree will actually rotate in the other direction instead.) Thus, useRotate()
method instead of explicit modify these fields and try to avoid large degree rotation. For more details, click here. - Transform also stores the tag of the gameObject.
- Retrieve the local X, Y, Z direction in world coordinate, a unit vector, by
right, up, forward
. Since it is in the local coordinate, it take the rotation of the object in the world coordinate as well. If we would like to retrieve the global X, Y, Z direction, usingVector3.[Static Properties]
. - For
Translate(), Rotate()
,Space.Self
is used as default coordinate. We can specify as, for instance, Space.World according to the signature of the methods. E.g.transform.Translate(Vector3.forward, Space.Self) == transform.Translate(transform.forward, Space.World)
.
- Get the parent by
-
Rigidbody: Control of an object's position through physics simulation. For detailed API, click here.
- Apply force and torque via
AddForce()
,AddTorque()
where the parameterforce
andtorque
is in world coordinate orAddRelativeForce()
,AddRelativeTorque()
where the parameterforce
andtorque
is in self coordinate. The second parameter isForceMode
, includingForce
which applies the forcef=m*a
,Acceleration
which applies the accelerationa
,Impulse
which applies the impulsej=m*dv
,VelocityChange
which applies the diff velocitydv
.
- Apply force and torque via
-
Physics: Global physics properties and helper methods. For detailed API, click here.
- Simulate a ray in the scene for collision detection.
Raycast(...)
returns true when the ray intersects any collider, otherwise false.Raycast(...)
has several signatures and those that has parameterout RaycastHit hitInfo
can store more information about where the closest collider was hit.
- Simulate a ray in the scene for collision detection.
-
RaycastHit: Structure used to get information back from a raycast. For more detailed API, click here.
-
Collision: Describes a collision with a specific GameObject. For more details, click here.
- Collision is linked with a specific GameObject. Therefore, the following attribute
gameObject
,relativeVelocity
,rigidbody
,transform
is all related to this collided GameObject and ther are all ReadOnly. - However, even if there is only one collided GameObject, there can be multiple contact points.
contactCount
tells the number of contact points.contacts
returns an array of ContactPoint. From insideOnCollisionStay
orOnCollisionEnter
you can always be sure that contacts has at least one element. However, avoid directly retrievingcontacts
, useGetContact(int index)
to get a certain ContactPoint.
- Collision is linked with a specific GameObject. Therefore, the following attribute
-
ContactPoint: Describes a contact point where the collision occurs with property
normal
,point
,seperation
and two colliders -thisCollider
andotherCollider
.normal
andpoint
are described in world coordinate. For more details, click here. -
Animator: Interface to control the Mecanim animation system. For detailed API, click here.
- Set parameters in controller by
SetFloat(), SetInteger(), SetBool(), SetTrigger()
which corresponds to the four data types in animator controller. - We can rotate the bone and its child joint by
SetBoneLocalRotation(HumanBodyBones humanBoneId, Quaternion rotation)
.HumanBodyBones
provides enums for predefined joint in humanoid avatar, for more details, click here.rotation
is measured in local coordinate, which is equalavent to what we get bytransform.localRotation
.
- Set parameters in controller by
-
AudioSource: A representation of audio sources in 3D. For more details, click here.
- The default clip is saved in
clip
. The volume is saved involume
. If loop is saved inloop
. - We can
Play()
/Pause()
/UnPause()
/Stop()
the AudioClip saved inclip
. - Play the clip with a delayed time via
PlayDelayed(float second)
- Play a temporary clip via
PlayOneShot(AudioClip clip, float volumeScale = 1.0F)
, it is not looped. After the clip is over, the default clip is resumed.
- The default clip is saved in
-
Input: Interface into the Input system. For detailed API, click here.
- Get the value of the virtual axis via
Input.GetAxis()
in continuous field in [-1,1] orInput.GetAxisRaw()
in discrete field in {-1 ,0 ,1}. To set up input or view the options foraxisName
viaEdit / Project Settings / Input Manager
. The options include the trigger event for positive and negative reactions. It is proper for retrieving user's mouse and joystick movement. - Get specific key interaction, including keyboard, mouse and joystick, via
GetKeyDown(...)
which detects if the user starts pressing one key down,GetKey(...)
which detects if the user keeps holding one key down,GetKeyUp(...)
which detects if the user starts releasing one key up. This brings more flexifibility than the previous introduced virtual axis. - Gey specific mouse interaction via
GetMouseButtonDown(...)
which detects if the user starts pressing one mouse button down,GetMouseButton(...)
which detects if the user keeps holding one mouse button down,GetMouseButtonUp(...)
which detects if the user starts releasing one mouse button up. This is equivalent toGetKeyXXX()
whose parameter isKeyCode.MouseX
.
- Get the value of the virtual axis via
-
Material: Describe the property of material. We can get the material of a gameObject by
Renderer.material
For detailed API, click here.- Get the attribute of texture by
mainTexture, mainTextureOffset, mainTextureScale
. These properties can be read as well as modified.
- Get the attribute of texture by
-
KeyCode: Key codes that map to physical key, including keyboard, mouse and joystick. For detailed API, click here.
-
Time: The interface to get time information. For detailed API, click here.
- deltaTime: The passed time of every frame.
- frameCount: The total number of passed frames.
- timeScale: The scale of time.
1.0f
is the normal speed,0.5f
slow the time to half and0.0f
freeze the time which can be used as the way of pausing the game.
-
Random: Generate random data. For detailed API, click here.
- Generate Vecotr4-like Color via
ColorHSV
. - Generate random float number via
Range(float min, float max)
. - Generate random unit vector via property
onUnitSphere
.
- Generate Vecotr4-like Color via
-
Debug: Class containing methods to ease debugging while developing. For detailed API, click here.
- Print a message at the bottom of game view via
Log()
.
- Print a message at the bottom of game view via
-
Mathf: A collection of common math functions. For detailed API, click here.
-
TextMeshPro: Interface to TextMeshPro component. For detailed API, click here
- To interact with
TextMeshPro
, using the interfaceTMPro
in the C# script. - We can get the gameObject of the UI component by
gameObject
property, then we can control it using the interface of gameObject in Unity.
- To interact with
-
Button: Class in UnityEngine.UI. A standard button that can be clicked in order to trigger an event. For detailed API, click here
- We can determine the behavior of button clicking using 2 methods - Editor /
button.onClick.AddListener()
. Editor implements a static binding which is faster whichbutton.onClick.AddListener()
implements a dynamic binding which enables us to choose the behavior via script with less limitations, e.g., more conditions. A good advice of coding is to callAddListener()
inOnEnable()
andRemoveListener()
inOnDisable()
.
- We can determine the behavior of button clicking using 2 methods - Editor /
-
Cursor: Interface for setting the cursor (mouse pointer). For detailed API, click here.
lockState
determines whether the hardware pointer is locked to the center of the view, constrained to the window, or not constrained at all.CursorLockMode.None
makes the cursor unmodified,CursorLockMode.Locked
makes the cursor lock at the center of the game window,CursorLockMode.Confined
constrain the cursor inside the window.visible
determines whether the cursor is visible. Note thatCursorLockMode.Locked
implicitly makes the cursor invisible.SetCursor(Texture2D texture, Vector2 hotspot, CursorMode cursorMode)
set cursor with texture.
-
SceneManager: API for Scene management at run-time. For detailed API, click here.
- We can switch the scenes by
void LoadScene(int sceneBuildIndex)
orvoid LoadScene(string sceneName)
. The index of the scenes can be found inFile / Build Settings
- We can get the current active scene by
GetActiveScene()
. The returnedScene
type has properties, e.g.,buildIndex
,name
ect.
- We can switch the scenes by
-
ParticleSystem: Interface for ParticleSystem, For detailed API, click here.
- The properties for every aspect in the edit panel corresponds to the specific attribute of
ParticleSystem
class. - Play and stop the effect by
Play()
andStop()
.
- The properties for every aspect in the edit panel corresponds to the specific attribute of