UNITY Lesson 1: Table of Contents
1a: Get Unity; Get Started
1b: Add a Character
1c: An Introduction to Scripting in C#
1d: Uniform Motion in Any Direction
1e: Move To a User-Clicked Location
1f: Background and Falling Rocks

UNITY Lesson 1d:
Uniform Motion in Any Direction

Create a Child for Wolf
To fully illustrate new concepts, we need Wolf to have a child:
  • Right-click on Wolf in Hierarchy;
    select 2D Object-Sprite.
  • Name your new sprite LittleWolf;
    give it a colorful icon.
  • Use the same image for LittleWolf that you used for Wolf, but make it smaller (use the scale tool).
    Note: If you click on Wolf's Inspector-Sprite Renderer-Sprite value, it will locate the image you used.
  • Set Transform-Position for LittleWolf:
    • set $\,x\,$ and $\,y\,$ to $\,1\,$
    • set $\,z\,$ to $\,0\,$
  • Rotate Wolf a bit:
    set Transform-Rotation-Z to (say) $\,40\,.$ (This is degrees.)
    Note: in Scene View, LittleWolf is rotated by the same amount.
  • As needed, adjust Wolf's position so that both Wolf and LittleWolf are fully inside the Camera Preview.
    Note: in Scene View, LittleWolf moves along with Wolf.
  • Create a tag for LittleWolf:
    • Inspector-Tag dropdown menu-Add Tag
    • click the plus (+) sign under Tags
    • type in ChildOfWolf
    • select LittleWolf-Inspector-Tag-ChildOfWolf
    This tag will be used to ‘find’ LittleWolf in our code.
You should have something similar to (1a) and (1b) at right.

(1a) create a child for Wolf



(1b) settings for LittleWolf
Child/Parent/Ancestor
The ‘relationship’ language used for nested GameObjects should feel natural:
  • LittleWolf is called a child of Wolf .
  • Wolf is called a parent of LittleWolf .
  • More generally, Wolf is called an ancestor of LittleWolf .
    Ancestors are a GameObject's parent, that parent's parent, and so on (as needed) up the Hierarchy.
Rectangular Coordinate Systems
Quantifying (i.e., assigning numbers to) any movement/position requires a coordinate system.
A coordinate system uses one or more numbers (usually called coordinates) to uniquely determine position.

The most common type of coordinate system is a rectangular coordinate system.
A rectangular coordinate system consists of intersecting number lines (called the axes) that are perpendicular to each other.
The single point that all axes have in common is called the origin of the rectangular coordinate system.

It's important to note that every number line has a specified unit, determined by the distance between (say) $\,0\,$ and $\,1\,.$
By knowing where is $\,1\,$ located in relation to $\,0\,,$ every real number can then be uniquely positioned on the number line.

Thus, every rectanglar coordinate system has these vital components (see (1) at right):
  • perpendicular axes with a specified origin
  • Units that indicate what ‘$\,1\,$’ means in each of the coordinate directions.
    In general, there can be different units in each of the coordinate directions.
    That is, ‘$\,1\,$’ in the $\,x\,$-direction may be different than ‘$\,1\,$’ in the $\,y\,$-direction,
    which may be different than ‘$\,1\,$’ in the $\,z\,$-direction.
Rectangular coordinate systems basically create an (invisible) rectangular ‘grid’.
Together, the axes/origin/units allow you to uniquely position any point.
The entire set of ‘coordinate-endowed’ points is often called a ‘space’.
Situations That Use More Than One Rectangular Coordinate System
Sometimes (like in Unity game development!) you find yourself in a situation where

more than one rectangular coordinate system is simultaneously being used to position objects.

In such cases, you
must be clear as to which coordinate system you are using.
‘Relative To’
The phrase ‘relative to’ is used in the context of ‘competing’ coordinate systems.
‘Relative to ...’   means   ‘using the axes/origin/units of ...’

Here's an example.
Let's name two different 2D rectangular coordinate systems $\,A\,$ and $\,B\,.$ See (2) at right.
Either coordinate system equally well assigns unique ‘names’ to every point in the plane.
However, points get different names, depending on which coordinate system we use.

Consider the coordinates $\,(1,2)\,.$
To plot this point relative to $\,A\,$:
  • Go to the origin for $\,A\,.$
    Move one unit in the positive direction of $\,x_A\,$ (using the $\,x_A\,$ units).
    Move two units in the positive direction of $\,y_A\,$ (using the $\,y_A\,$ units).
    You end up at the point labeled $\,(1,2)_A\,.$
To plot this point relative to $\,B\,$:
  • Go to the origin for $\,B\,.$
    Move one unit in the positive direction of $\,x_B\,$ (using the $\,x_B\,$ units).
    Move two units in the positive direction of $\,y_B\,$ (using the $\,y_B\,$ units).
    You end up at the point labeled $\,(1,2)_B\,.$
Notice that $\,(1,2)_A\,$ and $\,(1,2)_B\,$ are different points in the plane.

(1) common features of a rectangular coordinate system


(2) plotting points relative to different coordinate systems
UNITY COORDINATE SYSTEMS
Unity uses several different rectangular coordinate systems.
Three of them are discussed next: World Space, Object Space, and Local Space.
(There are more, which will be discussed as needed.)

For each space, we must be clear about its origin, the positive directions for the axes, and the units for the axes.
Furthermore, whenever you're presented with coordinates like $\,(x,y,z)\,,$ you must be clear what space you're using.
WORLD SPACE
All GameObjects live in World Space.
World Space is three-dimensional (3D).

WorldUnits
Go to Scene View in the Unity Editor; make sure that Gizmos-Show Grid is checked.
The distance between two consecutive grid lines (horizontal or vertical) is one world unit, which will be notated as  WorldUnit .
See (1) at right.
Indeed, all three axes ($\,x\,,$ $\,y\,$ and $\,z\,$) in World Space use the same units.

By (say) zooming, you can make  WorldUnits  appear bigger or smaller.
If convenient, you can think of  WorldUnits  as representing (say) meters, or inches, or any distance unit.
However, a  WorldUnit  is inherently unitless, and may render as different sizes on different platforms and in different situations.

World Space Origin
The World Space origin is $\,(0,0,0)\,.$
Since you can move around in a scene, the World Space origin can appear in different locations on the screen.

Positive Directions for World Space Axes
By default, Unity uses a left-handed rectangular coordinate system, with:
  • positive $\,x\,$ to the right
  • positive $\,y\,$ up
  • positive $\,z\,$ into the screen
Remember: in Unity World Space, one unit is the same in all three directions.

Left-handed means the following:
  • take your left hand
  • point your fingers in the positive $\,x\,$ direction
  • curl your fingers in the positive $\,y\,$ direction
  • then, your thumb points towards the positive $\,z\,$ direction

(1) World Space
OBJECT SPACE
Every GameObject has its own Object Space (so the name is appropriate).
Object Space is three-dimensional, but in 2D games we can largely ignore the $\,z\,$-axis.

If you select a GameObject and (say) make the Move Tool active,
you can see the perpendicular axes that define that GameObject's Object Space.
See (2ab) at right.
In these images, the $\,x\,$-axis is red and the $\,y\,$-axis is green.
The arrows point in the positive directions.

Whenever a GameObject is positioned (relative to any other rectangular coordinate system),
it is the the GameObject's Object Space origin that gets placed at the specified point.
See (2c) at right.
Note that this may or may not ‘center’ the GameObject at the specified point.

If you attach (say) a sprite to a GameObject, Object Space is used to render the pixels of the sprite.

(2a) Wolf 's Object Space

(2b) LittleWolf 's Object Space

(2c) Wolf with
world coordinates
set to $\,x = 0\,$ and $\,y = 0\,$;
this is where Wolf 's
Object Space origin
gets put.
If you rotate a GameObject via its Inspector-Transform-Rotation fields, then that GameObject's Object Space origin is the pivot point for the rotation. See (2de) at right.
(2d) LittleWolf, before rotation

(2e) LittleWolf, after a $\,-45^\circ\,$ rotation
A GameObject's Object Space can't be used to position itself, since Object Space moves with its GameObject.
A GameObject's Object Space is vitally important to the GameObject's children (and children of children, etc.)
Keep reading!
LOCAL SPACE
A GameObject's Local Space is the Object Space of its parent.

For GameObjects at the top level of Hierarchy, Local Space is the same as World Space.

For a given GameObject, in the Unity editor:

Inspector-Transform-Position and
Inspector-Transform-Rotation
always show Local Space.

Here are a couple examples (again, ignoring $\,z\,$):
  • Wolf is at the top level in Hierarchy.
    Thus, Local Space for Wolf is the same as World Space.
    Set Wolf-Inspector-Transform-Position to $\,(3,-2)\,.$
    Wolf is positioned at $\,(3,-2)\,$ in World Space, as shown in (3a) at right.
    Here, both $\,3\,$ and $\,-2\,$ are  WorldUnits , since we're using World Space.
  • LittleWolf has parent Wolf.
    Thus, Local Space for LittleWolf is the Object Space for Wolf.

    We already know the origin for Wolf 's Object Space.
    Here is an important fact to know about Local Space axes units:

    A GameObject's Local Space axes
    are scaled by the Transform-Scale values
    of all the ancestors of the GameObject.

(3a) Wolf-Inspector-Transform-Position-X set to $\,3\,$
Wolf-Inspector-Transform-Position-Y set to $\,-2\,$

(Red tick marks showing  WorldUnits
have been added for your convenience.)

The table below gives some sample calculations.
Verify these calculations (as desired) in the Unity Engine, or just study the table.
The scale values in this table will distort your sprites; they are merely for illustrative purposes.

All GameObject rotations have been set to $\,(0,0,0)\,,$ to simplify calculations.

GameObject Hierarchy info Transform-Position values Transform-Scale values World Space Coordinates
Wolf top level (1a) $$(-5,-1,-9)$$ (2a) $$(3\,,\,2\,,\,1)$$ (3a) $$(-5,-1,-9)$$
LittleWolf child of Wolf (1b) $$(1.5\,,\,0.5\,,\,0)$$
(relative to Wolf)
(2b)
$$(0.6\,,\,0.7\,,\,0.8)$$
(3b)
Below, the $\,\color{red}{\bigstar}\,$ operation between (2a) and (1b) denotes component-by-component multiplication. $$ \begin{align} \text{(3a)} \ &+\ \text{(2a)}\color{red}{\bigstar}\text{(1b)}\cr &= (-5,-1,-9) + (3\,,\,2\,,\,1)\color{red}{\bigstar} (1.5\,,\,0.5\,,\,0)\cr &= (-5,-1,-9) + (3\cdot 1.5\,,\, 2\cdot 0.5\,,\, 1\cdot 0)\cr &= (-5,-1,-9) + (4.5\,,\,1\,,\,0)\cr &= (-5+4.5\,,\, -1+1\,,\, -9+0)\cr &= (-0.5\,,\,0\,,\,-9) \end{align} $$
LittlestWolf child of LittleWolf (1c) $$(1\,,\,1\,,\,1)$$
(relative to LittleWolf)
$$ \text{not needed} $$ $$ \begin{align} \text{(3b)} \ &+\ \text{(2a)}\color{red}{\bigstar}\text{(2b)}\color{red}{\bigstar}\text{(1c)}\cr &= (-0.5\,,\,0\,,-9) + (3\,,\,2\,,\,1)\color{red}{\bigstar} (0.6\,,\,0.7\,,\,0.8)\color{red}{\bigstar}(1\,,\,1\,,\,1)\cr &= (-0.5\,,\,0\,,-9) + (3\cdot 0.6\cdot 1\,,\, 2\cdot 0.7\cdot 1\,,\, 1\cdot 0.8\cdot 1)\cr &= (-0.5\,,\,0\,,-9) + (1.8\,,\,1.4\,,\,0.8)\cr &= (-0.5+1.8\,,\, 0+1.4\,,\, -9+0.8)\cr &= (1.3\,,\,1.4\,,\,-8.2) \end{align} $$

See the table above for World Space coordinate calculations.
transform.position
In Unity C# scripts,  transform.position  always returns the World Space coordinates of any GameObject.

Use the table above to set Wolf and LittleWolf 's
Transform-Position and Transform-Scale values.

Write the script shown in (1a), and pull it onto Wolf.

Note that in line 11, LittleWolf 's tag is used to  ‘find’  LittleWolf.

See (1b) at right for the script output.
The World Space coordinates for LittleWolf are indeed as predicted!

(1a) script to explore world coordinates for parent (Wolf) and child (LittleWolf)
a text file containing this ExploreDifferentSpaces code


(1b) output from the code above
Understanding Frame Rate Dependence
The units of our previously-coded motion are ‘WorldUnits per frame’.
However, Unity frame rate is not constant:
  • Frame rate can change from platform-to-platform.
    Roughly, a platform is a hardware/software combination.
    A platform example is a desktop computer (hardware) running Windows (software).
  • Even on the same platform, frame rate can change from moment to moment.
    For example, a heavy load on the CPU (Central Processing Unit) can result in a slower frame rate.
A non-constant frame rate can cause:
  • movement to appear jerky
  • movement speed to be different on different platforms
Unity offers a simple solution to this problem, as follows.
Time.deltaTime
Time.deltaTime  gives the time (in seconds) between the current frame and the previous frame.

The current frame rate (which changes from frame-to-frame) is: $$\text{current frame rate} \ =\ \frac{1}{\text{Time.deltaTime}}$$ The simple program in (1) at right will help you explore:

How much variation is there in the
number of frames rendered per second
during Unity game play?

Below (2a–2c) are some console snapshots after I dragged TestScripts.cs onto Wolf, and then played the game:

(1) code to better understand frame rate and  Time.deltaTime
a text file containing this TestScript code

(2a) There is some ‘start-up’ slowness.

(2b) With nothing much going on,
the frame rate was fairly constant for me.

(2c) I started playing a DVD to ‘stress’ the system.
ILSpy
For experts only:
Ray uses ILSpy to decompile C# code.
Among other things, it shows the actual code that defines built-in methods.
Notes on the Program in (1)
In what follows, green entries specialize concepts to the code shown in (1).
  • Field Declarations (lines 8–10)
    Fields are used to store data that must persist through multiple method calls.
    Only  FrameInterval  was made public; you might want to tweak it from inside the Unity Editor.
  • Delete Start()
    Start() isn't needed in this script; delete it.
  • Mathf.Max  and Mathf.Min  Math Functions
    These are  UnityEngine  methods.
    The ‘ f ’ stands for ‘function’.
    They take two  float  inputs, and return a  float  output.
    • Mathf.Max(a,b)
      Returns the maximum of $\,a\,$ and $\,b\,$:
      If $\,a\ge b\,,$ return $\,a\,.$
      Otherwise, return $\,b\,.$
    • Mathf.Min(a,b)
      Returns the minimum of $\,a\,$ and $\,b\,$:
      If $\,a\le b\,,$ return $\,a\,.$
      Otherwise, return $\,b\,.$
  • Finding a Maximum Value
    Suppose you want to find the maximum (largest) number in a finite set of positive numbers.
    (We want the maximum frame rate, over all calls to  Update()  while playing our game.)
    • Start with zero.
      Line 8: _maxFrameRate  is declared, and initialized to $\,0\,$
    • Pick up a first positive number from your set; compare it to zero.
      It's guaranteed to be greater than zero, since any positive number is greater than zero.
      It becomes your new max.
      Line 16: _maxFrameRate is set to the first  currentFrameRate  value on the first  Update()  call
    • Go through each remaining number in the set: compare with the current max, and replace as needed.
      Line 16: On each subsequent call to  Update(),  currentFrameRate  is compared to  _maxFrameRate .
      If  currentFrameRate  is greater, this new value is stored in _maxFrameRate.
  • Finding a Minimum Value
    Suppose you want to find the minimum (smallest) number in a finite set of positive numbers.
    (We want the minimum frame rate, over all calls to  Update()  while playing our game.)
    • You can't start with zero, since  Mathf.Min(0,any positive number)  is zero.
      Instead, start with a number that is greater than everything in your set.
      Line 9: _minFrameRate  is declared, and initialized to  float.MaxValue (which is the largest possible number that can be represented in a float)
    • Pick up a first positive number from your set; compare it to your BIG number.
      It's guaranteed to be less than your BIG number.
      It becomes your new min.
      Line 17: _minFrameRate is set to the first  currentFrameRate  value on the first  Update()  call
    • Go through each remaining number in the set: compare with the current min, and replace as needed.
      Line 17: On each subsequent call to  Update(),  currentFrameRate  is compared to  _minFrameRate .
      If  currentFrameRate  is less, this new value is stored in _minFrameRate.
  • The Remainder Operator  %
    The remainder operator is useful whenever you want some action to take place on every multiple of a number.
    The multiples of $\,n\,$ are: $\,n\,,$ $\,2n\,,$ $\,3n\,,$ $\,4n\,,$ ...
    In some contexts, the remainder operator is called the modulo operator.

    By definition,  a % b  returns the remainder when $\,a\,$ is divided by $\,b\,.$

    Note:
    The symbol  %  is the percent symbol, but it is not read aloud as percent in this context.
    Instead, you can verbalize  ‘a % b’  as either  ‘a mod b’  or  ‘a, remainder operator, b’ .

    For example:
    • 7 % 2  returns  1 , since $\,7 = 3\cdot 2 \color{red}{+ 1}\,$
      Two goes into seven three times, with a remainder of one.
    • 8 % 2  returns  0 , since $\,8 = 4\cdot 2 \color{red}{+ 0}\,$
      Two goes into eight four times, with a remainder of zero.
      When $\,a\,$ is a multiple of $\,b\,,$ the remainder (when dividing $\,a\,$ by $\,b\,$) is zero.
    Line 19:  Time.frameCount  returns the total number of frames rendered since the beginning of game play.
    FrameInterval  (declared and initialized on line 10) gives the number of frames to wait before printing out statistics and starting over.
    Time.frameCount % FrameInterval  returns zero on all multiples of  FrameInterval .
  • The Equality Operator  ==
    Here is the official C# documentation on comparison operators and equality operators.
    (FYI, the full specifications are here.)

    a == b  returns  true  if  a  equals  b , and  false  otherwise.
    Line 19:  Time.frameCount % FrameInterval == 0  returns  true  whenever the frame count hits a multiple of  FrameInterval.
    In this case, the body of the  if() { }  statement is executed.
  • Local Variables
    A variable declared inside a method is called a local variable.
    (Note: There are other places that local variables can appear.)

    A local variable exists only in the block in which it is declared.
    If you try to use it elsewhere, you'll get an error!

    Local Variable Declaration
    To declare a local variable: give the type, followed by the variable name, followed by a semicolon.
    A declaration assigns the appropriate amount of memory for the variable type.
    By C# convention, local variables should begin with a lowercase letter.
    Example:
    int bookCount;

    Local Variable Initialization
    After a local variable has been declared, then it can be initialized.
    Initialization puts a value into the assigned memory.
    Example:
    bookCount = 23;

    Local Variable Combined Declaration/Initialization
    You can simultaneously declare and initialize local variables.
    Example:
    int bookCount = 23;

    Line 15:  float currentFrameRate = 1 / Time.deltaTime;
    Here, the local variable  currentFrameRate  is both declared and initialized.


Fields versus Local Variables
There are several important differences between fields and local variables.
For example:
Getting Rid of Frame Rate Dependence
Let  s  be a nonnegative real number, representing some number of  WorldUnits .
Our desired uniform speed for a GameObject is  s   WorldUnits per second.

Here's the problem with our earlier (frame rate dependent) code:
With a vector increment of (say)  s*(1,0,0) = (s,0,0) , the rate of advance in the $x$-direction for a single frame rendering is $$ \frac{s\color{red}{\text{ WorldUnits }}}{\text{Time.deltaTime}\color{red}{\text{ sec}}} = \left(\frac{s}{\text{Time.deltaTime}}\right) \frac{\color{red}{\text{WorldUnits}}}{\color{red}{\text{sec}}} $$ (Here, units are shown in red.)
Note that the magnitude of this rate is $\ \frac{s}{\text{Time.deltaTime}}\ $, which is not our target value of  s .

Here's the simple solution:
If we instead use a vector increment of    s*Time.deltaTime*(1,0,0) , then every single frame rendering yields $$ \frac{s\cdot\text{Time.deltaTime}\color{red}{\text{ WorldUnits }}}{\text{Time.deltaTime}\color{red}{\text{ sec}}} = s \ \frac{\color{red}{\text{WorldUnits}}}{\color{red}{\text{sec}}}\ , $$ since   Time.deltaTime  cancels out!

Multiplying the desired speed (in WorldUnits per second) by  Time.deltaTime  accomplishes this:
as the frame rate changes, the size of the movement step changes appropriately, to result in a constant speed.
More Vector Concepts
Below is C# code to further understand uniform motion (and practice C# coding).
To achieve uniform speed for movement in any direction, we need a few more vector concepts.
If you want a complete discussion of vectors, start here in my online Precalculus course.
Vector Magnitude; Unit Vectors
Let $\,(x,y,z)\,$ be a three-dimensional vector. (A similar discussion holds for two-dimensional vectors.)

The magnitude of $\,(x,y,z)\,$ is the square root of the sum of the squares of its components.
The magnitude gives the length of the arrow representing the vector. $$ \text{magnitude of the vector $\,(x,y,z)\,$ is: } \ \ \sqrt{x^2 + y^2 + z^2} $$ A vector with magnitude $\,1\,$ is called a unit vector.
Note that $\,(1,0,0)\,$ and $\,(-1,0,0)\,$ are both unit vectors, since: $$ \sqrt{\strut 1^2 + 0^2 + 0^2} = 1\ \ \ \ \text{ and }\ \ \ \ \sqrt{\strut(-1)^2 + 0^2 + 0^2} = 1 $$ For convenience, Unity defines the following unit vectors:
Direction:Vector:Available in Unity via:
RIGHT:
( 1 , 0 , 0 )
Vector3.right
LEFT:
( -1 , 0 , 0 )
Vector3.left
UP:
( 0 , 1 , 0 )
Vector3.up
DOWN:
( 0 , -1 , 0 )
Vector3.down
FORWARD:
( 0 , 0 , 1 )
Vector3.forward
BACK:
( 0 , 0 , -1 )
Vector3.back
Normalizing a Vector
If you take any vector and divide by its length, then a unit vector results.
The process of dividing by the length (and thus achieving a unit vector) is called normalizing the vector.
In C# scripts, if  myVector  is any vector (2D or 3D), then  myVector.normalized  is a unit vector that points in the same direction.

For example, $\,(-3,2,1)\,$ normalizes to (approximately) $\,(-0.802,0.535,0.267)\,$: $$ \sqrt{(-0.802)^2 + (0.535)^2 + (0.267)^2} \ \approx\ 1 $$ (WolframAlpha is a great online resource for computations!)
A Vector Can Represent Both Position and Direction
An astute reader may have noticed that we're using the same notation for a point and a vector.
For example, does  (a,b,c)  denote a point in World Space, or a vector pointing in a certain direction?

Strictly speaking, points are different from vectors:
  • A point represents a location/position.
    Points are usually represented graphically by dots.
  • A vector requires both size and direction to fully describe it.
    Vectors are usually represented graphically by arrows.
In mathematics, different notation is often used for points and vectors, when it's important to make a distinction.
In game development, however, we can usually get away with blurring the distinction between the two, and here's why.

With modest viewpoint adjustments, points and vectors can both give position information and direction information:
  • Although a point ‘natively’ represents position, it can also represent direction:
    just draw an arrow from (say) the origin to the point.
  • Although a vector ‘natively’ represents direction (as one of its two pieces of information),
    it can also represent position:
    just stick the tail (the non-arrow end) at the origin, and let the tip of the arrow represent a position.
Look at (1) at right.
You might ‘see’ the point at the tip of the arrow, and think of this as representing a point.
Or, you might focus on the direction the arrow is pointing, and think of this as a vector.
It really doesn't matter—and different viewpoints are better in different situations.
This is why—in game development—we can get away with using the same notation  (a,b)  for both a point and a vector.

(1) a vector can represent both position and direction
Getting a Direction Vector from Point $\,A\,$ to Point $\,B\,$
Let $\,A(x_A,y_A)\,$ and $\,B(x_B,y_B)\,$ be points.
Then, $\,B - A = (x_B - x_A\,,\,y_B - y_A)\,$ is a vector from $\,A\,$ to $\,B\,.$
The same thing works in 3D.

This is an immediate consequence of vector addition, as follows.
Travel from the origin to $\,B\,$ (the desired destination) in two different ways:
  • travel from the origin directly to $\,B\,$
  • travel from the origin to $\,A\,,$ and then from $\,A\,$ to $\,B\,$
These are equal vectors, hence: $$ \overbrace{\strut\text{vector $\,B\,$}}^{\text{from origin to $\,B\,$}} = \overbrace{\strut\text{vector $\,A\,$}}^{\text{from origin to $\,A\,$}} + \overbrace{\strut\text{desired vector}}^{\text{vector from $\,A\,$ to $\,B\,$}} $$ so that $$ \text{desired vector} = \text{vector $\,B\,$} - \text{vector $\,A\,$} $$ In words:
If you want a vector that points from one location to another,
just take your destination point, and subtract your starting point.
Going From a 2D Vector to an Angle Representing the Vector's Direction
Take a 2D vector $\,(x,y)\,$ and put its tail at the origin, as in (2ab) at right.
The vector then naturally lies in one of the four quadrants (or on an axis).
We will need to know the angle between the positive $\,x\,$-axis and the vector (denoted by $\,\theta\,$ at right).

Fortunately, Unity (making good use of the arctangent function) gives an easy way to go from vector coordinates $\,(x,y)\,$ to a convenient angle representing its direction.

For a given vector  (x,y) :

Mathf.Atan2(y,x) returns an angle that represents the direction the vector is pointing

(2a) For vectors  (x,y) 
in quadrants I and II,
Mathf.Atan2(y,x)
returns positive angles.

(2b) For vectors  (x,y) 
in quadrants III and IV,
Mathf.Atan2(y,x)
returns negative angles.
Here are details on  Mathf.Atan2(y,x) :
  • Mathf.Atan2  is a math function provided by Unity.
  • Mathf.Atan2(y,x) always returns a radian angle in the interval $\,(-\pi,\pi]\,.$
  • Recall: $\,\pi\,$ radians equals $\,180^\circ\,$
  • To convert an angle from radian measure to degree measure: $$ \text{degree measure} = \text{radian measure}\cdot\frac{180^\circ}{\pi} $$
  • Be careful!
    Although the vector is  (x,y) , the correct order to list the coordinates for use in the  Mathf.Atan2  function is  (y,x) .
  • If a vector points to the right, like  (1,0) , then Mathf.Atan2(0,1) returns $\,0\,.$
    If a vector points to the left, like  (-1,0) , then Mathf.Atan2(0,-1) returns $\,\pi\,.$
    If a vector points up, like  (0,1) , then Mathf.Atan2(1,0) returns $\,\frac\pi 2\,.$
    If a vector points down, like  (0,-1) , then Mathf.Atan2(-1,0) returns $\,-\frac\pi 2\,.$
  • If $\,x \ne 0\,,$ then Mathf.Atan2(y,x) returns a radian angle in the interval $\,(-\pi,\pi]\,$
    whose tangent value is $\,\frac yx\,.$
  • Quadrant Vectors look like Mathf.Atan2  returns angles
    I (+,+) between $\,0\,$ and $\,\frac\pi 2\,$
    II (-,+) between $\,\frac\pi 2\,$ and $\,\pi\,$
    III (-,-) between $\,-\frac\pi 2\,$ and $\,-\pi\,$
    IV (+,-) between $\,0\,$ and $\,-\frac\pi 2\,$

(3) the four quadrants
C# Code for Uniform Motion in Any Direction
Create a new script, as shown at right.
Drag the script onto Wolf.

Only new or notable code features are discussed here:
  • Lines 7-8
    Declare and initialize fields for the desired direction and speed. Both are public, so they can be edited from the Unity Editor.
  • Lines 10, 13
    A Sprite Renderer reference is needed, since the sprite must be flipped when traveling left.
  • Lines 14-15
    A C# statement can be broken across multiple lines.
  • Line 20
    Use Quaternion.Euler to create the desired rotation angle about the $\,z\,$-axis, using the $\,x\,$ and $\,y\,$ coordinates of the desired movement vector.

    Quaternion.Euler  requires degree input.
    Mathf.Atan2  returns radians.
    Note the conversion from radians to degrees.

    Assign the rotation to the GameObject's  transform.rotation  field.
  • Line 21
    If the GameObject moves left, Sprite Renderer-Flip-Y must be checked. Otherwise (since the rotation is more than $\,90^\circ\,$ in these situations), Wolf would appear upside-down.

    C# adheres to PEMDAS order of operations, and has additional operator precedence rules. Operators with higher precedence are ‘stronger’ and get applied first. ‘<’ has higher precedence than ‘=’.
    Thus, ‘<’ gets done first.

(1) move with uniform speed in a desired direction
a text file containing this TestScript code


(2) console output from above code
So, here are details on how line 21 behaves:
  • Line 21 acts as if the red parentheses shown below are in place:
    _mySpriteRenderer.flipY = ( DesiredMovementDirection.x < 0 )
  • DesiredMovementDirection.x < 0’  is a boolean: it returns either  true  or  false .
  • DesiredMovementDirection.x < 0’  returns  true  when  DesiredMovementDirection  causes movement to the left, and returns  false  otherwise.
  • _mySpriteRenderer.flipY’  is a boolean: a  true  value corresponds to the Flip-Y box being checked.
Continuing:
  • Line 24
    First,  DesiredMovementDirection  is normalized.
    Next,  DesiredMovementDirection  is scaled to have the desired speed.
    Multiplying by  Time.deltaTime  gets rid of the frame rate dependence.
  • Line 25
    If desired, line 25 could be replaced by:
    transform.Translate(changeInPosition, Space.World);
    See the Unity documentation for details.
  • Line 28
    OnApplicationQuit()  is a built-in Unity method, automatically called when a user stops play mode.
    Thus, the ‘report’ is printed to the console just prior to ending game play.
Analyzing the Code Output
Let's look at the console output, shown in (2) at right.

All movement is done in 2D, so we can ignore the $\,z\,$ coordinate.
The distance between the start point $\,(-7,2)\,$ and the end point $\,(5.0,-5.2)\,$ is: $$ \sqrt{(5-(-7))^2 + (-5.2-2)^2} \ \approx\ 14 $$ Since distance equals rate times time ($\,d = rt\,$), we have $$ \begin{gather} r = \frac{d}{t}\cr\cr r = \frac{14.03263}{15.5718} \approx 0.901156 \end{gather} $$ Not bad in matching the target speed of $\,0.9\,$!

Continue with this Unity lesson: Move To a User-Clicked Location