```c

// Add these global variables near the existing global variables

int rotatingGroup = -1; // Index of the rotating pipe group (0 to N_PIPES/4 - 1)

float rotationAngle = 0.0f; // Rotation angle in degrees

float gapOffset[N_PIPES]; // Per-pipe gap offset for dynamic gap size


void resetGame()

{

    bird_y = 400;

    bird_velocity = 0;

    gameOverSoundPlayed = false;

    int totalGroups = N_PIPES / 4;


    // Select a random group to rotate

    rotatingGroup = rand() % totalGroups;


    int groupSpacing = SCREEN_WIDTH / 2;


    for (int group = 0; group < totalGroups; group++) {

        int baseX = SCREEN_WIDTH + group * groupSpacing;

        int baseGapY = 150 + rand() % 200;


        for (int i = 0; i < 4; i++) {

            int idx = group * 4 + i;


            pipe_x[idx] = baseX + i * (PIPE_WIDTH + 10);

            pipe_gap_y[idx] = baseGapY + (i % 2) * 80;

            gapOffset[idx] = 0.0f; // Initialize gap offset


            int topPipeHeight = SCREEN_HEIGHT - (pipe_gap_y[idx] + PIPE_GAP);

            if (topPipeHeight < 0) topPipeHeight = 0;


            iResizeImage(&lowerPipeImages[idx], PIPE_WIDTH, pipe_gap_y[idx]);

            iResizeImage(&upperPipeImages[idx], PIPE_WIDTH, topPipeHeight);


            scoreCountedPerPipe[idx] = false;

        }

    }


    spawnBeams();


    for (int i = 0; i < N_COINS; i++) {

        coin_x[i] = SCREEN_WIDTH + i * 300;

        coin_y[i] = 100 + rand() % (SCREEN_HEIGHT - 200);

    }


    score = 0;

    gameOver = false;

    rotationAngle = 0.0f; // Reset rotation angle

    iResumeTimer(physicsTimer);

}


void spawnBeams()

{

    float baseX = SCREEN_WIDTH;

    float lineY = rand() % (SCREEN_HEIGHT - 200);


    for (int i = 0; i < N_BEAMS; i++) {

        bool overlaps;

        int attempts = 0;

        float candidateY = lineY;


        do {

            overlaps = false;

            for (int group = 0; group < N_PIPES / 4; group++) {

                int basePipeIndex = group * 4;

                float adjusted_gap_y = pipe_gap_y[basePipeIndex] + (group == rotatingGroup ? gapOffset[basePipeIndex] : 0.0f);

                int gapTop = adjusted_gap_y + PIPE_GAP;


                if (candidateY + BEAM_HEIGHT > adjusted_gap_y && candidateY < gapTop) {

                    overlaps = true;

                    candidateY = 100 + rand() % (SCREEN_HEIGHT - 200);

                    break;

                }

            }

            attempts++;

            if (attempts > 10) break;

        } while (overlaps);


        beam_x[i] = baseX + i * (BEAM_WIDTH + 50);

        beam_y[i] = candidateY;

        beam_active[i] = true;

    }

}


void updateGame()

{

    if (gameOver) return;


    bird_velocity -= GRAVITY;

    if (bird_velocity < -2 * JUMP_VELOCITY) bird_velocity = -2 * JUMP_VELOCITY;

    bird_y += bird_velocity;


    if (bird_y < 0) {

        bird_y = 0;

        gameOver = true;

        iPauseTimer(physicsTimer);

        if (!gameOverSoundPlayed) {

            PlaySound(NULL, 0, 0);

            PlaySound(TEXT("game_over.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);

            gameOverSoundPlayed = true;

        }

    }


    for (int i = 0; i < N_BEAMS; i++) {

        if (beam_active[i] &&

            bird_x + BIRD_WIDTH > beam_x[i] && bird_x < beam_x[i] + BEAM_WIDTH &&

            bird_y + BIRD_HEIGHT > beam_y[i] && bird_y < beam_y[i] + BEAM_HEIGHT) {

            gameOver = true;

            iPauseTimer(physicsTimer);

            if (!gameOverSoundPlayed) {

                PlaySound(NULL, 0, 0);

                PlaySound(TEXT("game_over.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);

                gameOverSoundPlayed = true;

            }

        }

    }


    if (bird_y + BIRD_HEIGHT > SCREEN_HEIGHT) {

        bird_y = SCREEN_HEIGHT - BIRD_HEIGHT;

    }


    rotationAngle += 1.0f; // Increment rotation angle (adjust speed as needed)

    if (rotationAngle >= 360.0f) rotationAngle -= 360.0f;


    for (int group = 0; group < N_PIPES / 4; group++) {

        bool groupReset = false;

        for (int i = 0; i < 4; i++) {

            int idx = group * 4 + i;

            pipe_x[idx] -= PIPE_SPEED;


            // Apply dynamic gap offset to rotating group

            if (group == rotatingGroup) {

                gapOffset[idx] = 50.0f * sin(rotationAngle * 3.14159f / 180.0f); // Oscillate gap by ±50 pixels

                int topPipeHeight = SCREEN_HEIGHT - (pipe_gap_y[idx] + PIPE_GAP + gapOffset[idx]);

                if (topPipeHeight < 0) topPipeHeight = 0;

                iResizeImage(&lowerPipeImages[idx], PIPE_WIDTH, pipe_gap_y[idx] + gapOffset[idx]);

                iResizeImage(&upperPipeImages[idx], PIPE_WIDTH, topPipeHeight);

            }


            if (pipe_x[idx] + PIPE_WIDTH < -250)

                groupReset = true;

        }


        if (groupReset) {

            int baseX = SCREEN_WIDTH;

            int baseGapY = 150 + rand() % 200;


            for (int i = 0; i < 4; i++) {

                int idx = group * 4 + i;


                pipe_x[idx] = baseX + i * (PIPE_WIDTH + 10);

                pipe_gap_y[idx] = baseGapY + (i % 2) * 80;

                gapOffset[idx] = 0.0f;


                int topPipeHeight = SCREEN_HEIGHT - (pipe_gap_y[idx] + PIPE_GAP);

                if (topPipeHeight < 0) topPipeHeight = 0;


                iResizeImage(&lowerPipeImages[idx], PIPE_WIDTH, pipe_gap_y[idx]);

                iResizeImage(&upperPipeImages[idx], PIPE_WIDTH, topPipeHeight);


                scoreCountedPerPipe[idx] = false;

            }

        }

    }


    for (int i = 0; i < N_PIPES; i++) {

        float adjusted_gap_y = pipe_gap_y[i] + (i / 4 == rotatingGroup ? gapOffset[i] : 0.0f);

        if (bird_x + BIRD_WIDTH > pipe_x[i] && bird_x < pipe_x[i] + PIPE_WIDTH &&

            (bird_y < adjusted_gap_y || bird_y + BIRD_HEIGHT > adjusted_gap_y + PIPE_GAP)) {

            gameOver = true;

            iPauseTimer(physicsTimer);

            if (!gameOverSoundPlayed) {

                PlaySound(NULL, 0, 0);

                PlaySound(TEXT("game_over.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);

                gameOverSoundPlayed = true;

            }

        }


        if (!scoreCountedPerPipe[i] && pipe_x[i] + PIPE_WIDTH < bird_x) {

            score++;

            scoreCountedPerPipe[i] = true;

        }

    }


    for (int i = 0; i < N_COINS; i++) {

        if (bird_x + BIRD_WIDTH > coin_x[i] && bird_x < coin_x[i] + COIN_WIDTH &&

            bird_y + BIRD_HEIGHT > coin_y[i] && bird_y < coin_y[i] + COIN_HEIGHT) {

            score += 1;

            coin_x[i] = SCREEN_WIDTH;

            coin_y[i] = 100 + rand() % (SCREEN_HEIGHT - 200);

            PlaySound(TEXT("coin_collect.wav"), NULL, SND_FILENAME | SND_ASYNC | SND_NODEFAULT);

        }

    }

}


void iDraw()

{

    iClear();

    if (gameState != 0) {

        iShowLoadedImage(backBtnX, backBtnY, hoverBack ? &backBtnHover : &backBtn);

    }


    if (gameState == 0) {

        iShowLoadedImage(0, 0, &background);

        iShowLoadedImage(playX, playY, hoverPlay ? &playHover : &play);

        iShowLoadedImage(helpX, helpY, hoverHelp ? &helpHover : &help);

        iShowLoadedImage(exitX, exitY, hoverExit ? &quitHover : &quit);

        iShowLoadedImage(continueX, continueY, hoverContinue ? &contHover : &cont);

        iShowLoadedImage(scoreX, scoreY, hoverScore ? &scoreBtnHover : &scoreBtn);

        iShowLoadedImage(levelX, levelY, hoverLevel ? &levelHover : &level);

    }

    else if (gameState == GAME_STATE_LEVEL_SELECT) {

        iSetColor(200, 200, 200);

        iFilledRectangle(easyX, easyY, levelBtnW, levelBtnH);

        iFilledRectangle(mediumX, mediumY, levelBtnW, levelBtnH);

        iFilledRectangle(hardX, hardY, levelBtnW, levelBtnH);


        iSetColor(0, 0, 0);

        iText(easyX + 40, easyY + 20, "Easy");

        iText(mediumX + 30, mediumY + 20, "Medium");

        iText(hardX + 40, hardY + 20, "Hard");


        iText(50, SCREEN_HEIGHT - 50, "Press 'H' to return to Home");

    }

    else if (gameState == 1) {

        iSetColor(135, 206, 235);

        iFilledRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);


        for (int i = 0; i < N_CLOUDS; i++) {

            iShowLoadedImage((int)cloud_x[i], (int)cloud_y[i], &cloudImages[i]);

        }


        for (int i = 0; i < N_BEAMS; i++) {

            if (beam_active[i]) {

                int centerX = (int)beam_x[i] + BEAM_WIDTH / 2;

                int centerY = (int)beam_y[i] + BEAM_HEIGHT / 2;

                int radius = BEAM_WIDTH / 2;


                for (int r = radius; r > 0; r--) {

                    int red = 255;

                    int green = (int)(100 * (float)r / radius);

                    int blue = (int)(100 * (float)r / radius);

                    iSetColor(red, green, blue);

                    iFilledCircle(centerX, centerY, r);

                }

            }

        }


        for (int i = 0; i < N_COINS; i++) {

            iShowLoadedImage((int)coin_x[i], (int)coin_y[i], &coinFrames[i][coinFrameIndex[i]]);

        }


        for (int group = 0; group < N_PIPES / 4; group++) {

            for (int i = 0; i < 4; i++) {

                int idx = group * 4 + i;

                float adjusted_gap_y = pipe_gap_y[idx] + (group == rotatingGroup ? gapOffset[idx] : 0.0f);

                if (group == rotatingGroup) {

                    // Calculate center of rotation (middle of the pipe group)

                    float centerX = pipe_x[idx] + PIPE_WIDTH / 2.0f;

                    float centerY = adjusted_gap_y + PIPE_GAP / 2.0f;

                    iRotate(centerX, centerY, rotationAngle);

                    iShowLoadedImage(pipe_x[idx], 0, &lowerPipeImages[idx]);

                    iShowLoadedImage(pipe_x[idx], adjusted_gap_y + PIPE_GAP, &upperPipeImages[idx]);

                    iUnRotate();

                } else {

                    iShowLoadedImage(pipe_x[idx], 0, &lowerPipeImages[idx]);

                    iShowLoadedImage(pipe_x[idx], adjusted_gap_y + PIPE_GAP, &upperPipeImages[idx]);

                }

            }

        }


        if (!gameOver) {

            iShowLoadedImage((int)bird_x, (int)bird_y, &birdFrames[flyingFrame]);

        }


        for (int i = 0; i < N_GERMS; i++) {

            if (germ_active[i]) {

                iShowLoadedImage((int)germ_x[i], (int)germ_y[i], &germFrames[germFrameIndex]);

            }

        }


        float rad_1 = rectAngle1 * 3.14159265f / 180.0f;

        float rad_2 = rectAngle2 * 3.14159265f / 180.0f;


        float rect1X = circleCenterX + circleRadius * cos(rad_1) - rectWidth / 2;

        float rect1Y = circleCenterY + circleRadius * sin(rad_1) - rectHeight / 2;


        float rect2X = circleCenterX + circleRadius * cos(rad_2) - rectWidth / 2;

        float rect2Y = circleCenterY + circleRadius * sin(rad_2) - rectHeight / 2;


        iSetColor(255, 0, 0); // Red color

        iFilledRectangle((int)rect1X, (int)rect1Y, rectWidth, rectHeight);

        iFilledRectangle((int)rect2X, (int)rect2Y, rectWidth, rectHeight);


        iShowLoadedImage((int)ground_x, 0, &groundImage);

        iShowLoadedImage((int)ground_x + SCREEN_WIDTH, 0, &groundImage);


        iSetColor(0, 0, 0);

        char scoreText[20];

        if (isHardLevel)

            sprintf(scoreText, "Score: Hard %d", score);

        else

            sprintf(scoreText, "Score: Medium %d", score);

        iText(10, SCREEN_HEIGHT - 130, scoreText);


        if (isEnteringName) {

            iSetColor(0, 0, 150);

            iFilledRectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);


            int boxWidth = 400;

            int boxHeight = 100;

            int boxX = (SCREEN_WIDTH - boxWidth) / 2;

            int boxY = (SCREEN_HEIGHT - boxHeight) / 2;

            iSetColor(50, 50, 50);

            iFilledRectangle(boxX, boxY, boxWidth, boxHeight);


            iSetColor(255, 255, 255);

            iRectangle(boxX, boxY, boxWidth, boxHeight);


            iText(boxX + 20, boxY + boxHeight - 30, "Game Over! Enter your name:");

            iText(boxX + 20, boxY + boxHeight / 2 - 10, playerName);


            static int blinkTimer = 0;

            blinkTimer = (blinkTimer + 1) % 60;

            if (blinkTimer < 30) {

                int charWidth = 12;

                int cursorX = boxX + 20 + (int)(strlen(playerName) * charWidth);

                int cursorY = boxY + boxHeight / 2 - 10;

                iLine(cursorX, cursorY, cursorX, cursorY + 20);

            }


            iText(boxX + 20, boxY + 10, "Press Enter to submit, Backspace to delete");

        }

        else if (gameOver) {

            int imgX = SCREEN_WIDTH / 2 - 400;

            int imgY = SCREEN_HEIGHT / 2 - 250;

            iShowLoadedImage(imgX, imgY, &gameOverImage);

        }

    }

    else if (gameState == 2) {

        iShowLoadedImage(0, SCREEN_HEIGHT - helpContentHeight + helpScrollY - 200, &helpImage);

    }

    else if (gameState == 3) {

        iText(300, 300, "Continue Screen. Press 'H' to return.");

    }

    else if (gameState == 4) {

        if (scoreScrollY < 0) scoreScrollY = 0;

        if (scoreScrollY > scoreContentHeight - SCREEN_HEIGHT)

            scoreScrollY = scoreContentHeight - SCREEN_HEIGHT;

        iShowLoadedImage(0, SCREEN_HEIGHT - scoreContentHeight + scoreScrollY, &scoreImage);

        iSetColor(255, 255, 255);

        int startY = SCREEN_HEIGHT - 400;

        iText(600, startY + 40, "High Scores:");

        for (int i = 0; i < 5; i++) {

            char buf[100];

            sprintf(buf, "%d. %s - %d", i + 1, highScores[i].name, highScores[i].score);

            iText(600, startY - i * 30, buf);

        }

    }

    else if (gameState == 5) {

        iText(300, 300, "Level Screen. Press 'H' to return.");

    }

}

```

Comments

Popular posts from this blog

DAY 02 Inline CSS

DAY 01 HTML