mirror of
https://github.com/BreizhHardware/bloubloulespoissons.git
synced 2026-01-19 09:07:33 +01:00
Compare commits
54 Commits
Random-spa
...
Refactor
| Author | SHA1 | Date | |
|---|---|---|---|
| 7cf0253d30 | |||
| cfc15cdb2c | |||
|
|
c2d786c151 | ||
|
|
2ea9c91cf1 | ||
| 38dbf78a7c | |||
| 75e44df256 | |||
| 1343fe01e7 | |||
| 7d11ece61b | |||
| 5ca2cae04e | |||
| d5658422f9 | |||
|
|
23db970f42 | ||
| 23f88b2a50 | |||
|
|
e42e4061b4 | ||
|
|
439c338380 | ||
| 096d1f0aa2 | |||
|
|
ca20c3e1bd | ||
|
|
f0b0334ff8 | ||
| dec3ab3aff | |||
| 1845c2f1c9 | |||
| 44bff8bbd8 | |||
|
|
44943caaa1 | ||
| 9f0ae6ac54 | |||
| 294d7503ed | |||
| bec39bbe3d | |||
|
|
6691c70d43 | ||
|
|
f7bb656436 | ||
| 82802cd33f | |||
|
|
beeb5fd187 | ||
|
|
558e2d9b36 | ||
|
|
46ca27705e | ||
|
|
742830def8 | ||
|
|
3cc095454e | ||
|
|
d12e6fbe60 | ||
|
|
fd1e4b9ba2 | ||
|
|
3267ddb97f | ||
|
|
1ebf2b2fdf | ||
| dd2c5c00c7 | |||
|
|
4f199389f0 | ||
|
|
40b70d6ce6 | ||
|
|
b9e8b32765 | ||
|
|
037a05b106 | ||
| 23a54cc9d5 | |||
|
|
fd070bb30f | ||
|
|
d691c6af62 | ||
| 797e148f22 | |||
|
|
081272f64f | ||
|
|
03737d9c3c | ||
| cf93e05955 | |||
|
|
4fddc26d91 | ||
|
|
cea9007684 | ||
| 566e066bdc | |||
|
|
682963e886 | ||
| 7d1ca2196b | |||
|
|
cbcc468fad |
20
.github/release-drafter.yml
vendored
Normal file
20
.github/release-drafter.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
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: 'next'
|
||||
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@@ -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
80
.github/workflows/release.yaml
vendored
Normal 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
2
.gitignore
vendored
@@ -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/
|
||||
|
||||
@@ -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()
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
@@ -172,7 +167,7 @@ void Player::drawEnergyBar(SDL_Renderer* renderer) {
|
||||
SDL_RenderFillRect(renderer, &energyBarForeground);
|
||||
}
|
||||
|
||||
int Player::getPlayerId() {
|
||||
int Player::getPlayerId() const {
|
||||
return playerId;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
//
|
||||
|
||||
#include "decors.h"
|
||||
#include <iostream>
|
||||
|
||||
#include "env.h"
|
||||
|
||||
void Rock::draw(SDL_Renderer* renderer) const{
|
||||
Camera& camera = Camera::getInstance();
|
||||
@@ -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
195
Game/launchGameMulti.cpp
Normal 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
20
Game/launchGameMulti.h
Normal 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
103
Game/launchGameSolo.cpp
Normal 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, 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;
|
||||
school.clear();
|
||||
players.clear();
|
||||
eventHandler.triggerEvent("playerLost");
|
||||
return 0;
|
||||
}
|
||||
20
Game/launchGameSolo.h
Normal file
20
Game/launchGameSolo.h
Normal 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
328
Game/menu.cpp
Normal 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, ¢er);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
66
README.md
66
README.md
@@ -1,8 +1,64 @@
|
||||
# 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
|
||||
- `SDL3-2.0` : La branche pour la version SDL3 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/)
|
||||
|
||||
## Lancement avec la binaire
|
||||
1. Téléchargez la dernière version de l'application
|
||||
```bash
|
||||
https://github.com/BreizhHardware/bloubloulespoissons/releases
|
||||
```
|
||||
2. Executez le fichier .exe
|
||||
|
||||
3. Jouez
|
||||
|
||||
## 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
147
Utility/close.cpp
Normal 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
21
Utility/close.h
Normal 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
|
||||
@@ -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);
|
||||
@@ -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) {
|
||||
@@ -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
34
Utility/event.h
Normal 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
192
Utility/music.h
Normal 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
253
Utility/utility.cpp
Normal 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
81
Utility/utility.h
Normal 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
|
||||
BIN
img/logo.ico
Normal file
BIN
img/logo.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 116 KiB |
BIN
img/logo.png
Normal file
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
BIN
img/perdu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
708
main.cpp
708
main.cpp
@@ -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
170
menu.cpp
@@ -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
1
resource.rc
Normal file
@@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON "../img/logo.ico"
|
||||
BIN
sounds/Menu.wav
Normal file
BIN
sounds/Menu.wav
Normal file
Binary file not shown.
BIN
sounds/Playing.wav
Normal file
BIN
sounds/Playing.wav
Normal file
Binary file not shown.
BIN
sounds/Shark-approching.wav
Normal file
BIN
sounds/Shark-approching.wav
Normal file
Binary file not shown.
BIN
sounds/death.wav
Normal file
BIN
sounds/death.wav
Normal file
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user