```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
Post a Comment