Compare commits

...

63 Commits

Author SHA1 Message Date
Félix MARQUET
52a6e9bdf3 Update README.md 2025-01-05 18:35:22 +01:00
Félix MARQUET
909f075695 Merge pull request #35 from BreizhHardware/fix-patch-535414755
fix: update player sprite timing and tick threshold
2024-12-19 15:57:08 +01:00
StevSpotted
3033f56820 fix: update player sprite timing and tick threshold 2024-12-19 15:55:42 +01:00
565dd66b02 Fix player speed 2024-12-19 13:49:10 +01:00
b72aceb55f Fix player speed 2024-12-19 13:46:23 +01:00
933fa18cc6 hvbjabfa 2024-12-19 12:38:42 +01:00
4bbeedbb77 fix: corriger la configuration de release-drafter.yml
- Correction du type de `version-resolver` pour être un objet.
- Ajout de la propriété `default` dans `version-resolver`.
2024-12-18 16:11:48 +01:00
7071624bbd fix: corriger la configuration de release-drafter.yml
- Correction du type de `version-resolver` pour être un objet.
- Ajout de la propriété `template` requise.
2024-12-18 16:09:23 +01:00
Félix MARQUET
9f872f42f7 Merge pull request #34 from BreizhHardware/Refactor
Refactor
2024-12-18 16:05:23 +01:00
7cf0253d30 fix: corriger les noms de fichiers dans CMakeLists.txt
- Renommage de `LaunchGameSolo.cpp` en `launchGameSolo.cpp`.
- Renommage de `LaunchGameSolo.h` en `launchGameSolo.h`.
- Renommage de `LaunchGameMulti.cpp` en `launchGameMulti.cpp`.
- Renommage de `LaunchGameMulti.h` en `launchGameMulti.h`.
2024-12-18 16:03:58 +01:00
cfc15cdb2c docs: mise à jour du README.md
- Ajout de la description du projet.
- Ajout des branches en développement.
- Ajout des instructions d'installation et de configuration.
- Mise à jour de la section To do.
2024-12-18 16:00:52 +01:00
StevSpotted
c2d786c151 feat: add Music and MusicManager classes for enhanced audio handling 2024-12-18 15:56:52 +01:00
StevSpotted
2ea9c91cf1 feat: integrate MusicManager for improved audio handling and remove legacy music code 2024-12-18 15:56:39 +01:00
38dbf78a7c fix: renommer LaunchGameMulti et LaunchGameSolo
- Renommage de `LaunchGameMulti` en `launchGameMulti`.
- Renommage de `LaunchGameSolo` en `launchGameSingle`.
2024-12-18 15:53:30 +01:00
75e44df256 feat: ajouter la génération automatique des notes de release
- Ajout de l'action `release-drafter/release-drafter` pour générer automatiquement les notes de release basées sur les messages de commit conventionnels.
- Mise à jour du workflow `release.yaml` pour inclure l'étape de génération des notes de release.
- Création du fichier de configuration `release-drafter.yml` pour définir les catégories et le modèle de notes de release.
2024-12-18 15:34:59 +01:00
1343fe01e7 fix: corrige la visibilité des autres joueurs en multijoueur
- Ajout de la méthode `getPlayerId` const dans `player.cpp` et `player.h`.
- Ajout de la fonction `receivePlayerListFromServer` et `addPlayerToGame` dans `networking_client.cpp` et `networking_client.h`.
- Correction de la fonction `sendPlayerListToNewClient` et `getAllPlayers` dans `networking.cpp` et `networking.h`.
- Ajout de l'affichage des joueurs proches en mode multijoueur dans `utility.cpp` et `utility.h`.
2024-12-18 15:31:51 +01:00
7d11ece61b feat: ajout d'une fonctionnalité pour basculer l'affichage du FPS avec la touche F2
- Ajout d'une variable `std::atomic<bool> displayFPSFlag` pour suivre l'état d'affichage du FPS
- Modification de la gestion des événements pour basculer `displayFPSFlag` lorsque la touche F2 est pressée
- Mise à jour de la fonction `renderScene` pour afficher le FPS uniquement si `displayFPSFlag` est vrai
2024-12-18 14:46:59 +01:00
5ca2cae04e fix: suppression des sorties de débogage pour accélérer le lancement du jeu
- Suppression des `std::cout` inutiles lors de la création des poissons
2024-12-18 14:39:58 +01:00
d5658422f9 refactor: déplacer les fichiers de lancement et de déplacement des éléments de jeu dans le dossier Game
- Déplacement des fichiers de lancement du jeu et de déplacement des éléments de jeu dans le dossier `Game`
- Ajustement des appels de fonctions en conséquence
2024-12-18 14:35:41 +01:00
Clément Fouché
23db970f42 refactor: réorganiser les fichiers et mettre à jour les chemins d'inclusion
- Déplacer `fish.h` et `fish.cpp` vers le dossier `Entities`
- Déplacer `player.h` et `player.cpp` vers le dossier `Entities`
- Déplacer `shark.h` et `shark.cpp` vers le dossier `Entities`
- Mettre à jour les chemins d'inclusion dans les fichiers concernés
- Mettre à jour `CMakeLists.txt` pour refléter les nouveaux chemins des fichiers
2024-12-18 14:15:50 +01:00
23f88b2a50 fix: correction des avertissements de compilation liés à l'utilisation incorrecte de empty()
- Remplacement des appels à `empty()` par `clear()` pour les vecteurs `players`, `players_server` et `school`
- Ajout de l'inclusion de `player.h` dans `env.cpp` pour résoudre les erreurs de compilation
2024-12-18 14:14:09 +01:00
Clément Fouché
e42e4061b4 refactor: réorganiser les fichiers et mettre à jour les chemins d'inclusion
- Déplacer `fish.h` et `fish.cpp` vers le dossier `Entities`
- Déplacer `player.h` et `player.cpp` vers le dossier `Entities`
- Déplacer `shark.h` et `shark.cpp` vers le dossier `Entities`
- Mettre à jour les chemins d'inclusion dans les fichiers concernés
- Mettre à jour `CMakeLists.txt` pour refléter les nouveaux chemins des fichiers
2024-12-18 14:14:03 +01:00
Clément Fouché
439c338380 Merge remote-tracking branch 'origin/Refactor' into Refactor 2024-12-18 14:08:21 +01:00
096d1f0aa2 refactor: correction des erreurs de définition multiple et de référence indéfinie
- Définition des variables `mtx` et `threadInfos` dans `utility.cpp`
- Déclaration des variables `mtx` et `threadInfos` comme `extern` dans `utility.h`
- Définition de la variable `fishTextures` dans `env.cpp`
- Correction de l'utilisation de `school.empty()` en `school.clear()` dans `main.cpp`
2024-12-18 14:08:03 +01:00
Clément Fouché
ca20c3e1bd Merge remote-tracking branch 'origin/Refactor' into Refactor
# Conflicts:
#	CMakeLists.txt
#	Entities/fish.h
#	Entities/shark.h
2024-12-18 14:07:53 +01:00
Clément Fouché
f0b0334ff8 refactor: réorganiser les fichiers et mettre à jour les chemins d'inclusion
- Déplacer `fish.h` et `fish.cpp` vers le dossier `Entities`
- Déplacer `player.h` et `player.cpp` vers le dossier `Entities`
- Déplacer `shark.h` et `shark.cpp` vers le dossier `Entities`
- Mettre à jour les chemins d'inclusion dans les fichiers concernés
- Mettre à jour `CMakeLists.txt` pour refléter les nouveaux chemins des fichiers
2024-12-18 14:06:10 +01:00
dec3ab3aff refactor: réorganisation du code et des fichiers
- Déplacement des fichiers `networking.cpp`, `networking.h`, `networking_client.h` vers le répertoire `Network`
- Mise à jour des inclusions de fichiers pour refléter les nouveaux chemins
- Ajout des nouvelles fonctions `handleQuitThread`, `handleQuit`, `cleanup` dans `close.cpp`
- Mise à jour de `CMakeLists.txt` pour inclure les nouveaux chemins des fichiers
- Mise à jour de `main.cpp` pour inclure les nouveaux chemins des fichiers
- Ajout de la gestion des threads pour les poissons, les joueurs et le requin
- Ajout de la gestion des événements de menu et de la musique de fond
2024-12-18 14:01:41 +01:00
1845c2f1c9 refactor: réorganisation du code et des fichiers
- Déplacement des fichiers `env.cpp`, `env.h`, `display.cpp`, `display.h`, `event.h` vers le répertoire `Utility`
- Ajout des nouvelles fonctions `handleQuitThread`, `handleQuit`, `cleanup` dans `close.cpp`
- Mise à jour de `CMakeLists.txt` pour inclure les nouveaux chemins des fichiers
- Mise à jour de `main.cpp` pour inclure les nouveaux chemins des fichiers
- Ajout de la gestion des threads pour les poissons, les joueurs et le requin
- Ajout de la gestion des événements de menu et de la musique de fond
2024-12-18 13:57:59 +01:00
44bff8bbd8 docs(Mise à jour du Readme): Mise à jour du Readme
Ajout du refactor dans le readme
2024-12-18 13:41:24 +01:00
Félix MARQUET
44943caaa1 Merge pull request #33 from BreizhHardware/new_menu
New menu
2024-12-16 15:03:38 +01:00
9f0ae6ac54 Fix sound not working properly 2024-12-16 13:58:42 +01:00
294d7503ed Add first music 2024-12-16 13:50:19 +01:00
bec39bbe3d Add mute when pressing M 2024-12-13 10:12:33 +01:00
Félix MARQUET
6691c70d43 Update README.md 2024-12-12 17:37:59 +01:00
Félix MARQUET
f7bb656436 Merge pull request #32 from BreizhHardware/new_menu
New menu
2024-12-12 17:36:43 +01:00
82802cd33f Add lost vfx 2024-12-12 17:32:14 +01:00
StevSpotted
beeb5fd187 add return to menu and reset player env 2024-12-12 17:18:25 +01:00
Félix MARQUET
558e2d9b36 Merge pull request #31 from BreizhHardware/fix-ci
release mode
2024-12-12 17:17:57 +01:00
Clément Fouché
46ca27705e release mode 2024-12-12 17:17:10 +01:00
Félix MARQUET
742830def8 Merge pull request #30 from BreizhHardware/fix-ci
fix name
2024-12-12 17:10:36 +01:00
Clément Fouché
3cc095454e fix name 2024-12-12 17:09:44 +01:00
Félix MARQUET
d12e6fbe60 Merge pull request #29 from BreizhHardware/fix-ci
fix env var
2024-12-12 17:06:24 +01:00
Clément Fouché
fd1e4b9ba2 fix env var 2024-12-12 17:05:52 +01:00
Félix MARQUET
3267ddb97f Merge pull request #28 from BreizhHardware/new_menu
New menu
2024-12-12 17:00:34 +01:00
Félix MARQUET
1ebf2b2fdf Merge pull request #27 from BreizhHardware/fix-ci
add auto tag
2024-12-12 17:00:16 +01:00
dd2c5c00c7 New menu 2024-12-12 16:59:51 +01:00
Clément Fouché
4f199389f0 add auto tag 2024-12-12 16:58:26 +01:00
Félix MARQUET
40b70d6ce6 Merge pull request #26 from BreizhHardware/fix-ci
fix ci
2024-12-12 16:52:03 +01:00
Clément Fouché
b9e8b32765 fix ci 2024-12-12 16:49:25 +01:00
StevSpotted
037a05b106 add rounded and gradient 2024-12-12 16:46:09 +01:00
23a54cc9d5 Fix CI release.yaml 2024-12-12 16:44:31 +01:00
Félix MARQUET
fd070bb30f Merge pull request #25 from BreizhHardware/ci
add release ci
2024-12-12 16:42:46 +01:00
Clément Fouché
d691c6af62 add release ci 2024-12-12 16:40:10 +01:00
797e148f22 Able to quit when in the menu 2024-12-12 16:38:31 +01:00
Clément Fouché
081272f64f add release ci 2024-12-12 16:36:23 +01:00
StevSpotted
03737d9c3c s 2024-12-12 16:28:20 +01:00
cf93e05955 V1.1 of new menu 2024-12-12 16:20:46 +01:00
Félix MARQUET
4fddc26d91 Merge pull request #24 from BreizhHardware/main
Main into new_menu
2024-12-12 16:00:54 +01:00
Félix MARQUET
cea9007684 Merge pull request #23 from BreizhHardware/Random-spawn
Fix multiplayer crash and remove debug display
2024-12-12 16:00:20 +01:00
566e066bdc Add proper icon and menu 2024-12-12 15:51:19 +01:00
Félix MARQUET
682963e886 Merge pull request #22 from BreizhHardware/main
Main into new_menu
2024-12-12 15:28:07 +01:00
7d1ca2196b Add new logo 2024-12-12 15:27:00 +01:00
StevSpotted
cbcc468fad Merge pull request #17 from BreizhHardware/main
Add video background
2024-12-12 09:52:30 +01:00
54 changed files with 1866 additions and 896 deletions

30
.github/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name-template: 'Release ${{ nextReleaseVersion }}'
tag-template: 'v${{ nextReleaseVersion }}'
categories:
- title: '🚀 Features'
labels:
- 'feat'
- title: '🐛 Bug Fixes'
labels:
- 'fix'
- title: '🛠 Maintenance'
labels:
- 'chore'
- title: '📚 Documentation'
labels:
- 'docs'
- title: '🧪 Refactor'
labels:
- 'refactor'
change-template: '- ${{ change.title }} (#${{ change.number }})'
version-resolver:
major:
type: 'MAJOR'
minor:
type: 'MINOR'
patch:
type: 'PATCH'
default: 'patch'
template: |
## What's Changed
$CHANGES

View File

@@ -4,7 +4,6 @@ on:
pull_request:
branches:
- main
- online
jobs:
build:
@@ -32,7 +31,7 @@ jobs:
run: mkdir build
- name: Configure CMake
run: cmake -S . -B build
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
- name: Build project
run: cmake --build build -- -j $(nproc)

80
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,80 @@
name: Build and Release
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
container:
image: fedora:latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up C++ environment
run: |
dnf install -y gcc gcc-c++ cmake make
- name: Install SDL2 dependencies
run: |
dnf install -y SDL2 SDL2-devel SDL2_image SDL2_image-devel SDL2_ttf SDL2_ttf-devel SDL2_net SDL2_net-devel SDL2_mixer SDL2_mixer-devel
- name: Clean build directory
run: rm -rf build
- name: Create build directory
run: mkdir build
- name: Configure CMake
run: cmake -S . -B build
- name: Build project
run: cmake --build build -- -j $(nproc)
- name: Archive build artifacts
uses: actions/upload-artifact@v3
with:
name: build-artifacts
path: build/
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: build-artifacts
path: build/
- name: Generate release tag
id: generate_release_tag
uses: amitsingh-007/next-release-tag@v6.0.0
with:
github_token: ${{ secrets.GH_TOKEN }}
tag_prefix: 'v'
tag_template: 'yyyy.mm.dd.i'
- name: Create Release
uses: softprops/action-gh-release@v2
with:
name: Release ${{ steps.generate_release_tag.outputs.next_release_tag }}
tag_name: ${{ steps.generate_release_tag.outputs.next_release_tag }}
files: build/bloubloulespoissons
generate_release_notes: false
token: ${{ secrets.GH_TOKEN }}
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
- name: Draft Release Notes
uses: release-drafter/release-drafter@v5
with:
config-name: release-drafter.yml
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

2
.gitignore vendored
View File

@@ -56,6 +56,8 @@ cmake-build-debug-wsl
cmake-build-debug-wsl/
cmake-build-release-mingw
cmake-build-release-mingw/
cmake-build-debug-msys2
cmake-build-debug-msys2/
# .vscode folder
.vscode/

View File

@@ -6,8 +6,6 @@ set(CMAKE_CXX_STANDARD 23)
# Ajouter le chemin de la bibliothèque SDL2
if (WIN32)
set(CMAKE_PREFIX_PATH "C:/SDL2")
else()
set(CMAKE_PREFIX_PATH "/usr/local/lib/cmake/SDL2")
endif()
find_package(SDL2 REQUIRED)
@@ -18,23 +16,36 @@ find_package(SDL2_mixer REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS} ${SDL2_TTF_INCLUDE_DIRS} ${SDL2_NET_INCLUDE_DIRS})
add_executable(bloubloulespoissons main.cpp fish.cpp decors.cpp
camera.cpp
camera.h
env.h
env.cpp
player.h
player.cpp
menu.h
menu.cpp
network/networking.cpp
network/networking.h
network/networking_client.cpp
network/networking_client.h
display.cpp
display.h
shark.cpp
shark.h
add_executable(bloubloulespoissons main.cpp
Entities/fish.cpp
Entities/fish.h
Game/decors.cpp
Game/camera.cpp
Game/camera.h
Entities/player.h
Entities/player.cpp
Utility/env.h
Utility/env.cpp
Game/menu.h
Game/menu.cpp
Network/networking.cpp
Network/networking.h
Network/networking_client.cpp
Network/networking_client.h
Entities/shark.cpp
Entities/shark.h
Entities/fish.h
Utility/display.cpp
Utility/display.h
Utility/utility.cpp
Utility/utility.h
Utility/close.cpp
Utility/close.h
Utility/music.h
Game/launchGameSolo.cpp
Game/launchGameSolo.h
Game/launchGameMulti.cpp
Game/launchGameMulti.h
)
# Lier SDL2 et SDL2_image
@@ -55,4 +66,5 @@ endif()
# Options pour la liaison statique en mode release
if (CMAKE_BUILD_TYPE STREQUAL "Release")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
target_sources(bloubloulespoissons PRIVATE resource.rc)
endif()

View File

@@ -6,8 +6,8 @@
#include <iostream>
#include <string>
#include <vector>
#include "camera.h"
#include "env.h"
#include "../Game/camera.h"
#include "../Utility/env.h"
class Fish {
private:

View File

@@ -1,10 +1,5 @@
#include "player.h"
#include <syncstream>
#include <tuple>
#include "network/networking_client.h"
#include "camera.h"
void Player::updatePlayerPos(int x, int y) {
this->x = x;
this->y = y;
@@ -30,17 +25,17 @@ void Player::draw(SDL_Renderer* renderer) {
case 0:
this->currentSprite = PLAYER_SPRITE_1;
break;
case 5:
case 50:
this->currentSprite = PLAYER_SPRITE_2;
break;
case 8:
case 150:
this->currentSprite = PLAYER_SPRITE_3;
break;
default:
break;
}
if (this->ticks >= 8) {
if (this->ticks >= 150) {
this->ticks = 0;
} else {
this->ticks++;
@@ -60,11 +55,12 @@ void Player::handlePlayerMovement(int ENV_WIDTH, int ENV_HEIGHT, int windowWidth
int tempY = this->y;
int speed = this->playerSpeed;
bool isSprinting = false;
/*
if (keystate[SDL_SCANCODE_LSHIFT]) {
speed = this->playerSpeed * 2;
isSprinting = true;
}
*/
bool moved = false;
if (this->energy != 0) {
if (isPlayingOnline) {
@@ -172,7 +168,7 @@ void Player::drawEnergyBar(SDL_Renderer* renderer) {
SDL_RenderFillRect(renderer, &energyBarForeground);
}
int Player::getPlayerId() {
int Player::getPlayerId() const {
return playerId;
}

View File

@@ -6,7 +6,14 @@
#include <iostream>
#include <tuple>
#include <vector>
#include <syncstream>
#include <tuple>
#include "../Network/networking_client.h"
#include "../Game/camera.h"
#include "fish.h"
#include <syncstream>
#include <tuple>
#include "../Network/networking_client.h"
enum playerData {
@@ -66,7 +73,7 @@ class Player {
void handlePlayerMovement(int ENV_WIDTH, int ENV_HEIGHT, int windowWidth, int windowHeight);
void drawEnergyBar(SDL_Renderer* renderer);
bool checkCollision(SDL_Rect fishRect);
int getPlayerId();
int getPlayerId() const;
void setPlayerPos(int x, int y);
void handleClientMessages();
void updatePosition(int x, int y);

View File

@@ -5,8 +5,6 @@
#define sharkIMG "../img/shark.png"
#include "shark.h"
#include "network/networking.h"
Shark::Shark(const int x, const int y, const float vx, const float vy, const int id, const int width, const int height, SDL_Renderer* renderer, std::vector<Player> &players_list)
: x(x), y(y), vx(vx), vy(vy), id(id), width(width), height(height), players_list(players_list) {
SDL_Surface* sharkSurface = IMG_Load(sharkIMG);
@@ -17,10 +15,15 @@ Shark::Shark(const int x, const int y, const float vx, const float vy, const int
SDL_FreeSurface(sharkSurface);
}
sharkSound = Mix_LoadWAV("../sounds/shark.wav");
if (sharkSound == nullptr) {
std::cerr << "Erreur de chargement du son du requin: " << Mix_GetError() << std::endl;
}
// sharkSound = Mix_LoadWAV("../sounds/shark.wav");
// if (sharkSound == nullptr) {
// std::cerr << "Erreur de chargement du son du requin: " << Mix_GetError() << std::endl;
// }
// approachingSound = Mix_LoadWAV("../sounds/Shark-approching.wav");
// if (approachingSound == nullptr) {
// std::cerr << "Erreur de chargement du son d'approche du requin: " << Mix_GetError() << std::endl;
// }
lastSoundTime = std::chrono::steady_clock::now();
}
@@ -69,6 +72,15 @@ void Shark::cycle() {
if (isInView(player)) {
checkNeighborhood(player, xpos_avg, ypos_avg, xvel_avg, yvel_avg, neighboring_player);
checkCollision(player);
//Mix_PlayChannel(SOUND_CHANNEL, approachingSound, 0);
musicManager.playMusic("Shark-approaching");
musicManager.pauseMusic("Playing");
}
if (!isInView(player)) {
// Cut the approach sound
musicManager.stopMusic("Shark-approaching");
musicManager.resumeMusic("Playing");
// Mix_HaltChannel(SOUND_CHANNEL);
}
}
if (neighboring_player > 0) {
@@ -93,9 +105,10 @@ void Shark::cycle() {
auto now = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::seconds>(now - lastSoundTime).count() > 15) {
if (sharkSound != nullptr) {
Mix_PlayChannel(-1, sharkSound, 0);
}
// if (sharkSound != nullptr) {
// Mix_PlayChannel(SOUND_CHANNEL, sharkSound, 0);
// }
musicManager.playMusic("Shark");
lastSoundTime = now;
}
@@ -113,10 +126,15 @@ Shark::~Shark() {
texture = nullptr;
}
if (sharkSound) {
Mix_FreeChunk(sharkSound);
sharkSound = nullptr;
}
// if (sharkSound) {
// Mix_FreeChunk(sharkSound);
// sharkSound = nullptr;
// }
// if (approachingSound) {
// Mix_FreeChunk(approachingSound);
// approachingSound = nullptr;
// }
}
void Shark::updatePosition(int newX, int newY) {

View File

@@ -10,6 +10,7 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <chrono>
#include "../Network/networking.h"
class Shark {
private:
@@ -30,7 +31,8 @@ private:
int width, height;
std::vector<Player> &players_list;
Mix_Chunk* sharkSound;
// Mix_Chunk* sharkSound;
// Mix_Chunk* approachingSound;
std::chrono::steady_clock::time_point lastSoundTime;
std::chrono::steady_clock::time_point lastSendTime;

View File

@@ -3,9 +3,6 @@
//
#include "decors.h"
#include <iostream>
#include "env.h"
void Rock::draw(SDL_Renderer* renderer) const{
Camera& camera = Camera::getInstance();

View File

@@ -9,7 +9,9 @@
#include <ctime>
#include <cstdlib>
#include <vector>
#include <iostream>
#include "camera.h"
#include "../Utility/env.h"
class Rock {
public:

195
Game/launchGameMulti.cpp Normal file
View File

@@ -0,0 +1,195 @@
//
// Created by BreizhHardware on 18/12/2024.
//
#include "launchGameMulti.h"
int pas_la_fontion_main_enfin_ce_nest_pas_la_fontion_principale_du_programme_mais_une_des_fonctions_principale_meme_primordiale_du_projet_denomme_bloubloulespoissons_mais_celle_ci_elle_lance_en_multijoueur(int argc, std::string args) {
// if (!initSDL()) {
// std::cerr << "Failed to initialize!" << std::endl;
// return -1;
// }
game_running = true;
musicManager.playMusic("Playing");
// Mix_HaltMusic();
// backgroundMusic = Mix_LoadMUS("../sounds/Playing.wav");
// if (backgroundMusic == nullptr) {
// std::cerr << "Erreur de chargement de la musique: " << Mix_GetError() << std::endl;
// return false;
// }
// Mix_VolumeMusic(MIX_MAX_VOLUME / 4);
// if (Mix_PlayMusic(backgroundMusic, -1) == -1) {
// std::cerr << "Erreur de lecture de la musique: " << Mix_GetError() << std::endl;
// return false;
// }
// Mix_PlayMusic(backgroundMusic, -1);
std::vector<Kelp> kelps;
std::vector<Rock> rocks;
std::vector<Coral> corals;
generateProceduralDecorations(kelps, rocks, corals, ENV_HEIGHT, ENV_WIDTH, renderer);
for (int i = 0; i < FISH_NUMBER; ++i) {
school.emplace_back(Fish(rand() % ENV_WIDTH, rand() % ENV_HEIGHT, 0.1, 0.1, school, i, 75, 75, renderer, rand() % 2 == 0 ? 1 : 0, fishTextures[rand() % fishCount]));
}
std::cout << "Thread: " << std::thread::hardware_concurrency() << std::endl;
std::vector<std::thread> threads;
int fishPerThread = school.size() / std::thread::hardware_concurrency();
int thread_id = 0;
for (int i = 0; i < school.size(); i += fishPerThread) {
threads.emplace_back(createThread("Fish thread", updateFishRange, std::ref(school), i, std::min(i + fishPerThread, static_cast<int>(school.size()))));
}
Shark shark(0, 0, 0.1, 0.1,0, 150, 150, renderer,players);
std::thread shark_thread = createThread("Shark", updateShark, std::ref(shark));
freopen("CON", "w", stdout);
freopen("CON", "w", stderr);
if (isPlayingOnline) {
if (argc == 0 && args == "") {
if (!initServer()) {
std::cerr << "Failed to initialize server!" << std::endl;
return -1;
}
isHost = true;
std::cout << "isHost: " << isHost << std::endl;
std::thread acceptThread = createThread("Accept thread", acceptClients);
IPaddress ip;
if (!initClient(ip, "localhost", 1234)) {
std::cerr << "Failed to initialize client!" << std::endl;
return -1;
}
players.emplace_back(Player(windowWidth / 2, windowHeight / 2, 5, renderer, 0));
std::ranges::sort(school, Fish::SortByX);
std::vector<std::thread> fish_threads;
int fishPerThread = school.size() / std::thread::hardware_concurrency();
for (int i = 0; i < school.size(); i += fishPerThread) {
fish_threads.emplace_back(createThread("Fish thread", updateFishRange, std::ref(school), i, std::min(i + fishPerThread, static_cast<int>(school.size()))));
}
messageThreadRunning = true;
std::thread messageThread = createThread("Message thread", handleClientMessages, std::ref(players[0]));
std::thread playerThread = createThread("Player thread", playerMovementThread, std::ref(players[0]));
while (game_running) {
renderScene(players, kelps, rocks, corals,shark);
SDL_Delay(10);
}
messageThreadRunning = false;
try{
//if(playerThread.joinable())
std::cout << "Killing playerThread.." << std::endl;
playerThread.join();
std::cout << "playerThread killed" << std::endl;
}catch(const std::system_error& e){
std::cerr << "Exception caught 1: " << e.what() << std::endl;
}
try {
for (auto& fish_thread : fish_threads) {
if (fish_thread.joinable())
fish_thread.join();
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 2: " << e.what() << std::endl;
}
for (auto& thread : threads) {
try {
std::cout << "Killing thread..." << std::endl;
thread.join();
std::cout << "Thread killed" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Exception caught 3: " << e.what() << std::endl;
}
}
try {
//if (messageThread.joinable())
closeClient();
std::cout << "Killing messageThread" << std::endl;
messageThread.join();
std::cout << "messageThread killed" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Exception caught 4: " << e.what() << std::endl;
}
try {
if (acceptThread.joinable()){
std::cout << "Killing acceptThread" << std::endl;
acceptThread.join();
std::cout << "acceptThread killed" << std::endl;
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 5: " << e.what() << std::endl;
}
school.clear();
players.clear();
eventHandler.triggerEvent("playerLost");
}
else if (argc > 0 && argc < 65535 && args != "") {
int port = 1234;
std::string host = args;
if (!initClient(ip, host.c_str(), 1234)) {
std::cerr << "Failed to initialize client!" << std::endl;
return -1;
}
players.emplace_back(Player(windowWidth / 2, windowHeight / 2, 5, renderer, 1));
std::ranges::sort(school, Fish::SortByX);
std::vector<std::thread> fish_threads;
int fishPerThread = school.size() / std::thread::hardware_concurrency();
for (int i = 0; i < school.size(); i += fishPerThread) {
fish_threads.emplace_back(createThread("Fish thread", updateFishRange, std::ref(school), i, std::min(i + fishPerThread, static_cast<int>(school.size()))));
}
messageThreadRunning = true;
std::thread messageThread = createThread("Message thread", handleClientMessages, std::ref(players[0]));
std::thread playerThread = createThread("Player thread", playerMovementThread, std::ref(players[0]));
while (running) {
renderScene(players, kelps, rocks, corals,shark);
SDL_Delay(10);
}
messageThreadRunning = false;
try{
//if(playerThread.joinable())
std::cout << "Killing playerThread.." << std::endl;
playerThread.join();
std::cout << "playerThread killed" << std::endl;
}catch(const std::system_error& e){
std::cerr << "Exception caught 1: " << e.what() << std::endl;
}
try {
for (auto& fish_thread : fish_threads) {
if (fish_thread.joinable())
fish_thread.join();
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 2: " << e.what() << std::endl;
}
for (auto& thread : threads) {
try {
std::cout << "Killing thread..." << std::endl;
thread.join();
std::cout << "Thread killed" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Exception caught 3: " << e.what() << std::endl;
}
}
try {
//if (messageThread.joinable())
closeClient();
std::cout << "Killing messageThread" << std::endl;
messageThread.join();
std::cout << "messageThread killed" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Exception caught 4: " << e.what() << std::endl;
}
school.clear();
players.clear();
eventHandler.triggerEvent("playerLost");
}
}
return 0;
}

20
Game/launchGameMulti.h Normal file
View File

@@ -0,0 +1,20 @@
//
// Created by BreizhHardware on 18/12/2024.
//
#ifndef LAUNCHGAMEMULTI_H
#define LAUNCHGAMEMULTI_H
#include <iostream>
#include <string>
#include <thread>
#include <algorithm>
#include "../Utility/env.h"
#include "decors.h"
#include "../Entities/fish.h"
#include "../Utility/utility.h"
int pas_la_fontion_main_enfin_ce_nest_pas_la_fontion_principale_du_programme_mais_une_des_fonctions_principale_meme_primordiale_du_projet_denomme_bloubloulespoissons_mais_celle_ci_elle_lance_en_multijoueur(int argc, std::string args);
#endif //LAUNCHGAMEMULTI_H

103
Game/launchGameSolo.cpp Normal file
View File

@@ -0,0 +1,103 @@
//
// Created by BreizhHardware on 18/12/2024.
//
#include "launchGameSolo.h"
int pas_la_fontion_main_enfin_ce_nest_pas_la_fontion_principale_du_programme_mais_une_des_fonctions_principale_meme_primordiale_du_projet_denomme_bloubloulespoissons(int argc, char* args[]) {
// if (!initSDL()) {
// std::cerr << "Failed to initialize!" << std::endl;
// return -1;
// }
game_running = true;
musicManager.playMusic("Playing");
// Mix_HaltMusic();
// backgroundMusic = Mix_LoadMUS("../sounds/Playing.wav");
// if (backgroundMusic == nullptr) {
// std::cerr << "Erreur de chargement de la musique: " << Mix_GetError() << std::endl;
// return false;
// }
// Mix_VolumeMusic(MIX_MAX_VOLUME / 4);
// if (Mix_PlayMusic(backgroundMusic, -1) == -1) {
// std::cerr << "Erreur de lecture de la musique: " << Mix_GetError() << std::endl;
// return false;
// }
// Mix_PlayMusic(backgroundMusic, -1);
std::vector<Kelp> kelps;
std::vector<Rock> rocks;
std::vector<Coral> corals;
generateProceduralDecorations(kelps, rocks, corals, ENV_HEIGHT, ENV_WIDTH, renderer);
freopen("CON", "w", stdout);
freopen("CON", "w", stderr);
for (int i = 0; i < FISH_NUMBER; ++i) {
int x = rand() % ENV_WIDTH;
int y = rand() % ENV_HEIGHT;
double speedX = 0.1;
double speedY = 0.1;
int textureIndex = rand() % fishCount;
int gender = rand() % 2 == 0 ? 1 : 0;
school.emplace_back(x, y, speedX, speedY, school, i, 75, 75, renderer, gender, fishTextures[textureIndex]);
}
std::ranges::sort(school, Fish::SortByX);
std::vector<std::thread> fish_threads;
int fishPerThread = school.size() / std::thread::hardware_concurrency();
for (int i = 0; i < school.size(); i += fishPerThread) {
fish_threads.emplace_back(createThread("Fish thread", updateFishRange, std::ref(school), i, std::min(i + fishPerThread, static_cast<int>(school.size()))));
}
//std::thread quit_thread = createThread("Quit thread", handleQuitThread);
// Offline
players.emplace_back(Player(windowWidth / 2, windowHeight / 2, 3, renderer, 0));
std::thread player_thread = createThread("Player thread", playerMovementThread, std::ref(players[0]));
Shark shark(0, 0, 0.1, 0.1,0, 150, 150, renderer,players);
std::thread shark_thread = createThread("Shark thread",updateShark, std::ref(shark));
while (game_running) {
renderScene(players, kelps, rocks, corals, shark);
//handleQuit();
}
try{
if(player_thread.joinable()){
std::cout << "Killing playerThread.." << std::endl;
player_thread.join();
}
}catch(const std::system_error& e){
std::cerr << "Exception caught 1: " << e.what() << std::endl;
}
try {
std::cout << "Killing fish_threads..." << std::endl;
for (auto& fish_thread : fish_threads) {
if (fish_thread.joinable())
fish_thread.join();
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 4: " << e.what() << std::endl;
}
try {
if (shark_thread.joinable()){
std::cout << "Killing shark_thread..." << std::endl;
shark_thread.join();
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 5: " << e.what() << std::endl;
}
std::cout << "All threads killed" << std::endl;
// running = false;
school.clear();
players.clear();
eventHandler.triggerEvent("playerLost");
return 0;
}

20
Game/launchGameSolo.h Normal file
View File

@@ -0,0 +1,20 @@
//
// Created by BreizhHardware on 18/12/2024.
//
#ifndef LAUNCGAMESOLO_H
#define LAUNCGAMESOLO_H
#include <iostream>
#include <vector>
#include <algorithm>
#include <thread>
#include "../Utility/env.h"
#include "../Utility/utility.h"
#include "../Entities/fish.h"
#include "../Entities/shark.h"
#include "decors.h"
int pas_la_fontion_main_enfin_ce_nest_pas_la_fontion_principale_du_programme_mais_une_des_fonctions_principale_meme_primordiale_du_projet_denomme_bloubloulespoissons(int argc, char* args[]);
#endif //LAUNCGAMESOLO_H

328
Game/menu.cpp Normal file
View File

@@ -0,0 +1,328 @@
#include "menu.h"
void drawRoundedRectWithGradient(SDL_Renderer* renderer, SDL_Rect rect, int radius, SDL_Color startColor, SDL_Color endColor, int gradientWidth) {
for (int i = 0; i < gradientWidth; i++) {
Uint8 r = startColor.r + i * (endColor.r - startColor.r) / gradientWidth;
Uint8 g = startColor.g + i * (endColor.g - startColor.g) / gradientWidth;
Uint8 b = startColor.b + i * (endColor.b - startColor.b) / gradientWidth;
Uint8 a = startColor.a + i * (endColor.a - startColor.a) / gradientWidth;
SDL_Color gradientColor = {r, g, b, a};
SDL_SetRenderDrawColor(renderer, gradientColor.r, gradientColor.g, gradientColor.b, gradientColor.a);
SDL_Rect gradientRect = {
rect.x - i,
rect.y - i,
rect.w + 2 * i,
rect.h + 2 * i
};
auto drawRoundedCorners = [&](int x, int y, int r) {
for (int dy = -r; dy <= r; dy++) {
for (int dx = -r; dx <= r; dx++) {
if (dx * dx + dy * dy <= r * r) {
SDL_RenderDrawPoint(renderer, x + dx, y + dy);
}
}
}
};
drawRoundedCorners(gradientRect.x + radius, gradientRect.y + radius, radius);
drawRoundedCorners(gradientRect.x + gradientRect.w - radius, gradientRect.y + radius, radius);
drawRoundedCorners(gradientRect.x + radius, gradientRect.y + gradientRect.h - radius, radius);
drawRoundedCorners(gradientRect.x + gradientRect.w - radius, gradientRect.y + gradientRect.h - radius, radius);
SDL_Rect top = {gradientRect.x + radius, gradientRect.y, gradientRect.w - 2 * radius, radius};
SDL_Rect bottom = {gradientRect.x + radius, gradientRect.y + gradientRect.h - radius, gradientRect.w - 2 * radius, radius};
SDL_Rect left = {gradientRect.x, gradientRect.y + radius, radius, gradientRect.h - 2 * radius};
SDL_Rect right = {gradientRect.x + gradientRect.w - radius, gradientRect.y + radius, radius, gradientRect.h - 2 * radius};
SDL_Rect center = {gradientRect.x + radius, gradientRect.y + radius, gradientRect.w - 2 * radius, gradientRect.h - 2 * radius};
SDL_RenderDrawRect(renderer, &top);
SDL_RenderDrawRect(renderer, &bottom);
SDL_RenderDrawRect(renderer, &left);
SDL_RenderDrawRect(renderer, &right);
}
}
void drawRoundedRect(SDL_Renderer* renderer, SDL_Rect rect, int radius, SDL_Color color) {
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
auto drawRoundedCorners = [&](int x, int y, int r) {
for (int dy = -r; dy <= r; dy++) {
for (int dx = -r; dx <= r; dx++) {
if (dx * dx + dy * dy <= r * r) {
SDL_RenderDrawPoint(renderer, x + dx, y + dy);
}
}
}
};
drawRoundedCorners(rect.x + radius, rect.y + radius, radius);
drawRoundedCorners(rect.x + rect.w - radius, rect.y + radius, radius);
drawRoundedCorners(rect.x + radius, rect.y + rect.h - radius, radius);
drawRoundedCorners(rect.x + rect.w - radius, rect.y + rect.h - radius, radius);
SDL_Rect top = {rect.x + radius, rect.y, rect.w - 2 * radius, radius};
SDL_Rect bottom = {rect.x + radius, rect.y + rect.h - radius, rect.w - 2 * radius, radius};
SDL_Rect left = {rect.x, rect.y + radius, radius, rect.h - 2 * radius};
SDL_Rect right = {rect.x + rect.w - radius, rect.y + radius, radius, rect.h - 2 * radius};
SDL_Rect center = {rect.x + radius, rect.y + radius, rect.w - 2 * radius, rect.h - 2 * radius};
SDL_RenderFillRect(renderer, &top);
SDL_RenderFillRect(renderer, &bottom);
SDL_RenderFillRect(renderer, &left);
SDL_RenderFillRect(renderer, &right);
SDL_RenderFillRect(renderer, &center);
}
std::string Menu::getCurrentPageName() {
if (currentPage == -1) {
return "";
}
return pages[currentPage].title;
}
void Menu::draw(SDL_Renderer* renderer) {
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, backgroundTxt, nullptr, &backgroundRect);
if (pages.size() > 0) {
if (currentPage == -1 && pages.size() > 0) {
currentPage = 0;
}
for (ImagePage image : pages[currentPage].images) {
SDL_RenderCopy(renderer, image.image, nullptr, &image.rect);
}
for (Text& text : pages[currentPage].texts) {
SDL_RenderCopy(renderer, text.txt, nullptr, &text.rect);
}
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
bool hover = false;
for (Button& button : pages[currentPage].buttons) {
// Activer le blending pour l'arrière-plan du bouton
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, button.bgColor.r, button.bgColor.g, button.bgColor.b, button.bgColor.a);
SDL_RenderFillRect(renderer, &button.rect);
// Dessiner la bordure du bouton
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(renderer, button.borderColor.r, button.borderColor.g, button.borderColor.b, button.borderColor.a);
SDL_Rect borderRect = {button.rect.x - button.borderWidth, button.rect.y - button.borderWidth, button.rect.w + 2 * button.borderWidth, button.rect.h + 2 * button.borderWidth};
SDL_RenderDrawRect(renderer, &borderRect);
SDL_RenderCopy(renderer, button.txt, nullptr, &button.txtRect);
if (button.isTextInput) {
TTF_Font* font_txt = TTF_OpenFont("../fonts/arial.ttf", 24);
SDL_Surface* textSurface = TTF_RenderText_Solid(font_txt, button.inputText.c_str(), button.fontColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Rect inputRect = {button.rect.x + 5, button.rect.y + 5, button.rect.w - 10, button.rect.h - 10};
SDL_RenderCopy(renderer, textTexture, nullptr, &inputRect);
SDL_FreeSurface(textSurface);
SDL_DestroyTexture(textTexture);
TTF_CloseFont(font_txt);
}
if (mouseX >= button.rect.x && mouseX <= button.rect.x + button.rect.w &&
mouseY >= button.rect.y && mouseY <= button.rect.y + button.rect.h) {
hover = true;
}
}
if (hover) {
SDL_Cursor* cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
SDL_SetCursor(cursor);
} else {
SDL_Cursor* cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
SDL_SetCursor(cursor);
}
}
SDL_RenderPresent(renderer);
}
void Menu::handleClickedButton() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = false;
return;
}
if (event.type == SDL_MOUSEBUTTONDOWN) {
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
activeTextInputIndex = -1;
for (int i = 0; i < pages[currentPage].buttons.size(); ++i) {
Button& button = pages[currentPage].buttons[i];
if (mouseX >= button.rect.x && mouseX <= button.rect.x + button.rect.w &&
mouseY >= button.rect.y && mouseY <= button.rect.y + button.rect.h) {
if (button.isTextInput) {
// Activer le champ de texte
SDL_StartTextInput();
activeTextInputIndex = i; // Mettre à jour l'élément de texte actif
} else {
button.callback();
}
}
}
} else if (event.type == SDL_TEXTINPUT) {
if (activeTextInputIndex != -1) {
Button& button = pages[currentPage].buttons[activeTextInputIndex];
if (button.isTextInput) {
button.inputText += event.text.text;
}
}
} else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_BACKSPACE) {
if (activeTextInputIndex != -1) {
Button& button = pages[currentPage].buttons[activeTextInputIndex];
if (button.isTextInput && !button.inputText.empty()) {
button.inputText.pop_back();
}
}
}
}
}
void Menu::hide(){
shown = false;
}
void Menu::show(){
shown = true;
}
bool Menu::isShown(){
return shown;
}
void Menu::changePage(std::string title){
for(int i = 0; i < pages.size(); i++){
if(pages[i].title == title){
currentPage = i;
}
}
}
void Menu::addButton(std::string page, int x, int y, int w, int h, std::string text, int size, std::function<void()> callback, bool isTextInput) {
for (Page& p : pages) {
if (p.title == page) {
TTF_Font* font_txt = TTF_OpenFont("../fonts/arial.ttf", size);
if (font_txt == nullptr) {
std::cerr << "Erreur de chargement de la police: " << TTF_GetError() << std::endl;
}
Button button;
button.rect = {x, y, w, h};
int textWidth = w / 2;
int textHeight = h / 1.5;
button.txtRect = {x + (w / 2) - (textWidth / 2), y + (h / 2) - (textHeight / 2), textWidth, textHeight};
button.fontColor = {255, 255, 255};
button.bgColor = {0, 0, 0, 75}; // Fond noir avec opacité de 13%
button.borderColor = {40, 120, 122, 255}; // Couleur de la bordure
button.borderWidth = 5; // Largeur de la bordure
button.borderRadius = 17; // Rayon de la bordure
button.isTextInput = isTextInput;
SDL_Surface* textSurface = TTF_RenderText_Solid(font_txt, text.c_str(), button.fontColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_FreeSurface(textSurface);
button.txt = textTexture;
button.callback = callback;
button.startGradientColor = {40, 120, 122, 255};
button.endGradientColor = {55, 171, 189, 255};
button.gradientWidth = 10;
p.buttons.push_back(button);
TTF_CloseFont(font_txt);
}
}
}
void Menu::addText(std::string page, int x, int y, int w, int h, std::string text, int size){
for(Page& p : pages){
if(p.title == page){
TTF_Font* font_txt = TTF_OpenFont("../fonts/arial.ttf", size);
if (font_txt == nullptr) {
std::cerr << "Erreur de chargement de la police: " << TTF_GetError() << std::endl;
}
Text txt;
txt.rect = {x, y, w, h};
txt.fontColor = {255, 255, 255};
txt.txtRect = {x, y, w, h};
SDL_Surface* textSurface = TTF_RenderText_Solid(font_txt, text.c_str(), txt.fontColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_FreeSurface(textSurface);
txt.txt = textTexture;
p.texts.push_back(txt);
TTF_CloseFont(font_txt);
}
}
}
void Menu::addPage(std::string title){
Page page;
page.title = title;
pages.push_back(page);
}
std::vector<Button> Menu::getButtons(){
return pages[currentPage].buttons;
}
void Menu::addImage(std::string page, int x, int y, int w, int h, std::string path) {
for (Page& p : pages) {
if (p.title == page) {
SDL_Surface* imageSurface = IMG_Load(path.c_str());
if (imageSurface == nullptr) {
std::cerr << "Erreur de chargement de l'image: " << IMG_GetError() << std::endl;
return;
}
SDL_Texture* imageTexture = SDL_CreateTextureFromSurface(renderer, imageSurface);
SDL_FreeSurface(imageSurface);
SDL_Rect imageRect = {x, y, w, h};
p.images.push_back(ImagePage(imageTexture, imageRect));
}
}
}
void Menu::drawLost(SDL_Renderer* renderer) {
// Charger l'image perdu.png
SDL_Surface* lostSurface = IMG_Load("../img/perdu.png");
if (lostSurface == nullptr) {
std::cerr << "Erreur de chargement de l'image perdu.png: " << IMG_GetError() << std::endl;
return;
}
SDL_Texture* lostTexture = SDL_CreateTextureFromSurface(renderer, lostSurface);
SDL_FreeSurface(lostSurface);
// Définir la transparence (alpha) de l'image
SDL_SetTextureBlendMode(lostTexture, SDL_BLENDMODE_BLEND);
SDL_SetTextureAlphaMod(lostTexture, 128); // 128 pour 50% de transparence
// Obtenir les dimensions de la fenêtre
int windowWidth, windowHeight;
SDL_GetRendererOutputSize(renderer, &windowWidth, &windowHeight);
// Définir le rectangle de destination pour l'image
SDL_Rect destRect = {0, 0, windowWidth, windowHeight};
// Dessiner l'image
SDL_RenderCopy(renderer, lostTexture, nullptr, &destRect);
// Détruire la texture après utilisation
SDL_DestroyTexture(lostTexture);
}

View File

@@ -1,5 +1,5 @@
#include <iostream>
#include "env.h"
#include "../Utility/env.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
@@ -18,6 +18,12 @@ struct Button {
std::function<void()> callback;
bool isTextInput = false;
std::string inputText;
SDL_Color borderColor;
int borderWidth;
int borderRadius;
SDL_Color startGradientColor;
SDL_Color endGradientColor;
int gradientWidth;
};
struct Text {
@@ -27,13 +33,22 @@ struct Text {
SDL_Rect txtRect;
};
struct ImagePage {
SDL_Texture* image;
SDL_Rect rect;
};
struct Page {
std::string title;
std::vector<Button> buttons;
std::vector<Text> texts;
std::vector<ImagePage> images;
};
void drawRoundedRectWithGradient(SDL_Renderer* renderer, SDL_Rect rect, int radius, SDL_Color startColor, SDL_Color endColor, int gradientWidth);
void drawRoundedRect(SDL_Renderer* renderer, SDL_Rect rect, int radius, SDL_Color color);
class Menu {
private:
SDL_Texture* backgroundTxt = nullptr;
@@ -70,13 +85,19 @@ class Menu {
void changePage(std::string title);
std::string getCurrentPageName();
void addButton(std::string page, int x, int y, int w, int h, std::string text, int size, std::function<void()> callback, bool isTextInput = false);
void addText(std::string page, int x, int y, int w, int h, std::string text, int size);
void addPage(std::string title);
void addImage(std::string page, int x, int y, int w, int h, std::string path);
std::vector<Button> getButtons();
void drawLost(SDL_Renderer* renderer);
};
#endif

View File

@@ -3,6 +3,8 @@
//
#include "networking.h"
#include "../Entities/player.h"
std::unordered_map<int, std::pair<int, int>> playerPositions;
std::unordered_map<int, std::chrono::time_point<std::chrono::steady_clock>> lastKeepAlive;
@@ -230,4 +232,26 @@ std::string processReceivedData(const std::string& data) {
}
}
return filteredData;
}
std::vector<PlayerInfo> getAllPlayers() {
std::vector<PlayerInfo> playersInfo;
for (const auto& player : players_server) {
auto [x, y] = player.getPlayerPos();
playersInfo.push_back({player.getPlayerId(), x, y});
}
return playersInfo;
}
void sendPlayerListToNewClient(int clientSocket) {
std::vector<PlayerInfo> players = getAllPlayers();
int playerCount = players.size();
std::string message = "playerList;" + std::to_string(playerCount) + ";";
sendMessage(server, message);
for (const auto& player : players) {
std::string playerInfo = std::to_string(player.id) + "," + std::to_string(player.x) + "," + std::to_string(player.y) + ";";
sendMessage(server, playerInfo);
}
}

View File

@@ -7,10 +7,10 @@
#include <thread>
#include <unordered_map>
#include <chrono>
#include "../env.h"
#include "../Utility/env.h"
#include "networking_client.h"
#include "../player.h"
#include "../shark.h"
#include "../Entities/player.h"
#include "../Entities/shark.h"
inline IPaddress ip;
inline TCPsocket server;
@@ -26,5 +26,12 @@ void closeServer();
void handleServerMessages();
void sendSharkPosition(TCPsocket socket, int sharkId, int x, int y);
std::string processReceivedData(const std::string& data);
struct PlayerInfo {
int id;
int x;
int y;
};
std::vector<PlayerInfo> getAllPlayers();
void sendPlayerListToNewClient(int clientSocket);
#endif //NETWORKING_H

View File

@@ -37,8 +37,10 @@ void sendMessage(TCPsocket socket, const std::string& message) {
int result = SDLNet_TCP_Send(socket, &len, sizeof(len));
if (result < sizeof(len)) {
std::cerr << "SDLNet_TCP_Send failed: " << SDLNet_GetError() << std::endl;
std::cerr << "Closing the game ..." << std::endl;
game_running = false;
//std::cerr << "Closing the game ..." << std::endl;
//game_running = false;
std::cout << "Return to menu..." << std::endl;
eventHandler.triggerEvent("playerLost");
return;
}
@@ -143,3 +145,54 @@ void startKeepAlive(TCPsocket serverSocket) {
}).detach();
}
void receivePlayerListFromServer(TCPsocket serverSocket) {
// Exemple de structure de données pour un joueur
struct PlayerInfo {
int id;
int x;
int y;
};
// Recevoir le message contenant la liste des joueurs
std::string message = receiveMessage(serverSocket);
if (message.empty()) {
std::cerr << "Failed to receive player list" << std::endl;
return;
}
std::istringstream iss(message);
std::string token;
std::getline(iss, token, ';'); // Lire "playerList"
if (token != "playerList") {
std::cerr << "Invalid message format" << std::endl;
return;
}
// Lire le nombre de joueurs
std::getline(iss, token, ';');
int playerCount = std::stoi(token);
// Lire les informations de chaque joueur
for (int i = 0; i < playerCount; ++i) {
std::getline(iss, token, ';');
int playerId, x, y;
sscanf(token.c_str(), "%d,%d,%d", &playerId, &x, &y);
// Mettre à jour l'état du client avec les informations du joueur
addPlayerToGame(playerId, x, y);
}
}
void addPlayerToGame(int playerId, int x, int y) {
// Vérifiez si le joueur existe déjà
auto it = std::find_if(players.begin(), players.end(), [playerId](const Player& player) {
return player.getPlayerId() == playerId;
});
if (it != players.end()) {
// Si le joueur existe déjà, mettez à jour sa position
it->updatePosition(x, y);
} else {
// Sinon, ajoutez un nouveau joueur
players.emplace_back(Player(x, y, 5, renderer, playerId));
}
}

View File

@@ -9,8 +9,8 @@
#include <sstream>
#include <thread>
#include <chrono>
#include "../env.h"
#include "../player.h"
#include "../Utility/env.h"
#include "../Entities/player.h"
class Player;
@@ -23,5 +23,6 @@ std::string receiveMessage(TCPsocket socket);
void handleClientMessage(Player& player);
void sendKeepAlive(TCPsocket serverSocket);
void startKeepAlive(TCPsocket serverSocket);
void receivePlayerListFromServer(int serverSocket);
void addPlayerToGame(int playerId, int x, int y);
#endif //NETWORKING_CLIENT_H

View File

@@ -1,8 +1,54 @@
# bloubloulespoissons
Bloublou les poissons est un jeu de simulation de comportement de poisson en réseau ou bien en solo.
Le jeu est codé en C++ avec la librairie SDL2.
# 🌱 Branches en développement
- `main` : La branche principale du projet
- `WII-U` : La branche pour la version Wii-U du jeu
# 🚀 Installation et configuration
## Prérequis
- [SDL2](https://www.libsdl.org/download-2.0.php)
- [SDL2_image](https://www.libsdl.org/projects/SDL_image/)
- [SDL2_ttf](https://www.libsdl.org/projects/SDL_ttf/)
- [SDL2_mixer](https://www.libsdl.org/projects/SDL_mixer/)
- [SDL2_net](https://www.libsdl.org/projects/SDL_net/)
- [CMake](https://cmake.org/download/)
- [Git](https://git-scm.com/downloads)
- [GCC](https://gcc.gnu.org/)
- [Make](https://www.gnu.org/software/make/)
## Compilation et lancement
1. Clonez le dépôt
```bash
git clone https://github.com/BreizhHardware/bloubloulespoissons.git
cd bloubloulespoissons
```
2. Créez un dossier build
```bash
mkdir build
cd build
```
3. Générez les fichiers de configuration
```bash
cmake ..
```
4. Compilez le projet
```bash
make -j
```
5. Lancez le jeu
```bash
./bloubloulespoissons
```
# To do
[ ] Voir les autres joueurs
[ ] Id Incrémental pour les players
[ ] Récupération des infos des champs de text pour le join
[X] Affichage de l'ip dans le champs d'host (fonctionnalité retiré)
[ ] Requin adversaire
- [x] Voir les autres joueurs
- [x] Id Incrémental pour les players
- [x] Récupération des infos des champs de text pour le join
- [X] Affichage de l'ip dans le champs d'host (fonctionnalité retiré)
- [x] Requin adversaire
- [x] Choix des musiques pour le jeux
- [x] Pouvoir mute les musiques via la touche M
- [x] Refactorer le code pour le rendre plus lisible

147
Utility/close.cpp Normal file
View File

@@ -0,0 +1,147 @@
//
// Created by BreizhHardware on 18/12/2024.
//
#include "close.h"
void handleQuitThread() {
std::cout << "handleQuitThread..." << std::endl;
while (game_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
handleQuit();
}
std::cout << "handleQuitThread" << std::endl;
}
void handleQuit() {
SDL_Event event;
const Uint8* keystate = SDL_GetKeyboardState(NULL);
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
if (isPlayingOnline && isHost) {
closeServer();
}
game_running = false;
}
}
if (keystate[SDL_SCANCODE_ESCAPE]) {
if (isPlayingOnline && isHost) {
closeServer();
}
game_running = false;
}
if (keystate[SDL_SCANCODE_M]) {
soundMuted = !soundMuted;
if (soundMuted) {
Mix_Volume(-1, 0);
Mix_VolumeMusic(0);
} else {
Mix_Volume(-1, MIX_MAX_VOLUME);
Mix_VolumeMusic(MIX_MAX_VOLUME);
}
}
if (keystate[SDL_SCANCODE_F2]) {
displayFPSFlag = !displayFPSFlag;
}
}
void cleanup() {
try {
if (font != nullptr) {
TTF_CloseFont(font);
font = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for CloseFont: " << e.what() << std::endl;
}
try {
TTF_Quit();
} catch (const std::exception& e) {
std::cerr << "Exception caught for TTF_Quit: " << e.what() << std::endl;
}
try {
if (playerTexture != nullptr) {
SDL_DestroyTexture(playerTexture);
playerTexture = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for DestroyTexture (playerTexture): " << e.what() << std::endl;
}
for (int i = 0; i < fishCount; ++i) {
try {
if (fishTextures[i] != nullptr) {
SDL_DestroyTexture(fishTextures[i]);
fishTextures[i] = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for DestroyTexture (fishTextures[" << i << "]): " << e.what() << std::endl;
}
}
try {
if (renderer != nullptr) {
SDL_DestroyRenderer(renderer);
renderer = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for DestroyRenderer: " << e.what() << std::endl;
}
try {
if (window != nullptr) {
SDL_DestroyWindow(window);
window = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for DestroyWindow: " << e.what() << std::endl;
}
// try {
// if (backgroundMusic != nullptr) {
// Mix_FreeMusic(backgroundMusic);
// backgroundMusic = nullptr;
// }
// } catch (const std::exception& e) {
// std::cerr << "Exception caught for FreeMusic: " << e.what() << std::endl;
// }
// try {
// if (menuMusic != nullptr) {
// Mix_FreeMusic(menuMusic);
// menuMusic = nullptr;
// }
// } catch (const std::exception& e) {
// std::cerr << "Exception caught for FreeMusic (menuMusic): " << e.what() << std::endl;
// }
try {
IMG_Quit();
} catch (const std::exception& e) {
std::cerr << "Exception caught for IMG_Quit: " << e.what() << std::endl;
}
try {
SDLNet_Quit();
} catch (const std::exception& e) {
std::cerr << "Exception caught for SDLNet_Quit: " << e.what() << std::endl;
}
try {
Mix_CloseAudio();
} catch (const std::exception& e) {
std::cerr << "Exception caught for Mix_CloseAudio: " << e.what() << std::endl;
}
try {
SDL_Quit();
} catch (const std::exception& e) {
std::cerr << "Exception caught for SDL_Quit: " << e.what() << std::endl;
}
}

21
Utility/close.h Normal file
View File

@@ -0,0 +1,21 @@
//
// Created by BreizhHardware on 18/12/2024.
//
#ifndef CLOSE_H
#define CLOSE_H
#include <SDL2/SDL.h>
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL_net.h>
#include <iostream>
#include <vector>
#include <thread>
#include <mutex>
#include "env.h"
#include "../Network/networking.h"
void cleanup();
void handleQuit();
void handleQuitThread();
#endif //CLOSE_H

View File

@@ -9,7 +9,7 @@
#include <vector>
#include <cmath>
#include <string>
#include "player.h"
#include "../Entities/player.h"
double calculateDistance(int x1, int y1, int x2, int y2);
void displayNearbyPlayers(SDL_Renderer* renderer, TTF_Font* font, Player& currentPlayer, std::vector<Player>& players, double threshold);

View File

@@ -1,6 +1,6 @@
#include "env.h"
#include <vector>
#include "../Entities/player.h"
#include "../Entities/fish.h"
int windowWidth = 1500;
int windowHeight = 800;
@@ -22,6 +22,23 @@ std::atomic<bool> game_running(false);
std::atomic<bool> isPlayingOnline(false);
std::atomic<bool> messageThreadRunning(false);
std::atomic<bool> isHost(false);
EventHandler eventHandler;
std::atomic<bool> soundMuted(false);
SDL_Texture* playerTexture = nullptr;
SDL_Texture* fishTextures[100];
std::vector<Fish> school;
MusicManager musicManager;
std::atomic<bool> displayFPSFlag(true);
void resetAll(){
game_running = false;
isPlayingOnline = false;
messageThreadRunning = false;
isHost = false;
players.clear();
players_server.clear();
}
bool initEnvironment(SDL_Renderer* renderer) {

View File

@@ -5,15 +5,20 @@
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_mixer.h>
#include <iostream>
#include <vector>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "music.h"
#include "event.h"
class Player;
class Fish;
extern int windowWidth;
extern int windowHeight;
extern int playerBaseX;
@@ -36,8 +41,17 @@ extern std::atomic<bool> messageThreadRunning;
extern std::vector<Player> players;
extern std::vector<Player> players_server;
extern std::atomic<bool> isHost;
extern EventHandler eventHandler;
extern std::atomic<bool> soundMuted;
extern SDL_Texture* fishTextures[100];
extern SDL_Texture* playerTexture;
extern std::vector<Fish> school;
extern MusicManager musicManager;
extern std::atomic<bool> displayFPSFlag;
bool initEnvironment(SDL_Renderer* renderer);
std::vector<SDL_Texture*> initTexture(SDL_Renderer* renderer);
void resetAll();
#endif // ENV_H

34
Utility/event.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef EVENTHANDLER_H
#define EVENTHANDLER_H
#include <functional>
#include <unordered_map>
#include <string>
class EventHandler {
public:
using EventCallback = std::function<void()>;
template <typename EventCallback, typename... Args>
void registerEvent(const std::string& eventName, EventCallback callback, Args&&... args) {
eventCallbacks[eventName] = [callback, ...args = std::forward<Args>(args)]() {
callback(args.get()...);
};
}
void triggerEvent(const std::string& eventName) {
if (eventCallbacks.find(eventName) != eventCallbacks.end()) {
eventCallbacks[eventName]();
}
}
private:
std::unordered_map<std::string, EventCallback> eventCallbacks;
};
#endif

192
Utility/music.h Normal file
View File

@@ -0,0 +1,192 @@
#ifndef MUSIC_H
#define MUSIC_H
#include <SDL2/SDL_mixer.h>
#include <string>
#include <iostream>
enum class AudioType {
MUSIC,
SOUND_EFFECT
};
enum AudioChannel {
MUSIC_CHANNEL = 0,
SOUND_CHANNEL = 1
};
struct Audio {
Mix_Music* music;
Mix_Chunk* sound;
};
class Music {
private:
AudioType type;
std::vector<Audio> audio;
std::string path;
std::string name;
AudioChannel channel;
public:
Music(std::string filePath, AudioType audio_type){
name = getNameFromPath(filePath);
path = filePath;
type = audio_type;
std::cout << "Loading " << name << " from " << path << std::endl;
if(type == AudioType::MUSIC){
channel = MUSIC_CHANNEL;
Mix_Music* music = Mix_LoadMUS(filePath.c_str());
Audio sss;
sss.music = music;
if(music == nullptr){
std::cerr << "Error loading music: " << Mix_GetError() << std::endl;
}else{
audio.push_back(sss);
}
}else if (type == AudioType::SOUND_EFFECT)
{
channel = SOUND_CHANNEL;
Mix_Chunk* sound = Mix_LoadWAV(filePath.c_str());
Audio sss;
sss.sound = sound;
if(sound == nullptr){
std::cerr << "Error loading sound effect: " << Mix_GetError() << std::endl;
}else{
audio.push_back(sss);
}
}
}
// ~Music(){
// if(type == AudioType::MUSIC){
// Mix_FreeMusic(audio[0].music);
// }else if (type == AudioType::SOUND_EFFECT)
// {
// Mix_FreeChunk(audio[0].sound);
// }
// }
std::string getName(){
return name;
}
std::string getNameFromPath(std::string path){
std::string name = path.substr(path.find_last_of("/\\") + 1);
name = name.substr(0, name.find_last_of("."));
std::cout << "Name: " << name << std::endl;
return name;
}
void play(){
if(type == AudioType::MUSIC){
Mix_HaltChannel(channel);
Mix_PlayMusic(audio[0].music, channel);
}else if (type == AudioType::SOUND_EFFECT)
{
Mix_HaltChannel(channel);
Mix_PlayChannel(channel, audio[0].sound, 0);
}
}
void stop(){
if(type == AudioType::MUSIC){
Mix_HaltChannel(channel);
}else if (type == AudioType::SOUND_EFFECT)
{
Mix_HaltChannel(channel);
}
}
void pause(){
if(type == AudioType::MUSIC){
Mix_PauseMusic();
}else if (type == AudioType::SOUND_EFFECT)
{
Mix_Pause(channel);
}
}
void resume(){
if(type == AudioType::MUSIC){
Mix_ResumeMusic();
}else if (type == AudioType::SOUND_EFFECT)
{
Mix_Resume(channel);
}
}
};
class MusicManager {
private:
std::vector<Music> musicList;
int volume = MIX_MAX_VOLUME;
public:
MusicManager(){
if(Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0){
std::cerr << "Error initializing SDL_mixer: " << Mix_GetError() << std::endl;
}
Mix_Volume(-1, volume);
Mix_VolumeMusic(volume);
}
~MusicManager(){
for(Music music : musicList){
music.stop();
}
Mix_CloseAudio();
}
void addMusic(std::string filePath, AudioType audio_type){
Music music(filePath, audio_type);
musicList.push_back(music);
}
void playMusic(std::string name){
for(Music music : musicList){
if(music.getName() == name){
music.play();
std::cout << "Started playing " << name << std::endl;
}
}
}
void stopMusic(std::string name){
for(Music music : musicList){
if(music.getName() == name){
music.stop();
}
}
}
void resumeMusic(std::string name){
for(Music music : musicList){
if(music.getName() == name){
music.resume();
}
}
}
void setVolume(int volume){
this->volume = volume;
Mix_Volume(-1, volume);
Mix_VolumeMusic(volume);
}
void pauseMusic(std::string name){
for(Music music : musicList){
if(music.getName() == name){
music.pause();
}
}
}
};
#endif

253
Utility/utility.cpp Normal file
View File

@@ -0,0 +1,253 @@
//
// Created by BreizhHardware on 18/12/2024.
//
#include "utility.h"
std::mutex mtx;
std::vector<ThreadInfo> threadInfos;
void checkThreads() {
std::lock_guard<std::mutex> lock(mtx);
for (const auto& threadInfo : threadInfos) {
if (threadInfo.isRunning) {
std::cout << "Thread " << threadInfo.functionName << " (ID: " << threadInfo.id << ") is still running." << std::endl;
} else {
std::cout << "Thread " << threadInfo.functionName << " (ID: " << threadInfo.id << ") has stopped." << std::endl;
}
}
}
void displayFPS(SDL_Renderer* renderer, TTF_Font* font, int fps) {
std::string fpsText = "FPS: " + std::to_string(fps);
SDL_Color color = {0, 255, 0}; // Green
SDL_Surface* textSurface = TTF_RenderText_Solid(font, fpsText.c_str(), color);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Rect textRect = {windowWidth - textSurface->w - 10, 10, textSurface->w, textSurface->h};
SDL_RenderCopy(renderer, textTexture, nullptr, &textRect);
SDL_FreeSurface(textSurface);
SDL_DestroyTexture(textTexture);
}
void displayPlayerCoord(SDL_Renderer* renderer, TTF_Font* font, int playerX, int playerY) {
Camera& camera = Camera::getInstance();
int cameraX = camera.getX();
int cameraY = camera.getY();
std::string coordText = "Camera: (" + std::to_string(cameraX) + ", " + std::to_string(cameraY) + ")";
std::string coordText2 = "Player: (" + std::to_string(playerX) + ", " + std::to_string(playerY) + ")";
SDL_Color textColor = {0, 255, 0};
SDL_Surface* textSurface = TTF_RenderText_Solid(font, coordText.c_str(), textColor);
SDL_Surface* textSurface2 = TTF_RenderText_Solid(font, coordText2.c_str(), textColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Texture* textTexture2 = SDL_CreateTextureFromSurface(renderer, textSurface2);
SDL_Rect textRect = {10, 30, textSurface->w, textSurface->h};
SDL_Rect textRect2 = {10, 50, textSurface2->w, textSurface2->h};
SDL_RenderCopy(renderer, textTexture, nullptr, &textRect);
SDL_RenderCopy(renderer, textTexture2, nullptr, &textRect2);
SDL_FreeSurface(textSurface);
SDL_FreeSurface(textSurface2);
SDL_DestroyTexture(textTexture);
SDL_DestroyTexture(textTexture2);
}
void displayUnifiedPlayerCoord(SDL_Renderer* renderer, TTF_Font* font, int unifiedX, int unifiedY) {
std::string coordText = "Unified: (" + std::to_string(unifiedX) + ", " + std::to_string(unifiedY) + ")";
SDL_Color textColor = {0, 255, 0};
SDL_Surface* textSurface = TTF_RenderText_Solid(font, coordText.c_str(), textColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Rect textRect = {10, 70, textSurface->w, textSurface->h};
SDL_RenderCopy(renderer, textTexture, nullptr, &textRect);
SDL_FreeSurface(textSurface);
SDL_DestroyTexture(textTexture);
}
void displayPlayerCount(SDL_Renderer* renderer, TTF_Font* font, int playerCount) {
std::string playerCountText = "Player count: " + std::to_string(playerCount);
SDL_Color color = {0, 255, 0}; // Green
SDL_Surface* textSurface = TTF_RenderText_Solid(font, playerCountText.c_str(), color);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Rect textRect = {windowWidth - textSurface->w - 10, 30, textSurface->w, textSurface->h};
SDL_RenderCopy(renderer, textTexture, nullptr, &textRect);
SDL_FreeSurface(textSurface);
SDL_DestroyTexture(textTexture);
}
bool initSDL() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
return false;
}
if (SDLNet_Init() < 0) {
std::cerr << "SDLNet could not initialize! SDLNet_Error: " << SDLNet_GetError() << std::endl;
return false;
}
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
std::cerr << "SDL_mixer could not initialize! SDL_mixer Error: " << Mix_GetError() << std::endl;
return false;
}
Mix_AllocateChannels(16);
// Charger la musique du menu
// menuMusic = Mix_LoadMUS("../sounds/Menu.wav");
// if (menuMusic == nullptr) {
// std::cerr << "Erreur de chargement de la musique du menu: " << Mix_GetError() << std::endl;
// return false;
// }
window = SDL_CreateWindow("BloubBloub les poissons",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
windowWidth, windowHeight,
SDL_WINDOW_SHOWN);
if (window == nullptr) {
std::cerr << "Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
return false;
}
SDL_Surface* iconSurface = IMG_Load("../img/logo.png");
if(iconSurface == nullptr) {
std::cerr << "Erreur de chargement de l'icône: " << IMG_GetError() << std::endl;
} else {
SDL_SetWindowIcon(window, iconSurface);
SDL_FreeSurface(iconSurface);
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == nullptr) {
std::cerr << "Erreur de création du renderer: " << SDL_GetError() << std::endl;
SDL_DestroyWindow(window);
SDL_Quit();
return false;
}
if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
std::cerr << "SDL_image could not initialize! SDL_image Error: " << IMG_GetError() << std::endl;
return false;
}
if (TTF_Init() == -1) {
std::cerr << "SDL_ttf could not initialize! SDL_ttf Error: " << TTF_GetError() << std::endl;
return false;
}
if (!initEnvironment(renderer)) {
return false;
}
for (int i = 0; i < fishCount; ++i) {
std::string fishTexturePath = "../img/fish/fish" + std::to_string(i) + ".png";
SDL_Surface* fishSurface = IMG_Load(fishTexturePath.c_str());
if (fishSurface == nullptr) {
std::cerr << "Erreur de chargement de l'image du poisson: " << IMG_GetError() << std::endl;
return false;
}
fishTextures[i] = SDL_CreateTextureFromSurface(renderer, fishSurface);
if (fishTextures[i] == nullptr) {
std::cerr << "Erreur de création de la texture du poisson: " << SDL_GetError() << std::endl;
return false;
}
SDL_FreeSurface(fishSurface);
}
texturesVector = initTexture(renderer);
return true;
}
void updateFishRange(std::vector<Fish>& school, int start, int end){
while (game_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(16));
{
std::lock_guard<std::mutex> lock(mtx);
Fish::insertionSort(school);
}
for (int i = start; i < end; ++i) {
school[i].cycle(i);
}
}
}
void playerMovementThread(Player& player) {
try {
std::cout << "Starting playerMovementThread for player " << player.getPlayerId() << std::endl;
while (game_running) {
player.handlePlayerMovement(ENV_WIDTH, ENV_HEIGHT, windowWidth, windowHeight);
std::this_thread::sleep_for(std::chrono::milliseconds(16)); // 60 FPS
}
std::cout << "Exiting playerMovementThread for player " << player.getPlayerId() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Exception in playerMovementThread: " << e.what() << std::endl;
}
}
void updateShark(Shark &shark) {
while (game_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(16));
shark.cycle();
}
}
void renderScene(std::vector<Player>& players, const std::vector<Kelp>& kelps, const std::vector<Rock>& rocks, const std::vector<Coral>& corals,Shark& shark) {
static Uint32 lastTime = 0;
static int frameCount = 0;
static int fps = 0;
//std::cout << "renderScene for " << players.size() << " players" << std::endl;
const Uint32 currentTime = SDL_GetTicks64();
frameCount++;
if (currentTime - lastTime >= 1000) {
fps = frameCount;
frameCount = 0;
lastTime = currentTime;
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
Camera& camera = Camera::getInstance();
SDL_Rect backgroundRect = { -camera.getX(), -camera.getY(), ENV_WIDTH, ENV_HEIGHT };
SDL_RenderCopy(renderer, backgroundTexture, nullptr, &backgroundRect);
for (const auto& kelp : kelps) {
kelp.draw(renderer);
}
for (const auto& rock : rocks) {
rock.draw(renderer);
}
for (const auto& coral : corals) {
coral.draw(renderer);
}
for (Fish& fish : school) {
fish.draw(renderer);
}
for (auto& player : players) {
player.draw(renderer);
}
if (isPlayingOnline) {
displayNearbyPlayers(renderer, font, players[0], players_server, 500);
}
shark.draw(renderer);
if (displayFPSFlag) {
displayFPS(renderer, font, fps);
}
SDL_RenderPresent(renderer);
}
void handleClientMessages(Player& player) {
std::cout << "messageThread started..." << std::endl;
while (messageThreadRunning) {
player.handleClientMessages();
}
std::cout << "messageThread ended" << std::endl;
}

81
Utility/utility.h Normal file
View File

@@ -0,0 +1,81 @@
//
// Created by BreizhHardware on 18/12/2024.
//
#ifndef UTILITY_H
#define UTILITY_H
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_image.h>
#include <SDL2/SDL_mixer.h>
#include <SDL2/SDL_net.h>
#include <vector>
#include <thread>
#include <mutex>
#include <iostream>
#include <string>
#include "env.h"
#include "../Game/camera.h"
#include "../Entities/fish.h"
#include "../Entities/player.h"
#include "../Entities/shark.h"
#include "../Game/decors.h"
#include "../Utility/display.h"
extern std::mutex mtx;
void displayFPS(SDL_Renderer* renderer, TTF_Font* font, int fps);
void displayPlayerCoord(SDL_Renderer* renderer, TTF_Font* font, int playerX, int playerY);
void displayUnifiedPlayerCoord(SDL_Renderer* renderer, TTF_Font* font, int unifiedX, int unifiedY);
void displayPlayerCount(SDL_Renderer* renderer, TTF_Font* font, int playerCount);
void checkThreads();
bool initSDL();
struct ThreadInfo {
std::thread::id id;
std::string functionName;
bool isRunning;
};
extern std::vector<ThreadInfo> threadInfos;
template <typename Function, typename... Args>
std::thread createThread(std::string key, Function&& func, Args&&... args) {
try {
std::cout << "Creating thread: " << key << std::endl;
std::thread thread([key, func = std::forward<Function>(func), ...args = std::forward<Args>(args)]() mutable {
ThreadInfo info;
info.id = std::this_thread::get_id();
info.functionName = key;
info.isRunning = true;
{
std::lock_guard<std::mutex> lock(mtx);
threadInfos.push_back(info);
}
try {
func(std::forward<Args>(args)...);
} catch (const std::exception& e) {
std::cerr << "Exception in thread " << key << ": " << e.what() << std::endl;
} catch (...) {
std::cerr << "Unknown exception in thread " << key << std::endl;
}
{
std::lock_guard<std::mutex> lock(mtx);
for (auto& threadInfo : threadInfos) {
if (threadInfo.id == std::this_thread::get_id()) {
threadInfo.isRunning = false;
break;
}
}
}
std::cout << "ThreadID = " << info.id << " ThreadFunction = " << info.functionName << " finished" << std::endl;
});
return thread;
} catch (const std::system_error& e) {
std::cerr << "Failed to create thread: " << e.what() << std::endl;
throw;
}
}
void updateFishRange(std::vector<Fish>& school, int start, int end);
void playerMovementThread(Player& player);
void updateShark(Shark &shark);
void renderScene(std::vector<Player>& players, const std::vector<Kelp>& kelps, const std::vector<Rock>& rocks, const std::vector<Coral>& corals,Shark& shark );
void handleClientMessages(Player& player);
#endif //UTILITY_H

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 142 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 130 KiB

BIN
img/logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 KiB

After

Width:  |  Height:  |  Size: 306 KiB

BIN
img/perdu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 60 KiB

708
main.cpp
View File

@@ -13,266 +13,32 @@
#include <algorithm>
#include <random>
#include "fish.h"
#include "decors.h"
#include "camera.h"
#include "display.h"
#include "env.h"
#include "player.h"
#include "menu.h"
#include "network/networking.h"
#include "network/networking_client.h"
#include "shark.h"
#include "Entities/fish.h"
#include "Game/decors.h"
#include "Game/camera.h"
#include "Utility/display.h"
#include "Utility/env.h"
#include "Utility/utility.h"
#include "Entities/player.h"
#include "Game/menu.h"
#include "Network/networking.h"
#include "Network/networking_client.h"
#include "Entities/shark.h"
#include "Utility/event.h"
#include "Utility/close.h"
#include "Game/launchGameSolo.h"
#include "Game/launchGameMulti.h"
#include <system_error>
std::mutex mtx;
std::atomic<bool> menuRunning(true);
std::mutex coutMutex;
SDL_Texture* playerTexture = nullptr;
SDL_Texture* fishTextures[100]; // Adjust the size as needed
std::vector<Fish> school;
std::vector<Player> players;
std::vector<Player> players_server;
struct ThreadInfo {
std::thread::id id;
std::string functionName;
bool isRunning;
};
std::vector<ThreadInfo> threadInfos;
bool initSDL();
void handleQuit();
void renderScene(std::vector<Player>& players, const std::vector<Kelp>& kelps, const std::vector<Rock>& rocks, const std::vector<Coral>& corals,Shark& shark );
void cleanup();
void closeGame();
void displayFPS(SDL_Renderer* renderer, TTF_Font* font, int fps);
void displayPlayerCoord(SDL_Renderer* renderer, TTF_Font* font, int playerX, int playerY);
void displayUnifiedPlayerCoord(SDL_Renderer* renderer, TTF_Font* font, int unifiedX, int unifiedY);
void displayPlayerCount(SDL_Renderer* renderer, TTF_Font* font, int playerCount);
void playerMovementThread(Player& player);
void handleClientMessages(Player& player);
void handleQuitThread();
void HandleMenuClick(Menu& menu);
void updateFishRange(std::vector<Fish>& school, int start, int end);
int pas_la_fontion_main_enfin_ce_nest_pas_la_fontion_principale_du_programme_mais_une_des_fonctions_principale_meme_primordiale_du_projet_denomme_bloubloulespoissons(int argc, char* args[]);
int pas_la_fontion_main_enfin_ce_nest_pas_la_fontion_principale_du_programme_mais_une_des_fonctions_principale_meme_primordiale_du_projet_denomme_bloubloulespoissons_mais_celle_ci_elle_lance_en_multijoueur(int argc, std::string args);
void checkThreads();
template <typename Function, typename... Args>
std::thread createThread(std::string key, Function&& func, Args&&... args) {
try {
std::cout << "Creating thread: " << key << std::endl;
std::thread thread([key, func = std::forward<Function>(func), ...args = std::forward<Args>(args)]() mutable {
ThreadInfo info;
info.id = std::this_thread::get_id();
info.functionName = key;
info.isRunning = true;
{
std::lock_guard<std::mutex> lock(mtx);
threadInfos.push_back(info);
}
try {
func(std::forward<Args>(args)...);
} catch (const std::exception& e) {
std::cerr << "Exception in thread " << key << ": " << e.what() << std::endl;
} catch (...) {
std::cerr << "Unknown exception in thread " << key << std::endl;
}
{
std::lock_guard<std::mutex> lock(mtx);
for (auto& threadInfo : threadInfos) {
if (threadInfo.id == std::this_thread::get_id()) {
threadInfo.isRunning = false;
break;
}
}
}
std::cout << "ThreadID = " << info.id << " ThreadFunction = " << info.functionName << " finished" << std::endl;
});
return thread;
} catch (const std::system_error& e) {
std::cerr << "Failed to create thread: " << e.what() << std::endl;
throw;
}
}
void checkThreads() {
std::lock_guard<std::mutex> lock(mtx);
for (const auto& threadInfo : threadInfos) {
if (threadInfo.isRunning) {
std::cout << "Thread " << threadInfo.functionName << " (ID: " << threadInfo.id << ") is still running." << std::endl;
} else {
std::cout << "Thread " << threadInfo.functionName << " (ID: " << threadInfo.id << ") has stopped." << std::endl;
}
}
}
void displayFPS(SDL_Renderer* renderer, TTF_Font* font, int fps) {
std::string fpsText = "FPS: " + std::to_string(fps);
SDL_Color color = {0, 255, 0}; // Green
SDL_Surface* textSurface = TTF_RenderText_Solid(font, fpsText.c_str(), color);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Rect textRect = {windowWidth - textSurface->w - 10, 10, textSurface->w, textSurface->h};
SDL_RenderCopy(renderer, textTexture, nullptr, &textRect);
SDL_FreeSurface(textSurface);
SDL_DestroyTexture(textTexture);
}
void displayPlayerCoord(SDL_Renderer* renderer, TTF_Font* font, int playerX, int playerY) {
Camera& camera = Camera::getInstance();
int cameraX = camera.getX();
int cameraY = camera.getY();
std::string coordText = "Camera: (" + std::to_string(cameraX) + ", " + std::to_string(cameraY) + ")";
std::string coordText2 = "Player: (" + std::to_string(playerX) + ", " + std::to_string(playerY) + ")";
SDL_Color textColor = {0, 255, 0};
SDL_Surface* textSurface = TTF_RenderText_Solid(font, coordText.c_str(), textColor);
SDL_Surface* textSurface2 = TTF_RenderText_Solid(font, coordText2.c_str(), textColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Texture* textTexture2 = SDL_CreateTextureFromSurface(renderer, textSurface2);
SDL_Rect textRect = {10, 30, textSurface->w, textSurface->h};
SDL_Rect textRect2 = {10, 50, textSurface2->w, textSurface2->h};
SDL_RenderCopy(renderer, textTexture, nullptr, &textRect);
SDL_RenderCopy(renderer, textTexture2, nullptr, &textRect2);
SDL_FreeSurface(textSurface);
SDL_FreeSurface(textSurface2);
SDL_DestroyTexture(textTexture);
SDL_DestroyTexture(textTexture2);
}
void displayUnifiedPlayerCoord(SDL_Renderer* renderer, TTF_Font* font, int unifiedX, int unifiedY) {
std::string coordText = "Unified: (" + std::to_string(unifiedX) + ", " + std::to_string(unifiedY) + ")";
SDL_Color textColor = {0, 255, 0};
SDL_Surface* textSurface = TTF_RenderText_Solid(font, coordText.c_str(), textColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Rect textRect = {10, 70, textSurface->w, textSurface->h};
SDL_RenderCopy(renderer, textTexture, nullptr, &textRect);
SDL_FreeSurface(textSurface);
SDL_DestroyTexture(textTexture);
}
void displayPlayerCount(SDL_Renderer* renderer, TTF_Font* font, int playerCount) {
std::string playerCountText = "Player count: " + std::to_string(playerCount);
SDL_Color color = {0, 255, 0}; // Green
SDL_Surface* textSurface = TTF_RenderText_Solid(font, playerCountText.c_str(), color);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Rect textRect = {windowWidth - textSurface->w - 10, 30, textSurface->w, textSurface->h};
SDL_RenderCopy(renderer, textTexture, nullptr, &textRect);
SDL_FreeSurface(textSurface);
SDL_DestroyTexture(textTexture);
}
bool initSDL() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
return false;
}
if (SDLNet_Init() < 0) {
std::cerr << "SDLNet could not initialize! SDLNet_Error: " << SDLNet_GetError() << std::endl;
return false;
}
if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) {
std::cerr << "SDL_mixer could not initialize! SDL_mixer Error: " << Mix_GetError() << std::endl;
return false;
}
window = SDL_CreateWindow("BloubBloub les poissons",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
windowWidth, windowHeight,
SDL_WINDOW_SHOWN);
if (window == nullptr) {
std::cerr << "Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
return false;
}
SDL_Surface* iconSurface = IMG_Load("../img/mory.png");
if(iconSurface == nullptr) {
std::cerr << "Erreur de chargement de l'icône: " << IMG_GetError() << std::endl;
} else {
SDL_SetWindowIcon(window, iconSurface);
SDL_FreeSurface(iconSurface);
}
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (renderer == nullptr) {
std::cerr << "Erreur de création du renderer: " << SDL_GetError() << std::endl;
SDL_DestroyWindow(window);
SDL_Quit();
return false;
}
if (!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG)) {
std::cerr << "SDL_image could not initialize! SDL_image Error: " << IMG_GetError() << std::endl;
return false;
}
if (TTF_Init() == -1) {
std::cerr << "SDL_ttf could not initialize! SDL_ttf Error: " << TTF_GetError() << std::endl;
return false;
}
if (!initEnvironment(renderer)) {
return false;
}
for (int i = 0; i < fishCount; ++i) {
std::string fishTexturePath = "../img/fish/fish" + std::to_string(i) + ".png";
SDL_Surface* fishSurface = IMG_Load(fishTexturePath.c_str());
if (fishSurface == nullptr) {
std::cerr << "Erreur de chargement de l'image du poisson: " << IMG_GetError() << std::endl;
return false;
}
fishTextures[i] = SDL_CreateTextureFromSurface(renderer, fishSurface);
if (fishTextures[i] == nullptr) {
std::cerr << "Erreur de création de la texture du poisson: " << SDL_GetError() << std::endl;
return false;
}
SDL_FreeSurface(fishSurface);
}
texturesVector = initTexture(renderer);
return true;
}
void playerMovementThread(Player& player) {
try {
std::cout << "Starting playerMovementThread for player " << player.getPlayerId() << std::endl;
while (game_running) {
player.handlePlayerMovement(ENV_WIDTH, ENV_HEIGHT, windowWidth, windowHeight);
std::this_thread::sleep_for(std::chrono::milliseconds(16)); // 60 FPS
}
std::cout << "Exiting playerMovementThread for player " << player.getPlayerId() << std::endl;
} catch (const std::exception& e) {
std::cerr << "Exception in playerMovementThread: " << e.what() << std::endl;
}
}
void handleClientMessages(Player& player) {
std::cout << "messageThread started..." << std::endl;
while (messageThreadRunning) {
player.handleClientMessages();
}
std::cout << "messageThread ended" << std::endl;
}
void handleQuitThread() {
std::cout << "handleQuitThread..." << std::endl;
while (game_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
handleQuit();
}
std::cout << "handleQuitThread" << std::endl;
};
void HandleMenuClick(Menu& menu){
try {
@@ -286,24 +52,19 @@ void HandleMenuClick(Menu& menu){
}
}
void updateFishRange(std::vector<Fish>& school, int start, int end){
while (game_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(16));
{
std::lock_guard<std::mutex> lock(mtx);
Fish::insertionSort(school);
}
for (int i = start; i < end; ++i) {
school[i].cycle(i);
}
}
}
void updateShark(Shark &shark) {
while (game_running) {
std::this_thread::sleep_for(std::chrono::milliseconds(16));
shark.cycle();
}
void onPlayerLost(Menu &menu){
//Affiche drawLost par dessus le jeu
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
menu.drawLost(renderer);
SDL_RenderPresent(renderer);
musicManager.playMusic("death");
std::this_thread::sleep_for(std::chrono::seconds(8));
menuRunning = true;
menu.changePage("Main");
musicManager.playMusic("Menu");
menu.show();
resetAll();
}
int main(int argc, char* args[]) {
@@ -315,17 +76,23 @@ int main(int argc, char* args[]) {
return -1;
}
Menu menu(renderer);
menu.addPage("Main");
menu.addPage("Multi");
menu.addPage("Multi-Join");
menu.changePage("Main");
eventHandler.registerEvent("playerLost", onPlayerLost, std::ref(menu));
std::thread menu_thread = createThread("Menu thread", HandleMenuClick, std::ref(menu));
std::thread quit_thread = createThread("Quit thread", handleQuitThread);
menu.addText("Main", (windowWidth/2) - 300, 50, 600, 100, "BloubBloub les poissons", 1024);
menu.addImage("Main", (windowWidth/2) - 100, 150, 200, 200, "../img/logo.png");
menu.addText("Multi-Join", (windowWidth/2) - 100, 50, 200, 100, "Join", 1024);
menu.addButton("Main", (windowWidth/2) - 100, windowHeight/2 - 25, 200, 50, "Solo", 1024, [](){
@@ -399,6 +166,22 @@ int main(int argc, char* args[]) {
//menu.addButton((windowWidth/2) - 100, (windowHeight/2 + 25) + 50, 200, 50, "Multi", 1024);
// menuMusic = Mix_LoadMUS("../sounds/Menu.wav");
// if (menuMusic != nullptr) {
// Mix_VolumeMusic(MIX_MAX_VOLUME / 4);
// if (Mix_PlayMusic(menuMusic, -1) == -1) {
// std::cerr << "Erreur de lecture de la musique du menu: " << Mix_GetError() << std::endl;
// }
// }
musicManager.addMusic("../sounds/Menu.wav", AudioType::MUSIC);
musicManager.addMusic("../sounds/Playing.wav", AudioType::MUSIC);
musicManager.addMusic("../sounds/death.wav", AudioType::SOUND_EFFECT);
musicManager.addMusic("../sounds/Shark-approching.wav", AudioType::SOUND_EFFECT);
musicManager.addMusic("../sounds/shark.wav", AudioType::SOUND_EFFECT);
musicManager.playMusic("Menu");
while (running) {
handleQuit();
@@ -439,394 +222,3 @@ int main(int argc, char* args[]) {
return 0;
}
int pas_la_fontion_main_enfin_ce_nest_pas_la_fontion_principale_du_programme_mais_une_des_fonctions_principale_meme_primordiale_du_projet_denomme_bloubloulespoissons(int argc, char* args[]) {
// if (!initSDL()) {
// std::cerr << "Failed to initialize!" << std::endl;
// return -1;
// }
game_running = true;
std::vector<Kelp> kelps;
std::vector<Rock> rocks;
std::vector<Coral> corals;
generateProceduralDecorations(kelps, rocks, corals, ENV_HEIGHT, ENV_WIDTH, renderer);
freopen("CON", "w", stdout);
freopen("CON", "w", stderr);
for (int i = 0; i < FISH_NUMBER ; ++i) {
school.emplace_back(rand() % ENV_WIDTH, rand() % ENV_HEIGHT, 0.1, 0.1, school, i, 75, 75, renderer, rand() % 2 == 0 ? 1 : 0, fishTextures[rand() % fishCount]);
}
std::ranges::sort(school, Fish::SortByX);
std::vector<std::thread> fish_threads;
int fishPerThread = school.size() / std::thread::hardware_concurrency();
for (int i = 0; i < school.size(); i += fishPerThread) {
fish_threads.emplace_back(createThread("Fish thread", updateFishRange, std::ref(school), i, std::min(i + fishPerThread, static_cast<int>(school.size()))));
}
//std::thread quit_thread = createThread("Quit thread", handleQuitThread);
// Offline
players.emplace_back(Player(windowWidth / 2, windowHeight / 2, 5, renderer, 0));
std::thread player_thread = createThread("Player thread", playerMovementThread, std::ref(players[0]));
Shark shark(0, 0, 0.1, 0.1,0, 150, 150, renderer,players);
std::thread shark_thread = createThread("Shark thread",updateShark, std::ref(shark));
while (game_running) {
renderScene(players, kelps, rocks, corals, shark);
//handleQuit();
}
try{
if(player_thread.joinable()){
std::cout << "Killing playerThread.." << std::endl;
player_thread.join();
}
}catch(const std::system_error& e){
std::cerr << "Exception caught 1: " << e.what() << std::endl;
}
try {
std::cout << "Killing fish_threads..." << std::endl;
for (auto& fish_thread : fish_threads) {
if (fish_thread.joinable())
fish_thread.join();
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 4: " << e.what() << std::endl;
}
try {
if (shark_thread.joinable()){
std::cout << "Killing shark_thread..." << std::endl;
shark_thread.join();
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 5: " << e.what() << std::endl;
}
std::cout << "All threads killed" << std::endl;
running = false;
return 0;
}
int pas_la_fontion_main_enfin_ce_nest_pas_la_fontion_principale_du_programme_mais_une_des_fonctions_principale_meme_primordiale_du_projet_denomme_bloubloulespoissons_mais_celle_ci_elle_lance_en_multijoueur(int argc, std::string args) {
// if (!initSDL()) {
// std::cerr << "Failed to initialize!" << std::endl;
// return -1;
// }
game_running = true;
std::vector<Kelp> kelps;
std::vector<Rock> rocks;
std::vector<Coral> corals;
generateProceduralDecorations(kelps, rocks, corals, ENV_HEIGHT, ENV_WIDTH, renderer);
for (int i = 0; i < FISH_NUMBER; ++i) {
school.emplace_back(Fish(rand() % ENV_WIDTH, rand() % ENV_HEIGHT, 0.1, 0.1, school, i, 75, 75, renderer, rand() % 2 == 0 ? 1 : 0, fishTextures[rand() % fishCount]));
}
std::cout << "Thread: " << std::thread::hardware_concurrency() << std::endl;
std::vector<std::thread> threads;
int fishPerThread = school.size() / std::thread::hardware_concurrency();
int thread_id = 0;
for (int i = 0; i < school.size(); i += fishPerThread) {
threads.emplace_back(createThread("Fish thread", updateFishRange, std::ref(school), i, std::min(i + fishPerThread, static_cast<int>(school.size()))));
}
Shark shark(0, 0, 0.1, 0.1,0, 150, 150, renderer,players);
std::thread shark_thread = createThread("Shark", updateShark, std::ref(shark));
freopen("CON", "w", stdout);
freopen("CON", "w", stderr);
if (isPlayingOnline) {
if (argc == 0 && args == "") {
if (!initServer()) {
std::cerr << "Failed to initialize server!" << std::endl;
return -1;
}
isHost = true;
std::cout << "isHost: " << isHost << std::endl;
std::thread acceptThread = createThread("Accept thread", acceptClients);
IPaddress ip;
if (!initClient(ip, "localhost", 1234)) {
std::cerr << "Failed to initialize client!" << std::endl;
return -1;
}
players.emplace_back(Player(windowWidth / 2, windowHeight / 2, 5, renderer, 0));
std::ranges::sort(school, Fish::SortByX);
std::vector<std::thread> fish_threads;
int fishPerThread = school.size() / std::thread::hardware_concurrency();
for (int i = 0; i < school.size(); i += fishPerThread) {
fish_threads.emplace_back(createThread("Fish thread", updateFishRange, std::ref(school), i, std::min(i + fishPerThread, static_cast<int>(school.size()))));
}
messageThreadRunning = true;
std::thread messageThread = createThread("Message thread", handleClientMessages, std::ref(players[0]));
std::thread playerThread = createThread("Player thread", playerMovementThread, std::ref(players[0]));
while (game_running) {
renderScene(players, kelps, rocks, corals,shark);
SDL_Delay(10);
}
messageThreadRunning = false;
try{
//if(playerThread.joinable())
std::cout << "Killing playerThread.." << std::endl;
playerThread.join();
std::cout << "playerThread killed" << std::endl;
}catch(const std::system_error& e){
std::cerr << "Exception caught 1: " << e.what() << std::endl;
}
try {
for (auto& fish_thread : fish_threads) {
if (fish_thread.joinable())
fish_thread.join();
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 2: " << e.what() << std::endl;
}
for (auto& thread : threads) {
try {
std::cout << "Killing thread..." << std::endl;
thread.join();
std::cout << "Thread killed" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Exception caught 3: " << e.what() << std::endl;
}
}
try {
//if (messageThread.joinable())
closeClient();
std::cout << "Killing messageThread" << std::endl;
messageThread.join();
std::cout << "messageThread killed" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Exception caught 4: " << e.what() << std::endl;
}
try {
if (acceptThread.joinable()){
std::cout << "Killing acceptThread" << std::endl;
acceptThread.join();
std::cout << "acceptThread killed" << std::endl;
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 5: " << e.what() << std::endl;
}
running = false;
}
else if (argc > 0 && argc < 65535 && args != "") {
int port = 1234;
std::string host = args;
if (!initClient(ip, host.c_str(), 1234)) {
std::cerr << "Failed to initialize client!" << std::endl;
return -1;
}
players.emplace_back(Player(windowWidth / 2, windowHeight / 2, 5, renderer, 1));
std::ranges::sort(school, Fish::SortByX);
std::vector<std::thread> fish_threads;
int fishPerThread = school.size() / std::thread::hardware_concurrency();
for (int i = 0; i < school.size(); i += fishPerThread) {
fish_threads.emplace_back(createThread("Fish thread", updateFishRange, std::ref(school), i, std::min(i + fishPerThread, static_cast<int>(school.size()))));
}
messageThreadRunning = true;
std::thread messageThread = createThread("Message thread", handleClientMessages, std::ref(players[0]));
std::thread playerThread = createThread("Player thread", playerMovementThread, std::ref(players[0]));
while (running) {
renderScene(players, kelps, rocks, corals,shark);
SDL_Delay(10);
}
messageThreadRunning = false;
try{
//if(playerThread.joinable())
std::cout << "Killing playerThread.." << std::endl;
playerThread.join();
std::cout << "playerThread killed" << std::endl;
}catch(const std::system_error& e){
std::cerr << "Exception caught 1: " << e.what() << std::endl;
}
try {
for (auto& fish_thread : fish_threads) {
if (fish_thread.joinable())
fish_thread.join();
}
} catch (const std::system_error& e) {
std::cerr << "Exception caught 2: " << e.what() << std::endl;
}
for (auto& thread : threads) {
try {
std::cout << "Killing thread..." << std::endl;
thread.join();
std::cout << "Thread killed" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Exception caught 3: " << e.what() << std::endl;
}
}
try {
//if (messageThread.joinable())
closeClient();
std::cout << "Killing messageThread" << std::endl;
messageThread.join();
std::cout << "messageThread killed" << std::endl;
} catch (const std::system_error& e) {
std::cerr << "Exception caught 4: " << e.what() << std::endl;
}
running = false;
}
}
return 0;
}
void handleQuit() {
SDL_Event event;
const Uint8* keystate = SDL_GetKeyboardState(NULL);
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
if (isPlayingOnline && isHost) {
closeServer();
}
game_running = false;
}
}
if (keystate[SDL_SCANCODE_ESCAPE]) {
if (isPlayingOnline && isHost) {
closeServer();
}
game_running = false;
}
}
void renderScene(std::vector<Player>& players, const std::vector<Kelp>& kelps, const std::vector<Rock>& rocks, const std::vector<Coral>& corals,Shark& shark) {
static Uint32 lastTime = 0;
static int frameCount = 0;
static int fps = 0;
//std::cout << "renderScene for " << players.size() << " players" << std::endl;
const Uint32 currentTime = SDL_GetTicks64();
frameCount++;
if (currentTime - lastTime >= 1000) {
fps = frameCount;
frameCount = 0;
lastTime = currentTime;
}
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
Camera& camera = Camera::getInstance();
SDL_Rect backgroundRect = { -camera.getX(), -camera.getY(), ENV_WIDTH, ENV_HEIGHT };
SDL_RenderCopy(renderer, backgroundTexture, nullptr, &backgroundRect);
for (const auto& kelp : kelps) {
kelp.draw(renderer);
}
for (const auto& rock : rocks) {
rock.draw(renderer);
}
for (const auto& coral : corals) {
coral.draw(renderer);
}
for (Fish& fish : school) {
fish.draw(renderer);
}
for (auto& player : players) {
player.draw(renderer);
}
shark.draw(renderer);
displayFPS(renderer, font, fps);
SDL_RenderPresent(renderer);
}
void cleanup() {
try {
if (font != nullptr) {
TTF_CloseFont(font);
font = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for CloseFont: " << e.what() << std::endl;
}
try {
TTF_Quit();
} catch (const std::exception& e) {
std::cerr << "Exception caught for TTF_Quit: " << e.what() << std::endl;
}
try {
if (playerTexture != nullptr) {
SDL_DestroyTexture(playerTexture);
playerTexture = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for DestroyTexture (playerTexture): " << e.what() << std::endl;
}
for (int i = 0; i < fishCount; ++i) {
try {
if (fishTextures[i] != nullptr) {
SDL_DestroyTexture(fishTextures[i]);
fishTextures[i] = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for DestroyTexture (fishTextures[" << i << "]): " << e.what() << std::endl;
}
}
try {
if (renderer != nullptr) {
SDL_DestroyRenderer(renderer);
renderer = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for DestroyRenderer: " << e.what() << std::endl;
}
try {
if (window != nullptr) {
SDL_DestroyWindow(window);
window = nullptr;
}
} catch (const std::exception& e) {
std::cerr << "Exception caught for DestroyWindow: " << e.what() << std::endl;
}
try {
IMG_Quit();
} catch (const std::exception& e) {
std::cerr << "Exception caught for IMG_Quit: " << e.what() << std::endl;
}
try {
SDLNet_Quit();
} catch (const std::exception& e) {
std::cerr << "Exception caught for SDLNet_Quit: " << e.what() << std::endl;
}
try {
Mix_CloseAudio();
} catch (const std::exception& e) {
std::cerr << "Exception caught for Mix_CloseAudio: " << e.what() << std::endl;
}
try {
SDL_Quit();
} catch (const std::exception& e) {
std::cerr << "Exception caught for SDL_Quit: " << e.what() << std::endl;
}
}

170
menu.cpp
View File

@@ -1,170 +0,0 @@
#include "menu.h"
void Menu::draw(SDL_Renderer* renderer){
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, backgroundTxt, nullptr, &backgroundRect);
if(pages.size() > 0){
if(currentPage == -1 && pages.size() > 0){
currentPage = 0;
}
for(Text& text : pages[currentPage].texts){
SDL_RenderCopy(renderer, text.txt, nullptr, &text.rect);
}
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
bool hover = false;
for(Button& button : pages[currentPage].buttons){
SDL_SetRenderDrawColor(renderer, button.bgColor.r, button.bgColor.g, button.bgColor.b, button.bgColor.a);
SDL_RenderFillRect(renderer, &button.rect);
SDL_RenderCopy(renderer, button.txt, nullptr, &button.txtRect);
if (button.isTextInput) {
// Afficher le texte saisi
TTF_Font* font_txt = TTF_OpenFont("../fonts/arial.ttf", 24);
SDL_Surface* textSurface = TTF_RenderText_Solid(font_txt, button.inputText.c_str(), button.fontColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_Rect inputRect = {button.rect.x + 5, button.rect.y + 5, button.rect.w - 10, button.rect.h - 10};
SDL_RenderCopy(renderer, textTexture, nullptr, &inputRect);
SDL_FreeSurface(textSurface);
SDL_DestroyTexture(textTexture);
TTF_CloseFont(font_txt);
}
if (mouseX >= button.rect.x && mouseX <= button.rect.x + button.rect.w &&
mouseY >= button.rect.y && mouseY <= button.rect.y + button.rect.h) {
hover = true;
}
}
if (hover) {
SDL_Cursor* cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
SDL_SetCursor(cursor);
} else {
SDL_Cursor* cursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
SDL_SetCursor(cursor);
}
}
SDL_RenderPresent(renderer);
}
void Menu::handleClickedButton(){
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_MOUSEBUTTONDOWN) {
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
activeTextInputIndex = -1;
for (int i = 0; i < pages[currentPage].buttons.size(); ++i) {
Button& button = pages[currentPage].buttons[i];
if (mouseX >= button.rect.x && mouseX <= button.rect.x + button.rect.w &&
mouseY >= button.rect.y && mouseY <= button.rect.y + button.rect.h) {
if (button.isTextInput) {
// Activer le champ de texte
SDL_StartTextInput();
activeTextInputIndex = i; // Mettre à jour l'élément de texte actif
} else {
button.callback();
}
}
}
}else if (event.type == SDL_TEXTINPUT) {
if (activeTextInputIndex != -1) {
Button& button = pages[currentPage].buttons[activeTextInputIndex];
if (button.isTextInput) {
button.inputText += event.text.text;
}
}
} else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_BACKSPACE) {
if (activeTextInputIndex != -1) {
Button& button = pages[currentPage].buttons[activeTextInputIndex];
if (button.isTextInput && !button.inputText.empty()) {
button.inputText.pop_back();
}
}
}
}
}
void Menu::hide(){
shown = false;
}
void Menu::show(){
shown = true;
}
bool Menu::isShown(){
return shown;
}
void Menu::changePage(std::string title){
for(int i = 0; i < pages.size(); i++){
if(pages[i].title == title){
currentPage = i;
}
}
}
void Menu::addButton(std::string page, int x, int y, int w, int h, std::string text, int size, std::function<void()> callback, bool isTextInput){
for(Page& p : pages){
if(p.title == page){
TTF_Font* font_txt = TTF_OpenFont("../fonts/arial.ttf", size);
if (font_txt == nullptr) {
std::cerr << "Erreur de chargement de la police: " << TTF_GetError() << std::endl;
}
Button button;
button.rect = {x, y, w, h};
int textWidth = w/2;
int textHeight = h/1.5;
button.txtRect = {x + (w/2) - (textWidth/2), y + (h/2) - (textHeight/2), textWidth, textHeight};
button.fontColor = {255, 255, 255};
button.bgColor = {0, 0, 255, 255};
button.isTextInput = isTextInput;
SDL_Surface* textSurface = TTF_RenderText_Solid(font_txt, text.c_str(), button.fontColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_FreeSurface(textSurface);
button.txt = textTexture;
button.callback = callback;
p.buttons.push_back(button);
TTF_CloseFont(font_txt);
}
}
}
void Menu::addText(std::string page, int x, int y, int w, int h, std::string text, int size){
for(Page& p : pages){
if(p.title == page){
TTF_Font* font_txt = TTF_OpenFont("../fonts/arial.ttf", size);
if (font_txt == nullptr) {
std::cerr << "Erreur de chargement de la police: " << TTF_GetError() << std::endl;
}
Text txt;
txt.rect = {x, y, w, h};
txt.fontColor = {255, 255, 255};
txt.txtRect = {x, y, w, h};
SDL_Surface* textSurface = TTF_RenderText_Solid(font_txt, text.c_str(), txt.fontColor);
SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
SDL_FreeSurface(textSurface);
txt.txt = textTexture;
p.texts.push_back(txt);
TTF_CloseFont(font_txt);
}
}
}
void Menu::addPage(std::string title){
Page page;
page.title = title;
pages.push_back(page);
}
std::vector<Button> Menu::getButtons(){
return pages[currentPage].buttons;
}

1
resource.rc Normal file
View File

@@ -0,0 +1 @@
IDI_ICON1 ICON "../img/logo.ico"

BIN
sounds/Menu.wav Normal file

Binary file not shown.

BIN
sounds/Playing.wav Normal file

Binary file not shown.

BIN
sounds/Shark-approching.wav Normal file

Binary file not shown.

BIN
sounds/death.wav Normal file

Binary file not shown.

Binary file not shown.

25
xxd_convert.sh Normal file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
# Vérifie si un argument de dossier est fourni
if [ $# -ne 1 ]; then
echo "Usage: $0 <dossier>"
exit 1
fi
# Vérifie si le dossier existe
DIR=$1
if [ ! -d "$DIR" ]; then
echo "Erreur : Le dossier '$DIR' n'existe pas."
exit 1
fi
# Parcourt tous les fichiers .png du dossier et sous-dossiers
find "$DIR" -type f -name "*.ttf" | while read -r file; do
# Récupère le nom du fichier sans extension
base_name=$(basename "$file" .ttf)
# Définit le nom de sortie avec extension .h
output_file="${file%/*}/${base_name}.h"
# Exécute la commande xxd -i
xxd -i "$file" > "$output_file"
echo "Converti : $file -> $output_file"
done