#include #include #include #include enum { WINDOW_WIDTH = 800, WINDOW_HEIGHT = 600, PLAYER_SIZE = 20, PLAYER_SPEED = 5, BULLET_SPEED = 50, OBSTACLE_SPEED = 3, NUM_OBSTACLES = 2, ZAPPER_HEIGHT = 50, SAW_RADIUS = 50, NUM_COINS = 20, COIN_RADIUS = 10, FLOOR_AND_CEILING_HEIGHT = 50, UPARROW = 'j', }; typedef enum { ZAPPER_WALL, SAW_BLADE } ObstacleType; typedef struct Obstacle { ObstacleType type; int x, y, exist; } Obstacle; typedef struct SawBlade { Obstacle obstacle; int radius; double angle; } SawBlade; typedef struct Coin { int x, y, exist; } Coin; typedef struct Bullet { int x, y, exist; } Bullet; Obstacle* obstacles[NUM_OBSTACLES]; int playerX = -PLAYER_SIZE, playerY = WINDOW_HEIGHT / 2 - PLAYER_SIZE / 2; int upPressed = 0, spacePressed = 0, gameStarted = 0; int currentSpeed = 0; int maxSpeed = 15; int acceleration = 1; int deceleration = 1; int gameOver = 0; int coinCounter = 0; Bullet bullet; Coin coins[NUM_COINS]; void eresized(int new) { if (new && getwindow(display, Refnone) < 0) sysfatal("can't reattach to window"); } void drawPlayer(void) { Rectangle r; r = Rect(playerX, playerY, playerX + PLAYER_SIZE, playerY + PLAYER_SIZE); draw(screen, r, display->black, nil, ZP); } void drawObstacles(void) { Rectangle r; for (int i = 0; i < NUM_OBSTACLES; i++) { if (obstacles[i]->exist == 0) continue; switch (obstacles[i]->type) { case ZAPPER_WALL: r = Rect(obstacles[i]->x, obstacles[i]->y, obstacles[i]->x + WINDOW_WIDTH, obstacles[i]->y + ZAPPER_HEIGHT); draw(screen, r, display->black, nil, ZP); break; case SAW_BLADE: { SawBlade* sawBlade = (SawBlade*)obstacles[i]; int x = sawBlade->obstacle.x + sawBlade->radius * cos(sawBlade->angle); int y = sawBlade->obstacle.y + sawBlade->radius * sin(sawBlade->angle); fillellipse(screen, Pt(x, y), sawBlade->radius, sawBlade->radius, display->black, ZP); break; } } } } void drawCoins(void) { Point c; for (int i = 0; i < NUM_COINS; i++) { if (coins[i].exist == 0) continue; c = Pt(coins[i].x, coins[i].y); fillellipse(screen, c, COIN_RADIUS, COIN_RADIUS, display->white, ZP); } } void drawFloorAndCeiling(void) { Rectangle r; r = Rect(0, 0, WINDOW_WIDTH, FLOOR_AND_CEILING_HEIGHT); draw(screen, r, display->black, nil, ZP); r = Rect(0, WINDOW_HEIGHT - FLOOR_AND_CEILING_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT); draw(screen, r, display->black, nil, ZP); } void redraw(void) { draw(screen, screen->r, display->white, nil, ZP); drawFloorAndCeiling(); drawPlayer(); drawObstacles(); drawCoins(); } void init(void) { // Initialize obstacles Obstacle* zapperWall = malloc(sizeof(Obstacle)); if (zapperWall) { zapperWall->type = ZAPPER_WALL; zapperWall->x = WINDOW_WIDTH; zapperWall->y = nrand(WINDOW_HEIGHT - ZAPPER_HEIGHT); zapperWall->exist = 1; obstacles[0] = zapperWall; } SawBlade* sawBlade = malloc(sizeof(SawBlade)); if (sawBlade) { sawBlade->obstacle.type = SAW_BLADE; sawBlade->obstacle.x = WINDOW_WIDTH; sawBlade->obstacle.y = nrand(WINDOW_HEIGHT - SAW_RADIUS); sawBlade->obstacle.exist = 1; sawBlade->radius = SAW_RADIUS; sawBlade->angle = 0; obstacles[1] = (Obstacle*)sawBlade; } // Initialize coins for (int i = 0; i < NUM_COINS; i++) { coins[i].exist = 1; coins[i].x = WINDOW_WIDTH + (nrand(WINDOW_WIDTH)); coins[i].y = nrand(WINDOW_HEIGHT - COIN_RADIUS); } } int checkCollision(void) { for (int i = 0; i < NUM_OBSTACLES; i++) { if (obstacles[i]->exist == 1) { switch (obstacles[i]->type) { case ZAPPER_WALL: if (playerX < obstacles[i]->x + WINDOW_WIDTH && playerX + PLAYER_SIZE > obstacles[i]->x && playerY < obstacles[i]->y + ZAPPER_HEIGHT && playerY + PLAYER_SIZE > obstacles[i]->y) return 1; break; case SAW_BLADE: { SawBlade* sawBlade = (SawBlade*)obstacles[i]; if ((playerX - obstacles[i]->x) * (playerX - obstacles[i]->x) + (playerY - obstacles[i]->y) * (playerY - obstacles[i]->y) <= (sawBlade->radius + PLAYER_SIZE) * (sawBlade->radius + PLAYER_SIZE)) return 1; break; } } } } // Check collision with coins for (int i = 0; i < NUM_COINS; i++) { if (coins[i].exist == 1) { if (playerX < coins[i].x + COIN_RADIUS && playerX + PLAYER_SIZE > coins[i].x && playerY < coins[i].y + COIN_RADIUS && playerY + PLAYER_SIZE > coins[i].y) { coins[i].exist = 0; coinCounter++; } } } return 0; } void main(void) { Event e; Mouse m; if (initdraw(0, 0, "Jetpack Game") < 0) sysfatal("initdraw failed: %r"); einit(Emouse | Ekeyboard); eresized(0); init(); for (;;) { while (ecanread(Emouse | Ekeyboard)) { switch (event(&e)) { case Ekeyboard: if (e.kbdc == UPARROW) { upPressed = 1; gameStarted = 1; } else if (e.kbdc == -UPARROW) { // Arrow up released upPressed = 0; } else if (e.kbdc == 'q') { exits(0); } break; case Emouse: m = e.mouse; if (m.buttons == 4) { exits(0); } break; } } if (gameStarted) { if (upPressed) { if (currentSpeed < maxSpeed && playerY > FLOOR_AND_CEILING_HEIGHT) currentSpeed += acceleration; playerY -= currentSpeed; if (bullet.exist == 0) { bullet.exist = 1; bullet.x = playerX; bullet.y = playerY + PLAYER_SIZE; } } else { if (currentSpeed > 0 && playerY < WINDOW_HEIGHT - FLOOR_AND_CEILING_HEIGHT - PLAYER_SIZE) { currentSpeed -= deceleration; playerY -= currentSpeed; } else { if (playerY < WINDOW_HEIGHT - FLOOR_AND_CEILING_HEIGHT - PLAYER_SIZE) { currentSpeed -= deceleration; playerY -= currentSpeed; } } } if (bullet.exist) { bullet.y += BULLET_SPEED; if (bullet.y >= WINDOW_HEIGHT) bullet.exist = 0; } for (int i = 0; i < NUM_OBSTACLES; i++) { if (obstacles[i]->exist == 1) { obstacles[i]->x -= OBSTACLE_SPEED; switch (obstacles[i]->type) { case ZAPPER_WALL: if (obstacles[i]->x < -WINDOW_WIDTH) { obstacles[i]->x = WINDOW_WIDTH; obstacles[i]->y = nrand(WINDOW_HEIGHT - ZAPPER_HEIGHT); } break; case SAW_BLADE: { SawBlade* sawBlade = (SawBlade*)obstacles[i]; sawBlade->angle += 0.05; if (obstacles[i]->x < -SAW_RADIUS) { obstacles[i]->x = WINDOW_WIDTH; obstacles[i]->y = nrand(WINDOW_HEIGHT - SAW_RADIUS); } break; } } if (checkCollision()) gameOver = 1; } } if (gameOver == 0) redraw(); else { print("Game Over! Final score: %d\n", coinCounter); exits(0); } } else { playerX += PLAYER_SPEED; if (playerX >= WINDOW_WIDTH / 2 - PLAYER_SIZE / 2) gameStarted = 1; redraw(); } sleep(16); // update approximately every 16 ms or about 60 times per second } }