Create a simple 2D AI C++

1.3k views Asked by At

I would like to receive some insight as to how I can make an AI, that can walk smoothly around the map(between window size). Like, if the AI reached that defined spot, then it will walk to another spot. Here is what I have tried,

First, I get a random float number from 0.0f to 608.0f because my window size is 640,640.

void AIntelligence::GenRandom()
{
    MapX = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / 608.0f));
    MapY = MapX;
}

Then,I pass in the current position of my sprite to this function

void AIntelligence::RandomMove(float PosX, float PosY)
{
    this->PosX = PosX;
    this->PosY = PosY;

    if (PosX == MapX || PosY == MapY) //If the current is the same as the generated random, then
    {                                   generate it again.
        GenRandom();
    }
    else
    {
        if (PosX < MapX || PosY < MapY) //If not then I see if the position less than the
        {                                 generated and translate it.
            this->PosX += 8.0f;
            this->PosY += 8.0f;
        }
        else if (PosX > MapX || PosY > MapY)
        {
            this->PosX -= 8.0f;
            this->PosY -= 8.0f;
        }
        else
            this->PosX += 0.0f;
            this->PosY += 0.0f;
    }
}

In my message loop, here is how I call the method

while (GetMessage(&Msg, NULL, 0, 0))
        {
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
            Inputs->GetInput(); //Not related
            Moving->RandomMove(PosX,PosY);
            D3DXVECTOR2 SpritePos = D3DXVECTOR2(Moving->getPosX(), Moving->getPosY());
            PosX = Moving->getPosX();
            PosY = Moving->getPosY();
            Graphic->ClearBegin(); //Begin the direct3d scene

            Sprite->Begin(D3DXSPRITE_ALPHABLEND);
            float Radian = D3DXToRadian(Rotation);
            D3DXMatrixTransformation2D(&Mat, NULL, 0.0f, &SpriteScaling, &SpriteCenter, Radian, &SpritePos); // This is where the transformation is set.
            Sprite->SetTransform(&Mat);
            Sprite->Draw(Texture, NULL, NULL, NULL, D3DCOLOR_XRGB(255, 255, 255));
            Sprite->End();

            Graphic->EndPresent();
        }

The sprite did move but only moving downward right. And once it reached the same certain spot, it will only stay and vibrate there.... Sorry if my explanation is not clear enough or did not provide enough information needed. enter image description here

1

There are 1 answers

2
emartel On BEST ANSWER

Here are a few things that should help you:

1) In RandomMove, your last else doesn't have braces, since you're performing two operations, you should wrap both of them in braces like you did elsewhere

2) float comparison is tricky. It's very unlikely that your PosX == MapX || PosY == MapY will ever trigger. A better idea would be to calculate the distance between your current position and the random position and then execute the code if the distance is less than an epsilon (small value). Here is a pretty detailed post about float comparison (link)

3) GenRandom always assigns the same value to MapX and MapY. You should try to execute two random calls instead (and probably use a const float to define your max value or make it configurable instead of hardcoding that width

4) Your RandomMove method is a bit misleading. It's not performing random movement, it's going towards MapX and MapY. You should separate the calls to GenRandom from your movement code.

5) Your movement code is meant to work only in diagonals since you always increment or decrement your position in both axes at the same time, in the same direction.

Here is a suggestion (not tested) of what your code could look like:

void AIntelligence::GenRandom(const float in_MaxValueX, const float in_MaxValueY)
{
    MapX = in_MaxValueX * (float)rand() / (float)RAND_MAX;
    MapY = in_MaxValueY * (float)rand() / (float)RAND_MAX;
}

bool AIntelligence::MoveTowards(const float in_PosX, const float in_PosY)
{
    // how far are we from our objective
    const float distX = in_PosX - PosX; // by calculating the distance from the target position, it makes our speed calculations easier later on
    const float distY = in_PosY - PosY;

    // tolerance in pixels
    const float tolerance = 1.0f;

    const float absDistX = abs(distX);
    const float absDistY = abs(distY);

    if(absDistX <= tolerance && absDistY <= tolerance) // destination reached
        return true;
    else
    {
        // here, normally, you would use a desired speed AND a delta time (your message loop is not really good for that though) to compute how much movement you can execute in a given frame
        const float movement = min(10.f, absDistX + absDistY); // by using min, we're making sure not to overshoot our destination

        // compute how this movement is spread on each axis
        const float movementX = movement * distX / (absDistX + absDistY);
        const float movementY = movement * distY / (absDistX + absDistY);

        PosX += movementX;
        PosY += movementY;
    }

    return false;
}

// in your loop

if(Moving->MoveTowards(MapX, MapY))
{
    Moving->GenRandom(608.f, 608.f); // you should definitely not hardcode these values
}

Feel free to comment if there's parts you don't quite understand