0:00:03.362,0:00:05.920 Neste vídeo vamos criar o 0:00:05.920,0:00:07.920 script de gerenciamento da fase, que irá 0:00:07.920,0:00:10.664 gerar proceduralmente nossas fases 0:00:10.664,0:00:14.560 para que ela seja diferente cada vez que o jogador joga. 0:00:14.560,0:00:17.993 Vamos começar criando dois scripts vazios, 0:00:17.993,0:00:21.619 o board manager e o game manager. 0:00:22.234,0:00:24.879 Clique em Create - C# Script. 0:00:25.542,0:00:27.542 Chame o primeiro BoardManager. 0:00:31.327,0:00:33.327 Chame o segundo GameManager. 0:00:33.711,0:00:35.915 Vamos também criar um game object vazio 0:00:36.239,0:00:38.239 chamado GameManager. 0:00:43.810,0:00:46.616 Vamos começar adicionanado nosso código de geração de fase 0:00:46.616,0:00:47.937 ao script BoardManager. 0:00:47.937,0:00:49.937 Vamos abrir o MonoDevelop. 0:00:51.474,0:00:53.474 O script BoardManager irá 0:00:53.474,0:00:55.474 criar fases 0:00:55.474,0:00:57.965 geradas aleatoriamente cada vez que 0:00:57.965,0:00:59.965 o jogador inicia uma nova fase 0:01:00.282,0:01:03.200 baseado no número da fase atual. 0:01:03.661,0:01:05.661 A primeira coisa que iremos fazer é adicionar 0:01:05.661,0:01:08.878 uma declaração de namespace usando System. 0:01:09.435,0:01:11.435 Faremos isso para podermos utilizar a 0:01:11.435,0:01:13.196 propriedade serialisable. 0:01:13.196,0:01:16.289 A propriedade serialisable nos permite 0:01:16.289,0:01:18.289 modificar como as variáveis serão exibidas 0:01:18.289,0:01:20.107 no inspector e no editor 0:01:20.375,0:01:23.921 e para que possamos escondê-las e exibí-las. 0:01:24.593,0:01:25.875 Iremos também adicionar 0:01:25.875,0:01:28.230 using Systems.Collections.Generic 0:01:28.230,0:01:30.230 para que possamos criar listas. 0:01:30.577,0:01:32.451 Finalmente vamos incluir 0:01:32.451,0:01:34.451 using Random e vamos 0:01:34.451,0:01:38.158 configurar-la para ser igual a UnityEngine.Random. 0:01:38.741,0:01:40.741 Temos que especificar qual Random usar porque há uma classe 0:01:40.741,0:01:43.568 chamada Random tanto no namespace System 0:01:43.568,0:01:46.154 como no namespace UnityEngine. 0:01:48.355,0:01:50.355 Na nossa classe vamos começar 0:01:50.355,0:01:55.106 declarando uma classe pública serialisable chamada Count. 0:01:57.479,0:01:59.886 Em Count vamos declarar duas variáveis publicas 0:01:59.886,0:02:04.372 chamadas minimum e maximum, ambas do tipo int. 0:02:05.899,0:02:07.899 Vamos também incluir uma instrução 0:02:07.899,0:02:09.899 de assignment para Count, assim podemos 0:02:09.899,0:02:12.620 configurar os valores de minimum e maximum 0:02:12.620,0:02:14.620 quando declaramos uma nova instância de Count. 0:02:15.129,0:02:17.943 Vamos acrescentar parâmetros Min e Max, 0:02:17.943,0:02:19.943 que serão utilizados para configurar os valores de 0:02:19.943,0:02:21.943 minimum e maximum. 0:02:23.672,0:02:26.425 Em seguida vamos declarar nossas variáveis. 0:02:27.203,0:02:29.068 Vamos iniciar com as variáveis públicas, 0:02:29.068,0:02:32.540 as duas primeiras serão um inteiro para colunas, 0:02:32.540,0:02:34.540 e um inteiro para linhas 0:02:34.540,0:02:38.338 Essas variáveis irão limitar as dimensões da nossa fase 0:02:38.338,0:02:40.144 e nos permitirão fazer uma fase 0:02:40.144,0:02:42.824 maior ou menor simplesmente 0:02:42.824,0:02:43.970 mudando as variáveis. 0:02:43.970,0:02:46.237 Por enquanto vamos inicializar ambas com o valor oito 0:02:46.237,0:02:49.444 isso significa que nossa fase terá um tamanho de oito por oito. 0:02:50.332,0:02:53.052 Em seguida vamos usar Count para especificar 0:02:53.052,0:02:56.223 um intervalo randômico de quantas paredes 0:02:56.223,0:02:58.925 nós queremos criar em cada fase. 0:03:00.317,0:03:02.317 nessa caso isso significa que teremos 0:03:02.317,0:03:05.069 um mínimo de cinco paredes por fase, 0:03:05.069,0:03:08.455 e um máximo de nove paredes por fase. 0:03:10.827,0:03:14.607 Vamos fazer o mesmo para nossos items de comida. 0:03:17.409,0:03:20.291 Em seguida vamos declarar algumas variáveis 0:03:20.291,0:03:23.444 para armazenar os prefabs que iremos gerar 0:03:23.444,0:03:25.039 na nossa fase. 0:03:25.039,0:03:27.039 Vamos ter um único game object chamado 0:03:27.039,0:03:30.412 Exit, pois nossa fase terá somente uma saída. 0:03:30.925,0:03:32.925 Para os outros objetos vamos utilizar 0:03:32.925,0:03:35.161 vetores, dessa maneira podemos buscar 0:03:35.161,0:03:37.161 múltiplos objetos e escolher 0:03:37.161,0:03:39.855 qual deles queremos gerar 0:03:39.855,0:03:41.855 entre todas as variações. 0:03:41.855,0:03:43.855 vamos começar com os tiles do piso. 0:03:46.837,0:03:49.627 Faremos o mesmo para wallTiles, 0:03:49.627,0:03:54.075 foodTiles, enemyTiles e nosso outerWallTiles. 0:03:55.614,0:03:57.897 Vamos preencher cada um desses vetores 0:03:57.897,0:04:00.425 com nossos prefabs diferentes para serem escolhidos 0:04:00.425,0:04:02.425 no inspector. 0:04:03.194,0:04:06.018 Em seguida vamos declarar duas variáveis privadas 0:04:06.018,0:04:10.003 incluindo um transform chamado boardHolder. 0:04:10.787,0:04:12.787 Vamos usar BoardHolder apenas para manter a 0:04:12.787,0:04:15.266 hierarquia limpa, pois vamos 0:04:15.266,0:04:17.266 criar vários game objects e vamos torná-los todos filhos 0:04:17.266,0:04:19.619 do BoardHolder 0:04:19.619,0:04:21.619 para que nós possamos escondê-los na hierarquia 0:04:21.619,0:04:24.698 evitando que nossa hierarquia fique cheia de objetos. 0:04:25.526,0:04:28.237 Vamos também declarar uma lista privada 0:04:28.237,0:04:31.268 de vector3s chamada "gridPos". 0:04:31.268,0:04:33.490 Vamos utilizá-la para controlar 0:04:33.490,0:04:35.829 todas as possíveis posições 0:04:35.829,0:04:38.305 da nossa fase e para controlar se um 0:04:38.305,0:04:40.305 já foi criado naquela 0:04:40.305,0:04:42.305 posição ou não. 0:04:43.000,0:04:45.902 Em seguida vamos declarar uma função chamada 0:04:45.902,0:04:49.402 InitialiseList que irá retornar void. 0:04:49.402,0:04:51.892 Em InitialiseList vamos começar 0:04:51.892,0:04:54.232 limpando nossa lista de grid positions 0:04:54.232,0:04:57.649 chamando a função Clear na nossa lista. 0:04:58.551,0:05:02.275 Em seguida vamos usar um par de loops aninhados 0:05:02.275,0:05:04.275 para preencher a lista 0:05:04.275,0:05:07.672 com cada posição da nossa fase 0:05:07.672,0:05:11.553 como são vector3, vamos começar com o eixo X. 0:05:14.127,0:05:16.127 O primeiro loop irá executar 0:05:16.127,0:05:20.981 enquanto o eixo X for menor que o número de colunas. 0:05:20.981,0:05:25.562 E em seguida vamos fazer o mesmo para o eixo Y dentro do primeiro loop. 0:05:31.450,0:05:33.769 Dentro do loop vamos adicionar 0:05:33.769,0:05:38.007 um novo vector3 com os valores dos eixos X e Y 0:05:38.007,0:05:40.496 na nossa lista de grid positions. 0:05:40.785,0:05:42.785 O que estamos fazendo aqui é criar 0:05:42.785,0:05:45.249 a lista de possíveis posições 0:05:45.249,0:05:49.033 onde podemos criar paredes, inimigos e pickups. 0:05:49.033,0:05:51.033 Estamos faze o loop entre um 0:05:51.033,0:05:53.033 e columns - 1 0:05:53.033,0:05:56.105 é para deixar uma borda de tiles 0:05:56.105,0:05:58.354 diretamente dentro das paredes externas, 0:05:58.354,0:06:00.566 assim garantimos que não iremos criar 0:06:00.566,0:06:03.196 uma fase impossível de completar. 0:06:04.708,0:06:06.708 Em seguida vamos declarar uma nova 0:06:06.708,0:06:09.216 função privada que retorna void 0:06:09.216,0:06:11.071 chamada BoardSetup. 0:06:11.071,0:06:13.071 Vamos usar BoardSetup para 0:06:13.071,0:06:15.071 configurar a parede externa e 0:06:15.071,0:06:17.681 o piso da nossa fase. 0:06:17.681,0:06:19.681 Vamos começar configurando boardHolder para 0:06:19.681,0:06:21.681 ser igual ao transform de um novo 0:06:21.681,0:06:23.681 game object chamado Board. 0:06:25.789,0:06:27.789 Em seguida vamos usar o mesmo padrão 0:06:27.789,0:06:31.995 de loop para configurar o piso 0:06:31.995,0:06:34.464 e as paredes externas. 0:06:34.464,0:06:36.464 Então nós vamos utilizar outro loop for nos 0:06:36.464,0:06:39.478 eixos X e Y. 0:06:43.195,0:06:45.195 A razão pela qual cada um desses loops 0:06:45.195,0:06:50.558 vai de -1 a columns -1 ou rows - 1 0:06:50.558,0:06:52.853 é porque estamos criando uma borda 0:06:52.853,0:06:55.281 em volta da parte "ativa" da nossa fase 0:06:55.281,0:06:57.959 usando os objetos da parede externa. 0:06:59.887,0:07:03.479 Em seguida vamos escolher os tiles do piso aleatoriamente 0:07:03.479,0:07:06.407 a partir do nosso vetor de tiles 0:07:06.407,0:07:08.712 e prepará-los para serem instanciados. 0:07:11.930,0:07:13.930 O que estamos fazendo aqui é declarar uma 0:07:13.930,0:07:15.930 variável do tipo GameObject 0:07:15.930,0:07:17.778 chamada toInstantiate 0:07:17.778,0:07:19.778 e configurando-a para ser igual 0:07:19.778,0:07:24.039 a um índice da nosso vetor de game objects chamado floorTiles 0:07:24.039,0:07:26.136 que estamos escolhendo aleatoriamente 0:07:26.136,0:07:30.994 entre 0 e o length do vetor de tiles do piso. 0:07:30.994,0:07:34.321 Isso significa que não temos que pré-configurar o length, 0:07:34.321,0:07:36.321 podemos simplesmente chamar length e escolher 0:07:36.321,0:07:38.321 um número dentro do vetor. 0:07:40.374,0:07:42.374 Em seguida vamos verificar 0:07:42.374,0:07:45.478 se estamos numa posição que faz parte da parede externa, 0:07:45.478,0:07:47.961 e nesse caso vamos escolher um 0:07:47.961,0:07:50.554 tile da parede externa para instanciar. 0:07:50.554,0:07:52.554 Para isso vamos checar se X é igual a 0:07:52.554,0:07:56.153 -1 ou ao valor de columns, 0:07:56.153,0:07:59.468 ou se Y é igual a -1 ou o valor de rows 0:07:59.468,0:08:02.218 nesse caso vamos instanciar 0:08:02.218,0:08:04.218 um tile escolhido aleatoriamente do 0:08:04.218,0:08:06.455 vetor de tiles da parede externa. 0:08:11.364,0:08:13.364 Uma vez escolhido qual tile queremos 0:08:13.364,0:08:16.252 instanciar nós vamos efetivamente instanciar o tile. 0:08:17.209,0:08:19.209 Para isso vamos declarar uma variável do tipo 0:08:19.209,0:08:22.271 GameObject chamada instance e em seguida vamos configurá-la para 0:08:22.271,0:08:25.044 o objeto que estamos instanciando. 0:08:25.044,0:08:27.118 Para isso chamamos Instantiate, 0:08:27.118,0:08:30.852 passamos como parâmetro o prefab escolhido, 0:08:31.477,0:08:33.996 num novo vector3 0:08:33.996,0:08:35.996 baseado na nossa coordenada 0:08:35.996,0:08:38.247 X e Y atual no loop 0:08:38.247,0:08:41.153 e vamos utilizar o valor zero para o eixo Z 0:08:41.153,0:08:43.153 pois estamos trabalhando em 2D. 0:08:43.153,0:08:45.153 Quaternion.identity significa que o objeto vai ser 0:08:45.153,0:08:47.419 instanciado sem rotação 0:08:47.419,0:08:50.375 e vamos fazer o cast para game object. 0:08:50.375,0:08:53.732 Em seguida configuramos o parent 0:08:53.732,0:08:56.485 do nosso recém criado game object 0:08:56.485,0:08:58.485 para boardHolder. 0:09:01.828,0:09:03.828 BoardSetup vai criar nossos 0:09:03.828,0:09:07.411 tiles de parede externa e de piso. 0:09:07.411,0:09:09.411 O que faremos em seguida é 0:09:09.411,0:09:11.411 começar a escrever algumas funções que irão 0:09:11.411,0:09:15.382 colocar objetos aleatórios na fase 0:09:15.382,0:09:19.232 como paredes, inimigos e power ups. 0:09:21.382,0:09:23.382 Vamos declarar uma nova função 0:09:23.382,0:09:27.765 que retorna um vector3 chamada RandomPosition. 0:09:28.320,0:09:30.320 Em RandomPosition vamos declarar 0:09:30.320,0:09:32.736 um inteiro chamado randomIndex 0:09:32.736,0:09:35.999 e gerar um número aleatório dentro de um intervalo. 0:09:36.540,0:09:38.540 O intervalo no qual vamos gerar o número 0:09:38.540,0:09:40.957 é entre zero 0:09:40.957,0:09:42.957 e o número de posições 0:09:42.957,0:09:46.714 armazenadas na nossa lista gridPositions, 0:09:46.714,0:09:50.854 que iremos acessar usando gridPositions.Count. 0:09:51.506,0:09:53.829 Em seguida vamos declarar um vector3 0:09:53.829,0:09:55.829 chamado randomPositions e iremos 0:09:55.829,0:09:58.998 set it to equal the gridPositions[br]configurar-lo para ser igual a gridPositions 0:09:58.998,0:10:01.814 armazenado na lossa lista gridPositions 0:10:01.814,0:10:04.774 no índice que sorteamos aleatoriamente. 0:10:05.939,0:10:08.262 Para garantir que não iremos gerar dois objetos 0:10:08.262,0:10:10.916 no mesmo lugar vamos remover 0:10:10.916,0:10:13.843 a posição da nossa lista. 0:10:13.843,0:10:15.843 Fazemos isso usando o comando RemoveAt 0:10:15.843,0:10:19.554 e passando o índice randomIndex. 0:10:19.554,0:10:21.554 Em seguida retornamos o valor de 0:10:21.554,0:10:23.554 randomPosition para utilizar-lo 0:10:23.554,0:10:26.582 para gerar o objeto numa posição aleatória. 0:10:26.582,0:10:28.582 Agora que obtivemos uma posição aleatória 0:10:28.582,0:10:31.759 da nossa lista e nos certificamos que ela não é duplicada, 0:10:31.759,0:10:33.759 vamos escrever uma função que irá efetivamente 0:10:33.759,0:10:38.462 gerar os tiles na posição aleatória escolhida. 0:10:39.225,0:10:42.533 Essa função irá chamar LayoutObjectAtRandom 0:10:42.533,0:10:44.700 e irá receber três parâmetros. 0:10:44.700,0:10:48.242 Um vetor de game objects chamado tileArray, 0:10:48.242,0:10:52.011 um inteiro minimum e um inteiro maximum. 0:10:52.011,0:10:53.645 A primeira coisa que vamos fazer é 0:10:53.645,0:10:56.335 declarar um inteiro chamado objectCount 0:10:56.335,0:10:59.643 e inicializar-lo com um valor aleatório entre 0:10:59.643,0:11:02.760 minimum e maximum + 1. 0:11:02.760,0:11:04.760 objectCount vai controlar 0:11:04.760,0:11:06.760 quantas unidades de um dado objeto 0:11:06.760,0:11:11.354 vamos criar, por exemplo o número de paredes em uma fase. 0:11:11.354,0:11:13.575 Em seguida vamos escrever um loop for. 0:11:13.991,0:11:15.991 Vamos repetir este loop for enquanto 0:11:15.991,0:11:18.117 i for menos que nosso objectCount, 0:11:18.117,0:11:20.117 isso quer dizer que vamos gerar o número de objetos 0:11:20.117,0:11:22.960 especificado por objectCount. 0:11:22.960,0:11:25.763 Vamos começar escolhendo uma posição aleatória[br]230[br]00:11:25,763 --> 00:11:28,480\[br]chamando a função RandomPosition. 0:11:28.480,0:11:31.507 Em seguida vamos escolher um tile aleatório 0:11:31.507,0:11:36.909 do nosso vetor de game objects tileArray para gerar o objeto. 0:11:37.344,0:11:39.344 Faremos isso gerando um 0:11:39.344,0:11:44.825 número aleatório usando Random.Range entre zero e tileArray.length. 0:11:45.269,0:11:47.603 Vamos instanciar o tile que 0:11:47.603,0:11:50.669 selecionamos na nossa posição aleatória. 0:11:52.319,0:11:54.684 Podemos apagar as funções start e update. 0:11:55.207,0:11:58.674 E declarar uma nova função pública que retorna void 0:11:58.674,0:12:02.568 chamada SetupScene, que recebe um parâmetro do tipo int 0:12:02.568,0:12:04.001 chamado Level. 0:12:04.001,0:12:07.127 E repare que SetupScene é a única função pública 0:12:07.127,0:12:09.127 dessa clase. 0:12:09.127,0:12:11.127 Essa é a função que será chamada pelo 0:12:11.127,0:12:13.857 game manager quando for o momento de configurar a fase. 0:12:15.091,0:12:17.091 Dentro de SetupScene a primeira coisa que vamos fazer 0:12:17.091,0:12:19.091 é chamar BoardSetup. 0:12:19.368,0:12:22.059 Em seguida vamos chamar initialiseLise. 0:12:22.059,0:12:24.727 Vamos chamar LayoutObjectAtRandom 0:12:24.727,0:12:29.010 e vamos adicionar nosso vetor de wallTiles 0:12:29.010,0:12:33.538 e também os valores minimo e máximo de wallCount. 0:12:34.234,0:12:37.461 Em seguida vamos fazer o mesmo para foodTiles. 0:12:42.781,0:12:45.727 Ao invés de gerar um número aleatório de inimigos 0:12:45.727,0:12:48.472 vamos gerar um número de inimigos 0:12:48.472,0:12:50.751 baseado no número da fase 0:12:50.751,0:12:52.876 usando MathF.Log 0:12:52.876,0:12:55.931 para gerar uma progressão de dificuldade logaritmica. 0:12:56.597,0:12:58.892 MathF.Log retorna um número de ponto flutuante (float) 0:12:58.892,0:13:01.201 então temos que converte-lo para inteiro. 0:13:01.655,0:13:04.720 Isso quer dizer que teremos um inimigo na fase dois, 0:13:04.720,0:13:06.568 dois inimigos na fase quatro, 0:13:06.568,0:13:08.263 três inimigos na fase oito, 0:13:08.263,0:13:11.450 e a dificuldade vai crescendo 0:13:11.450,0:13:13.575 conforme o jogador avança de fase. 0:13:13.575,0:13:16.816 Agora que temos o número de inimigos que queremos gerar 0:13:16.816,0:13:20.064 vamos posicioná-los usando LayoutObjectAtRandom. 0:13:20.548,0:13:23.010 Repare que os valores mínimo e máximo nesse 0:13:23.010,0:13:26.806 caso são os mesmos porque não estamos especificando um intervalo aleatório. 0:13:26.806,0:13:29.365 Finalmente vamos instanciar a saída. 0:13:29.365,0:13:31.365 A saída será colocada sempre no mesmo 0:13:31.365,0:13:34.087 lugar e sempre será o mesmo objeto 0:13:34.087,0:13:35.169 então vamos apenas chamar 0:13:35.169,0:13:38.260 Instantiate e passar o prefab Exit. 0:13:38.593,0:13:41.208 A saída sempre estará no canto superior direito 0:13:41.208,0:13:43.040 da fase, e é por isso que estamos usando 0:13:43.040,0:13:46.420 coluna -1 e fila -1 0:13:46.420,0:13:48.420 e isso significa que se decidirmos mudar o tamanho 0:13:48.420,0:13:51.928 da fase a saída ainda estará no lugar certo. 0:13:52.594,0:13:54.594 Vamos salvar o script. 0:13:55.967,0:13:57.967 Agora que o código de geração de fase está 0:13:57.967,0:14:00.191 escrito no nosso Board Manager 0:14:00.191,0:14:02.191 no próximo vídeo iremos começar a escrever 0:14:02.191,0:14:05.662 o Game Manager e configurar o Game Manager prefab.