0

I am trying to build an autoclicker using C++ to beat a 2D videogame in which the following situation appears:

The main character is in the center of the screen, the background is completely black and enemies are coming from all directions. I want my program to be capable of clicking on enemies just as they appear on the screen.

What I came up at first is that the enemies have a minimum size of 15px, so I tried doing a search every 15 pixels and analyze if any pixel is different than the background's RGB, using GetPixel(). It looks something like this:

COLORREF color;
int R, G, B;

for(int i=0; i<SCREEN_SIZE_X; i+=15){   //These SCREEN_SIZE values are #defined with the ones of my screen
   for(int j=0;j<SCREEN_SIZE_Y, j+=15){
      //The following conditional excludes the center which is the player's position
      if((i<PLAYER_MIN_EDGE_X or i>PLAYER_MAX_EDGE_X) and (j<PLAYER_MIN_EDGE_Y or j>PLAYER_MAX_EDGE_Y)){
      
         color = GetPixel(GetDC(nullptr), i, j);
         R = GetRValue(color);
         G = GetGValue(color);
         B = GetBValue(color);
         if(R!=0 or G!=0 or B!=0) cout<<"Enemy Found"<<endl;       
      }
   }
}

It turns out that, as expected, the GetPixel() function is extremely slow as it has to verify about 4000 pixels to cover just one screen scan. I was thinking about a way to solve this faster, and while looking at the keyboard I noticed the button "Pt Scr", and then realized that whatever that button is doing it is able to almost instantly save the information of millions of pixels.

I surely think there is a proper and different technic to approach this kind of problem. What kind of theory or technic for pixel analyzing should I investigate and read about so that this can be considered respectable code, and to get it actually work, and much faster?

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
Saul Martinez
  • 114
  • 11
  • A faster solution would be to capture the screen as a bitmap and then iterate through that. – Retired Ninja Jun 29 '20 at 07:01
  • Use [BitBlt](https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-bitblt) to read into a block of memory – Alan Birtles Jun 29 '20 at 07:22
  • From memory, I always used `GetDIBits` when doing this kind of stuff. https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-getdibits – enhzflep Jun 29 '20 at 07:47

2 Answers2

1

The GetPixel() routine is slow because it's fetching the data from the videocard (device) memory one by one. So to optimize your loop, you have to fetch the entire screen at once, and put it into an array of pixels. Then, you can iterate over that array of pixels much faster, because it'll be operating over the data in your RAM (host memory).

For a better optimization, I also recommend clearing the pixels of your player (in the center of the screen) after fetching the screen into your pixel array. This way, you can eliminate that if((i<PLAYER_MIN_EDGE_X or i>PLAYER_MAX_EDGE_X) and (j<PLAYER_MIN_EDGE_Y or j>PLAYER_MAX_EDGE_Y)) condition inside the loop.

Hack06
  • 963
  • 1
  • 12
  • 20
1
CImage image;
//Save DC to image
int R, G, B;
BYTE *pRealData =   (BYTE*)image.GetBits();
int pit         =   image.GetPitch(); 
int bitCount    =   image.GetBPP()/8; 
int w=image.GetWidth();
int h=image.GetHeight();
for (int i=0;i<h;i++)
{
    for (int j=0;j<w;j++)
    {
        B=*(pRealData + pit*i + j*bitCount);  
        G=*(pRealData + pit*i + j*bitCount +1);  
        R=*(pRealData + pit*i + j*bitCount +2);  
    }
}
Chan Xiang
  • 56
  • 3