diff options
-rw-r--r-- | pong.c | 192 |
1 files changed, 192 insertions, 0 deletions
@@ -0,0 +1,192 @@ +#define SDL_DISABLE_IMMINTRIN_H +#include <limits.h> +#include <stdlib.h> +#include <time.h> +#include <SDL2/SDL.h> + +#define WINDOW_W 800 +#define WINDOW_H 600 +#define MARGIN 20 +#define PLAYER_W 10 +#define PLAYER_H 100 +#define PLAYER_V 5 +#define BALL_SIZE 10 + +typedef struct { + float x, y; + char dir; + int score; + int stuck; +} Player; + +typedef struct { + float x, y; + float vx, vy; +} Ball; + +void initBall(Ball *b) { + b->x = WINDOW_W / 2; + b->y = WINDOW_H / 2; + b->vx = 2 * (rand() % 2 ? 1 : -1); + b->vy = 2 * (rand() % 2 ? 1 : -1); +} + +int abs(int n) { + return (n >= 0 ? n : -n); +} + +void limit(float *n, float min, float max) { + if (abs(*n) > max) *n = *n > 0 ? max : -max; + else if (abs(*n) < min) *n = *n > 0 ? min : -min; +} + +float randfloat(float from, float to) { + return from + (to - from) * ((float)rand()/INT_MAX); +} + +void collision(Ball *b, Player *p) { + if (b->x + BALL_SIZE >= p->x && + b->x <= p->x + PLAYER_W && + b->y + BALL_SIZE >= p->y && + b->y <= p->y + PLAYER_H) { + if (!p->stuck) { + b->vx = -b->vx; + b->vx *= randfloat(0.5, 1.5); + limit(&b->vx, 4, 8); + b->vy += randfloat(0.2, 0.8) * p->dir; + limit(&b->vy, 2, 8); + p->stuck = 1; + } + } + else { + p->stuck = 0; + } +} + +void move(Player *p, float n) { + if (n > 0) p->dir = 1; + else if (n < 0) p->dir = -1; + p->y += n; + if (p->y > WINDOW_H - PLAYER_H) { + p->y = WINDOW_H - PLAYER_H; + p->dir = 0; + } + else if (p->y < 0) { + p->y = 0; + p->dir = 0; + } +} + +void input(Player *p) { + const Uint8 *state = SDL_GetKeyboardState(0); + if (state[SDL_SCANCODE_UP]) + move(p, -PLAYER_V); + else if (state[SDL_SCANCODE_DOWN]) + move(p, PLAYER_V); + else + p->dir = 0; +} + +void ai(Ball *b, Player *p) { + if (abs(b->x - p->x) < 300) { + if (b->y - p->y > PLAYER_H - 10 - BALL_SIZE) + move(p, PLAYER_V); + else if (b->y - p->y < 10) + move(p, -PLAYER_V); + } + else { + if (p->y >= WINDOW_H * 5 / 6 - PLAYER_H) { + p->dir = -1; + } + else if (p->y <= WINDOW_H / 6) { + p->dir = 1; + } + move(p, p->dir * PLAYER_V); + } +} + +void update(Ball *b, Player *p1, Player *p2) { + b->x += b->vx; + b->y += b->vy; + if (b->y < 0 || b->y + BALL_SIZE > WINDOW_H) + b->vy = -b->vy; + if (b->x < 0) { + p2->score++; + initBall(b); + } + if (b->x + BALL_SIZE > WINDOW_W) { + p1->score++; + initBall(b); + } + if (p1->score > 5 || p2->score > 5) { + p1->score = 0; + p2->score = 0; + } + collision(b, p1); + collision(b, p2); + input(p1); + ai(b, p2); +} + +void render(SDL_Renderer *r, Ball *b, Player *p1, Player *p2) { + SDL_SetRenderDrawColor(r, 0, 0, 0, 255); + SDL_RenderClear(r); + SDL_SetRenderDrawColor(r, 40, 40, 40, 255); + SDL_Rect canvas = {0, 0, WINDOW_W, WINDOW_H}; + SDL_RenderFillRect(r, &canvas); + SDL_SetRenderDrawColor(r, 255, 255, 255, 255); + SDL_Rect net[10]; + for (int i = 0; i < 10; i++) { + net[i].x = WINDOW_W / 2; + net[i].y = i * (WINDOW_H / 10) + 10; + net[i].w = 10; + net[i].h = WINDOW_H / 10 - 20; + } + SDL_RenderFillRects(r, net, 10); + + SDL_SetRenderDrawColor(r, 255, 255, 255, 255); + SDL_Rect ball_r = {b->x, b->y, BALL_SIZE, BALL_SIZE}; + SDL_RenderFillRect(r, &ball_r); + + int p1factor = 255 - p1->score * 50; + SDL_SetRenderDrawColor(r, 255, p1factor, p1factor, 255); + SDL_Rect p1_r = {p1->x, p1->y, PLAYER_W, PLAYER_H}; + SDL_RenderFillRect(r, &p1_r); + + int p2factor = 255 - p2->score * 50; + SDL_SetRenderDrawColor(r, 255, p2factor, p2factor, 255); + SDL_Rect p2_r = {p2->x, p2->y, PLAYER_W, PLAYER_H}; + SDL_RenderFillRect(r, &p2_r); + + SDL_RenderPresent(r); + SDL_Delay(10); +} + +int main() { + srand(time(0)); + SDL_Init(SDL_INIT_VIDEO); + SDL_Window *w; + SDL_Renderer *r; + SDL_CreateWindowAndRenderer(WINDOW_W, WINDOW_H, SDL_WINDOW_RESIZABLE, &w, &r); + SDL_RenderSetLogicalSize(r, WINDOW_W, WINDOW_H); + Player p1, p2; + Ball b; + p1.x = MARGIN; + p1.y = WINDOW_H / 2; + p2.x = WINDOW_W - MARGIN - PLAYER_W; + p2.y = WINDOW_H / 2; + p1.score = p2.score = 0; + p1.stuck = p2.stuck = 0; + p1.dir = p2.dir = 0; + initBall(&b); + SDL_Event e; + while (e.type != SDL_QUIT) { + SDL_PollEvent(&e); + update(&b, &p1, &p2); + render(r, &b, &p1, &p2); + } + SDL_DestroyRenderer(r); + SDL_DestroyWindow(w); + SDL_Quit(); + return 0; +} |