Introduction

Numeric sets are used to group numbers that have similar characteristics. It is one of the basic concepts of mathematics so it is important to understand what they are and what characteristics each has.

What are number sets used for?

Numeric sets are used to separate numbers into different classes that have similar properties.

We must see this simply as a form of organization, in which given any number we say that this number belongs to such a set.

Numerical Sets

The basic numerical sets are as follows:

  • Natural – ℕ
  • Integer – ℤ
  • Rational – ℚ
  • Real – ℝ
  • Complex – ℂ

Each more general set encompasses the previous set, i.e. for example all natural numbers are integers, but not all integers are natural.

Set of Natural Numbers (ℕ)

This set is made up of the numbers {1,2,3,…} (the suspension points indicate that the enumeration continues indefinitely), these numbers are all positive and represent integer magnitudes, i.e. they have no decimal part.

Set of integer numbers (ℤ)

If to the natural numbers we add the number 0 and the negative numbers without decimal part we obtain the set of integers. {…,-3,-2,-1,0,1,2,3,…}.

With negative numbers we can represent subtraction operations, missing magnitudes, values below the reference zero and so on.

Some examples are outgoing flows of money, that is, money that we pay and subtract from what we have; temperatures below zero are expressed as negative values of degrees Celsius.

Sets of Rational Numbers (ℚ)

The set of rational numbers arises from making divisions of two whole numbers. For example 1 divided 2 is an operation that results in a number that is smaller than 1 but larger than 0.

These numbers are used to represent non integer magnitudes, for example variables of continuous nature such as speed, weight, electric current; to express fractional quantities such as half a kilo of flour are 0.5 kg of flour.

Set of Real Numbers (ℝ)

If to the set of rational numbers we add the set of irrational numbers we get the set of real numbers.

Irrational numbers arise from performing certain operations and it is not possible to express them as the quotient between two whole numbers.

An example of this type of numbers is the well-known Pi number which is composed of infinite decimal digits.

Set of Complex Numbers (ℂ)

If we add imaginary numbers to the set of real numbers, we get the set of complex numbers. Any number we choose will be, in general terms, a complex number.

The imaginary number i is the result of the square root of -1.

Complex numbers are composed of a real part and an imaginary part and are very useful for the study of electrical circuits involving capacitive or inductive elements. They are also used in Fourier transform calculations.

Numerical Sets in Videogames

Modeling of game elements

To model the behavior of different elements in our game we will probably need to use different types of numbers.

For example a character may have a standard of living represented by hearts. When it is damaged it loses a heart and when it takes a healing potion it recovers a heart. In this case the health level is a whole magnitude.

We can also think, for example, that each heart can be divided into four parts and each blow received takes away a quarter of our heart. In addition it could be that a strong enemy takes away three quarters of our heart with each blow. In this case we are thinking of hearts as rational magnitudes and we are going to need decimal numbers to represent them.

It all depends on how we want our model to be.

Numerical sets in programming

To represent the different types of numbers we need to build models, we have elements called variables, which are spaces in the memory where information is stored.

Some time ago I made a video about what a variable in programming is and also wrote an article for this page.

Types of numerical variables in C#

The programming language we use in Unity offers us different types of variables.

Integers

To represent integer magnitudes we have for example the byte, the short, int and long

Each has its own range of representation, for example the int allows us to represent integers that are between -2,147,483,648 and 2,147,483,647. The short instead allows us to represent numbers between -32,768 and 32,767, which is also a fairly large range.

By default we are going to use the int variable type to represent integer magnitudes.

Reals

The floating point system is used to represent decimal values in computation.

We have 32-bit float type variables, 64-bit double type variables and 128-bit decimal type variables. Each one has a certain range of representation and precision.

In computation, infinite digits cannot be stored, so irrational numbers will be represented as rational numbers and a truncation error will arise.

Complex

Complex numbers can be represented with two real numbers, one is the real part and the other is the imaginary part, the latter will be multiplied by the number i. As expressed in the following equation:

Z = X + i . Y

X and Y being real numbers and Z being a complex number.

We can represent complex numbers using two floats with significant names for the real and imaginary parts, we can use two-component vectors, or we can use the Complex class of C#.

Conclusion

Numeric sets are names we use to classify the different types of numbers that exist.

Knowing the different types of numbers and their properties will help us in building models for our games.

Para implementar los números en programación contamos con elementos llamados variables. Existen distintos tipos de variables para representar números enteros y racionales, cada tipo tiene su propio rango de representación.

Introduction

In this article we are going to study how to use the OnTriggerStay method to detect the character in a certain region and apply actions when that happens. Specifically, we’re going to make the damage and health regeneration stations affect the character.

Go to the project’s main page

Procedure

We are going to use the “OnTriggerStay” station, which consists of two metal-detector-shaped devices, one red and one green, whose function is to affect our health system. When entering the red station our health should decrease and with the green station it should increase.

Fig. 1: GameDevLab OnTriggerStay Station.

All these objects are inside the empty GameObject “#5 OnTriggerStay“. We have a regeneration station (HealthStation) and a damage station (DamageStation).

Fig. 2: Hierarchy of the scene. All elements of the station are in the GameObject #5 OnTriggerStay.

Both HealthStation and DamageStation are assigned the same script, “OnTriggerStayAction“.

Fig. 3: Script asignado a los GameObjects “HealthStation” y “DamageStation”.

In the inspector we can modify the amount of health that gives or takes away through the float “amountHealth” and we can choose the type of station that is.

Fig. 4: The script allows us to choose whether the station does damage or regenerates.

In order for the stations to be able to do their work, it is necessary for the player to have some kind of health system to affect. This is already solved in the GameDevLab. The GameObject FirstPersonPlayer is assigned a script called “HealthSimple” that has the necessary variables and methods to provide the player with a simple health system.

Fig. 5: Script asignado al GameObject FirstPersonPlayer.

Resolution

When opening the OnTriggerStayAction script for the first time we find what you see in figure 6. There is a defined region between comments where it is suggested to redefine the OnTriggerStay method.

Fig. 6: Script OnTriggerStayAction sin completar.

How does the OnTriggerStay method work?

This method is defined in the MonoBehaviour class, so it will be present by default in any new script we make.

Runs automatically if a GameObject with Collider enters the region defined by another Collider who is in Trigger Mode. In addition, at least one of the two GameObjects must have a RigidBody component assigned to it.

Fig. 7: As long as the colliders do not touch, the OnTriggerStay method does not run.

Fig. 8: Colliders are playing, so the OnTriggerStay method is executed.

Figure 9 shows the resolution for the exercise.

Fig. 9: OnTriggerStayAction script resolution.

We redefine the OnTriggerStay method that receives as parameter the Collider that has come in contact with the trigger. We give the name “col” to the reference of this Collider.

What we have to do is first determine if the GameObject whose Collider came into contact has a health system to affect, we do this by getting the reference of the HealthSimple component that can be assigned to this GameObject.

If the GameObject has health system, we will have a component HealthSimple, otherwise our variable will have the value null. We use this as a condition in the if statement.

If the condition is true we execute the playerIsUnderTheStation method and pass as parameter the HealthSimple reference found in health.

With this we have solved the problem of video, from that point the component HealthSimple will handle the issue of health.

Fig. 10: Health value after a few seconds in the damage station.

Upon entering the damage station our health begins to decline, if it reaches zero value the scene is restarted.

Upon entering the regeneration station, health begins to increase until the maximum value is reached.

Fig. 11: Health value after a few seconds at the regeneration station.

Conclusion

The objective of this article and corresponding video is to study an application of the OnTriggerStay method, to understand how it works and then be able to apply it to any situation in which it may be useful.

There are many situations in which this method could serve, for example modeling the behavior of a pressure plate, make us affect an opposite force to gravity that makes us levitate if we are in a certain region. In short, this method is a useful tool that we have to understand.

It is not the point of this article to study the health system, but it is interesting to note that the stations are going to act on any GameObject that has the HealthSimple script, regardless of the player. This suggests that in our game we could have a single script that manages the health of any living being in our game and has properties common to all, as well as unique properties for each being. Creating this kind of solutions is what I find most interesting

On this occasion I bring a mix of one hour of environmental instrumental music to study or work on a project for an hour.

You can put this melody in the background while you do some homework, for example studying a language or doing a job. You can also use it to read a book for an hour.

The idea is to propose maximum concentration for the duration of the melody. At the end you will have dedicated an hour to your projects.

It may not seem like much of an hour for a project, but if we transform this practice into an everyday habit, after a few weeks the progress will be remarkable.

Video Purpose

I made this video mostly for my own use as a way of measuring time commitment.

Whether you want to read a book, study, write, make 3D models, practice a language, program or any other task, I intend to concentrate on maximum concentration for the duration of this video.

It depends on the occasion, but in general instrumental music is appropriate for me to isolate myself from the environment without losing concentration. That’s why I made the video have a low volume, but maybe too much.

We all have an hour a day if we gather free time, television time or perhaps a nap that was not necessary. It is true that it is often difficult to overcome tiredness after a day’s work, so you need willpower to start.

But if we manage to establish the habit of devoting one hour a day to a personal project, you can soon see the progress.

About Phrases

The phrases I chose are positive and motivating, which is what we need every morning to get the day off to a good start.

With the exception of the introduction, all phrases are attributed to recognized philosophers, writers, artists, scientists and brilliant minds, as well as proverbs and phrases of unknown origin.

I did not want to include the author because of possible errors in the sources of information. I believe that these phrases have a value of truth and wisdom regardless of to whom they are attributed.

Some names of authors are:

-Johann Wolfgang von Goethe

-René Descartes

-Martin Fierro

-Paulo Coehlo

-Albert Einstein

-Steve Jobs

-Charles Dickens

-Charles Chaplin

-Bill Gates

-Isaac Asimov

-Bruce Lee

-Henry Ford

-Pablo Picasso

About music

At all times you can hear in the background the sound captured somewhere in Argentinian Patagonia, far away from the city.

Various birds such as sparrows, pigeons and parrots, as well as roosters and geese.
Children playing, dogs, perhaps a light wind and the sound of leaves.

As far as possible I tried to suppress the sound of vehicles and noises that do not come from nature.

The songs you hear are a mix taken from the YouTube library for creators, some names are:

-Angelic Forest – Doug Maxwell

-Dreamer – DivKid

-Neither Sweat nor Tears – Dan Bodan

-Serenity – Aakash Gandhi

-WaterFall – Aakash Gandhi

-Stale Mate – Jingle Punks

-Quiet Nights – Nate Blaze

La música se encuentra limitada a un tope de decibeles, de modo que se puede ajustar un determinado volumen esperando que se mantenga a ese nivel en todo momento.

Introduction

In this article we are going to see what a linear function is, its mathematical expression, its characteristics, how to graph it in the Cartesian plane and what it can be useful for in the development of videogames with examples in Unity.

Mathematical expression of a linear function

A linear function is a polynomial function whose expression is:

f (X) = a . X + b

It is commonly read “f of x”, being X the independent variable, a and b constant real numbers.

Analyzing the expression we see that given any value of X, we first multiply it by a and then add b. The result of all that operation will be the value of f (X).

Characteristics of a linear function

Domain

The domain is the range of allowable values for the independent variable, commonly referred to as X.

In the case of the linear function, the domain is the set of real numbers.

In other words we can choose any value of X belonging to the set of real numbers and we will find its corresponding value f (X).

Graph in the Cartesian plane of a linear function

The graph of f (X) in the Cartesian plane is a straight line. We can easily draw it by finding two points of the function and then using a ruler, draw the line that joins the two points.

We can easily find one of these points by considering X = 0.

The second point can be found by choosing a different value for X and making calculations, for example for the function in figure 1, if we consider X = 2, the result of f (X) is equal to 2.

Fig. 1: Example of the graph of a linear function.

Ordinate of the origin

It is the value of the function when X = 0, graphically it is the point where the function cuts off the vertical axis known as the ordinate axis. This point is known as the ordinate to the origin.

In the graph of figure 1 we see that the ordinate to the origin is the point (0,1).

Abscissa of the origin

Analogously to the previous case, the abscissa of the origin is the point at which the function intersects the horizontal axis or abscissa axis. At this point Y = 0.

A linear function may have no abscissa at the origin if it is a line parallel to the x-axis and displaced.

In the graph of figure 1 we see that the abscissa of the origin is the point (-2,0).

Slope of a linear function

The term that multiplies X is known as slope and is the one that establishes how much the function changes when the variable X changes by one unit.

If we only have the graph of a linear function, we can calculate the slope as the tangent of the angle that forms the line with the horizontal axis. We can also find the slope using the Pythagorean Theorem.

Parallel lines

Two straight lines are parallel if they have the same slope.

Example of two parallel lines:

f (X) = 2 . X – 1

g (X) = 2 . X + 3

Perpendicular lines

Two straight lines are perpendicular if the slope of one of them is equal to inverting the slope of the other and multiplying it by -1.

Example of two perpendicular lines:

f (X) = 3 . X + 2

g (X) = – ( 1/3 ) . X + 5

Some examples in Unity of linear function

The linear function is one of the most useful mathematical functions and its field of application is very varied. Let’s give some examples of possible applications.

Represent trajectories

The most basic thing I can think of is for objects to move in a straight path, which can be described as a linear function.

For example in figure 2 we see a scene in Unity in which the spheres are describing a trajectory that is described as their position in x is equal to their position in y.

Fig. 2: The spheres are advancing in the positive direction of the X-axis, their height Y is determined by the calculation of function y = x.

The same concept and with different combinations of planes can be applied to other cases such as vehicle movements, projectile trajectories, etc.

In the last video of my Unity fundamental series, I use a linear function for the movement of the camera, which advances inside the tunnel.

Relate parameters linearly

Let’s suppose that we have any two parameters, for example the position of the player on the X axis and the rotation of a mechanism with respect to one of its axes.

Let’s also say that we would like these parameters to be connected in some way, that is to say that the rotation of the mechanism will depend on the position of the player.

We can then establish a linear relationship between these two parameters, for example we could say that the rotation of the mechanism with respect to its z-axis is equal to half the value of the player’s position on the x-axis plus five units.

With this we can relate these two parameters through a linear function.

Implement linear magnitudes in our game

In physics there are many linear magnitudes that we might be interested in implementing in our game. An example of this can be the uniform rectilinear movement, in which we have a direction of movement established and the position will be defined by a linear function in which the slope of the line is the velocity of the object and the ordinate to the origin is the initial position.

In the case of Ohm’s Law for example, if we have a circuit with a source connected to a resistance, the circulating current is equal to the voltage of the source divided the resistance, this is nothing other than a linear function with the form i = v / R.

The potential gravitational energy of an object is a linear function of its height above ground.

There are several physical phenomena that are characterized by linear behavior and that we might be interested in implementing.

Conclusion

The linear function is one of the most basic functions but also one of the most useful.

The graph in the Cartesian plane corresponds to a line in which we can identify a slope and an ordinate to the origin, point in which the line cuts to the vertical axis or abscissa.

We can use it to establish linear relationships between different parameters of our game and represent physical phenomena of linear character.

Introduction

In this article we see how to CALL FUNCTIONS and READ VARIABLES that are defined in a different script in Unity. This is especially important to create object-oriented solutions, because being able to access other scripts allows us to create scripts that solve specific problems and work with other scripts to achieve a bigger result, separating responsibility, increasing abstraction. In addition you will also find two videos about calling functions and reading variables from another script in Unity.

All the IMPORTANT information is summarized in the following TUTORIAL FROM MY YOUTUBE CHANNEL




Interaction between scripts – A couple things to keep in mind

Let’s look at a list of items to keep in mind to understand the basis behind the interaction between scripts.

About the Scripts

In this case we are going to see an example in Unity, therefore the two Scripts we are going to use will be an extension of the MonoBehaviour class. This, in practical terms, means that when the game starts, a “Start” function will be executed and also in each frame of the game an “Update” method will be automatically executed.

About the execution of Scripts

In order to execute the code that we will include in our scripts, those scripts must be assigned to at least one “GameObject” in the hierarchy of the scene we will run. In programming, there must exist an Instance of the class defined in the Script.

Instances of a classes

When we add the same Script to two different GameObjects we are creating two separate instances of the class, i.e. two objects that are going to be similar because they come from the same class, but their internal state will not necessarily be the same all the time.

Having the reference of an object

This is one of the key points to pay attention to and try to understand in depth.

Objects in programming are instances of a certain class and in order to access its functionality, that is to say read its public parameters or execute its public functions, we must have the reference of the object we need to use, in other words find the object among all the other objects that exist in the program.

The Dot Operator

The dot operator in several programming languages allows us to access the public fields and methods from an object. In other words, if we have the object reference, we can apply the dot operator to it in order to execute any of its public methods or read and write any of its public fields.



Practical example of Interaction between Scripts in C# – Unity

Previous Steps

In any Unity project we create two Scripts, ScriptA and ScriptB, in the first one we define the function that will be executed from the second Script.

Fig. 1: We create two scripts called ScriptA and ScriptB.

In the hierarchy we are going to create two empty GameObjects to be able to create instances of both Scripts.

Fig. 2: Create two Empty GameObjects in the hierarchy to contain both Scripts.

In GameObjectA we add the ScriptA as component and in GameObjectB the ScriptB. We can do this from the inspector with the “Add Component” button or by dragging the script to the inspector of the GameObject.

Fig. 3: Select object A and in the inspector, using Add Component, add ScriptA to its components.
Fig. 4: Another way to add components is to drag them directly into the GameObject inspector.

Code inside the Scripts

Let’s write the instructions we’ll use to perform the interaction between Scripts.

When you create a new Script in Unity, it will come with some functions predefined, as you can see in figure 5. The “Start” and “Update” method, which will be automatically executed if the Script is assigned to at least one GameObject from the hierarchy.

Fig. 5: We open both Scripts in some editor. We can see some code already written.

Functions and Variables from “ScriptA”

In the first Script we are going to write the following code:

Fig. 6: Fields and methods belonging to Script A.

A public string called “name” that will help us identify which instance it is.

Two methods, one called “Function1” and the other “Function2“, the first function we will define it as public and the second private, lines 10 and 16 respectively from figure 6.

We will be able to access the “Function1” method through the dot operator because it was defined with public visibility. , as it’s defined as public.

As we can see in figure 6, “Function1” prints in console the result of the execution of “Function2“. This method returns a text that will allow us to see who is the object that is executing the “Function1” method and which instance of the ScriptA class it is.



Functions and Variables from “ScriptB”

The “ScriptB” script will be the one that calls the function defined in the other Script A. In figure 7 we see the instructions defined in the “ScriptB” script.

Fig. 7: Fields and methods belonging to Script B.

We define a string to assign a name and know which instance it is.

To be able to execute functions defined in another Script we must have the reference of the instance of that class. So let’s define a ScriptA type variable and name it “scriptA” (first letter with lowercase), as we see in line 13 of figure 7.

Here we only have half of the work done, we declared the
“A” variable inside “B”, but this variable is empty (a null variable) and will remain empty unless we do something about it.

To find the reference of an object in a Script there are several ways, in this case I will use a function calle “FindObjectOfType<T>” where “T” is the type of the variable we want to find. This function will search in the hierarchy an object of the indicated type and return the reference of that object if it founds it. See line 18 of figure 7.

More methods to FIND REFERENCES in Unity

Now that we have the reference of the “A” object, inside “B” we can execute the “Function1” function that is defined inside the A Script. Line 20 from figure 7).

Dot Operator

As mentioned before, the dot operator will allow us to access all the fields and public methods defined within the class.

In figures 8 and 9 we see that using the reference of the ScriptA-type object followed by a dot, we can see the list of fields and methods that are available to use.

In figure 8 we see the “name” variable that was the public string defined inside “ScriptA” and in figure 9 we see the “Function1” method, also defined as public. We can’t see the “Function2” method because it was declared as private.

Fig. 8: The dot operator allows us to read and write the “name” field, which is a string defined as public.

Fig. 9: The point operator allows us to execute the “Function1” method defined as public.

First exectution test

Before enter in the Play mode, we select GameObjects “A” and “B” from the hierarchy and write names in the “name” fields to be able to analyze the execution of our code.

The “ScriptA” instance will be called “George (A)” and the
ScriptB” instance will be called “Mike (B)“, as we see in figures 10 and 11.

Fig. 10: In the GameObjectA inspector, we put a name to know that it is that instance of the Script A class.

Fig. 11: In the GameObjectB inspector, we put a name to know that it is that instance of the Script B class.

When entering in the Play mode we see in the inspector of GameObjectB that the “ScriptA” field shows an object (unlike figure 11 where it said “none”). This means that the “ScriptB” was able to find the “ScriptA” reference.

Figure 13 shows the on-screen message, printed by the ScriptA Function1 method, which was called from the ScriptB.

The message says: “Mike(B) has executed my Function1. I’m George(A), by the way.

Fig. 12: When running the game, the ScriptA object reference is found due to the FindObjectOfType<> instruction.

Fig. 13: This message is printed because a method defined in ScriptA is executed from the ScriptB.



Second execution test

Let’s go a little deeper into the concept of programming object as an instance of a class.

Choose GameObjectA from the hierarchy and add a second instance of the ScriptA class using the “Add Component” or drag and drop button.

This second instance will be called “Luke (A)“, in figure 14 we see both instances of the class.

Fig. 14: A second instance of the ScriptA class is added to the GameObjectA with a different name.

When running the game as it is, we see in the console that Mike (B) has executed the Function1 method of Luke (A), see figure 15.

What has happened here is that the “FindObjectOfType<>” function in line 18 of figure 7, has found a different reference of a ScriptA type object than before, the “name” variable from this references is “Luke (A)“. A different instance of the same class as the one that has the text “George (A)” in its “name” variable.

Fig. 15: When running the game we now see that the Function1 method of the instance called Luke is being executed.

Now lets modify the code in “ScriptB” so that it is able to find all the “ScriptA” references in the scene and execute the “Function1” method of each one of them.

Fig. 16: We modify the ScriptB in this way so that it executes the functions of the two instances of ScriptsA.

In the object declaration we have now defined an array (or vector) of “ScriptA” type objects (line 13 figure 16), this means that we will be able to save several references of ScriptsA objects.

In line 18 of figure 16 the change is rather subtle, instead of running the “FindObjectOfType<T>” function we use “FindObjectsOfType<T>“, this other function returns all the references of the indicated “T” type that is able to find in the hierarchy.

The last thing we do is go through all the elements of the array using a foreach loop and we execute the “Function1” method to all of them, as can be seen in lines 20 to 23 of figure 16.

Fig. 17: When running the game we see that the two references of the ScriptA objects are found and we have them stored in the array.

When entering again in the Play Mode, we see that now in the GameObjectB inspector we have the “ScriptA” object references (figure 17) inside an array of size 2.

And now in the console appear two messages, the first corresponds to the execution of Luke’s “Function1” method and the second to the execution of George’s “Function2” method.

Fig. 18: In the console we see that the Function1 methods of each ScriptA object are executed.



Third execution test

We are going to modify the ScriptB again to see another way to obtain the references of the objects and thus to be able to call their functions from another Script.

In this case, in the “ScriptB“, we are going to declare two serialized ScriptA” objects (they can also be public, the idea is that they appear in the inspector). These objects will be called “scriptALuke” and “ScriptAGeorge“.

Then in the Start method we are going to execute the “Function1” methods directly using these objects. In this case it is not necessary to find the references through code since we will assign them directly in the inspector.

The modified “ScriptB” is shown below.

Fig. 19: We modify the ScriptB in this way to try another way of having the reference of the objects.

In the inspector we can see the new fields for “ScriptA” objects (figure 20).

Fig. 20: In the inspector we have fields for two ScriptA objects.

We will modify a little the GameObjects of the hierarchy, we will have an Empty GameObject called A-Luke and another called A-George.

Fig. 21: Instead of the GameObjectA we will have two empty GameObjects for each instance of the ScriptA class.

In each GameObject we assign the ScriptA component and complete the corresponding name, see figures 22 and 23.

Fig. 22: In the GameObject A-Luke we add the ScriptA component and enter the corresponding name.

Fig. 23: In the GameObject A-George we add the ScriptA component and enter the corresponding name.

Now let’s take the GameObjects from the hierarchy and assign them in the corresponding fields of the “ScriptB”

Fig. 24: With these GameObjects we will drag and drop in the ScriptB fields.

In figures 25 and 26 we see that the references have been assigned manually, this means that we can execute the “Function1” methods from each instance.

Fig. 25: We can assign the GameObject directly to the corresponding field whenever there is such an object among its components.

Fig. 26: The references of both ScriptA objects have been assigned to the corresponding fields.

In console we see that the messages are printed due to the execution of “Function1” method on both instances.

Fig. 27: When running the game we see that the Function1 methods of both instances are executed.

Before finishing I would like to change the order of execution of the Function1 methods in the ScriptB, as seen in figure 28.

Fig. 28: Reverse the order of the instructions and perform another test.

When we do this and enter in the Play Mode again we see that the messages on the console switch places, figure 29.

Fig. 29: We see that the messages change the order of appearance in the console.



Conclusion

We have seen how to call functions that are defined in other Scripts. This is only possible if the functions are declared with public visibility, this allows the access from external contexts.

In addition we must have the reference of the object that contains that method to execute, this can be achieved in several ways, in this article we saw three ways to do it. It’s important to understand the concept of instances in programming, it can be two or more instances of the same class and therefore multiple objects with the same function defined but the result of the execution of that function on each instance could be different.

Understand in depth the concept of object in programming, which is the instance of a class and the fact that in order to access another object we must have the reference of that object, allow us to build more complex solutions, separating responsibility, increasing the abstraction of our solutions.

Introduction

In this article we’re going to look at how to create and destroy GameObjects at runtime. Achieving this is very important for creating games, because it allows us to place objects when and where we want and then destroy them.

Go to the project’s main page

Procedure

In this challenge we are going to use the Creation/Destruction station shown in figure 1, to make a small Lucy appear and disappear cyclically while the game is running.

Fig. 1: Creation Destruction Station of the GameDevLab.

Fig. 2: Creation Destruction Station of the GameDevLab. Lucy appears for a few seconds.
Fig. 3: Creation Destruction Station of the GameDevLab. Lucy disappears.

Figures 2 and 3 illustrate the cycle of Lucy’s appearance and disappearance.

Fig. 4: Fields of the CreationDestruction Script corresponding to the challenge of video 4 of the Fundamental Series.

Figures 1 and 2 show the fields and components in the “CreationDestruction” Script inspector.

Fig. 5: The GameObject “#4 Creation Destruction” is assigned the Script Creation Destruction. This is seen in the inspector.

The challenge is to complete the createObject() and destroyObject() methods of the Script.

Solving this exercise

Creating the object

For the creation of the object we are going to use the Instantiate method, this method is defined in the MonoBehaviour class that by default is the super class or parent class of every new Script that we make in Unity.

At the moment I don’t have enough articles or videos about object-oriented programming to clarify the super classes, I know I will eventually do them, but for now if you want to know more research the topic Heritage in object-oriented programming.

The Instantiate method has more than ten variants, but in all of them we basically need two things: the object we are going to create and where in the space we are going to put it.

Click here to read an article on programming methods.

In this case the object that we are going to create we indicate it using the prefab SmallLucy that is in the folder Internal Use, this prefab we place it in the space Object To Create in the inspector, as it is observed in the figure 5.

To indicate the point of the space where we are going to place the new object we are going to use a GameObject called Position that is in the hierarchy. We also assign it in the inspector (figure 5).

We are going to use a variant of the Instantiate method that will create the object and place it in the hierarchy as a child of the GameObject we indicate. This means that our object will appear in the position of the parent GameObject (Position) plus the own displacement that SmallLucy has (in this case SmallLucy is in the origin so its displacement is zero).

I know that the paragraph above is somewhat confusing, but later I would like to make a video and article about global and local coordinates in order to explain this more clearly. For now, let’s move on. We write the following line in the createObject method:

createdObject = Instantiate (objectToCreate,position.transform);

First of all createdObject is an auxiliary GameObject type object (see figure 4) that we define to save the reference of the new object we are going to create. This is very important because otherwise later we won’t know which object we have to destroy.

Find the references of the GameObjects from the Hierarchy

The Instantiate method will return a GameObject type object (the new object) and with the equal sign we assign it to createdObject.

In parentheses indicate the two parameters separated by a comma. The first parameter is the object to create and the second is the Transform component of the GameObject Position

Fig. 6: Methods defined in the CreationDestruction Script corresponding to the challenge of video 4 of the Fundamental Series.

Destruction of the object

To destroy the object we use the Destroy method (which is defined in the MonoBehaviour class) and give it as a parameter the reference of the object we have saved in the createdObject field. We write this in the destroyObject method.

Cyclic behaviour

We want Lucy to appear and disappear continuously in the Creation Destruction station, so we have to run the createObject method. Then wait a few seconds and call the destroyObject method, then wait and call the create method again.

We did this first by calling the createObject method from Start, so that when you start the game, Lucy appears. Then at the end of the create method we use Invoke to call the destroyObject method after two seconds. We do the same thing at the end of the destroyObject method, we use Invoke to call the create method. We can see this in figure 6.

Conclusion

We have managed to make new objects appear on the stage at runtime, that is, while the game is running, this is no small thing, understanding this we can achieve many things.

To create a new object in the world we basically need a copy of the object to create, this we achieve with a prefab. And we have to know exactly where to place it, this can be achieved in many ways, that’s why the Instantiate method has so many variants.

If we want to destroy a GameObject of the hierarchy we need to know what it is, so it is very important the object reference, if we create the object without assigning it to any field, the object will be in the hierarchy but we can not do anything with it unless we find it again.

Introduction

In this article we see what is a method in programming, what they are for and how to declare them in C# language with concrete examples in a game project in Unity.

¿What is a Method in Programming?

In this context a method is a function that has a set of instructions defined within it.

The method has a name to identify it.

We can make it require different type of input data to run. And we can make the method return data as a result.

When we need to execute the instructions contained in the method, we do so simply by using its name.

Fig. 1: Scheme illustrating the basic properties of a method.

Modularity

In figure 1 we see the method represented as a box, in which the name of the method appears as title, the beginning and end of the method is specified and the set of instructions is within this region.

To understand what modularization is all about, see figure 2. On the left we see a long list of programming instructions.

Now within that list are a number of instructions that are used in more than one place, instructions A, B, C, and D. Let’s say these instructions perform a particular task and are always executed together.

Fig. 2: On the left a code with repeated instructions. To the right the same code with modules.

Suppose we now have to make changes to those instructions (for example to improve the way it solves the task or add functionality), what happens is that we have to identify all the regions where those instructions are.

It would be great if we could change things in one place and the changes apply to all regions where these instructions are used, wouldn’t it?

This is precisely what we achieve with the methods, they allow us to group sets of instructions in an independent module that can be called when necessary, as we can see on the right in figure 2, the instructions were now replaced by the name of the method.

Input and Output parameters

In figure 1 there are arrows that go in and out of the method. With this I try to represent the input and output of parameters.

We can make our method require input parameters, which we use inside to make calculations or perform any type of task.

In addition we can make the execution of the method produce an output data, which we will use outside the method.

Public and private methods – Visibility

Finally in figure 1 we see a normal eye and another crossed out eye. This represents the visibility that the method will have, which is an object-oriented programming topic, we are not going to delve into this article but in principle let’s say that we can have public methods and private methods.

Public methods can be executed from other Scripts for example, or we can execute them from a component in the hierarchy in Unity, for example a button.

Private methods will not be accessible from contexts external to the script where it is defined.

Syntax

The syntax is the set of rules established in a language to write the code, in figure 3 we see possible syntax of a method,

Fig. 3: Different combinations of input and output parameters for the methods.

This syntax can be applied to C# and Java, one detail is that all methods are public, but we could replace the word “public” with “private” and the syntax would be correct.

Declaration of a method

Example 1

Let’s analyze the method that is above to the left in figure 3.

We have the structure of a public method that does not require parameters and does not return parameters.

This structure can be found for example in the script “GameControl” of the project My first game in Unity.

We worked on this script in video 4 of the series.

Fig. 4: Method belonging to the script: “GameControl”.

We observe that it has been declared as private instead of public, then we find the word “void” with which we indicate that this method will not return parameters.

Then the name of the method: “placePlayerRandomly”.

We open and close parentheses indicating that this method does not need parameters.

The beginning and end of the method is indicated using keys. Inside will be all method instructions.

Invocation or call to the Method

Once the method is defined we can make it run from any part of the script, we can even invoke it from other scripts.

The following figure shows the invocation of the “placePlayerRandomly” method in the “startGame” method of the same “GameControl” script.

Fig. 5: In yellow: invocation of the “placePlayerRandomly” method.

To invoke this method we write its name and open and close parentheses, we close the instruction with semicolon. By doing this we are achieving that all the instructions of the method are executed.

Notice how the names of the methods are already helping us to understand what is going on. At the beginning of the game the character should be placed randomly.

From the “startGame” point of view the “placePlayerRandomly” method is a function that does everything necessary to place the character randomly. The startGame method doesn’t know exactly how it does it but it doesn’t care, because placePlayerRandomly does its job well.

Example 2

In the upper right corner of figure 3 we have the structure of a method that does not return parameters but does require them to work.

Fig. 6: UIManager script “writeTimer” method.

This method requires two parameters to work: an integer value m that will indicate the minutes of the timer and an integer value s that will indicate the seconds.

Fig. 7: Invocation of the “writeTimer” method from the “Timer” script.

The invocation of this method occurs in several places of the code, in particular the method “addSeconds” belonging to the Script “Timer”, this method receives as parameters an integer “s” that represents the amount of seconds that must be added to the timer because the character grabbed one of the clocks that are on the stage.

The “addSeconds” method does some operations with the “s” variable to update the time and finally executes the “writeTimer” method that shows the new time values on screen.

Two observations: the first is that since we are executing the method from another Script it is necessary to add “uiManager”. (pay attention to the dot) before writing the name of the method “writeTimer”.

The second is that parameters are entered within parentheses and separated by comma.

In both scripts I used confusing names (m and s) on purpose so that in the future, when we talk about contexts, we can analyze them.

Example 3

We move on to methods that return parameters.

The following example corresponds to the structure illustrated in the lower left corner of figure 3, a method that returns data and does not require parameters to function.

Fig. 8: “getRandomPosition” method of the “LabyrinthPiece” script.

The data returned by this method is a “Vector3” and is indicated in the declaration, after the word “public”. Notice that the first line that is not a comment says: “Vector3 position;”, there we are declaring a Vector3 that we call “position”, then we do some calculations and at the end of the method we write: “return position;” indicating that we return that Vector3.

This method returns a Vector3 (component x,y,z) that represents a random position belonging to the inside of a given piece of labyrinth. In this way we can use this position to place the pedestal or clocks without worrying for example that they are embedded in a wall.

Fig. 9: Invocation of the “getRandomPosition” method.

It is not easy to understand the instruction highlighted in figure 9. For now let’s look at two things, the first is that we make a call to the “getRandomPosition” method using its name (as seen at the end of the instruction). The second is that the result of that invocation is a Vector3 data, therefore, using the equal sign, we assign it to the “rP” data that is defined as Vector3.

Example 4

The last example corresponds to the structure illustrated in the lower right corner of figure 3, a method that returns data and requires parameters to function.

Fig. 10: Declaration of the “isBestScore” method.

We see that in the declaration we say that the method “isBestScore” returns a bool type data and requires an int type data that we call “val”.

If you want to know a little about primitive data I invite you to read this article about variables or watch this video.

The “isBestScore” method returns a variable that can be true or false. The utility of this method is that we use it to ask if the score obtained in the game (val) is better than the one saved so far (bestScoreValue).

Fig. 11: Invocation of the “isBestScore” method.

This method is invoked in the “gameWon” method. Since the method returns a bool value, we can use it directly as an argument for an if statement, because “score.isBestScore(time)” is equivalent to having a true or false value.

StartGame() Mehotd from GameControl

To finish figure 12, the “startGame” method is observed along with the other methods it invokes.

In addition to grouping instructions, a method must have a well-established purpose that is consistent with the name we gave it, so that we can quickly know what its function is and what type of instructions it may contain.

Fig. 12: Declaration of the “isBestScore” method.

For example, the “startGame” method is in charge of coordinating a series of actions to start the game, but it is not he who directly performs these actions, but invokes other methods with more specific tasks.

This makes it easier for us to make changes to the code and debug errors.

Conclusion

Methods are a powerful tool for developing specific, efficient, reusable and sustainable solutions.

Sustainable in time because at all stages of development we will have to make changes, so we have to be able to remember or quickly understand how our code works.

This is achieved by using descriptive names, documenting our code, and applying the object-oriented paradigm.

Introduction

In this article we’re going to analyze how to apply the LookAt function in Unity, to make a GameObject look in the direction of another GameObject.

Procedure

We are going to work with the Look At station, which consists of a containment capsule in which Lucy’s model is floating. The goal is to get Lucy to follow us with her gaze all over the stage.

Go to the project’s main page

Fig. 1: Lucy is inside this capsule.

In the hierarchy we have a GameObject called “#3 LookAtObject”.

Fig. 2: Hierarchy of the scene. The LookAt station is GameObject #3.

This GameObject is assigned the “LookAtObject” Script, which will see to it that Lucy follows her gaze on the player.

Fig. 3: Script to complete in this challenge.

Figure 4 shows that there are 3 fields to complete, the first is for the observer object, the second is for the observation objective and the third is for Lucy to look at a fixed height of the stage, so she does not leave the border of her capsule containment.

Fig. 4: Script assigned to the GameObject “#3 LookAtObject” shown in figure 2.

We’re going to assign Lucy directly from the hierarchy and we’re going to find the character through her tag.

If you want to learn different ways to find the references of the GameObjects of the hierarchy to use in the Scripts you can read the previous article or watch this video with subtitles.

If we open the script we find some things done. In the FixedUpdate method, which is executed once every so often, we make the call to the “lookAtObject” method, which will fulfill the function.

Fig. 5: Script LookAtObject sin completar.

In the start method seen in figure 5, we have an instruction that was commented at the time of making the capture. You have to remove the comment bars to find the player’s reference and get Lucy to look at it.

Fig. 6: Fields defined in the Script.

Figure 6 shows the fields defined in the Script. We are going to use the Vector3 called “objectToLookPosition” for the coordinates that Lucy must look at.

Fig. 7: With these two instructions we get Lucy to look at the origin of the character.

Within the “lookAtObject” method we write these instructions:

objectToLookPosition = objectToLook.transform.position;

objectThatLooks.transform.LookAt(objectToLookPosition);

With these two instructions, Lucy is always oriented towards the player’s origin.

Fig. 8: Lucy sigue al personaje con la mirada.

Fig. 9: When approaching the capsule, Lucy leans so far that she goes beyond the boundaries of the capsule.

The challenge is partially solved, we still have to solve the problem illustrated in figure 9.

Fig. 10: Three GameObjects showing their origins. The origin is represented by a gizmo showing the local axes.

First let’s understand what’s going on.

All GameObjects have a coordinate in the space where their origin is located.

The LookAt method will modify the orientation of the object to which it is applied (in this case Lucy). It will do this in such a way that the local forward axis points to the origin of the object to look at. As illustrated in the following figure.

Fig. 11: Lucy with the At look method applied, character away.

If the character is far from Lucy his inclination is small, but when he gets closer the following happens:

Fig. 11: Lucy with the applied lookAt method, character in close proximity.

How can we correct this?

We need to get Lucy to look at a coordinate that’s at the same height as her origin. That way her tilt angle will be small.

So we are going to overwrite the component and of Vector3 by the value of the variable “yPos” that we will adjust from the inspector.

Ideally we could make the component and the Vector3 worth exactly the height of Lucy’s origin, this is something I realized later in the post production of the video. However it is good as an example that there is no single way to solve the problems.

Fig. 12: An instruction is added between means that overwrites the value of the component and the Vector3.

You can try writing the variable yPos at runtime, but when you stop the simulation all changed values will return to their initial value.

The value 0.75 works well for this case. A number less than this causes Lucy to lean down and come out the front of the capsule.

Fig. 13: The value -0.3 causes Lucy to exit from the front of the capsule.

Fig. 14: With yPos equal to 0.75 Lucy looks correctly at the character.

Fig. 15: With yPos equal to 0.75 Lucy looks correctly at the character.

In the following article we will study how to create and destroy objects at runtime. Subscribe to the YouTube channel to stay on top of new videos and articles.

Introduction

In this article we are going to explain what is a variable in programming, what types of variables there are, what they are used for and show some examples of variables in C#, in the development of video games with Unity.

What is a Variable in programming?

Variables are used in many disciplines, perhaps the most common example is the “X” variable in mathematics, which is generally an unknown value that we must find. In programming, variables are a somewhat different concept.

To understand the essence of computer variables we need to know a little about computer memories.

Computer memories store information in the form of bit registers (i.e. sets of values that can be 0 or 1). This information will be interpreted and used by the computer programs. Computer memories contain many of these registers, so each register has an address that allows it to be found, read and written.

Then we can say that a variable is a piece of information stored in the memory of the computer. The identification name that we assign is associated with the address within the memory and the value we save is the information contained in the variable.

Examples of variables in programming

The variables can be of different types, depending on the information we need to store. In figure 1 we see different types of variables and their assigned value.

Fig. 1: Examples of variables, identification name and value.

The variable “age” contains the value 22, this means that when we use the word “age” in our program, indirectly we will be using the value 22.

If we do the operation “2*age” (2 multiplied by age) it will have a result of 44.

Fig. 2: Examples of variables with poorly chosen names.

Choosing Names for Variables

Figure 2 shows variables that have been defined with confusing names. This happens very often when we want to solve things fast. It is important to choose representative names of the variables, because after a while we forget what we did and when we have to make changes it is difficult to understand.

The variable “house” in figure 2 has the value “false”. This variable could have been used, for example, to know if a character is in his house and if it is true to restore his health.

When putting a context it makes sense that “house” is false, this means that the character is not at home. However, it may take us a while to figure out what the function of the variable was.

We can save the effort by simply defining the variable as for example “characterAtHome”. Now the name of the variable suggest us its function.

Types of Variables in Programming

Let’s know the most basic variables that we are going to use to solve our problems. The examples are taken from the Labyrinth Game Series (click on the link to go to the main page of the series).

Variables type Boolean (bool)

The bool variables are named after the Boole Algebra developed by mathematician George Boole. They can be found in 2 possible states: True or False. We use them to solve logical operations.

Fig. 3: Fragment of the “GameControl” script from the My First Game on Unity project.

In the method seen in figure 3, we define the bool “validSelection” and initialize it with the false value.

Inside the while loop you select a random piece from the labyrinth and check if it is far enough from the character.

If the labyrinth piece is very close to the character, validSelection remains false and the program chooses another labyrinth piece again.

If the labyrinth piece is far enough away, validSelection will become true and the program will go ahead using that piece.

Fig. 4: The object to be found in the labyrinth is a pedestal with a sword.

Integer type variables (int)

The “int” type variables do not serve to store positive and negative integer values.


Fig. 5: Fragment of the “GameControl” script from the My First Game on Unity project.

In the method shown in figure 4, you see several integers, “nPieces”, “labyrinthPieces.Length”, “nClocks”, the numbers 0 and 1 and the iteration variable “i”.

Let’s take the case of the iterator variable “i”, it is declared and initialized with value 0 inside the for loop and it is used to execute the “placeAClock” method as many times as the value of nClocks is.

For example if we want to have 10 clocks in the scenario, we make “nClocks” worth 10, then the for loop will execute 10 times the “placeAClock” method.

Fig. 6: Watches that appear in the maze and give the player extra time.

Float Variables

Floating point variables are used to represent real numbers. That is to say, besides positive and negative integers we can represent numbers with decimal part. This type of variables can serve us for example to represent physical magnitudes.


Fig. 7: Fragment of the “Lucy” script from the project My First Game at Unity.

In the video of the Halloween 2018 special we defined a script for the NPC Lucy, a ghost that dwells in the labyrinth. Lucy chases the character with some speed.

To solve this behavior we make a linear interpolation between the position of the character and Lucy’s position using as parameter the float “velocity” multiplied by the float “Time.deltaTime”.

Fig. 8: Lucy chasing the character.

String Variables

Strings are not a variable in itself, but instances of a class, however many development environments allow us to treat strings as primitive variables.

We use them to store text.

Fig. 9: Fragment of the script “UIManager” from the project My first game at Unity.

The “showMessage” method seen in figure 9 belongs to the script “UIManager”, this method receives as a parameter a string called “message” and is responsible for displaying it in the user interface, as illustrated in figure 10.

Fig. 10: Example of a message displayed when interacting with certain objects.

Conclusion

In this article we saw what a variable is in programming and how we can use it to represent different types of data.

A variable in programming is a reference to a space in the memory in which a data is stored. We can assign it the name we want and when using that name we will be referring to that data stored in that particular part of the memory.

IMPORTANT UPDATE

This article is part of an older video series, a NEW SERIES is now available that goes into more depth on the topic of finding any GameObject or Components from a Script.

The following video is the introduction of the series on how to FIND GameObjects and components from a script in Unity

COMPLETE PLAYLIST HERE

OLD ARTICLE CONTINUES BELOW

Introduction

In this article we are going to study different ways to find, from a Script, the GameObjects that are in the hierarchy in Unity.

Among the forms we have to assign directly the objects from the inspector or find them through methods like “FindGameObject”.

Go to the project’s main page

Procedure

Let’s work with the Find GameObjects station, which consists of 5 objects on a table. The function of this station is to return objects that are disturbed to the resting state.

The problem is that initially we don’t have the object references, so the function can’t be carried out.

Fig. 1: 5 modelos 3d similares a trofeos en una mesa

Fig. 2: Station for finding disturbed objects. After a few seconds the objects disappear.

Fig. 3: Station to find objects returning to the resting state. After a few seconds the objects reappear in their initial position.

Inside the “FindGameObject” Script we have some code already written.

Fig. 4: FindGameObject script. Definition of the objects to be found.

The 5 objects are declared as private and are serialized, so they appear in the inspector (as shown in the following figure).

Fig. 5: Fields in the inspector for the references of the GameObjects.

In the Start method there is a call to 5 methods that will find the references.

Fig. 6: Call to the methods in charge of finding the object references.

The methods are incomplete. Our goal is to complete them and discover different ways to find the references.

Fig. 7: Methods for finding object references.

Way #1: Assign objects directly in the inspector to a serialized field.

As you can see in figure 4, all objects are defined as private and serialized, but this is more than anything for us to see in the inspector, how to start the game we find the reference.

For the 1st way, we take the object from the hierarchy and drag it into the field in the inspector. As illustrated below.

Fig. 8: Assignment of GameObject to field in the hierarchy.

With this we already tell our Script which object of the hierarchy is the GameObject defined with the name “Object1a”.

Way #2: Assign objects directly in the inspector to a public field.

This form is practically the same as the previous one, only now GameObject is defined as public.

Fig. 9: Definition of a GameObject with public visibility.

Defining a field as public makes it accessible from any context and therefore also appears in the inspector.

As in the previous form, we take the GameObject from the hierarchy and drag it into the field in the inspector.

Way #3: Labels. FindGameObjectWithTag method of the GameObject class.

The GameObject class has a method that allows you to find a GameObject in the hierarchy using the tags.

Fig. 10: Tag drop-down menu present in all GameObject in the hierarchy.

Fig. 11: Window that appears when you click on “Add Tag” (figure 10) and then on the “+” sign.

Then we proceed to write the code necessary to find the GameObject from the Script. We are going to write it inside the method “findGameObject2” that is seen in figure 7.

The code line is as follows:

object2=GameObject.FindGameObjectWithTag(“Object2”);

We are going to analyze it in parts, when writing “object2=” we are saying that the field object2 is going to be worth whatever we place after the sign “=”. As can be seen in figure 9, object2 is of the GameObject type, so what we place after the sign “=” will have to return an object of the GameObject type.

By typing “GameObject.” (GameObject dot), we are indicating that we want to access the attributes and methods that are defined in the GameObject class.

We run a method called FindGameObjectWithTag” (translated means: “find GameObject with tag”), this method needs that we enter (within parentheses) the String with the tag.

Reading this and interpreting it is complicated, but little by little it makes sense as we learn.

In the video we can see that when running the game, we managed to find the object2 reference.

In the C# language, capital and small letters are distinguished, so they must be respected.

Way #4: Name. Find method of the GameObject class.

As you can see in figure 10 above the Tag dropdown menu, there is a space with the text “Object2”, this is the name assigned to the GameObject and with that name is listed in the hierarchy.

Using the Find method of the GameObject class we can find a GameObject by name, as follows:

object3=GameObject.Find(“Object3”);

With this instruction, Unity will review the hierarchy, find the object named “Object3” (if there is one) and assign it to the object3 field.

If there is no GameObject named “Object3” in the hierarchy, the object3 field will have the value null. If there is more than one object that has the same name, we can’t be sure we’re going to find the one we want.

Way #5: Single component. Method FindObjectOfType.

The last way we’re going to see is a little more complicated.

The GameObject class allows us to find the reference to a component that is present in the hierarchy, for example the Transform component, Collider, RigidBody, etc.

Of course, practically all GameObjects have the Transform component, so in principle it wouldn’t be very useful. But what if the component we’re interested in is unique in the hierarchy? In other words, we know that there’s only one GameObject in the hierarchy that has it. This might help us, because finding that single component is equivalent to finding that GameObject.

It could be any component as long as it is unique, in this case we create a new Script with the name: “Object4Script” and we assign it to the GameObject of the hierarchy called “Object4”.

Then we write the following code in the “findGameObject4” method (see figure 7).

object4=GameObject.FindObjectOfType<Object4Script>().transform.gameObject;

First we find the Object4Script type object reference with the FindObjectOfType method of the GameObject class, then we access its transform component through the dot operator and then the gameObject component. The result of this is assigned to object4.

In this way we can find the GameObject from one of its components. Of course, if there is another GameObject that also has that component, we might find the wrong GameObject.

Introduction

In this article we are going to see several methods from the Input class that will alloud us to read keyboard and mouse inputs in Unity.

Go to the Project’s main page

Before we begin, I invite you to watch the following video that resolves this problem, make sure to activate the english subtitles.

Procedure

In the first video we are going to work on the input station, which consists of models for the “WASD” keys and mouse buttons.

The goal is to get them to change color when the corresponding entry is pressed.

Fig. 1: GameDevLab input station.

En la jerarquía hay un GameObject llamado #1 Input. Este objeto tiene todos los elementos relacionados a la estación de entradas.

Fig. 2: Hierarchy. The input station is the GameObject called #1 Input.

This GameObject is assigned the Read Input script, which will be responsible for reading the entries and performing actions on the elements of the station.

Fig. 3: Script Read Input assigned to GameObject #1 Input.

There’s no need to do anything in the hierarchy. Go to the folder “Scripts to Complete”, “Video 1 – Read Inputs” and open the script “ReadInput”.

Fig. 4: Script Read Input not completed. The missing code goes into the Update method.

Why should the code go in the Update method?

All scripts that extend their MonoBehaviour class behavior have an implicit Update method, which is automatically evaluated in each frame of our game.

As explained in the video, if our game runs at constant 60 fps, the Update method runs 60 times per second.

The reading of the Inputs is a random event, so we cannot determine when the player will press a button. For this reason, when we need to read the entries, we must do so in all frames.

How do we read the inputs?

Let us imagine that we can ask the computer in colloquial language about the state of the entries, what questions would we ask?

Fig. 5: Questions to ask.

If the answer to these questions is yes, we will execute an appropriate action for each one.

We already have the idea, now we just have to ask these questions using a language that the computer understands.

Using the if sentence, we can ask questions whose answer is true or false.

Unity’s Input class handles the inputs, so we use their methods to solve the problem. We have the GetKey method for the keys and GetMouseButton for the mouse buttons, in the argument of these methods we indicate the key using the enum KeyCode and the mouse button using integers, as can be seen in figure 6.

Solution

Fig. 6: The missing code is complete.

In this way, we can ensure that the Input station fulfils its function.

Fig. 7: Input station. W key pressed.

Fig. 8: Input station. Key A pressed.

Fig. 9: Input station. Click left.

Fig. 10: Input station. Right click.

Conclusion

As a first conclusion, I would like to mention how we went from thinking about the problem in colloquial language (figure 5) to writing it in C# language (figure 6). Thinking about the problems in this way is simpler, because we abstract ourselves from the programming language.
An intermediate step between this colloquial language and the C# code would be the pseudocode.

Reading Inputs is the way we know what the player wants to do, so we have to define what tickets we are going to offer and when we want to read them (for example perhaps we are not interested in reading the WASD tickets when we show a cinematic).

Input events are random, that’s why we must read them continuously using the Update method.

To avoid complications it is advisable to read the inputs in a single script.

There may be other types of inputs, such as a JoyStick or tactile entry. We must study Unity’s Input class to understand how to handle them.

Introduction

A vector is a mathematical tool that allows us to represent magnitudes in which not only the intensity (or modulus), but also the direction and direction in which they are applied are important.

The vectors are very useful in the development of games, they allow us to define directions for movement, do ray tracing, among other applications.

The simplest and perhaps the most everyday example I can think of is that of a force. Forces are vector magnitudes, not only does the amount of force applied matter, but also direction and meaning.

If, for example, we change the direction of the force we apply to an object, the object will probably move in the opposite direction.

Other examples of vector magnitudes can be torque, angular momentum, velocity. In electricity and magenithm we have the electric field at one point, the Poynting Vector.

Vectors in the plane and in space

For practical reasons we are going to look at the case of vectors in the plane and in space, i.e. vectors of two and three components respectively.

Mathematically

Usually a vector is identified by a letter with an arrow at the top.

There are different types of notations, one of them is to write the components of the vector in parentheses and separated with comma. In the plane we use two components and in the space three.

Fig. 1: Examples of vectors in the plane and in space.

Graphic Representation

The value of the vector represents the final point of an arrow starting from the origin of coordinates (i.e. (0.0) in the plane and (0.0.0) in space), to the coordinate indicated by the vector. As illustrated in figure 2.

Fig. 2: Graphic representation of vectors in the plane (left) and vectors in space (right).

Characteristics of a vector

Components

The components are the actual values for each axis of the coordinate system.

In the plane a vector has two components, generally x and y, in space we need three components, in general they are called x, y and z.

Magnitude

The module, norm or magnitude of a vector tells us about the size of the vector, the magnitude or intensity it has, in other words is how much the vector measures from the origin to the final point.

To calculate the module, Pitagoras’ theorem is used on the right triangles formed by the vector with the coordinate axes. This sounds somewhat complicated but the formulas are simple, in figure 3 we see the calculation of the norm of a vector in the plane and in space. Formula with examples.

Fig. 3: Calculation of the module or norm of a vector in the plane and in space.

Orientation

The orientation of the vector in the plane or in space. This allows us to calculate angles with respect to coordinate axes using right triangles, sinuses and cosines.

Given a vector we can find a single line that contains it.

Here we begin to see the usefulness of knowing about vectors to program video games, with the vectors we can represent movements in a determined direction or calculate the trajectory of a projectile for example.

Sense

Given a direction for the vector, we said that there is only one line that contains it, however the vector could be pointing to one side or the other of the line. With meaning we solve this ambiguity.

To change the direction of a vector it is enough to multiply by -1 all its components.

Vector in mathematics vs Vector in programming

In programming there is also a type of data known as vectors, arrays or arrays. However, this refers to a programming structure in which we can order data of the same type and use them to solve algorithms.

We can model mathematical vectors using arrays, however arrays can contain strings of text for example.

Mathematical Vectors in Unity

In Unity there are several components that use vectors, the simplest of which is the Transform component that determines the position, rotation and scale of a GameObject in Unity.

For this it uses three three-dimensional vectors. In figure 4 we can see these vectors in the inspector. Unity gives the vector components the name x, y and z.

Fig. 4: Transform component that has all GameObject in Unity.

Other components such as Colliders use vectors to draw the Collider, define its position and size. In figure 5 we see an example of Collider in three dimensions in which three component vectors are used and in figure 6 an example of Collider 2D in which two component vectors are used.

Fig. 5: 3-component vectors in for the diensions of a Collider.

Fig. 6: 2-component vectors for the dimensions of a 2D Collider.

In addition to the Unity components, in our Script we can create vectors to use in our algorithms.

The name of the object by which we refer to these vectors in a C# Script for Unity is Vector2 and Vector3. We can see some examples in figure 7.

Fig. 7: Examples of the use of mathematical vectors in Scripts C#, in Unity.

Conclusion

Vectors in mathematics are a useful tool for representing trajectories and forces.

A vector has a module that determines its size, a direction that determines its orientation in space, and a sense within that direction.

Given a vector we can find a single line that contains it.

Updated information about this project

This article belongs to a series that consist on making a first person game about finding objects inside a maze. It’s one of my very first series from the channel. Now I reworked this project and you can download it to import in your own Unity project. Some day I will make a new series about this project, subscribe to my channel to see all the fresh content about Blender, Unity and programming.

Follow me on itch.io and download the source code of this project



YOU CAN TRY THIS GAME HERE, IT MAY TAKE A LITTLE WHILE TO LOAD
🔻

MOVEMENT: WASD CAMERA LOOK: MOUSE



Introduction of the old article

In this article we are going to see a way to place collectable objects in Unity, these objects will be watches that when collecting them will add time in the countdown.

We are going to use the prefabricated clock that we configured in the second article of the project, click here to download the files and see how to configure the prefabs.

Go to the project’s Main Page

Before we begin I invite you to watch this video:




Objective description

We must establish rules and make an exhaustive description of the behavior of the clocks, for example how they will interact with the character, how they will appear on the stage, etc. The better the description, the easier it will be to create a solution using programming.

What we are looking for is that a certain number of clocks appear in the labyrinth. We must make sure that these clocks do not appear inside the walls and do not overlap each other.

To achieve this I am going to reuse the solution from the previous article to place the pedestal in a random position, in the solution I made each piece of the labyrinth know its own geometry and give us a position of its interior if we ask for it.

Fig. 1: The clocks will appear in random positions in the labyrinth.

In addition, I am going to make sure that each piece of the labyrinth can contain only one watch, in this way we do not run the risk of placing two superimposed watches.

To achieve this we must keep a record of the pieces of the labyrinth that have a clock inside, so when we are going to place a new clock, those pieces will not be considered in the selection.

When the character takes a watch, a certain number of seconds will be added to the countdown.

Every time a watch is destroyed, a new one appears on the stage, so that all the time we will have the same number of watches on the stage.

Resolution

Previous steps

We start by selecting GameObject Control from the hierarchy and assigning it the tag “GameController”. Then select the GameObject FPSController and assign the tag Player.

Fig. 2: Select the control object and assign the tag “GameController”.

Fig. 3: Select the player’s prefab and assign the tag “Player”.

Next we are going to create a new Script called Clock, which we will later assign to the prefabricated clock.

Fig. 4: We create a new script with the name “Clock”.

This script will model the behavior of clocks.

Fields of Clock Script

We are going to define a serialized String that we will call “playerTag”, this variable will contain simply the name of the tag that we have assigned in the player.

Then we will define a float type variable to indicate the life time in seconds of the clock on the stage.

We define a GameObject called labyrinthPiece with “get” and “set” as shown in Figure 5, this way it will be a parameter that can be read and written. I usually like to define public methods to access variables, but this is a very practical way to do it.

Finally we define a GameControl type object because the clock needs to inform the control what is happening.

Fig. 5: We define these fields for use in the solution.

Methods of Clock Script

First we define the SetLifeTime public method with float parameter that we will use so that the GameControl object assigns a certain life time to the clock.

Then there’s the SelfDestruction method that will run when the clock’s life time runs out or the character grabs it.

The Collect method will run when the character picks up the clock, alerts GameControl and then self-destruct.

Finally the OnTriggerEnter method to detect the character, when this happens we will execute the Collect method.

Fig. 6: We define these methods to use in the solution,

Fields in GameControl Script

Let’s go to the GameControl Script and define four serialized fields.

ClockPrefab will contain the prefab of the clock that we will place on the stage. The nClocks integer will indicate how many clocks should be placed on the stage. The float clockLifetime will be the average lifetime of a clock on the stage. Finally the whole timePerClock will indicate how many seconds are added to the Timer after the character takes a clock.

Fig. 7: In GameControl we are going to define some fields to solve the problem.

GameControl Script Methods Statement

The PlaceAllTheClocks method will make sure that it is possible to set the indicated number of clocks and then run the PlaceAClock method as many times as clocks need to be set.

ClockDestroyed will be executed by a clock that has just self-destruct, that way the GameControl Script will be able to re-consider the maze piece where the clock was and place a new clock in a random position.

ClockCollected will be executed by a clock when the character comes into contact with it, this way we can add time to the timer.

Finally, the DestroyAll method will destroy everything that must be destroyed at the end of a game (pedestal, clocks, character, etc.).

Fig. 8: We define some methods in GameControl.

Clock Method Instructions

To start in the Clock Start method we find the reference of the GameControl object, then we invoke the selfDestruction method in a time that is the result of the sum of the life time of the clock with a random value between 0 and 1. In this way we achieve that the clocks are not destroyed in the same frame.

Fig. 9: In the Clock Start method we are going to find the reference of the GameControl component and invoke self-destruction.

In the SelfDestruction method, we inform the GameControl object that a clock has been destroyed and pass the maze piece assigned to the clock as a parameter, so that the GameControl object can remove it from the exclusion list. Then we run the Destroy method with parameter “gameObject” so that the object destroys itself.

Fig. 10: In SelfDestruction we are going to tell the Control that the clock was destroyed and then run the Destroy method.

In the Collect method we are first going to cancel the pending invocation of the selfDestruction method. Then we inform the GameControl object that a clock was collected. Finally we run the selfDestruction method.

Fig. 11: The Collect method informs the event control and then self-destruct.

In the OnTriggerEnter method we are going to ask if the tag of the Collider that touched the clock is the one of the player and if this is true we are going to execute the Collect method.

Fig. 12: If the Collider that comes into contact with the clock has the tag “Player” we will execute the Collect method.

GameControl Methods Instructions

PlaceAllTheClocks Methods

In the PlaceAllTheClocks method of GameControl we will read the amount of labyrinth pieces we have available to place the clocks. If it turns out that more clocks must be placed than the number of labyrinth pieces, let’s make nClocks equal to the number of labyrinth pieces minus one, this way we’ll prevent the program from entering into an infinite loop.

Then we will do a loop executing the PlaceAClock method to place a clock on the stage.

Fig. 13: In the PlaceAllTheClocks method we will put all the clocks on the stage.

StartGame Method

In the StartGame method we are going to create the GameObjects List object (line 182 of figure 14).

To create the object is very important, so much so that in a computer exam in which it was necessary to write code on paper, I forgot to place the new instruction to create the object and I subtracted almost 40 points from 100. When I went to defend my exam they considered that they had exaggerated a little given that it had been my only error and they forgave me.

Fig. 14: In GameControl Start we create the list object and then execute the PlaceAllTheClocks method.

PlaceAClock Method

Returning to the subject of methods, in PlaceAClock we have to randomly choose a piece from the labyrinth assuring us that the piece no longer contains a clock, once we get it, we ask for a random position of its interior. To solve this it is necessary to have solved the exercise of the previous article, in which we created the Script Labyrinth Piece.

The algorithm for placing the watch part can be seen in figure 15.

Fig. 15: The PlaceAClock method will choose a piece from the labyrinth and place the watch.

ClockDestroyed Method

In the ClockDestroyed method we are going to remove from the list the piece of the labyrinth that is passed to us as a parameter and then execute the PlaceAClock method to place a new clock in the scenario.

Fig. 16: In Clock Destroyed we removed the maze piece containing the watch from the list and placed a new watch.

AddSeconds Method of Timer

We need to define a public method within Timer that allows us to add a number of seconds to the timer.

At the end of the script we make the declaration of the AddSeconds method, we will complete it at the end.

Fig. 17: In the Timer Script we are going to add a public method to add seconds to the timer.

Returning to the GameControl Script, in the ClockCollected method we make the call to the AddSeconds method of timer, passing as parameter the whole timePerClock.

Fig. 18: In the Clock Collected method we are going to add seconds to the countdown.

Now let’s go to the EndGame method, where the Destroy lines are, let’s run the DestroyAll method and cut the two Destroy instructions that we had previously placed in other items.

Fig. 19: Let’s go to the EndGame method, cut the destruction instructions and execute the DestroyAll method.

We paste those two instructions into the DestroyAll method and then find all the clocks on stage and destroy them using a foreach loop.

Fig. 20: In DestroyAll we paste the previously cut instructions and remove all clocks from the stage.

Setup Clock Prefab

Now let’s select the prefabricated clock from the project folder and drag it to the scenario to set it up.

Fig. 21: Select the prefab of the clock.

We create the Clock tag and assign it to the GameObject of the clock.

Fig. 22: We created a new Tag called Clock.

Fig. 23: We assign the Clock tag to the prefab of the clock.

Fig. 24: Clock with the assigned tag.

Then drag the Script Clock to its components or use the AddComponent button. Then we introduce “Player” in the tag field (figure 25).

Fig. 25: Assign the Script Clock to the prefab of the clock and enter the player’s Tag.

Let’s go to GameObject Control and enter the new parameters that we had previously defined.

Fig. 26: Select the Control object and set the new parameters in the inspector.

Now let’s complete the AddSeconds method of the Timer Script that we had pending.

Inside we will simply increase the seconds, adjust the minutes and execute the WriteTimer method to update the values.

Fig. 27: Back to the Timer Script and complete the AddSeconds method.

Programming error

At this point an error appeared in the console saying that there is no version of the PlaceAClock method that does not have parameters.

Fig. 28: An error occurs saying that there is no method definition that does not contain parameters.

I go to line 184 of the GameControl Script where the error appeared, in effect we see in figure 29 that the execution of the PlaceAClock method is done without parameters.

Fig. 29: I go to the instruction where the error is located.

I define the integer nPieces with the value of the amount of elements in the labyrinth parts list and enter this integer as a method parameter.

Fig. 30: I define an integer with the number of labyrinth pieces and pass it as parameter to the method.

Bug correction

When I test the game, the clocks didn’t seem to have appeared on the stage. When I paused the simulation and searched the hierarchy, I discovered that they had appeared but were upside down, as shown in figure 31.

Fig. 31: When running the game we find a bug, the clocks appear face down.

To correct this bug I go to the method where a clock is placed on the stage and I look for the instruction in which I make the Instantiate, instruction 173 in figure 32.

Instead of giving the new GameObject the rotation of the Quaternion identity I’m going to give it the rotation that is defined in the prefab of the clock, which when placed on the stage appears correctly oriented.

Fig. 32: I go to the point where I place the clocks on the stage.

Fig. 33: Instead of using Quaternion.Identity I use the rotation defined in Prefab.

Final Details and Test

When I tried the game, I noticed that there were few watches and that they gave up very little time when I picked them up.

In order to balance the elements correctly it is necessary to make several tests and see what works best, in addition this can form part of a system of difficulty in which a high difficulty implies less frequent clocks that deliver little time when picking them up.

Fig. 34: I adjust the values in GameControl to give me more time to collect them.

In figure 35 we have two clocks in front of nostors and the timer marks approximately one minute fifty, the figure 36 was taken moments after grabbing the two watches, we see that the Timer now marks a little more than two minutes ten. This concludes the problem.

Fig. 35: In the scene two clocks are observed in front of the character and the time indicates 1:47.

Fig. 36: After picking up both watches, the time is 2:13.

Conclusion

In this article we have seen how to randomly place collectables in Unity, these collectables were the clocks that when collecting them had to add time to the countdown.

The object GameControl is in charge of placing them on the stage randomly using the solution created in the previous article to place the pedestal randomly in a piece of the labyrinth.

To solve the problem we have created a Script that will model the behavior of the clock and will exchange messages with other Scripts to report events such as a self-destruction or that the character has picked up the clock.

The effect of collectable element we do it simply executing appropriate actions when the character passes over them.

Updated information about this project

This article belongs to a series that consist on making a first person game about finding objects inside a maze. It’s one of my very first series from the channel. Now I reworked this project and you can download it to import in your own Unity project. Some day I will make a new series about this project, subscribe to my channel to see all the fresh content about Blender, Unity and programming.

Follow me on itch.io and download the source code of this project



YOU CAN TRY THIS GAME HERE, IT MAY TAKE A LITTLE WHILE TO LOAD
🔻

MOVEMENT: WASD CAMERA LOOK: MOUSE



Introduction of the old article

In this article we are going to see a strategy to place an object in a random labyrinth position using the Random.Range method and the sword pedestal prefab created in the second article of the project, click here to download the files and see how to configure the prefabs.

Go to the project’s Main Page

Before we begin I invite you to watch this video.




Descripción del problema

We need the pedestal with the incrusted sword observed in figure 1 to appear anywhere in the labyrinth.

In video 4 of the series we solved a similar problem to place the character in one of the doors at the start of the game. Here is the article if you want to take a look.

Fig. 1: El pedestal con la espada aparece en una posición aleatoria del escenario.
Fig. 2: En el video y artículo 4 colocamos al personaje aleatoriamente en una de las puertas.

In video 4 we use empty GameObjects to designate specific positions in which to place the character’s prefab.

In this case we are looking for a more complex solution, first we are going to choose one of the pieces that compose the labyrinth. The piece we choose will be a duplicate of one of the pieces shown in figure 3.

Fig. 3: These are the pieces of the labyrinth in which you can walk.

It is not enough just to choose the piece, we need to obtain a position within it and this position must be within a region in which you can walk. We see these regions in figure 4.

Fig. 4: In these regions we will be able to place the pedestal.

When analyzing the problem we see that we will have to make several random decisions and it would be desirable that the solution we propose is independent of the number of pieces that the labyrinth has. In other words, if we add more pieces from figure 4, they are automatically added to the selection system.

Strategy: Define Segments

Given one of the pieces in figure 4, we are able to draw one or two internal lines where the player can circulate within the piece.

Let’s consider the ends of these two lines. Figure 6 identifies four points that would be the ends of these two segments.

These points could be represented with Empty GameObjects as children of the piece.

Fig. 5: Crossroads of the labyrinth.

Fig. 6: At the ends of the piece we place 4 points.

In figure 7 we see these two segments drawn.

Then we could place the pedestal with the sword at any point of one of the segments.

Fig. 7: These points form two segments, horizontal and vertical.

First of all, let’s choose one of the two segments, let’s suppose segment B (figure 8) formed by empty GameObjects B1 and B2.

Then we’ll take a random point between the two empty GameObjects, figure 9.

Fig. 8: Suppose we choose segment B.

Fig. 9: We choose a random point of segment B.

Finally at that chosen point we will place the pedestal.

Fig. 10: At the chosen point, place the pedestal with the sword.

In the case of the pieces of the corridor and dead end that only have one direction, we will make coincide the points A and B, that way we will have two coincident segments, then we will be able to use the same solution that for the rest of the pieces.

Fig. 11: In the case of the corridor, we will make segments A and B coincide.

Implementation of the strategy

We have worked out a plan to place the pedestal somewhere inside one of the pieces of the labyrinth. Now based on this we are going to solve the problem.

First in the hierarchy I’m going to separate the obstruction pieces from the others, because these pieces are not going to be considered in our solution.

In the figure 1 we see selected the pieces that we are going to use.

Fig. 12: Select the labyrinth and separate the obstructing parts.

We need to find the references of these pieces in our code to be able to choose one of them. The simplest way to do this is to use a Tag.

Fig. 13: We create the SpawnPiece tag for the pieces that can contain the labyrinth.

I’m going to create a Tag called “SpawnPiece” and assign it to all the pieces selected in figure 12.

Fig. 14: We select all the parts that can contain the pedestal.

Fig. 15: The selected pieces are assigned the SpawnPiece tag.

Next we create the Script “LabyrinthPiece” (labyrinth piece) that will be assigned to all the pieces selected in figure 12.

Fig. 16: We create a new script called LabyrinthPiece, which we will assign to the parts that can contain the pedestal.

In the Script first we will define four GameObjects that will be points A1, A2, B1 and B2. We declare them as serializable fields so that they appear in the inspector and we can assign them manually.

Fig. 17: We define four GameObject type fields to contain the points of each piece.

We select any piece type Crossroads and assign the Script LabyrinthPiece. In figure 19 we see that in the inspector appear the fields for GameObjects.

Fig. 18: In the hierarchy we select the crossroads.

Fig. 19: We assign the Script LabyrinthPiece to the crossroads.

Next we’re going to create the four empty GameObjects that we’ll call A1, A2, B1 and B2. In figure 20 we see created the first point. Note that it is defined as the son of an Empty GameObject called Spawn, which in turn is the son of the crossroads piece.

Fig. 20: We created four empty GameObjects as sons of this piece.

We are going to position these four objects according to figure 6, at the ends of the imaginary segments that represent the walkable area inside the piece.

Fig. 21: Using the orthographic perspective, we position the empty GameObjects, one at each end.

Fig. 22: Using the orthographic view, we position the empty GameObjects, one at each end.

We assign these objects to their respective fields in the inspector, within the LabyrinthPiece component.

Finally we apply the changes. This is very important because we are applying the changes on the Prefab of the crossroads, that is to say that all the crossroads of the labyrinth will now have their own objects A1, A2, B1 and B2 and will have assigned the component LabyrinthPiece, with their own points loaded in the fields.

Fig. 23: We assign the empty GameObjects to the spaces in the inspector.

Fig. 24: We apply the changes so that all the crossroads of the scenario have the same configuration.

We can check that by checking every crossroads in the hierarchy and checking that it has these points and the Script assigned to it.

Fig. 25: When applying the changes, all the labyrinth crossroads become empty objects and the Script LabyrinthPiece.

What follows is to repeat the process for the other pieces. In figure 26 we see the T-shaped piece, this case is similar to the bifurcation only that one of the imaginary segments will have its end in the center of the piece.

Fig. 26: Empty objects for the bifurcation piece.

In the corridor piece we create only points A1 and A2. In figure 28 we see that these points are also assigned in fields B1 and B2 respectively.

Fig. 27: Empty objects for the aisle piece.

Fig. 28: For the aisle part we assign points A1 and A2 also to fields B1 and B2.

In the corner piece, figure 29, the imaginary segments will have two coincident points, we could create only three Empty GameObjects and one of them assign it for example to A2 and B1, but we chose to create the four points.

Fig. 29: Empty objects for the corner piece.

The case of the dead-end piece is the same as that of the aisle only with less distance.

In figure 31 we see that in points B1 and B2 we repeat points A.

Fig. 30: Empty objects for the dead-end piece

Fig. 31: For the dead end piece we assign points A1 and A2 also to fields B1 and B2.

Method for choosing a random position of a piece – Random.Range

In the Script LabyrinthPiece we are going to create a public method that will return a Vector3 that will indicate a random position of the piece.

The first instruction will be to declare a Vector3 called position which will be the one we return to at the end of the execution.

Let us remember that they are two imaginary segments formed one by points A1 and A2, another by points B1 and B2. So then let’s do an if to choose one segment or the other.

In the if argument we use Random.Value to generate a random number between 0-1 and check if this value is less than 0.5f. This means that we will have a 50% chance of choosing segment A and another 50% of choosing segment B.

To choose a random point of the imaginary segment formed by the points we use the Vector3.Lerp method, which will make a linear interpolation between two Vectors3 that we indicate.

The method receives three arguments, the first two are the Vector3 between which it will be interpolated and the third parameter is the interpolation point we are interested in.

To exemplify the interpolation function consider the following: if the third value of the Lerp method is 0 we will have a Vector3 equal to the first parameter indicated. If it is worth 1 we will have a Vector3 equal to the second parameter indicated. And if it is worth 0.5f we will have a Vector3 that will be located exactly in the central point between the two Vectors3 that we indicate as parameters.

In this way we use Random.Range to generate a Vector3 that will be in some position between the points indicated in the first two parameters of the Lerp method and we assign that vector to the Vector3 position that we had defined at the beginning.

In an if region we use the position of points A1 and A2. In the other if region we do exactly the same but with points B1 and B2.

Finally we return the Vector3 position.

All this explained is summarized in the 7 lines of the GetRandomPosition method in figure 32.

Fig. 32: The GetRandomPosition method will deliver a random position inside the part.

Now, this we did was for the Script LabyrinthPiece that is assigned to each piece of the labyrinth.

In the GameControl Script we are going to create a method that will place the pedestal in a random position in the labyrinth and make use of the public method of LabyrinthPiece.

We begin by defining the fields shown in figure 33 below the comment “//Video 9”. These are the fields and variables that we will use to solve the problem.

Fig. 33: In the GameControl Script we define a GameObjects array for the labyrinth pieces.

In the GameControl component in the inspector (assigned to GameObject Control), fill in the fields. In SpawnPieceTag type “SpawnPiece”.

Fig. 34: We write the name of the tag that we assign in the pieces of the labyrinth, in this case “SpawnPiece”.

In ObjectToFind we will assign the Prefab of the pedestal with the sword, which is the object to find.

Fig. 35: We looked for the prefab of the pedestal with the sword we made in video 2 of the series.

In the minimum distance for the moment we write the value 75. Then we will see what this variable is used for.

Fig. 36: Assign the Prefab of the pedestal to the ObjectToFind field.

It is not necessary that the LabyrinthPieces array appears in the inspector so I am going to remove the [SerializeField] selected in figure 37.

Fig. 37: It is not necessary for the GameObject array of labyrinth pieces to be visible in the inspector.
Fig. 38: It is not necessary for the GameObject array of labyrinth pieces to be visible in the inspector.
Fig. 39: When removing the SerializeField line, the field does not appear in the inspector as it is private.

In the StartGame method we are going to find all the GameObjects of the hierarchy that have the Tag that we indicate in the inspector. Last instruction of the startGame method in figure 40.

Fig. 40: In the GameControl Start method we find all GameObjects with the indicated Tag.

Then we declare the PlaceObjectToFind method (figure 41) and call this method from the StartGame method (figure 42).

Fig. 41: We define a private method that will be in charge of placing the pedestal in some part of the labyrinth.

Fig. 42: We make the call from the StartGame method, i.e. when the game starts the pedestal is placed on the stage.

PlaceObjectToFind Method

What we will do with this method is to choose a random piece from the labyrinth, making sure that piece is far enough away from the player using the “minDistance” variable that we assigned 70 in the inspector. If the selected piece does not meet this requirement we will choose another piece again. This is taken care of by the While loop shown in figure 43.

Once we find a part that meets the requirements, we will place the pedestal at a random point inside. For this we use a version of the Instantiate method, which receives three parameters: The first is the object to be found stored in the “objectToFind” field, the second is the position that we will receive automatically from the labyrinth piece executing the GetRandomPosition method of the LabyrinthPiece component assigned to it. The third parameter is the rotation, here we will indicate: Quaternion.identity (a rotation identity).

Fig. 43: Instructions for the PlaceObjectToFind method.

It is important that we save the reference of this new object that we have created, we will do it in “objectToFindInstance” (last instruction in figure 43). This way when the game is over we can destroy this object manually.

In the EndGame method we destroy the instance of the object to be found, figure 44.

Fig. 44: In the EndGame method, the pedestal instance is destroyed.

When you enter the game mode and press the Start button, everything seems to be working correctly. The pedestal with the sword appears in a random labyrinth position inside one of the pieces.

Fig. 45: When entering the game mode the pedestal is placed on one of the pieces of the stage.

Fig. 46: We can see from the editor window which part it is.

Place object in other regions

There are regions of the labyrinth that are outside the pieces, for example the one highlighted in figure 47. We might be interested in placing the object in a position belonging to this area.

How could we reuse what we have done?

Fig. 47: This region can be a place where we would like the pedestal to appear.

To begin with we created an Empty GameObject and called it SpawnArea and placed it between the pieces of the labyrinth.

Fig. 48: Create an Empty GameObject and call it SpawnArea, this will allow us to place the pedestal in other parts of the labyrinth.

Fig. 49: The four points in the region are children of GameObject SpawnArea.

Then we created four empty GameObjects to represent points A1, A2, B1 and B2. We place these objects at the ends of the two imaginary segments of the area highlighted in green in Figure 49.

Fig. 50: We are going to create 4 empty GameObjects to use in the LabyrinthPiece script.

Then we create a Prefab along with the other pieces of the labyrinth (figure 51), because we may reuse this object by changing the internal points.

Fig. 51: We took the GameObject SpawnArea and created a Prefab for reuse.

Then we assign the component LabyrinthPiece and place the internal points in the respective fields.

Fig. 52: Asignamos el Script LabyrinthPiece al GameObject SpawnArea.

Do not forget to assign the Tag SpawnPiece in the inspector, otherwise these areas will not be considered when choosing a position for the pedestal. In my case, as can be seen in figure 53, I had not assigned it and I spent several minutes testing for the pedestal to appear in these areas.

Fig. 53: We must remember to assign the SpawnPiece tag to the GameObject SpawnArea. Apply changes.

Final Details

When I tried the game, I noticed that the door was quite large in relation to the character, so I made it a little smaller and applied the changes.

Fig. 54: The doors were too big in relation to the character.

Another problem I detected was that there were pieces with the Tag SpawnPiece whose inner region was inaccessible to the player. In figure 55 you see one of these pieces, if the pedestal appears here, the player won’t be able to find it.

The solution to this is to select this piece and remove the Tag SpawnPiece, this way the piece will not be considered.

Fig. 55: This piece is out of reach of the character, the pedestal does not have to appear here.

Fig. 56: Select that piece and in the tag field select: “Untagged”. We do not apply the changes.

Conclusion

In this article we managed to place the pedestal in a random position within the labyrinth.

To do this we had to analyze the type of pieces that make up the labyrinth, establish certain rules and propose a strategy to solve our problem.

We used object-oriented programming thinking to create a flexible solution that fits all types of parts.

As usually happens, there is no single way to solve a problem. Another way to address this situation is to make a Navmesh Bake and take a point within these regions.

Updated information about this project

This article belongs to a series that consist on making a first person game about finding objects inside a maze. It’s one of my very first series from the channel. Now I reworked this project and you can download it to import in your own Unity project. Some day I will make a new series about this project, subscribe to my channel to see all the fresh content about Blender, Unity and programming.

Follow me on itch.io and download the source code of this project

YOU CAN TRY THIS GAME HERE, IT MAY TAKE A LITTLE WHILE TO LOAD
🔻

MOVEMENT: WASD CAMERA LOOK: MOUSE

Introduction of the old article

In this article we are going to see how to create a terrain in Unity using its own tools and we are going to create a labyrinth using the prefabs that were configured in the second article of the project, click here to download the files and to see how to configure the prefabs.

Go to the project’s Main Page

Before we begin I invite you to watch this video.


Description of the objective

Create the labyrinth

To create a model of the labyrinth we are going to use the prefabricated ones that we created previously, we will place them in the hierarchy and we will begin to duplicate them and to arrange them in the space, as it is observed in the following figure.

Fig. 1: Setting up the stage using the prefabricated elements shown in video 2.

Create terrain in Unity

To create a terrain in Unity we will use the GameObject “Terrain”, which will allow us to modify its relief and textures in a simple way using different brushes and parameters.

Fig. 2: Using Unity tools we can sculpt relief in the terrain.

Download Files

First we download the next Zip file, extract the folders and take them to Unity.

Fig. 3: Extract the textures from the download file to add them to the project.

Fig. 4: Each texture comes with its Albedo, Metallic and Normal maps.


The next thing we do is remove all the elements belonging to the scenario.

Fig. 5: We start by completely cleaning the stage.

Terrain Component – Unity

As mentioned above we will use the Terrain component to create a mountainous relief for the terrain.

This component uses “Height Maps” or height maps to create reliefs, these maps are grayscale textures in which completely black areas are mapped with minimum height and white areas with maximum height (both heights configured in the parameters), the rest of the gray areas will have a height proportional to its color tone.

We can see this in the following image.

Fig. 6: The terrain works with Height maps.

In the hierarchy right click > 3D Object > Terrain.

Fig. 7: From the hierarchy we create a GameObject type terrain.

In the stage a white plane appears and in the inspector we can see that it has two components that define it, the component Terrain and a Collider type Terrain.

Fig. 8: The terrain appears in the scenario and we can see its properties in the inspector.

Terrain Component Setup

It is important that we first configure the basic parameters of the terrain, such as the dimension and the difference that will exist between the maximum and minimum height. Then we can modify these parameters but we will probably lose the design we had.

As shown in figure 9, click on the gear icon to go to the configuration. Then enter the parameters.

The only thing I’m going to change is the resolution of the land, which will be 1000 x 1000.

Fig. 9: First configure the basic parameters of the inspector.

Fig. 10: We adjust the resolution of the terrain.

Texture Setup

We can paint the terrain using different sets of textures that will consist of Albedo and Normal maps. First we select all the normal maps we have, in the inspector we choose the type of texture as “Normal map” and apply the changes. We do this for all the normal maps we have.

Fig. 11: Select textures such as Normal Map or Normal Map.

Fig. 12: In the inspector we can select the type of texture. Select Normal Map and apply.

Then select the terrain again and click on the brush icon, then on “Edit Textures…”, “Add Textures” (figures 13 and 14).

Fig. 13: Select the brush tool on the ground component.

Fig. 14: We must configure at least one painting for the terrain.

In the pop-up window we can select a texture that represents the Albedo in the RGB channels and its Alpha channel is mapped in the softness. Another texture for the surface Normals. We can also configure the size of the mosaic or TileSize using the fields “Size” and “Offset” that are observed in figure 15.

Fig. 15: In the pop-up window we select an Albedo texture and a normal texture.

Click on Select and choose first the Albedo map and then the normal map.

Fig. 16: We must make sure to select the appropriate maps.

We’ll do this for all the textures we’ll use to paint the terrain.

Figure 17 shows some values that work for TileSizes.

Fig. 17: Working mosaic size values.

Once we set up all the textures, we should have them all available for use in the Textures in Inspector window, as shown in figure 18.

Fig. 18: All the textures of the download have been configured.


Making the labyrinth

First to keep things tidy I’m going to create an Empty GameObject that I call “Maze”, inside which will be all the prefabricated ones that I use to make the labyrinth.

Fig. 19: We create an empty object that will contain all the pieces of the labyrinth.

Then I drag all the prefabs to the stage and start duplicating them and moving them to form the corridors.

Fig. 20: We start by placing all the prefabricated parts on the stage.

To facilitate the positioning of the pieces we can use the orthographic view. In figure 20 at the top right we have what is called a “Gizmo” that shows the axes X in red and Z in blue. By clicking on these arrows we can change the view of the scene and if we click on the cube in the center we can alternate the view from Perspective to Orthographic.

In figures 20 and 21 we can see how this orthographic view is. The effect it produces is as if all the elements were compressed into one plane, so we do not observe the depth.

Fig. 21: Duplicate the pieces and move them on stage to build the labyrinth.

Fig. 22: Using the orthographic view and bringing the camera closer we make sure that the pieces fit together.

We also put some doors on the stage. In video 4 of the series we created the prefabricated door, here is the article.

Fig. 23: We place several doors in the labyrinth.

We go into game mode and go through the labyrinth to detect problems. In figure 5 you can see one of the badly placed doors.

Fig. 24: We test the scene for problems.

Fig. 25: Walking through the labyrinth we found a door that was badly positioned.

Fig. 26: We stopped the game mode to correct the problem.

Relief modeling

Then we’re going to start modeling the mountains. Select the GameObject Terrain from the hierarchy and in the inspector click on the first icon of the component (figure 27).

Then we select some pattern in the section “Brushes” that is observed in figure 28.

Fig. 27: Select the Raise/Lower tool in the terrain component.

Fig. 28: We choose a brush to apply the modification to the terrain.

The next thing we do is paint in the editor and the terrain will gain height.

Fig. 29: We start painting regions of the terrain to produce elevations and create relief.

Another useful tool is the levelling tool (selected in figure 30).

Fig. 30: Select the ground leveling tool.

Fig. 31: We choose the height value at which we want to level the terrain.

This will allow us to establish a certain height and as we pass it over the terrain in the editor, the lower areas will begin to rise and the higher areas will descend, this is illustrated in figures 32 and 33.

Fig. 32: The regions below the level rise and those above descend.

Fig. 33: We can establish zones that will have a certain height in all its extension.

Fig. 34: We go into game mode to observe the mountainous relief from the perspective of the labyrinth.

Fig. 35: The highest part of the relief is in the opposite direction to the sun of the scene.

After playing with the tools for a while, I ended up with something similar to figure 36.

The most important purpose of the relief is to cover the horizon and somehow provide guidance to the player.

Fig. 36: We use the above tools until we are satisfied with the design.

Apply textures to the terrain

In the final phase of this article on how to create a terrain in Unity we will apply the textures configured above.

Select the brush tool in the inspector, a pattern and a texture.

Fig. 37: Select the brush tool, choose the pattern and texture to apply.

Then in the editor we go around the terrain and paint.

We can alternate the textures and with this we can avoid that the ground looks monotonous with an only texture.

Fig. 38: To the base texture we apply another texture in different places to break the pattern of repetition.

The mountains will have a base of earth and then we will be applying in different parts a rock texture

Fig. 39: We give mountains a base with the ground texture.
Fig. 41: We apply the rock texture in different parts of the relief.

Fig. 40: Ground texture in the mountains.
Fig. 42: Rock texture in the mountains.
Fig. 43: Rock texture in the mountains.

From time to time we go into game mode to see how the relief looks from inside the labyrinth.

Fig. 44: We enter the game mode to observe the results.

Fig. 45: Final design of the labyrinth.

Fig. 46: Final design of the mountainous relief seen from the labyrinth.

Conclusion

We’ve seen how easily we can create a piece of land in Unity using the same tools that the engine provides us. We also apply different textures to give it diversity.

The exercise proposed in this article and video is very simple, but with enough time and practice we can build a number of reliefs.

This type of land has the limitation that caverns or caves cannot be built. For that we will have to superimpose another 3D model.

In addition we have created the labyrinth using the prefabricated ones configured in previous entries. Simply by making duplicates and moving in space.

We can make both simple and complex labyrinths and assemble a level selection system if we wish. The possibilities are unlimited.

Let’s bear in mind that this project is only a prototype, in order to achieve a better graphic quality it is necessary to build better 3D models and use a greater diversity of textures and higher quality. It would be nice to add decorative elements such as rubble or trees.

Exit mobile version
Secured By miniOrange