Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ NAME = nibbler_client
CC = c++
CFLAGS = -O2 -Wall -Wextra -std=c++17 -pthread
FSANITIZE = -fsanitize=thread
SOURCES_M := src/main.cpp src/Client.cpp src/Drawer.cpp
SOURCES_M := src/main.cpp src/Client.cpp src/Drawer.cpp src/EventManager.cpp

OBJECTS := $(SOURCES_M:.cpp=.o)

Expand Down
4 changes: 4 additions & 0 deletions client/assets.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
assets/body.png
assets/head.png
assets/food.png

54 changes: 48 additions & 6 deletions client/includes/nibbler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <signal.h>
#include <unistd.h>
#include <cstdlib>
#include <cstdint>

#define TILE_SIZE 0.05f
#define SCALE 20.0f
Expand Down Expand Up @@ -47,17 +48,58 @@ enum actions
KEY_3
};

struct rgb
{
float r;
float g;
float b;
};

// Created to accommodate sf::Vector2i from SFML
// Graphics-agnostic 2D integer vector for window size and mouse position
struct Vec2i {
int x;
int y;
};

enum type {
KEY,
MOUSE,
EXIT,
EMPTY
// Old types (removed, kept for reference):
// KEY, // Replaced by KEY_PRESSED/KEY_RELEASED
// MOUSE, // Replaced by MOUSE_BUTTON_PRESSED/MOUSE_BUTTON_RELEASED
// EXIT, // Replaced by CLOSED

// Match EventManager's EventType enum
CLOSED = 0, // Window closed (was EXIT)
RESIZED = 1, // Window resized
FOCUS_LOST = 2, // Window lost focus
FOCUS_GAINED = 3, // Window gained focus
TEXT_ENTERED = 4, // Text input
KEY_PRESSED = 5, // Key pressed (was KEY)
KEY_RELEASED = 6, // Key released
MOUSE_WHEEL_SCROLLED = 7, // Mouse wheel scrolled
MOUSE_BUTTON_PRESSED = 8, // Mouse button pressed (was MOUSE)
MOUSE_BUTTON_RELEASED = 9, // Mouse button released
MOUSE_MOVED = 10, // Mouse moved
MOUSE_MOVED_RAW = 11, // Mouse moved (raw)
MOUSE_ENTERED = 12, // Mouse entered window
MOUSE_LEFT = 13, // Mouse left window
EMPTY = 99 // No event (used by graphics libraries for polling)
};

typedef struct s_event {
type type;
int a;
int b;
union {
int keyCode; // When type == KEY_PRESSED/KEY_RELEASED: key code (UP, DOWN, LEFT, RIGHT, M, N, KEY_1, KEY_2, KEY_3)
struct {
int x, y; // When type == MOUSE_*: mouse coordinates
int button; // When type == MOUSE_BUTTON_*: button code (0=left, 1=right, 2=middle)
} mouse;
struct {
int width, height; // When type == RESIZED: new window dimensions
} window;
int wheelDelta; // When type == MOUSE_WHEEL_SCROLLED: scroll delta
std::uint32_t unicode; // When type == TEXT_ENTERED: unicode character
};
} t_event;

typedef void *(*initFunc)(int, int, void *);
Expand Down
18 changes: 18 additions & 0 deletions client/keys.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Window_close 0:0
Fullscreen_toggle 5:89
Move 21:0 20:38
Intro_Continue 5:57
Mouse_Left 9:0
Key_Escape 5:36
Key_P 5:15
Key_Up 5:73
Key_Down 5:74
Key_Left 5:71
Key_Right 5:72
Key_W 5:22
Key_A 5:0
Key_S 5:18
Key_D 5:3
Key_M 5:12
Key_N 5:13

11 changes: 11 additions & 0 deletions client/src/BaseState.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "BaseState.hpp"

// BaseState implementation is empty - all methods are pure virtual
// or have inline implementations in the header







39 changes: 39 additions & 0 deletions client/src/BaseState.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include <SFML/Graphics.hpp>

class StateManager;

class BaseState {
friend class StateManager;
public:
BaseState(StateManager* l_stateManager)
: m_stateMgr(l_stateManager), m_transparent(false),
m_transcendent(false) {}
virtual ~BaseState() {}

virtual void OnCreate() = 0;
virtual void OnDestroy() = 0;
virtual void Activate() = 0;
virtual void Deactivate() = 0;
virtual void Update(const sf::Time& l_time) = 0;
virtual void Draw() = 0;

void SetTransparent(const bool& l_transparent) {
m_transparent = l_transparent;
}
bool IsTransparent() const { return m_transparent; }

void SetTranscendent(const bool& l_transcendence) {
m_transcendent = l_transcendence;
}
bool IsTranscendent() const { return m_transcendent; }

StateManager* GetStateManager() { return m_stateMgr; }

protected:
StateManager* m_stateMgr;
bool m_transparent;
bool m_transcendent;
};

174 changes: 140 additions & 34 deletions client/src/Drawer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Drawer.hpp"
#include "EventManager.hpp"

#define WIDTH 1000
#define HEIGHT 1000
Expand All @@ -11,6 +12,29 @@ multiplayerButton{400, 300, 200, 60, "Multiplayer", Button::MULTIPLAYER},
singlePlayerButton{400, 400, 200, 60, "Single-player", Button::SINGLE_PLAYER}
{
tilePx = std::max(1, std::min(WIDTH / screenSize, HEIGHT / screenSize));

// Initialize EventManager
eventManager = new EventManager();

// Register movement callbacks (arrow keys and WASD) - only active in Game state
eventManager->AddCallback(StateType::Game, "Key_Up", &Drawer::MoveUp, this);
eventManager->AddCallback(StateType::Game, "Key_Down", &Drawer::MoveDown, this);
eventManager->AddCallback(StateType::Game, "Key_Left", &Drawer::MoveLeft, this);
eventManager->AddCallback(StateType::Game, "Key_Right", &Drawer::MoveRight, this);
eventManager->AddCallback(StateType::Game, "Key_W", &Drawer::MoveUp, this);
eventManager->AddCallback(StateType::Game, "Key_A", &Drawer::MoveLeft, this);
eventManager->AddCallback(StateType::Game, "Key_S", &Drawer::MoveDown, this);
eventManager->AddCallback(StateType::Game, "Key_D", &Drawer::MoveRight, this);

// Register zoom callbacks
eventManager->AddCallback(StateType::Game, "Key_M", &Drawer::ZoomIn, this);
eventManager->AddCallback(StateType::Game, "Key_N", &Drawer::ZoomOut, this);

// Register mouse callback - only active in Menu state (not during gameplay)
eventManager->AddCallback(StateType::MainMenu, "Mouse_Left", &Drawer::OnMouseClick, this);

// Set initial state to Menu (since we start with the menu)
eventManager->SetCurrentState(StateType::MainMenu);

assets = (char **)malloc(sizeof(char *) * 4);
assets[0] = strdup("assets/body.png");
Expand All @@ -21,6 +45,7 @@ singlePlayerButton{400, 400, 200, 60, "Single-player", Button::SINGLE_PLAYER}

Drawer::~Drawer()
{
delete eventManager;
this->closeDynamicLib();

for (int i = 0; assets[i]; ++i)
Expand Down Expand Up @@ -95,19 +120,27 @@ void Drawer::start()
this->beginFrame(this->window);

t_event event = this->checkEvents(this->window);
switch (event.type)
{
case EXIT:
gameRunning = false;
break;
case KEY:
onKeyPress(event.a);
break;
case MOUSE:
onMouseUp(event.a, event.b);
break;
default:
break;

// Debug: log all events
if (event.type != EMPTY) {
std::cout << "[Drawer] Event received: type=" << static_cast<int>(event.type);
if (event.type == MOUSE_BUTTON_PRESSED || event.type == MOUSE_BUTTON_RELEASED) {
std::cout << " mouse button=" << event.mouse.button << " at (" << event.mouse.x << ", " << event.mouse.y << ")";
} else if (event.type == KEY_PRESSED || event.type == KEY_RELEASED) {
std::cout << " keyCode=" << event.keyCode;
}
std::cout << std::endl;
}

// Handle CLOSED event directly
if (event.type == CLOSED) {
gameRunning = false;
}

// Pass event to EventManager (only if not EMPTY)
if (event.type != EMPTY) {
eventManager->HandleEvent(event);
eventManager->Update();
}

if (this->gameMode == GAME)
Expand Down Expand Up @@ -250,44 +283,117 @@ void Drawer::onMouseUp(float x, float y)
std::cout << " - Starting local server";
std::cout << std::endl;

this->client->setIsDead(false);
this->client->setStopFlag(false);
this->client->setIsDead(false);
this->client->setStopFlag(false);
this->clientThread = std::thread(&Client::start, this->client, serverIP, isSinglePlayer);
this->gameMode = GAME;
eventManager->SetCurrentState(StateType::Game);
}
}

void Drawer::onKeyPress(int key)
// Old onKeyPress - kept for reference, replaced by EventManager callbacks
// void Drawer::onKeyPress(int key)
// {
// actions action = (actions)key;
//
// switch (action)
// {
// case UP:
// case DOWN:
// case RIGHT:
// case LEFT:
// this->client->sendDirection(action);
// break;
// case M:
// this->screenSize = this->screenSize * 1.10 + 0.5;
// this->tilePx = std::max(1, std::min(WIDTH / screenSize, HEIGHT / screenSize));
// break;
// case N:
// this->screenSize = this->screenSize / 1.10;
// this->tilePx = std::max(1, std::min(WIDTH / screenSize, HEIGHT / screenSize));
// break;
// case KEY_1:
// this->switchLibPath = "../libs/lib1/lib1";
// this->gameRunning = false;
// break;
// case KEY_2:
// this->switchLibPath = "../libs/lib2/lib2";
// this->gameRunning = false;
// break;
// case KEY_3:
// this->switchLibPath = "../libs/lib4/lib3";
// this->gameRunning = false;
// break;
// }
// }

// EventManager callbacks
void Drawer::MoveUp(EventDetails* l_details)
{
actions action = (actions)key;
(void)l_details; // Unused, but required by callback signature
this->client->sendDirection(UP);
}

switch (action)
void Drawer::MoveDown(EventDetails* l_details)
{
case UP:
case DOWN:
case RIGHT:
case LEFT:
this->client->sendDirection(action);
break;
case M:
(void)l_details;
this->client->sendDirection(DOWN);
}

void Drawer::MoveLeft(EventDetails* l_details)
{
(void)l_details;
this->client->sendDirection(LEFT);
}

void Drawer::MoveRight(EventDetails* l_details)
{
(void)l_details;
this->client->sendDirection(RIGHT);
}

void Drawer::ZoomIn(EventDetails* l_details)
{
(void)l_details;
this->screenSize = this->screenSize * 1.10 + 0.5;
this->tilePx = std::max(1, std::min(WIDTH / screenSize, HEIGHT / screenSize));
break;
case N:
}

void Drawer::ZoomOut(EventDetails* l_details)
{
(void)l_details;
this->screenSize = this->screenSize / 1.10;
this->tilePx = std::max(1, std::min(WIDTH / screenSize, HEIGHT / screenSize));
break;
case KEY_1:
}

void Drawer::SwitchLib1(EventDetails* l_details)
{
(void)l_details;
this->switchLibPath = "../libs/lib1/lib1";
this->gameRunning = false;
break;
case KEY_2:
}

void Drawer::SwitchLib2(EventDetails* l_details)
{
(void)l_details;
this->switchLibPath = "../libs/lib2/lib2";
this->gameRunning = false;
break;
case KEY_3:
}

void Drawer::SwitchLib3(EventDetails* l_details)
{
(void)l_details;
this->switchLibPath = "../libs/lib4/lib3";
this->gameRunning = false;
break;
}

void Drawer::OnMouseClick(EventDetails* l_details)
{
// Only process mouse clicks when in menu mode
if (this->gameMode != MENU) {
return;
}
std::cout << "[Drawer::OnMouseClick] Mouse clicked at (" << l_details->m_mouse.x << ", " << l_details->m_mouse.y << ")" << std::endl;
// Extract mouse coordinates from EventDetails
onMouseUp(l_details->m_mouse.x, l_details->m_mouse.y);
}
Loading