#include <SDL2/SDL.h>
#include <stdbool.h>
#include <SDL2/SDL_image.h>
// Screen dimensions
const int SCREEN_WIDTH = 1200;
const int SCREEN_HEIGHT = 600;
// Player dimensions
const int PLAYER_WIDTH = 50;
const int PLAYER_HEIGHT = 100;
// Jumping variables
const int JUMP_HEIGHT = 10000;
// Player speeds
const int PLAYER_SPEED = 10;
// Ball dimensions
const int BALL_SIZE = 20;
// Ball speed
const float BALL_SPEED = 5.0f;
// Background image
SDL_Texture *backgroundTexture = NULL;
// Player struct
typedef struct
{
int x;
int y;
int velocity_y;
int remaining_jumps;
bool jumping;
} Player;
// Ball struct
typedef struct
{
float x;
float y;
float velocity_x;
float velocity_y;
} Ball;
// Initialize SDL and create a window
bool init(SDL_Window **window, SDL_Renderer **renderer)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
return false;
}
*window = SDL_CreateWindow("Two Players", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (*window == NULL)
{
printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
return false;
}
*renderer = SDL_CreateRenderer(*window, -1, SDL_RENDERER_ACCELERATED);
if (*renderer == NULL)
{
printf("Renderer could not be created! SDL_Error: %s\n", SDL_GetError());
return false;
}
return true;
}
// Load background image
bool loadBackground(SDL_Renderer *renderer)
{
SDL_Surface *backgroundSurface = IMG_Load("background.jpg");
if (backgroundSurface == NULL)
{
printf("Unable to load background image! SDL_Image Error: %s\n", IMG_GetError());
return false;
}
backgroundTexture = SDL_CreateTextureFromSurface(renderer, backgroundSurface);
if (backgroundTexture == NULL)
{
printf("Unable to create texture from background image! SDL Error: %s\n", SDL_GetError());
return false;
}
SDL_FreeSurface(backgroundSurface);
return true;
}
// Draw a player
void drawPlayer(SDL_Renderer *renderer, Player *player, Uint8 red, Uint8 green, Uint8 blue)
{
SDL_SetRenderDrawColor(renderer, red, green, blue, 255);
SDL_Rect playerRect = {player->x, player->y, PLAYER_WIDTH, PLAYER_HEIGHT};
SDL_RenderFillRect(renderer, &playerRect);
}
// Draw the ball
void drawBall(SDL_Renderer *renderer, Ball *ball)
{
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_Rect ballRect = {(int)ball->x, (int)ball->y, BALL_SIZE, BALL_SIZE};
SDL_RenderFillRect(renderer, &ballRect);
}
// Check for Collision
bool checkCollision(int x1, int y1, int x2, int y2, int width, int height)
{
return (x1 < x2 + width &&
x1 + PLAYER_WIDTH > x2 &&
y1 < y2 + height &&
y1 + PLAYER_HEIGHT > y2);
}
void updatePlayerPosition(Player *player)
{
if (player->jumping)
{
player->y += player->velocity_y;
player->velocity_y += 1;
if (player->y >= SCREEN_HEIGHT - PLAYER_HEIGHT)
{
player->y = SCREEN_HEIGHT - PLAYER_HEIGHT;
player->jumping = false;
player->remaining_jumps = 2;
}
}
}
void updateBallPosition(Ball *ball)
{
ball->x += ball->velocity_x;
ball->y += ball->velocity_y;
// Reflect the ball if it hits the screen boundaries
if (ball->x <= 0 || ball->x + BALL_SIZE >= SCREEN_WIDTH)
{
ball->velocity_x = -ball->velocity_x;
}
if (ball->y <= 0 || ball->y + BALL_SIZE >= SCREEN_HEIGHT)
{
ball->velocity_y = -ball->velocity_y;
}
}
int main(int argc, char *argv[])
{
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
if (!init(&window, &renderer))
{
return 1;
}
if (!loadBackground(renderer))
{
return 1;
}
Player player1 = {100, SCREEN_HEIGHT - PLAYER_HEIGHT, 0, 2, false};
Player player2 = {650, SCREEN_HEIGHT - PLAYER_HEIGHT, 0, 2, false};
Ball ball = {SCREEN_WIDTH / 2 - BALL_SIZE / 2, SCREEN_HEIGHT / 2 - BALL_SIZE / 2, BALL_SPEED, BALL_SPEED};
bool quit = false;
SDL_Event e;
while (!quit)
{
Uint64 start = SDL_GetPerformanceCounter();
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
quit = true;
}
if (e.type == SDL_KEYDOWN)
{
// Player 1 jump
if (e.key.keysym.sym == SDLK_w)
{
if (player1.remaining_jumps > 0)
{
player1.jumping = true;
player1.velocity_y = -20;
player1.remaining_jumps--;
}
}
// Player 2 jump
if (e.key.keysym.sym == SDLK_UP)
{
if (player2.remaining_jumps > 0)
{
player2.jumping = true;
player2.velocity_y = -20;
player2.remaining_jumps--;
}
}
}
}
updatePlayerPosition(&player1);
updatePlayerPosition(&player2);
updateBallPosition(&ball);
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
quit = true;
}
}
const Uint8 *currentKeyStates = SDL_GetKeyboardState(NULL);
if (checkCollision(player1.x, player1.y, ball.x, ball.y, PLAYER_WIDTH, PLAYER_HEIGHT))
{
ball.velocity_x = -ball.velocity_x;
}
if (checkCollision(player2.x, player2.y, ball.x, ball.y, PLAYER_WIDTH, PLAYER_HEIGHT))
{
ball.velocity_x = -ball.velocity_x;
}
if (checkCollision(player1.x, player1.y, player2.x, player2.y, PLAYER_WIDTH, PLAYER_HEIGHT))
{
if (player1.x < player2.x)
{
player1.x--;
player2.x++;
}
else
{
player1.x++;
player2.x--;
}
}
else
{
// Player 1 movement
if (currentKeyStates[SDL_SCANCODE_A])
{
player1.x -= PLAYER_SPEED;
}
if (currentKeyStates[SDL_SCANCODE_D])
{
player1.x += PLAYER_SPEED;
}
// Player 2 movement
if (currentKeyStates[SDL_SCANCODE_LEFT])
{
player2.x -= PLAYER_SPEED;
}
if (currentKeyStates[SDL_SCANCODE_RIGHT])
{
player2.x += PLAYER_SPEED;
}
// Keep players within the screen boundaries
if (player1.x < 0)
{
player1.x = 0;
}
if (player1.x > SCREEN_WIDTH - PLAYER_WIDTH)
{
player1.x = SCREEN_WIDTH - PLAYER_WIDTH;
}
if (player2.x < 0)
{
player2.x = 0;
}
if (player2.x > SCREEN_WIDTH - PLAYER_WIDTH)
{
player2.x = SCREEN_WIDTH - PLAYER_WIDTH;
}
}
// Clear the screen
SDL_RenderClear(renderer);
// Draw the background
SDL_RenderCopy(renderer, backgroundTexture, NULL, NULL);
// Draw Player 1 (red rectangle)
drawPlayer(renderer, &player1, 255, 0, 0);
// Draw Player 2 (blue rectangle)
drawPlayer(renderer, &player2, 0, 0, 255);
// Draw the ball
drawBall(renderer, &ball);
// Update the screen
SDL_RenderPresent(renderer);
Uint64 end = SDL_GetPerformanceCounter();
float elapsedMS = (end - start) / (float)SDL_GetPerformanceFrequency() * 1000.0f;
// Cap to 60 FPS
SDL_Delay((int)(16.666f - elapsedMS));
}
// Cleanup and exit
SDL_DestroyTexture(backgroundTexture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}