#9 Object in a Random position of the Labyrinth

Updated information about this project

This arti­cle belongs to a series that con­sist on mak­ing a first per­son game about find­ing objects inside a maze. It's one of my very first series from the chan­nel. Now I reworked this project and you can down­load it to import in your own Uni­ty project. Some day I will make a new series about this project, sub­scribe to my chan­nel to see all the fresh con­tent about Blender, Uni­ty and pro­gram­ming.

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 arti­cle we are going to see a strat­e­gy to place an object in a ran­dom labyrinth posi­tion using the Random.Range method and the sword pedestal pre­fab cre­at­ed in the sec­ond arti­cle of the project, click here to down­load the files and see how to con­fig­ure the pre­fabs.

Go to the project's Main Page

Video related to this article

Before we begin I invite you to watch this video. 


Descripción del problema

We need the pedestal with the incrust­ed sword observed in fig­ure 1 to appear any­where in the labyrinth.

In video 4 of the series we solved a sim­i­lar prob­lem to place the char­ac­ter in one of the doors at the start of the game. Here is the arti­cle if you want to take a look.

pedestal con espada instanciado aleatoriamente en un laberinto utilizando random.range unity
Fig. 1: El pedestal con la espa­da aparece en una posi­ción aleato­ria del escenario.
miniatura video 4 del juego del laberinto, colocar personaje aleatoriamente en escenario, unity
Fig. 2: En el video y artícu­lo 4 colo­camos al per­son­aje aleato­ri­a­mente en una de las puertas.

In video 4 we use emp­ty GameOb­jects to des­ig­nate spe­cif­ic posi­tions in which to place the character's prefab. 

In this case we are look­ing for a more com­plex solu­tion, first we are going to choose one of the pieces that com­pose the labyrinth. The piece we choose will be a dupli­cate of one of the pieces shown in fig­ure 3.

piezas simples que forman un laberinto para un prototipo en unity
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 posi­tion with­in it and this posi­tion must be with­in a region in which you can walk. We see these regions in fig­ure 4. 

piezas simples que forman un laberinto para un prototipo en unity
Fig. 4: In these regions we will be able to place the pedestal.

When ana­lyz­ing the prob­lem we see that we will have to make sev­er­al ran­dom deci­sions and it would be desir­able that the solu­tion we pro­pose is inde­pen­dent of the num­ber of pieces that the labyrinth has. In oth­er words, if we add more pieces from fig­ure 4, they are auto­mat­i­cal­ly added to the selec­tion system.

Strategy: Define Segments

Giv­en one of the pieces in fig­ure 4, we are able to draw one or two inter­nal lines where the play­er can cir­cu­late with­in the piece.

Let's con­sid­er the ends of these two lines. Fig­ure 6 iden­ti­fies four points that would be the ends of these two segments. 

These points could be rep­re­sent­ed with Emp­ty GameOb­jects as chil­dren of the piece.

encrucijada de laberinto con texturas
Fig. 5: Cross­roads of the labyrinth.

encrucijada de laberinto con texturas, puntos extremos marcados
Fig. 6: At the ends of the piece we place 4 points.

In fig­ure 7 we see these two seg­ments drawn.

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

encrucijada de laberinto con texturas, puntos extremos forman dos segmentos
Fig. 7: These points form two seg­ments, hor­i­zon­tal and vertical.

First of all, let's choose one of the two seg­ments, let's sup­pose seg­ment B (fig­ure 8) formed by emp­ty GameOb­jects B1 and B2.

Then we'll take a ran­dom point between the two emp­ty GameOb­jects, fig­ure 9.

encrucijada de laberinto con texturas, uno de los segmentos se eligen al azar con random.range
Fig. 8: Sup­pose we choose seg­ment B.

encrucijada de laberinto con texturas, se elige un punto aleatorio del segmento con random.range
Fig. 9: We choose a ran­dom point of seg­ment B.

Final­ly at that cho­sen point we will place the pedestal.

encrucijada de laberinto con texturas, posicion final donde se coloca el pedestal utilizando Random.Range
Fig. 10: At the cho­sen point, place the pedestal with the sword.

In the case of the pieces of the cor­ri­dor and dead end that only have one direc­tion, we will make coin­cide the points A and B, that way we will have two coin­ci­dent seg­ments, then we will be able to use the same solu­tion that for the rest of the pieces.

pasillo de laberinto con texturas, tomaremos un punto aleatorio del segmento con random.range
Fig. 11: In the case of the cor­ri­dor, we will make seg­ments A and B coincide.

Implementation of the strategy

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

First in the hier­ar­chy I'm going to sep­a­rate the obstruc­tion pieces from the oth­ers, because these pieces are not going to be con­sid­ered in our solution.

In the fig­ure 1 we see select­ed the pieces that we are going to use.

prototipo de laberinto hecho en unity
Fig. 12: Select the labyrinth and sep­a­rate the obstruct­ing parts. 

We need to find the ref­er­ences of these pieces in our code to be able to choose one of them. The sim­plest way to do this is to use a Tag.

crear tag en unity, spawnpiece para las piezas en las que podremos colocar el objeto de manera aleatoria usando random.range
Fig. 13: We cre­ate the Spawn­Piece tag for the pieces that can con­tain the labyrinth.

I'm going to cre­ate a Tag called "Spawn­Piece" and assign it to all the pieces select­ed in fig­ure 12.

se seleccionan todas las piezas que pueden contener al pedestal
Fig. 14: We select all the parts that can con­tain the pedestal.

asignacion de tag a uno o mas gameobjects en unity
Fig. 15: The select­ed pieces are assigned the Spawn­Piece tag.

Next we cre­ate the Script "Labyrinth­Piece" (labyrinth piece) that will be assigned to all the pieces select­ed in fig­ure 12.

creacion de script en unity que se encargara de colocar un objeto en una posicion aleatoria del laberinto usando random.range
Fig. 16: We cre­ate a new script called Labyrinth­Piece, which we will assign to the parts that can con­tain the pedestal.

In the Script first we will define four GameOb­jects that will be points A1, A2, B1 and B2. We declare them as seri­al­iz­able fields so that they appear in the inspec­tor and we can assign them manually.

definicion de campos serializados en script c sharp, unity
Fig. 17: We define four GameOb­ject type fields to con­tain the points of each piece.

We select any piece type Cross­roads and assign the Script Labyrinth­Piece. In fig­ure 19 we see that in the inspec­tor appear the fields for GameObjects.

prototipo de laberinto hecho en unity
Fig. 18: In the hier­ar­chy we select the crossroads.

ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity
Fig. 19: We assign the Script Labyrinth­Piece to the crossroads.

Next we're going to cre­ate the four emp­ty GameOb­jects that we'll call A1, A2, B1 and B2. In fig­ure 20 we see cre­at­ed the first point. Note that it is defined as the son of an Emp­ty GameOb­ject called Spawn, which in turn is the son of the cross­roads piece.

encrucijada de laberinto con texturas
Fig. 20: We cre­at­ed four emp­ty GameOb­jects as sons of this piece.

We are going to posi­tion these four objects accord­ing to fig­ure 6, at the ends of the imag­i­nary seg­ments that rep­re­sent the walk­a­ble area inside the piece.

encrucijada de laberinto con texturas
Fig. 21: Using the ortho­graph­ic per­spec­tive, we posi­tion the emp­ty GameOb­jects, one at each end.

encrucijada de laberinto con texturas
Fig. 22: Using the ortho­graph­ic view, we posi­tion the emp­ty GameOb­jects, one at each end.

We assign these objects to their respec­tive fields in the inspec­tor, with­in the Labyrinth­Piece component.

Final­ly we apply the changes. This is very impor­tant because we are apply­ing the changes on the Pre­fab of the cross­roads, that is to say that all the cross­roads of the labyrinth will now have their own objects A1, A2, B1 and B2 and will have assigned the com­po­nent Labyrinth­Piece, with their own points loaded in the fields.

ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity
Fig. 23: We assign the emp­ty GameOb­jects to the spaces in the inspector.

aplicar cambios en inspector para extender la configuracion a los demas prefabricados
Fig. 24: We apply the changes so that all the cross­roads of the sce­nario have the same configuration.

We can check that by check­ing every cross­roads in the hier­ar­chy and check­ing that it has these points and the Script assigned to it.

ventana jerarquia en unity, gameobjects que representas piezas de un laberinto
Fig. 25: When apply­ing the changes, all the labyrinth cross­roads become emp­ty objects and the Script LabyrinthPiece.

What fol­lows is to repeat the process for the oth­er pieces. In fig­ure 26 we see the T‑shaped piece, this case is sim­i­lar to the bifur­ca­tion only that one of the imag­i­nary seg­ments will have its end in the cen­ter of the piece.

prototipo de laberinto hecho en unity, piezas de laberinto en la jerarquia
Fig. 26: Emp­ty objects for the bifur­ca­tion piece.

In the cor­ri­dor piece we cre­ate only points A1 and A2. In fig­ure 28 we see that these points are also assigned in fields B1 and B2 respectively. 

prototipo de laberinto hecho en unity, piezas de laberinto en la jerarquia
Fig. 27: Emp­ty objects for the aisle piece.

ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity
Fig. 28: For the aisle part we assign points A1 and A2 also to fields B1 and B2.

In the cor­ner piece, fig­ure 29, the imag­i­nary seg­ments will have two coin­ci­dent points, we could cre­ate only three Emp­ty GameOb­jects and one of them assign it for exam­ple to A2 and B1, but we chose to cre­ate the four points.

prototipo de laberinto hecho en unity, piezas de laberinto en la jerarquia
Fig. 29: Emp­ty objects for the cor­ner piece.

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

In fig­ure 31 we see that in points B1 and B2 we repeat points A.

prototipo de laberinto hecho en unity, piezas de laberinto en la jerarquia
Fig. 30: Emp­ty objects for the dead-end piece

ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity
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 Labyrinth­Piece we are going to cre­ate a pub­lic method that will return a Vector3 that will indi­cate a ran­dom posi­tion of the piece.

The first instruc­tion will be to declare a Vector3 called posi­tion which will be the one we return to at the end of the execution.

Let us remem­ber that they are two imag­i­nary seg­ments formed one by points A1 and A2, anoth­er by points B1 and B2. So then let's do an if to choose one seg­ment or the other. 

In the if argu­ment we use Random.Value to gen­er­ate a ran­dom num­ber between 0–1 and check if this val­ue is less than 0.5f. This means that we will have a 50% chance of choos­ing seg­ment A and anoth­er 50% of choos­ing seg­ment B.

To choose a ran­dom point of the imag­i­nary seg­ment formed by the points we use the Vector3.Lerp method, which will make a lin­ear inter­po­la­tion between two Vectors3 that we indicate.

The method receives three argu­ments, the first two are the Vector3 between which it will be inter­po­lat­ed and the third para­me­ter is the inter­po­la­tion point we are inter­est­ed in.

To exem­pli­fy the inter­po­la­tion func­tion con­sid­er the fol­low­ing: if the third val­ue of the Lerp method is 0 we will have a Vector3 equal to the first para­me­ter indi­cat­ed. If it is worth 1 we will have a Vector3 equal to the sec­ond para­me­ter indi­cat­ed. And if it is worth 0.5f we will have a Vector3 that will be locat­ed exact­ly in the cen­tral point between the two Vectors3 that we indi­cate as parameters.

In this way we use Random.Range to gen­er­ate a Vector3 that will be in some posi­tion between the points indi­cat­ed in the first two para­me­ters of the Lerp method and we assign that vec­tor to the Vector3 posi­tion that we had defined at the beginning.

In an if region we use the posi­tion of points A1 and A2. In the oth­er if region we do exact­ly the same but with points B1 and B2.

Final­ly we return the Vector3 position.

All this explained is sum­ma­rized in the 7 lines of the GetRan­dom­Po­si­tion method in fig­ure 32.

metodo publico en script c sharp para colocar objeto en posicion aleatoria usando Random.Range
Fig. 32: The GetRan­dom­Po­si­tion method will deliv­er a ran­dom posi­tion inside the part.

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

In the Game­Con­trol Script we are going to cre­ate a method that will place the pedestal in a ran­dom posi­tion in the labyrinth and make use of the pub­lic method of LabyrinthPiece.

We begin by defin­ing the fields shown in fig­ure 33 below the com­ment "//Video 9". These are the fields and vari­ables that we will use to solve the problem. 

definicion de campos serializados en script c sharp, unity
Fig. 33: In the Game­Con­trol Script we define a GameOb­jects array for the labyrinth pieces.

In the Game­Con­trol com­po­nent in the inspec­tor (assigned to GameOb­ject Con­trol), fill in the fields. In Spawn­Piec­eTag type "Spawn­Piece".

ventana inspector de un gameobject, el campo spawn piece tag pertenece a todas las piezas en las que podremos colocar el objeto de manera aleatoria usando Random.Range
Fig. 34: We write the name of the tag that we assign in the pieces of the labyrinth, in this case "Spawn­Piece".

In Object­ToFind we will assign the Pre­fab of the pedestal with the sword, which is the object to find.

prefabs en unity, pedestal con espada y reloj de pendulo, estos objetos seran colocados en una posicion aleatoria del laberinto usando Random.Range
Fig. 35: We looked for the pre­fab of the pedestal with the sword we made in video 2 of the series.

In the min­i­mum dis­tance for the moment we write the val­ue 75. Then we will see what this vari­able is used for.

ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity
Fig. 36: Assign the Pre­fab of the pedestal to the Object­ToFind field.

It is not nec­es­sary that the Labyrinth­Pieces array appears in the inspec­tor so I am going to remove the [Seri­al­ize­Field] select­ed in fig­ure 37.

campos serializados, privados y publicos en un script c sharp para un prototipo de juego de laberinto en unity
Fig. 37: It is not nec­es­sary for the GameOb­ject array of labyrinth pieces to be vis­i­ble in the inspector.
campos serializados, privados y publicos en un script c sharp para un prototipo de juego de laberinto en unity
Fig. 38: It is not nec­es­sary for the GameOb­ject array of labyrinth pieces to be vis­i­ble in the inspector.
ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity
Fig. 39: When remov­ing the Seri­al­ize­Field line, the field does not appear in the inspec­tor as it is private.

In the StartGame method we are going to find all the GameOb­jects of the hier­ar­chy that have the Tag that we indi­cate in the inspec­tor. Last instruc­tion of the startGame method in fig­ure 40.

metodo start de script c sharp en unity para un prototipo de juego de laberinto
Fig. 40: In the Game­Con­trol Start method we find all GameOb­jects with the indi­cat­ed Tag.

Then we declare the PlaceOb­ject­ToFind method (fig­ure 41) and call this method from the StartGame method (fig­ure 42).

este metodo se encargara de colocar un objeto en una posicion aleatoria del laberinto usando Random.Range
Fig. 41: We define a pri­vate method that will be in charge of plac­ing the pedestal in some part of the labyrinth.

metodo start game de script c sharp en unity para un prototipo de juego de laberinto
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 ran­dom piece from the labyrinth, mak­ing sure that piece is far enough away from the play­er using the "minDis­tance" vari­able that we assigned 70 in the inspec­tor. If the select­ed piece does not meet this require­ment we will choose anoth­er piece again. This is tak­en care of by the While loop shown in fig­ure 43.

Once we find a part that meets the require­ments, we will place the pedestal at a ran­dom point inside. For this we use a ver­sion of the Instan­ti­ate method, which receives three para­me­ters: The first is the object to be found stored in the "object­ToFind" field, the sec­ond is the posi­tion that we will receive auto­mat­i­cal­ly from the labyrinth piece exe­cut­ing the GetRan­dom­Po­si­tion method of the Labyrinth­Piece com­po­nent assigned to it. The third para­me­ter is the rota­tion, here we will indi­cate: Quaternion.identity (a rota­tion identity).

este metodo se encargara de colocar un objeto en una posicion aleatoria del laberinto usando Random.Range
Fig. 43: Instruc­tions for the PlaceOb­ject­ToFind method.

It is impor­tant that we save the ref­er­ence of this new object that we have cre­at­ed, we will do it in "object­ToFind­In­stance" (last instruc­tion in fig­ure 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, fig­ure 44.

la instancia del objeto que fue colocado en una posicion aleatoria usando Random.Range
Fig. 44: In the EndGame method, the pedestal instance is destroyed.

When you enter the game mode and press the Start but­ton, every­thing seems to be work­ing cor­rect­ly. The pedestal with the sword appears in a ran­dom labyrinth posi­tion inside one of the pieces.

prototipo de laberinto hecho en unity, pedestal con espada. el objeto es colocado en una posicion aleatoria del laberinto usando Random.Range
Fig. 45: When enter­ing the game mode the pedestal is placed on one of the pieces of the stage.

prototipo de laberinto hecho en unity, el objeto es colocado en una posicion aleatoria del laberinto usando Random.Range
Fig. 46: We can see from the edi­tor win­dow which part it is.

Place object in other regions

There are regions of the labyrinth that are out­side the pieces, for exam­ple the one high­light­ed in fig­ure 47. We might be inter­est­ed in plac­ing the object in a posi­tion belong­ing to this area. 

How could we reuse what we have done?

prototipo de laberinto hecho en unity. en una posicion aleatoria de estas areas colocaremos el objeto usando Random.Range
Fig. 47: This region can be a place where we would like the pedestal to appear.

To begin with we cre­at­ed an Emp­ty GameOb­ject and called it SpawnArea and placed it between the pieces of the labyrinth.

jerarquia de un prototipo de juego de laberinto hecho en unity
Fig. 48: Cre­ate an Emp­ty GameOb­ject and call it SpawnArea, this will allow us to place the pedestal in oth­er parts of the labyrinth.

jerarquia de un prototipo de juego de laberinto hecho en unity
Fig. 49: The four points in the region are chil­dren of GameOb­ject SpawnArea.

Then we cre­at­ed four emp­ty GameOb­jects to rep­re­sent points A1, A2, B1 and B2. We place these objects at the ends of the two imag­i­nary seg­ments of the area high­light­ed in green in Fig­ure 49.

prototipo de laberinto hecho en unity. en una posicion aleatoria de estas areas colocaremos el objeto usando Random.Range
Fig. 50: We are going to cre­ate 4 emp­ty GameOb­jects to use in the Labyrinth­Piece script.

Then we cre­ate a Pre­fab along with the oth­er pieces of the labyrinth (fig­ure 51), because we may reuse this object by chang­ing the inter­nal points.

prefabs en unity, piezas para crear un laberinto
Fig. 51: We took the GameOb­ject SpawnArea and cre­at­ed a Pre­fab for reuse.

Then we assign the com­po­nent Labyrinth­Piece and place the inter­nal points in the respec­tive fields.

ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity
Fig. 52: Asig­namos el Script Labyrinth­Piece al GameOb­ject SpawnArea.

Do not for­get to assign the Tag Spawn­Piece in the inspec­tor, oth­er­wise these areas will not be con­sid­ered when choos­ing a posi­tion for the pedestal. In my case, as can be seen in fig­ure 53, I had not assigned it and I spent sev­er­al min­utes test­ing for the pedestal to appear in these areas.

ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity, asignar tags
Fig. 53: We must remem­ber to assign the Spawn­Piece tag to the GameOb­ject SpawnArea. Apply changes.

Final Details

When I tried the game, I noticed that the door was quite large in rela­tion to the char­ac­ter, so I made it a lit­tle small­er and applied the changes.

prototipo de laberinto hecho en unity, puertas de entrada-salida
Fig. 54: The doors were too big in rela­tion to the character.

Anoth­er prob­lem I detect­ed was that there were pieces with the Tag Spawn­Piece whose inner region was inac­ces­si­ble to the play­er. In fig­ure 55 you see one of these pieces, if the pedestal appears here, the play­er won't be able to find it.

The solu­tion to this is to select this piece and remove the Tag Spawn­Piece, this way the piece will not be considered.

prototipo de laberinto hecho en unity
Fig. 55: This piece is out of reach of the char­ac­ter, the pedestal does not have to appear here.

ventana inspector de un gameobject perteneciente a un prototipo de laberinto hecho en unity, asignar tags
Fig. 56: Select that piece and in the tag field select: "Untagged". We do not apply the changes.

Conclusion

In this arti­cle we man­aged to place the pedestal in a ran­dom posi­tion with­in the labyrinth.

To do this we had to ana­lyze the type of pieces that make up the labyrinth, estab­lish cer­tain rules and pro­pose a strat­e­gy to solve our problem.

We used object-ori­ent­ed pro­gram­ming think­ing to cre­ate a flex­i­ble solu­tion that fits all types of parts.

As usu­al­ly hap­pens, there is no sin­gle way to solve a prob­lem. Anoth­er way to address this sit­u­a­tion is to make a Navmesh Bake and take a point with­in these regions.

Scroll to Top
Secured By miniOrange