Unity - Acessar nomes de arquivos diretamente da pasta


Introdução:
Olá! Bem vindos a mais um tutorial aqui no blog! Hoje irei mostrar como você pode ter acesso aos nomes dos arquivos de assets dentro do seu projeto, assim você vai poder armazená-los numa lista para poder usá-los posteriormente.

A ideia de criar este tutorial veio de uma dúvida postada num fórum sobre Unity que eu frequento, na verdade a pessoa apenas queria saber como adicionar prefabs num array sem precisar anexá-los manualmente através do inspector, mas o tutorial de hoje vai não só apenas mostrar como carregar prefabs diretamente da pasta, mas também qualquer asset que você quiser.

Anexando arquivos manualmente:
Antes de mostrar o tutorial, vamos entender como o processo é feito "manualmente" dentro da Unity.
Digamos que você tenha um array do tipo GameObject chamado "objects" e nele você deseja armazenar os prefabs do seu jogo para então poder instanciá-los aleatoriamente na cena.
Para tal, você colocou os prefabs dentro de uma pasta chamada "Prefabs" e então irá anexá-los um por um diretamente no inspector dentro do array "objects":


Agora com os prefabs anexados você pode instanciar algum deles aleatoriamente através do script:



Veja que essa é a forma mais simples de poder instanciar aleatoriamente um prefab na cena do jogo.
Mas digamos que você queira adicionar um novo prefab a ser instanciado, neste caso você terá que adicionar esse novo prefab no array pelo inspector. Caso queira deletar algum prefab já adicionado no array, você terá um erro se não desassociá-lo corretamente no script ou no inspector, ou caso queria que algum prefab seja adicionado em tempo de execução dentro do array, da forma como o script se encontra é praticamente impossível. Outra ação que não podemos realizar primariamente é adicionar mais elementos ao array através do inspector se ele for estatico (static).
Veja então que a manutenção e dinamização do código estão precárias. Para resolver este impasse nós podemos carregar arquivos diretamente da pasta através do método "Resources.Load()".

Resources.Load:
Esse método genérico pode nos auxiliar a carregar recursos diretamente da pasta aonde eles se encontram, assim podemos adicionar os prefabs dentro do array diretamente da pasta sem precisar anexá-los pelo inspector. 
Isso resolveria o nosso problema com relação ao ''static'' e a poder adicionar elementos em tempo de execução.
Para usar o método é bem simples: Basta que a pasta com os arquivos que você deseja carregar estejam dentro de uma subpasta de "Assets" chamada "Resources", e então para manipular os arquivos via script basta referenciar o caminho do arquivo (o diretório de pasta + o nome do asset) e o tipo do arquivo a ser carregado, por exemplo:



Se você testar o código acima verá que ele vai funcionar da mesma forma que antes, só que agora o array "objects" é privado, então não anexamos os prefabs através do inspector, mas sim com a utilização do método Resources.Load.

Veja que o argumento passado para o método é justamente o caminho onde o arquivo está (no meu caso numa pasta chamada "Prefabs") e depois o nome do arquivo. Também note que o tipo usado aqui é o "GameObject" por se tratar de prefabs.

Mas agora você deve pensar... "Como eu faria para adicionar esses recursos diretamente da pasta no meu array, mas sem precisar ficar toda hora especificando o seu nome?" É aí que entra o nosso tutorial, acompanhe:

Obtendo nome dos arquivos:
Agora que entendeu o ponto central do nosso tutorial podemos finalmente começar:
Crie um novo C# script com o nome "FilesName" e delete tudo nele, apenas referencie as bibliotecas: System.Collections (para podermos utilizar arrays), System.Collections.Generic (para podemos utilizar lists) e System.IO (para podermos usar classes de acesso a diretórios de pastas):



Agora crie uma classe estática e pública com o mesmo nome do arquivo criado, ou seja, "FilesName".
Dentro dessa classe vamos criar um método público, estático, que retornará uma list de strings chamado "GetFilesNames", recebendo como parâmetro duas strings, uma chamada "path" (caminho do arquivo) e o outra chamada "extension" (para receber a extensão do arquivo):


O que faremos é o seguinte: esse método irá ter acesso à pasta que contém os arquivos que queremos acessar os nomes, e então ele vai adicionar todos os nomes desses arquivos em uma list de strings que será retornada do método.

Para fazer acesso ao diretório da pasta, basta utilizar um objeto do tipo "DirectoryInfo" e dentro do seu construtor passar o diretório (caminho) da pasta dos arquivos desejados.
Após isso, vamos criar uma variável que receba todos os arquivos que estão contidos naquele diretório, para isso, basta utilizar o método "GetFiles" da instância de "DirectoryInfo". Esse método retorna um array do tipo "FileInfo":


Para garantir que apenas seja retornado arquivos de um único tipo (por exemplo, retornar apenas arquivos com extensão do tipo .prefab) passe como argumento de "GetFiles" a extensão desejada:



Nesse momento, estamos armazenando dentro do array "infos" todos os arquivos do diretório referenciado, então, podemos realizar um foreach dentro deste array:
Antes disso, crie uma list local do tipo string com o nome de "names".
Após fazer isso, faça com que o laço foreach percorra o array "infos":



Dentro do laço crie uma variável local chamada "name" e nela armazene o nome do arquivo através da propriedade "Name".
Para "apagar" a extensão do arquivo no nome (que não é solicitado pelo ResourcesLoad) utilize o método "Replace".
Após tudo isso, adicione "name" na list "names" e no final do laço retorne essa list (se quiser pode adicionar tags de explicações do script com XML summary):



Salve o script.

Utilizando o script:
Para utilizar o nosso script, basta criar um array do tipo string e chamar nosso método "GetFilesNames" passando como argumento o caminho da pasta onde os arquivos se encontram e a extensão dos mesmos:


Agora dentro do array "namesFiles" você tem todos os nomes de todos os arquivos da pasta "Prefabs" que são do tipo ".prefab".
Nesse momento, basta utilizar o Resources.Load como vínhamos fazendo, mas agora quando devemos referenciar o nome do arquivo, podemos utilizar o array "namesFiles" diretamente:


Veja que ao salvar o script e executá-lo, um prefab será instanciado na cena, sem que você precise anexá-los pelo inspector ou ficasse especificando seus nomes.
Agora se você adicionar ou remover prefabs da pasta não precisará alterar nada no script, também poderá manipular esses elementos se o array for estático ou privado e instanciar prefabs em tempo de execução, tudo isso utilizando nosso método "GetFilesNames"!

Veja que esse método não é eficiente apenas para prefabs/gameobjects, você pode utilizar para randomizar um material de um elemento também:


Os materiais que tenho na pasta "Materials" são bem simples:


Note que cada vez que você roda o teste, o elemento muda de cor aleatoriamente:


Finalização:
E aqui chega o fim de mais um tutorial do blog! Espero que tenham gostado e que este método seja útil para você em algum momento de seu desenvolvimento. Até a próxima!

Comentários