about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorCharadon <dev@iotib.net>2022-05-30 21:07:45 -0400
committerCharadon <dev@iotib.net>2022-05-30 21:07:45 -0400
commitb1de6008bdfbd5bdeb62d2d3dad953019555556b (patch)
treef3ec65de21ef7294f53b0114616ccaca04bb4415
downloadPong-C-b1de6008bdfbd5bdeb62d2d3dad953019555556b.tar.gz
Initial Commit
-rw-r--r--Makefile25
-rw-r--r--net.iotib.Pong.yml20
-rw-r--r--resources/ball.pngbin0 -> 120 bytes
-rw-r--r--resources/bounce.wavbin0 -> 417592 bytes
-rw-r--r--resources/defeat.wavbin0 -> 488992 bytes
-rw-r--r--resources/paddle.pngbin0 -> 586 bytes
-rw-r--r--resources/title.wavbin0 -> 11835216 bytes
-rw-r--r--resources/victory.wavbin0 -> 521000 bytes
-rw-r--r--src/ball.c68
-rw-r--r--src/enemy.c37
-rw-r--r--src/main.c218
-rw-r--r--src/pong.h49
-rw-r--r--src/sounds.h10
-rw-r--r--src/title.c72
14 files changed, 499 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..153d346
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,25 @@
+CC := gcc
+CFLAGS = -Og -Wall -std=c11 -Isrc/
+LDFLAGS = 
+PKG_CONF := pkg-config
+PKG_CONF_ARGS = --exists --modversion
+PKG_CONF_LDFLAGS = `pkgconf --libs raylib`
+PKG_CONF_CFLAGS = `pkgconf --cflags raylib`
+
+all: check_deps build pong
+	
+
+check_deps:
+	@echo "Checking for dependencies..."
+	@printf "Raylib | "
+	@$(PKG_CONF) $(PKG_CONF_ARGS) raylib
+
+build: src/main.c src/enemy.c src/ball.c src/title.c
+	$(CC) $(CFLAGS) $(PKG_CONF_CFLAGS) -c $?
+
+pong: main.o enemy.o ball.o title.o
+	$(CC) $? -o $@ $(LDFLAGS) $(PKG_CONF_LDFLAGS) -lGL -lm -lpthread -ldl -lrt -lX11
+	
+clean:
+	rm -fv *.o
+	rm -fv pong
diff --git a/net.iotib.Pong.yml b/net.iotib.Pong.yml
new file mode 100644
index 0000000..49d10bd
--- /dev/null
+++ b/net.iotib.Pong.yml
@@ -0,0 +1,20 @@
+app-id: net.iotib.Pong
+runtime: org.freedesktop.Platform
+runtime-version: '21.08'
+sdk: org.freedesktop.Sdk
+command: /app/Pong/Pong
+modules:
+  - name: Pong
+    buildsystem: simple
+    build-commands:
+      - make
+      - mkdir -p /app/Pong
+      - cp -r resources /app/Pong
+      - install -Dm755 Pong /app/Pong/Pong
+    sources:
+      - type: file
+        path: Makefile
+      - type: dir
+        path: src/
+      - type: dir
+        path: resources/
\ No newline at end of file
diff --git a/resources/ball.png b/resources/ball.png
new file mode 100644
index 0000000..cba7f00
--- /dev/null
+++ b/resources/ball.png
Binary files differdiff --git a/resources/bounce.wav b/resources/bounce.wav
new file mode 100644
index 0000000..6b3e7fc
--- /dev/null
+++ b/resources/bounce.wav
Binary files differdiff --git a/resources/defeat.wav b/resources/defeat.wav
new file mode 100644
index 0000000..010707d
--- /dev/null
+++ b/resources/defeat.wav
Binary files differdiff --git a/resources/paddle.png b/resources/paddle.png
new file mode 100644
index 0000000..c27108b
--- /dev/null
+++ b/resources/paddle.png
Binary files differdiff --git a/resources/title.wav b/resources/title.wav
new file mode 100644
index 0000000..5641e18
--- /dev/null
+++ b/resources/title.wav
Binary files differdiff --git a/resources/victory.wav b/resources/victory.wav
new file mode 100644
index 0000000..7ac4dfa
--- /dev/null
+++ b/resources/victory.wav
Binary files differdiff --git a/src/ball.c b/src/ball.c
new file mode 100644
index 0000000..7a9e7cb
--- /dev/null
+++ b/src/ball.c
@@ -0,0 +1,68 @@
+#include "raylib.h"
+#include "pong.h"
+
+void ball(Rectangle *Player, Rectangle *Enemy, struct Balls *Ball, int *PlayerScore, int *EnemyScore) {
+	
+	// Moves ball
+	Ball->Y += Ball->Angle;
+	if (Ball->Direction == LEFT) {
+		Ball->X -= Ball->Speed;
+	} else {
+		Ball->X += Ball->Speed;
+	}
+	// Moves hitbox with ball.
+	Ball->HitBox.x = Ball->X;
+	Ball->HitBox.y = Ball->Y;
+
+	// Check collisions against players.
+	if (CheckCollisionRecs(*Player, Ball->HitBox) && Ball->Direction == LEFT) {
+		Ball->Direction = RIGHT;
+		Ball->Speed *= 1.5f;
+        if (Ball->Speed > 40) {
+            Ball->Speed = 40;
+        }
+        if (Ball->Speed != 40) {
+		    Ball->Angle = GetRandomValue(-10, 10);
+        } else {
+            Ball->Angle = GetRandomValue(-20, 20);
+        }
+        play_audio(0);
+	}
+	if (CheckCollisionRecs(*Enemy, Ball->HitBox) && Ball->Direction == RIGHT) {
+		Ball->Direction = LEFT;
+		Ball->Speed *= 1.5f;
+       	if (Ball->Speed > 40) {
+	    	Ball->Speed = 40;
+	    }
+		if (Ball->Speed != 40) {
+		    Ball->Angle = GetRandomValue(-10, 10);
+        } else {
+            Ball->Angle = GetRandomValue(-30, 30);
+        }
+        play_audio(SOUND_BOUNCE);
+	}
+	
+	// Bounce ball if touches top or bottom of screen.
+	if ( (Ball->Y+32 >= 720 && Ball->Angle >=1) || (Ball->Y <= 0 && Ball->Angle <= -1) ) {
+		Ball->Angle *= -1;
+        play_audio(SOUND_BOUNCE);
+	}
+
+	// Calculates score and resets ball.
+	bool Scored = false;
+	if (Ball->X < 0) {
+		*EnemyScore += 1;
+		Scored = true;
+	} else if (Ball ->X > 1280) {
+		*PlayerScore += 1;
+		Scored = true;
+	}
+	if (Scored == true) {
+		Ball->X = 1280/2.0f;
+		Ball->Y = 720/2.0f;
+		Ball->Speed = 3.0f;
+		Ball->Angle = 0;
+	}
+
+	return;
+}
\ No newline at end of file
diff --git a/src/enemy.c b/src/enemy.c
new file mode 100644
index 0000000..e5e0a2b
--- /dev/null
+++ b/src/enemy.c
@@ -0,0 +1,37 @@
+#include "raylib.h"
+#include "pong.h"
+
+void enemy(struct Players *Enemy, struct Balls ball) {
+	if (atomic_load(&Ticks) % 1 == 0) {
+		if (!CheckCollisionRecs(ball.HitBox, Enemy->BallDetector)) {
+			if (Enemy->Y+120 > ball.Y) {
+				Enemy->Direction = 0;
+			} else if (Enemy->Y < ball.Y) {
+				Enemy->Direction = 1;
+			}
+		} else {
+			Enemy->Direction = 3;
+		}
+	}
+
+	switch(Enemy->Direction) {
+		case 0:
+			Enemy->Y -= 15;
+			break;
+		case 1:
+			Enemy->Y += 15;
+			break;
+		default:
+			break;
+	}
+
+	// Prevents from going off screen.
+	if ( Enemy->Y > 480 ) {
+		Enemy->Y = 480;
+	} else if (Enemy->Y < 0) {
+		Enemy->Y = 0;
+	}
+	Enemy->HitBox.y = Enemy->Y;
+	Enemy->BallDetector.y = Enemy->Y+80;
+	return;
+}
\ No newline at end of file
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..d4120e8
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,218 @@
+#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);
+}
diff --git a/src/pong.h b/src/pong.h
new file mode 100644
index 0000000..ab74d07
--- /dev/null
+++ b/src/pong.h
@@ -0,0 +1,49 @@
+#ifndef PONG_H
+#define PONG_H
+#include "raylib.h"
+#include <stdatomic.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdatomic.h>
+#include <threads.h>
+#include <setjmp.h>
+
+#define LEFT 0
+#define RIGHT 1
+
+struct Players {
+	float Y;
+	Rectangle HitBox;
+	int Score;
+	int Direction;
+	Rectangle BallDetector;
+};
+
+struct Balls {
+	float X;
+	float Y;
+	float Angle;
+	float Speed;
+	int Direction;
+	Rectangle HitBox;
+};
+
+extern int Difficulty;
+extern bool GameGoing;
+extern atomic_int Ticks;
+
+void enemy(struct Players *Enemy, struct Balls ball);
+void ball(Rectangle *Player, Rectangle *Enemy, struct Balls *Ball, int *PlayerScore, int *EnemyScore);
+bool play_audio(int SoundEffect);
+void title_screen();
+
+//Sounds
+extern const int SOUND_BOUNCE;
+extern const int MUSIC_DEFEAT;
+extern const int MUSIC_VICTORY;
+extern const int MUSIC_TITLE;
+extern const int STOP_ALL_SOUNDS;
+
+#endif
\ No newline at end of file
diff --git a/src/sounds.h b/src/sounds.h
new file mode 100644
index 0000000..75a2455
--- /dev/null
+++ b/src/sounds.h
@@ -0,0 +1,10 @@
+#ifndef SOUNDS_H
+#define SOUNDS_H
+
+const int SOUND_BOUNCE = 0;
+const int MUSIC_DEFEAT = 1;
+const int MUSIC_VICTORY = 2;
+const int MUSIC_TITLE = 3;
+const int STOP_ALL_SOUNDS = 99;
+
+#endif
\ No newline at end of file
diff --git a/src/title.c b/src/title.c
new file mode 100644
index 0000000..fd57c2e
--- /dev/null
+++ b/src/title.c
@@ -0,0 +1,72 @@
+#include "pong.h"
+
+void help_text() {
+
+}
+
+void title_screen() {
+    Camera2D MainCamera;
+    MainCamera.offset = (Vector2){0,0};
+    MainCamera.target = (Vector2){0,0};
+    MainCamera.rotation = 0.0f;
+    bool TitleScreenGoing = true;
+    play_audio(MUSIC_TITLE);
+    Rectangle Versus = {
+        20, 150, 230, 48
+    };
+    Rectangle Marathon = {
+        20, 200, 230, 48
+    };
+    Rectangle Settings = {
+        20, 250, 230, 48
+    };
+    Rectangle Help = {
+        20, 300, 230, 48
+    };
+    Rectangle Exit = {
+        20, 350, 230, 48
+    };
+    Rectangle Mouse = {
+        0, 0, 10, 10
+    };
+    Rectangle *Selected;
+    Selected = &Versus;
+    while(!WindowShouldClose() && TitleScreenGoing == true) {
+        MainCamera.zoom = GetScreenHeight()/720.0f;
+        Mouse.x = GetMouseX()/MainCamera.zoom;
+        Mouse.y = GetMouseY()/MainCamera.zoom;
+        if (CheckCollisionRecs(Mouse, Versus)) {
+            Selected = &Versus;
+            if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
+                return;
+            }
+        } else if (CheckCollisionRecs(Mouse, Marathon)) {
+            Selected = &Marathon;
+        } else if (CheckCollisionRecs(Mouse, Settings)) {
+            Selected = &Settings;
+        } else if (CheckCollisionRecs(Mouse, Help)) {
+            Selected = &Help;
+        } else if (CheckCollisionRecs(Mouse, Exit)) {
+            Selected = &Exit;
+            if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
+                GameGoing = false;
+                return;
+            }
+        }
+        MainCamera.zoom = GetScreenHeight()/720.0f;
+        BeginDrawing();
+            ClearBackground(BLACK);
+            BeginMode2D(MainCamera);
+                DrawRectangleRec(*Selected, RED);
+                DrawText("PONG", 0, 0, 128, WHITE);
+                DrawText("Versus", 20, 150, 48, WHITE);
+                DrawText("Marathon", 20, 200, 48, WHITE);
+                DrawText("Settings", 20, 250, 48, WHITE);
+                DrawText("Help", 20, 300, 48, WHITE);
+                DrawText("Exit", 20, 350, 48, WHITE);
+                DrawRectangleRec(Mouse, YELLOW);
+            EndMode2D();
+        EndDrawing();
+    }
+    return;
+}
\ No newline at end of file