Robô expert no jogo do Dino do Chrome

Boa noite pessoal, tudo bem?

Meu nome é Guilherme. Sou novo aqui no fórum! :slight_smile:

Estou desenvolvendo no meu tempo livre, um robô em Java que será expert em jogar aquele joguinho do Dino do Google Chrome.

Já desenvolvi a maior parte: os detectores de cactos, os detectores de passáros e os controladores de teclado (utilizando a classe java.awt.Robot).

Detector.java

import java.awt.Color;
import java.awt.Robot;
import java.awt.AWTException;

public abstract class Detector {

    private final Robot robot;
    
    private final int x;
    private final int y;
    private final Color pixelColor;
    
    public Detector(int x, int y, Color pixelColor) throws AWTException {
        
        this.robot = RobotContainer.getInstance();
        
        this.x = x;
        this.y = y;
        this.pixelColor = pixelColor;
        
    }
    
    public boolean detect() {
        
        Color detectedPixelColor = this.robot.getPixelColor(this.x, this.y);
        
        if (detectedPixelColor.getRed() != this.pixelColor.getRed()) {
            
            return false;
            
        }
        
        if (detectedPixelColor.getGreen() != this.pixelColor.getGreen()) {
        
            return false;
        
        }
        
        if (detectedPixelColor.getBlue() != this.pixelColor.getBlue()) {
        
            return false;
        
        }
        
        return true;
    
    }

}

CactusDetector.java

import java.awt.Color;
import java.awt.AWTException;

public final class CactusDetector extends Detector {

    public CactusDetector() throws AWTException {
    
        super(300, 478, new Color(172, 172, 172));
    
    }

}

BirdDetector.java

import java.awt.AWTException;
import java.awt.Color;

public final class BirdDetector extends Detector {

    public BirdDetector() throws AWTException {
    
        super(181, 432, new Color(172, 172, 172));
        
    }
    
}

RestartDetector.java

import java.awt.Color;
import java.awt.AWTException;

public final class RestartDetector extends Detector {

    public RestartDetector() throws AWTException {
        
        super(654, 388, new Color(172, 172, 172));
        
    }

}

Control.java

import java.awt.Robot;
import java.awt.AWTException;
import java.awt.event.KeyEvent;

public abstract class Control {
    
    private Robot robot;
    
    public Control() throws AWTException {
    
        this.robot = RobotContainer.getInstance();
    
    }
    
    public void restart() {
        
        this.robot.keyPress(KeyEvent.VK_SPACE);
        this.robot.keyRelease(KeyEvent.VK_SPACE);
    
    }
    
    public void jump() {
        
        this.robot.keyPress(KeyEvent.VK_UP);
        this.robot.keyRelease(KeyEvent.VK_UP);
    
    }
    
    public void down() {
    
        this.robot.keyPress(KeyEvent.VK_DOWN);
        this.robot.keyRelease(KeyEvent.VK_DOWN);
        
    }

}

KeyboardControl.java

import java.awt.AWTException;

public final class KeyboardControl extends Control {
    
    public KeyboardControl() throws AWTException {
    
        super();
    
    }

}

RobotContainer.java - Encapsulei a classe Robot em um container Singleton para gerenciar a quantidade de instâncias de Robot em tempo de execução.

import java.awt.Robot;
import java.awt.AWTException;

public final class RobotContainer {

    private static Robot robot;
    
    private RobotContainer() {
    
    }
    
    public static Robot getInstance() throws AWTException {
    
        if (robot == null) {
        
            robot = new Robot();
            robot.setAutoWaitForIdle(true);
            
        }
        
        return robot;
    
    }

}

Start.java

import java.awt.AWTException;

public final class Start {
    
    private Start() {
    
    }
    
    public static void main(String[] args) {
        
        try {
            
            Detector restartDetector = new RestartDetector();
            Detector cactusDetector = new CactusDetector();
            Detector birdDetector = new BirdDetector();
            
            Control keyboardControl = new KeyboardControl();
            
            while(true) {
            
                if (cactusDetector.detect()) {
                
                    keyboardControl.jump();
                    System.out.println("cacto");
                 
                } else if (birdDetector.detect()) {
                
                    keyboardControl.down();
                    System.out.println("passaro");
                    
                } else if (restartDetector.detect()) {
                
                    keyboardControl.restart();
                    System.out.println("restart");
                
                }
                
            }
            
        } catch (AWTException e) {
        
            System.out.println(e);
            
        }
        
    }
    
}

O Problema:

Como visto no método main da classe Start, há 3 detectores que utilizam a classe Robot: detector de cactus, detector de passáros e detector de botão de Restart (para o robô reinicializar o jogo sozinho, se precisar).

O problema é que quando utilizo somente 1 detector (qualquer um deles), tudo parece funcionar bem, o objeto é detectado na tela e a referida ação é realizada pelo teclado. Mas, quando utilizo os 3 detectores de uma vez, todos começam a perder desempenho, não detectando apropriadamente os objetos na tela e/ou não realizando as devidas ações no teclado.

Acredito que seja porque devo estar fazendo muitas requisições para a classe Robot. A classe Robot deve estar ficando confusa e/ou sobrecarregada, mas ainda não sei como corrigir, visto que preciso utilizar todos os detectores.

Alguém ai tem alguma idéia genial que pode me ajudar? Se tiver, agradeço imensamente! :slight_smile:

O link para o meu repositório no GitHub é https://github.com/guibaranch/dino_robot_m2.

Muito obrigado!

O buraco é muito mais embaixo. Olhando rapidamente, seu “detector” fica procurando por pixels de determinadas cores para saber que um determinado objeto apareceu na tela. O seu problema deveria ser resolvido com alguma técnica mais sofisticada de visão computacional, não é tão simples assim, ou vc poderia adaptar sua classe para fazer os três (ou mais) tipos de detecção em cada ciclo. Você não vai ter performance com isso. Uma biblioteca famosa para visão computacional se chama OpenCV, mas nunca usei. Dei uma olhada rápida no Google e há uma implementação em Java.

1 curtida

Olá davidbuzatto! Muito obrigado pela sua resposta!

Hoje de madrugada, eu adaptei algumas soluções que parecem ter aumentado a performance do programa:

1 - Ao invés de a cada ciclo (iteração do loop) os 3 detectores “printarem a tela” e procurarem por um obstáculo especifico, a cada ciclo (iteração do loop), somente um print é realizado e os 3 detectores leêm esse print. No próximo ciclo (iteração do loop) o print anterior é descartado e um novo print é feito, diminuindo a quantidade de requisições para Robot.

2 - No momento do print, diminuí bastante o tamanho da imagem que deve ser gerada. Antes, estava printando partes desnecessárias da tela e agora, somente a parte necessária (que será utilizada pelos detectores) é printada. Isso diminuiu ainda mais a quantidade de memória utilizada pela classe Robot.

Com o ganho de performance que eu tive, adptei mais uma solução:

3 - Detector de pontos: ao invés de capturar somente 1 pixel por detecção, eu detecto mais pixels para me certificar de que não é um erro de leitura do detector, dando mais segurança para realizar a ação do teclado.

Acredito que tudo ficou mais rápido, seguro e performático! :smiley:

Mas você está certo, ainda preciso de uma solução mais sofisticada, pois o jogo aumenta de velocidade à medida que você desvia dos cactos e também, alguns cactos podem estar muito perto de outros cactos (aumentando o tamanho horizontal).

Ainda não cheguei a utilizar, mas agradeço imensamente pela indicação da biblioteca OpenCV. Vou dar uma olhada. Muito obrigado!

As novas soluções implementadas estão no repositório do projeto em: https://github.com/guibaranch/dino_robot_m2

Obrigado!