Ir para o conteúdo

Manter Outro Robô na Mira

Neste tutorial vamos ver como podemos manter sob a nossa mira um robô inimigo. Embora focarmos apenas um inimigo, dos vários que certamente existirão na arena, possa complicar a nossa sobrevivência, é mesmo assim, um bom exercício e pode ser usado como parte de uma estratégia de combate.

Para detectar e manter sob mira um determinado robô, iremos usar a função onScannedRobot, e implementar código de modo a sabermos sempre onde anda o nosso inimigo

double gunTurnAmt = normalRelativeAngle(e.getBearing() + (getHeading() - getRadarHeading()));
setTurnGunRight(gunTurnAmt);

De forma simples, estamos a dar uma ordem de modo a que o canhão rode segundo: o ângulo da direcção do nosso robô em relação ao norte, menos o ângulo do nosso radar (é o mesmo do canhão) em relação a direcção para onde estamos virados, mais o ângulo do robô que acabámos de detectar, em relação à direcção para onde o nosso robô está virado.

A chamada do método normalRelativeAngle serve para normalizar o ângulo, evitando assim que a arma vá dar a volta ao bilhar grande. Essa função é introduzida no tutorial normalizar, e terá de ser adicionada ao robô para que o código acima funcione.

Após um turno, ou após a execução das tarefas que o robô tenha para fazer, a arma do nosso robô vai rodar de forma a que aponte para o sítio onde vimos um inimigo pela última vez. Como isto é executado cada vez que encontramos um robô, enquanto não perdermos o inimigo da mira a nossa arma segue-o sempre.

É necessário ter em atenção que este método usa a rotação do canhão para seguir o robô inimigo, podíamos usar antes o radar que se move a uma velocidade maior e dessa forma não deixa escapar o inimigo tão facilmente, mas usar o canhão é mais simples e assim está sempre pronto a disparar.

Este método facilita a questão de apontar, mas tem uma desvantagem: se nunca deixarmos um inimigo escapar, o nosso robô pode realizar todos os seus movimentos e ficar apenas focado em manter outro robô na mira. Acaba por ficar parado, e isso é meio caminho andado para levar uma chuva de chumbo. Por isso, é recomendado, após algum tempo a monitorizar um robô, esqueçamos esse inimigo e rodemos o canhão para outro lado.

Uma boa forma de evitar isso é usando um computador, ao fim de algumas passagens de radar deixamos aquele robô e vamos à procura de outros.

Alteramos o nosso método onScannedRobot.

if(i % teimosia == 0){
    turnGunRight(180); // virar para outro lado
} else {
    double gunTurnAmt = normalRelativeAngle(e.getBearing() + (getHeading() - getRadarHeading()));
    setTurnGunRight(gunTurnAmt);
}
i++;

E no início da classe:

private int i = 0;
private int teimosia = 20; //ajustar a gosto

A variável teimosia pode ser ajustada, quanto mais alto for o valor mais obcecado fica o nosso robô em relação aos outros robôs que encontra.

Para ver esta técnica em acção podem compilar um pequeno robô seguinte1:

import robocode.*;
import robocode.util.*;
import java.awt.Color;

public class TutorialBot extends AdvancedRobot{

    int shots = 0;
    int a = 0;
    public void run() {
        //definir algumas cores
        setBodyColor(new Color(200, 200, 30));
        setGunColor(new Color(45, 100, 0));
        setRadarColor(new Color(0, 255, 100));
        setBulletColor(new Color(255, 255, 100));
        setScanColor(new Color(0, 255, 0));

        while (true) {
            turnGunLeft(10);
        }
    }

    public void onScannedRobot(ScannedRobotEvent e) {
        if (a % 25 == 0 ) {
           turnGunLeft(180);
        } else {
            double gunTurnAmt = normalRelativeAngle(e.getBearing() + (getHeading() - getRadarHeading()));
            setTurnGunRight(gunTurnAmt);
            a++;
            //System.out.print("n==========================");
            //System.out.print("nradar heading:");
            //System.out.print(getRadarHeading());
            //System.out.print("nenemy angle:");
            //System.out.print(e.getBearing());
            //System.out.print("nremain angle:");
            //System.out.print(getRadarHeading()-e.getBearing());
        }
    }

    public double normalRelativeAngle(double angle) {
        if (angle > -180 && angle <= 180) {
            return angle;
        }

        double fixedAngle = angle;
        while (fixedAngle <= -180) {
            fixedAngle += 360;
        }

        while (fixedAngle > 180) {
            fixedAngle -= 360;
        }

        return fixedAngle;
    }
} 

Não fiquem admirados por ele não disparar, é mesmo só para mostrar como manter outro robô na mira. Para verem melhor podem activar a opção que permite mostrar os feixes do radar, essa opção está disponível no painel de opções do Robocode.


  1. Também disponível no pastbin