#include <SDL2/SDL.h>
#include <stdbool.h>
#include <SDL2/SDL_image.h>
#include <stdio.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;
// Digit dimensions
const int DIGIT_WIDTH = 30;
const int DIGIT_HEIGHT = 50;
// Number of digits in the score
const int numDigits = 0;
// Player 1 initial position
int player1_x = 100;
int player1_y = SCREEN_HEIGHT - PLAYER_HEIGHT - 90;
int player1_velocity_y = 0;
int player1_remaining_jumps = 2;
// Player 2 initial position
int player2_x = 1050;
int player2_y = SCREEN_HEIGHT - PLAYER_HEIGHT - 90;
int player2_velocity_y = 0;
int player2_remaining_jumps = 2;
// Player 1 and 2 scores
int player1_score = 0;
int player2_score = 0;
// Jumping variables
bool player1_jumping = false;
bool player2_jumping = false;
const int JUMP_HEIGHT = 10000;
// Player speeds
const int PLAYER_SPEED = 4;
// Add gravity and friction constants
const double GRAVITY = 0.2; // Adjust as needed
const double FRICTION = 0.97; // Adjust as needed
// Ball dimensions
const int BALL_SIZE = 40;
// Ball initial position and velocity
int ball_x = SCREEN_WIDTH / 2 - BALL_SIZE / 2;
int ball_y = SCREEN_HEIGHT / 2 - BALL_SIZE / 2;
double ball_velocity_x = 3.0; // Use double for smoother movement
double ball_velocity_y = 1.0;
// Goal dimensions and positions
const int GOAL_WIDTH = 20;
const int GOAL_HEIGHT = 190;
// Goal Bar dimensions and positions
const int GOAL_BAR_WIDTH = 50;
const int GOAL_BAR_HEIGHT = 20;
int left_goal_x = 50; // Update left goal position
int left_goal_y = (SCREEN_HEIGHT - GOAL_HEIGHT) - 100;
int right_goal_x = SCREEN_WIDTH - GOAL_WIDTH - 50; // Update right goal position
int right_goal_y = SCREEN_HEIGHT - GOAL_HEIGHT - 100;
const int INVISIBLE_FLOOR = SCREEN_HEIGHT - 90; // Adjust the height as needed
// Background image
SDL_Texture *backgroundTexture = NULL;
// Goal Post image
SDL_Texture *goalPostTexture = NULL;
// Load the player1 image and create a texture for it
SDL_Texture *player1Texture = NULL;
// Load the player2 image and create a texture for it
SDL_Texture *player2Texture = NULL;
// Load the ball image and create a texture for it
SDL_Texture *ballTexture = NULL;
// Load the fan image and create a texture for it
SDL_Texture *fanTexture = NULL;
// Load digit images from 0 to 9
SDL_Texture *digitTextures[10];
// Function to reset the game
void resetGame()
{
// Reset player positions
player1_x = 100;
player1_y = SCREEN_HEIGHT - PLAYER_HEIGHT - 90;
player2_x = 1050;
player2_y = SCREEN_HEIGHT - PLAYER_HEIGHT - 90;
// Reset ball position and velocity to the middle of the screen
ball_x = SCREEN_WIDTH / 2 - BALL_SIZE / 2;
ball_y = SCREEN_HEIGHT / 2 - BALL_SIZE / 2;
ball_velocity_x = 3.0;
ball_velocity_y = 1.0;
}
// 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;
}
// Load PNG image and create texture
bool loadGoalPost(SDL_Renderer *renderer, const char *imagePath, SDL_Texture **texture)
{
SDL_Surface *imageSurface = IMG_Load("goalPost.png");
if (imageSurface == NULL)
{
printf("Unable to load PNG image! SDL_Image Error: %s\n", IMG_GetError());
return false;
}
*texture = SDL_CreateTextureFromSurface(renderer, imageSurface);
if (*texture == NULL)
{
printf("Unable to create texture from PNG image! SDL Error: %s\n", SDL_GetError());
return false;
}
SDL_FreeSurface(imageSurface);
return true;
}
// Load fan image and create texture
bool loadFanImage(SDL_Renderer *renderer, const char *imagePath, SDL_Texture **texture)
{
SDL_Surface *imageSurface = IMG_Load("fan.png");
if (imageSurface == NULL)
{
printf("Unable to load PNG image! SDL_Image Error: %s\n", IMG_GetError());
return false;
}
*texture = SDL_CreateTextureFromSurface(renderer, imageSurface);
if (*texture == NULL)
{
printf("Unable to create texture from PNG image! SDL Error: %s\n", SDL_GetError());
return false;
}
SDL_FreeSurface(imageSurface);
return true;
}
// Load ball image and create texture
bool loadBallImage(SDL_Renderer *renderer, const char *imagePath, SDL_Texture **texture)
{
SDL_Surface *imageSurface = IMG_Load("Ball.png");
if (imageSurface == NULL)
{
printf("Unable to load PNG image! SDL_Image Error: %s\n", IMG_GetError());
return false;
}
*texture = SDL_CreateTextureFromSurface(renderer, imageSurface);
if (*texture == NULL)
{
printf("Unable to create texture from PNG image! SDL Error: %s\n", SDL_GetError());
return false;
}
SDL_FreeSurface(imageSurface);
return true;
}
// Load digit images and create textures
bool loadDigitImage(SDL_Renderer *renderer, const char *imagePath, SDL_Texture **texture, int digit)
{
char digitPath[20];
sprintf(digitPath, "number/%d.png", digit);
SDL_Surface *imageSurface = IMG_Load(digitPath);
if (imageSurface == NULL)
{
printf("Unable to load PNG image! SDL_Image Error: %s\n", IMG_GetError());
return false;
}
*texture = SDL_CreateTextureFromSurface(renderer, imageSurface);
if (*texture == NULL)
{
printf("Unable to create texture from PNG image! SDL Error: %s\n", SDL_GetError());
return false;
}
SDL_FreeSurface(imageSurface);
return true;
}
// Load player1 image and create texture
bool loadPlayer1Image(SDL_Renderer *renderer, const char *imagePath, SDL_Texture **texture)
{
SDL_Surface *imageSurface = IMG_Load("player1.png");
if (imageSurface == NULL)
{
printf("Unable to load PNG image! SDL_Image Error: %s\n", IMG_GetError());
return false;
}
*texture = SDL_CreateTextureFromSurface(renderer, imageSurface);
if (*texture == NULL)
{
printf("Unable to create texture from PNG image! SDL Error: %s\n", SDL_GetError());
return false;
}
SDL_FreeSurface(imageSurface);
return true;
}
// Load ball image and create texture
bool loadPlayer2Image(SDL_Renderer *renderer, const char *imagePath, SDL_Texture **texture)
{
SDL_Surface *imageSurface = IMG_Load("player2.png");
if (imageSurface == NULL)
{
printf("Unable to load PNG image! SDL_Image Error: %s\n", IMG_GetError());
return false;
}
*texture = SDL_CreateTextureFromSurface(renderer, imageSurface);
if (*texture == NULL)
{
printf("Unable to create texture from PNG image! SDL Error: %s\n", SDL_GetError());
return false;
}
SDL_FreeSurface(imageSurface);
return true;
}
// Render the score
void renderScore(SDL_Renderer *renderer, SDL_Texture **digitTextures, int score, int x, int y)
{
int tempScore = score;
int numDigits = 0;
// Count the number of digits in the score
do
{
numDigits++;
tempScore /= 10;
} while (tempScore > 0);
// Render the score digits from right to left
tempScore = score;
for (int i = numDigits - 1; i >= 0; i--)
{
int digit = tempScore % 10;
SDL_Rect digitRect = {x + i * DIGIT_WIDTH, y, DIGIT_WIDTH, DIGIT_HEIGHT};
SDL_RenderCopy(renderer, digitTextures[digit], NULL, &digitRect);
tempScore /= 10;
}
}
// Draw the players and background on the screen
void draw(SDL_Renderer *renderer)
{
// Clear the screen
SDL_RenderClear(renderer);
// Draw the background
SDL_RenderCopy(renderer, backgroundTexture, NULL, NULL);
// Draw the fans
SDL_RenderCopy(renderer, fanTexture, NULL, NULL);
// Draw Player 1 score
renderScore(renderer, digitTextures, player1_score, 50, 50);
// Draw Player 2 score
renderScore(renderer, digitTextures, player2_score, SCREEN_WIDTH - 100 - numDigits * DIGIT_WIDTH, 50);
// Draw Player 1 (red rectangle)
SDL_Rect player1Rect = {player1_x, player1_y, PLAYER_WIDTH, PLAYER_HEIGHT};
SDL_RenderCopy(renderer, player1Texture, NULL, &player1Rect);
// Draw Player 2 (blue rectangle)
SDL_Rect player2Rect = {player2_x, player2_y, PLAYER_WIDTH, PLAYER_HEIGHT};
SDL_RenderCopy(renderer, player2Texture, NULL, &player2Rect);
// Draw the ball (yellow circle)
SDL_Rect ballRect = {ball_x, ball_y, BALL_SIZE, BALL_SIZE};
SDL_RenderCopy(renderer, ballTexture, NULL, &ballRect);
// Draw the PNG image (on top of the background)
SDL_RenderCopy(renderer, goalPostTexture, NULL, NULL);
// Update the screen
SDL_RenderPresent(renderer);
}
// Player collisions
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);
}
// Function to handle ball-wall collisions
void handleBallWallCollision()
{
if (ball_x <= 0 || ball_x + BALL_SIZE >= SCREEN_WIDTH)
{
ball_velocity_x = -ball_velocity_x;
}
if (ball_y <= 0) {
ball_velocity_y = -ball_velocity_y;
} else if (ball_y + BALL_SIZE >= SCREEN_HEIGHT) {
if (fabs(ball_velocity_y) < 0.1) {
ball_velocity_y = 0.0;
} else {
ball_velocity_y = -ball_velocity_y * FRICTION;
}
}
}
bool checkBallPlayerCollision(int player_x, int player_y)
{
return (ball_x < player_x + PLAYER_WIDTH &&
ball_x + BALL_SIZE > player_x &&
ball_y < player_y + PLAYER_HEIGHT &&
ball_y + BALL_SIZE > player_y);
}
// Function to handle ball-goal collisions
void handleBallGoalCollision()
{
int ball_center_x = ball_x + BALL_SIZE / 2;
int ball_center_y = ball_y + BALL_SIZE / 2;
// Check if the ball's center crosses the left goal line
if (ball_center_x <= left_goal_x + GOAL_WIDTH && ball_center_y >= left_goal_y && ball_center_y <= left_goal_y + GOAL_HEIGHT)
{
// Ball's center crossed the left goal line, player 2 scores
printf("Player 2 scores!\n");
player2_score += 1;
printf("Player 2: %d\n", player2_score);
resetGame();
}
// Check if the ball's center crosses the right goal line
else if (ball_center_x >= right_goal_x && ball_center_y >= right_goal_y && ball_center_y <= right_goal_y + GOAL_HEIGHT)
{
// Ball's center crossed the right goal line, player 1 scores
printf("Player 1 scores!\n");
player1_score += 1;
printf("Player 1: %d\n", player1_score);
resetGame();
}
}
// Function to update the ball's position and velocity
void updateBallPosition()
{
ball_x += ball_velocity_x;
ball_y += ball_velocity_y;
// Apply gravity
ball_velocity_y += GRAVITY;
// Apply friction
ball_velocity_x *= FRICTION;
ball_velocity_y *= FRICTION;
// Ensure the ball stays above the invisible floor
if (ball_y + BALL_SIZE >= INVISIBLE_FLOOR)
{
ball_y = INVISIBLE_FLOOR - BALL_SIZE;
// Decrease the velocity over time to simulate slowing down
ball_velocity_x += 0.02;
ball_velocity_y -= 0.01;
// Check if the ball's velocity is very small or zero
if (fabs(ball_velocity_x) < 0.01 && fabs(ball_velocity_y) < 0.01)
{
ball_velocity_x = 0.0;
ball_velocity_y = 0.0;
}
}
}
int main(int argc, char *argv[])
{
printf("Welcome to Head Soccer!\n");
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
if (!init(&window, &renderer))
{
return 1;
}
if (!loadBackground(renderer))
{
return 1;
}
if (!loadBallImage(renderer, "Ball.png", &ballTexture))
{
return 1;
}
if (!loadGoalPost(renderer, "goalPost.png", &goalPostTexture))
{
return 1;
}
if (!loadFanImage(renderer, "fan.png", &fanTexture))
{
return 1;
}
if (!loadPlayer1Image(renderer, "player1.png", &player1Texture))
{
return 1;
}
if (!loadPlayer2Image(renderer, "player2.png", &player2Texture))
{
return 1;
}
for (int i = 0; i < 10; i++)
{
char digitPath[20];
sprintf(digitPath, "number/%d.png", i);
if (!loadDigitImage(renderer, digitPath, &digitTextures[i], i))
{
return 1;
}
}
bool quit = false;
SDL_Event e;
while (!quit)
{
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--;
}
}
}
}
if (player1_jumping)
{
player1_y += player1_velocity_y;
player1_velocity_y += 1;
// Ensure player 1 stays above the invisible floor
if (player1_y >= INVISIBLE_FLOOR - PLAYER_HEIGHT)
{
player1_y = INVISIBLE_FLOOR - PLAYER_HEIGHT;
player1_jumping = false;
player1_remaining_jumps = 2;
}
}
if (player2_jumping)
{
player2_y += player2_velocity_y;
player2_velocity_y += 1;
// Ensure player 2 stays above the invisible floor
if (player2_y >= INVISIBLE_FLOOR - PLAYER_HEIGHT)
{
player2_y = INVISIBLE_FLOOR - PLAYER_HEIGHT;
player2_jumping = false;
player2_remaining_jumps = 2;
}
}
const Uint8 *currentKeyStates = SDL_GetKeyboardState(NULL);
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
{
// resetGame;
if (currentKeyStates[SDL_SCANCODE_ESCAPE])
{
if (currentKeyStates[SDL_SCANCODE_R])
{
resetGame();
}
}
// 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;
}
}
if (checkBallPlayerCollision(player1_x, player1_y) && checkBallPlayerCollision(player2_x, player2_y))
{
ball_velocity_y = -ball_velocity_y;
ball_y += ball_velocity_y;
} else {
// Check for collision with Player 1
if (checkBallPlayerCollision(player1_x, player1_y))
{
// Calculate the direction of the collision
int collisionDirection = (ball_x + BALL_SIZE / 2) - (player1_x + PLAYER_WIDTH / 2);
// Adjust the ball's velocity based on the collision direction
ball_velocity_x = collisionDirection / 5.0; // Use double for smoother adjustment
// Move the ball slightly away from the player to avoid getting stuck
ball_x += ball_velocity_x * 2.0; // Use double for smoother adjustment
}
// Check for collision with Player 2
if (checkBallPlayerCollision(player2_x, player2_y))
{
// Calculate the direction of the collision
int collisionDirection = (ball_x + BALL_SIZE / 2) - (player2_x + PLAYER_WIDTH / 2);
// Adjust the ball's velocity based on the collision direction
ball_velocity_x = collisionDirection / 5.0; // Use double for smoother adjustment
// Move the ball slightly away from the player to avoid getting stuck
ball_x += ball_velocity_x * 2.0; // Use double for smoother adjustment
}
// Player 1 kick
if (e.key.keysym.sym == SDLK_s)
{
if (checkBallPlayerCollision(player1_x + 30, player1_y))
{
int collisionDirection = (ball_x + BALL_SIZE / 2) - (player1_x + PLAYER_WIDTH / 2);
ball_velocity_x = collisionDirection / 5.0;
ball_x += ball_velocity_x * 5.0;
printf("p1 kick %f -> ", ball_velocity_y);
ball_velocity_y = -ball_velocity_y*2;
ball_y += ball_velocity_y*2;
printf("%f\n", ball_velocity_y);
}
}
// Player 2 kick
if (e.key.keysym.sym == SDLK_DOWN)
{
if (checkBallPlayerCollision(player2_x - 30, player2_y))
{
int collisionDirection = (ball_x + BALL_SIZE / 2) - (player2_x + PLAYER_WIDTH / 2);
ball_velocity_x = collisionDirection / 5.0;
ball_x += ball_velocity_x * 5.0;
printf("p2 kick %f -> ", ball_velocity_y);
ball_velocity_y = -ball_velocity_y*2;
ball_y += ball_velocity_y*2;
printf("%f\n", ball_velocity_y);
}
}
}
// Handle ball-goal collisions
handleBallGoalCollision();
// Handle ball-wall collisions
handleBallWallCollision();
// Update the ball's position
updateBallPosition();
draw(renderer);
}
// Cleanup and exit
SDL_DestroyTexture(backgroundTexture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}