summary refs log blame commit diff stats
path: root/src/main.c
blob: d4120e843a7bba881756eb2a722b01d7d048fe44 (plain) (tree)

























































































































































































































                                                                                                                         
#include "pong.h"
#include "sounds.h"
#include <setjmp.h>


int Difficulty = 1;
atomic_int Ticks = 0;
bool GameGoing = true;

mtx_t AudioQueueBeingModified;

int AudioQueue[20];

int internal_clock() {
	const struct timespec Delay = {
		0, 20000000
	};
	struct timespec Remaining;
	while(GameGoing == true) {
		atomic_fetch_add(&Ticks, 1);
		thrd_sleep(&Delay, &Remaining);
	}
	thrd_exit(0);
}

int audio() {
	int i;
	InitAudioDevice();
	Sound Bounce = LoadSound("resources/bounce.wav");
	Sound TitleScreen = LoadSound("resources/title.wav");
	Sound Victory = LoadSound("resources/victory.wav");
	Sound Defeat = LoadSound("resources/defeat.wav");
	const struct timespec Delay = {
		0, 20000000
	};
	struct timespec Remaining;
	while(GameGoing == true) {
		for(i = 0; i < 20; i++) {
			if(AudioQueue[i] != -1){
				switch(AudioQueue[i]) {
					case 0: //Play bounce sound.
						PlaySoundMulti(Bounce);
						break;
					case 1: //Play game over
						PlaySoundMulti(Defeat);
						break;
					case 2: //Play win
						PlaySoundMulti(Victory);
						break;
					case 3: //Title Screen
						PlaySoundMulti(TitleScreen);
						break;
					case 99: //Stop All Sounds
						StopSoundMulti();
						break;
					default:
						break;
				}
				while(mtx_trylock(&AudioQueueBeingModified) == thrd_busy) thrd_sleep(&Delay, &Remaining);
				AudioQueue[i] = -1;
				mtx_unlock(&AudioQueueBeingModified);
			}
		}
		thrd_sleep(&Delay, &Remaining);
	}
	thrd_exit(0);
}

bool play_audio(int SoundEffect) {
	int i;
	while(mtx_trylock(&AudioQueueBeingModified) == thrd_busy);
	for(i = 1; i != 20; i++) {
		if (AudioQueue[i-1] == -1) {
			AudioQueue[i-1] = AudioQueue[i];
		}
	}
	for(i = 0; AudioQueue[i] != -1; i++) {
		if(i > sizeof(AudioQueue)) {
			mtx_unlock(&AudioQueueBeingModified);
			return false;
		}
	}
	AudioQueue[i] = SoundEffect;
	mtx_unlock(&AudioQueueBeingModified);
	return true;
}

int main() {
	//Raylib Init
	InitWindow(1280, 720, "Pong");
	SetTargetFPS(60);
	SetExitKey(KEY_Q);
	Image Icon = LoadImage("resources/ball.png");
	SetWindowIcon(Icon);
	SetWindowState(FLAG_VSYNC_HINT);
	SetWindowState(FLAG_WINDOW_RESIZABLE);
	
	//Initialize Variables
	Camera2D MainCamera;
	MainCamera.target = (Vector2){0, 0};
	MainCamera.offset = (Vector2){0, 0};
	MainCamera.rotation = 0;
	//Populate Audio Queue
	for(int i = 0; i < sizeof(AudioQueue); i++) {
		AudioQueue[i] = -1;
		printf("%d\n", AudioQueue[i]);
	}
	mtx_init(&AudioQueueBeingModified, mtx_plain);

	// Init Player Variables
	struct Players Player;
	Player.Score = 0;
	char PlayerScore[50]; // Used later to display score on screen.

	// Init Enemy Variables
	struct Players Enemy;
	Enemy.Score = 0;
	Enemy.Direction = 0;
	char EnemyScore[50];

	struct Balls Ball;
	Ball.X = 1280/2.0f;
	Ball.Y = 720/2.0f;
	Ball.Direction = LEFT;
	Ball.Speed = 3.0f;
	Ball.Angle = 0.0f;
	
	
	// Set Sprites
	Texture2D PaddleSprite = LoadTexture("resources/paddle.png");
	Texture2D BallSprite = LoadTexture("resources/ball.png");
	
	// Set Collision Boxes
	Player.HitBox = (Rectangle){80, Player.Y, 5, PaddleSprite.height};
	Enemy.HitBox = (Rectangle){1200, Enemy.Y, 5, PaddleSprite.height};
	Ball.HitBox = (Rectangle){Ball.X, Ball.Y, BallSprite.width, BallSprite.height};
	Enemy.BallDetector = (Rectangle){0, Enemy.Y+120, 1280, PaddleSprite.height/5.0f};

	// Debug
	Player.Y = 200;

	// Initialize Internal Clock
	thrd_t InternalClock;
	thrd_create(&InternalClock, internal_clock, NULL);
	thrd_t AudioThread;
	thrd_create(&AudioThread, audio, NULL);
	
	// Launch Title Screen
	jmp_buf RestartGame;
	setjmp(RestartGame);
	title_screen();
	play_audio(99);
	Enemy.Score = 0;
	Player.Score = 0;
	
	while(!WindowShouldClose() && GameGoing == true) {
		MainCamera.zoom = GetScreenHeight()/720.0f;
		if (Enemy.Score >= 5) {
			play_audio(MUSIC_DEFEAT);
			longjmp(RestartGame, 0);
		} else if (Player.Score >= 5) {
			play_audio(MUSIC_VICTORY);
			longjmp(RestartGame, 0);
		}
		//Controls
		if(IsKeyDown(KEY_UP)) {
			Player.Y -= 10;
		} else if (IsKeyDown(KEY_DOWN)) {
			Player.Y += 10;
		} else if(IsKeyPressed(KEY_ESCAPE)) {
			EnableCursor();
		} else if(IsMouseButtonPressed(MOUSE_BUTTON_LEFT) || IsCursorHidden() == true) {
			Player.Y = GetMouseY()-PaddleSprite.height/2.0f;
			DisableCursor();
		}
		
		if(GetMouseY() < 0) {
			SetMousePosition(0, 0);
		} else if(GetMouseY() > 720) {
			SetMousePosition(0, 720);
		}

		//Check if players are off-screen
		if (Player.Y < 0) {
			Player.Y = 0;
		} else if (Player.Y > 480) {
			Player.Y = 480;
		}

		enemy(&Enemy, Ball);
		
		// Collision
		ball(&Player.HitBox, &Enemy.HitBox, &Ball, &Player.Score, &Enemy.Score);

		//Updates hitbox with player's position.
		Player.HitBox.y = Player.Y;

		//Turn Scores into strings.
		snprintf(PlayerScore, 50, "Player: %d", Player.Score);
		snprintf(EnemyScore, 50, "Enemy: %d", Enemy.Score);
		
		BeginDrawing();
			ClearBackground(BLACK);
			BeginMode2D(MainCamera);
				DrawTexture(PaddleSprite, 0, Player.Y, WHITE);
				DrawTexture(PaddleSprite, 1200, Enemy.Y, WHITE);
				DrawTexture(BallSprite, Ball.X, Ball.Y, WHITE);
				//DrawRectangleRec(Enemy.BallDetector, RED);
				DrawText(PlayerScore, 0, 0, 32, GREEN);
				DrawText(EnemyScore, 1130, 688, 32, RED);
			EndMode2D();
		EndDrawing();
	}
	GameGoing = false;
	thrd_join(AudioThread, NULL);
	CloseWindow();
	return(0);
}