Ferramenta e Versão: Game Maker 2
A engine Game Maker oferece duas opções nativas para selecionar um objeto. Você pode selecionar o mais próximo (instance_nearest), ou você pode selecionar o mais distante (instance_furthest). Essas duas opções, embora cubram uma vasta variedade de casos, são insuficientes para situações mais específicas. O que acontece se você quiser o nth mais próximo? Pesquisando na Internet eu encontrei várias soluções nada elegantes para o problema, a vasta maioria delas sugerindo que você mova os n-1 objetos mais próximos para um lugar distante fora do mapa e use a seleção do mais próximo. Esse tipo de solução gera complexidade desnecessária já que você precisa armazenar todos os lugares originais dos objetos e depois restaurá-los as suas posições originais em um passo posterior. Como eu disse, nada elegante.
Segue a minha solução, que eu irei comentar linha a linha.
Sendo um script de GML, ele recebe os argumentos na forma de um array de argumentos referenciados por variaveis pré-definidas no estilo argument(x) onde x é o número do argumento começando em 0.
No script abaixo, argument0 é self, e argument1 é o tipo de objeto que você quer selecionar. Em geral, será algo do tipo obj_enemy, mas poderão haver circunstâncias onde você pode querer ser mais específico.
Código: Selecionar todos
var instance = instance_nearest(argument0.x, argument0.y, argument1);
var character_current_target = argument0.character_target;
Código: Selecionar todos
do
{
while (character_current_target != instance && character_current_target != noone)
{
instance_deactivate_object(instance);
instance = instance_nearest(argument0.x, argument0.y, argument1);
}
O loop possui uma segunda condição que testa se o objeto selecionado atual é noone, ou seja, ninguém está selecionado, o que torna o loop para procura-lo desnecessario.
Código: Selecionar todos
//the current target was found, we disable it and get the next one.
if(character_current_target != noone)
{
instance_deactivate_object(instance);
instance = instance_nearest(argument0.x, argument0.y, argument1);
}
Código: Selecionar todos
//all objects deactivated, the current selected one was the last on list
if (instance == noone)
{
instance_activate_object(argument1);
//will attempt to use the first on list
instance = instance_nearest(argument0.x, argument0.y, argument1);
}
Esse ultimo código verifica o ultimo caso restante, onde o objeto selecionado atual era o ultimo do ciclo, onde nesse caso todos os objetos do tipo terão sido desabilitados pelos loops anteriores e o ultimo instance_nearest vai retornar noone. Nesse caso eu imediatamente reativo todos os objetos e pego o primeiro da lista novamente, reiniciando o ciclo.
Código: Selecionar todos
character_current_target = instance;
} until (character_current_target != character_state.is_dying);
Código: Selecionar todos
instance_activate_object(argument1);
return character_current_target;
O codigo funciona exatamente igual se você quiser usar instance_furthest. De fato, você poderia até mesmo colocar ambas as funções no script, possivelmente controlando qual delas usar por meio de um terceiro argumento, e o codigo vai funcionar sem problemas.