mirror of
https://github.com/zhenyan121/SporeBG-Conid.git
synced 2026-04-10 06:14:08 +08:00
feat: add online functionality
This commit is contained in:
@@ -18,6 +18,7 @@ enum class GameState {
|
|||||||
GAME_RUNING, // 游戏进行中
|
GAME_RUNING, // 游戏进行中
|
||||||
GAME_LOSE, // 游戏失败
|
GAME_LOSE, // 游戏失败
|
||||||
GAME_WIN, // 游戏胜利
|
GAME_WIN, // 游戏胜利
|
||||||
|
GAME_PREGAME // 游戏未开始
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class GameMode {
|
enum class GameMode {
|
||||||
|
|||||||
@@ -247,10 +247,10 @@ void TextRenderer::autoCleanCache(size_t keepKey) {
|
|||||||
|
|
||||||
// 计算需要删除的数量
|
// 计算需要删除的数量
|
||||||
size_t itemsToRemove = m_cache.size() - MIN_CACHE_SIZE;
|
size_t itemsToRemove = m_cache.size() - MIN_CACHE_SIZE;
|
||||||
|
/*
|
||||||
SDL_Log("缓存清理:删除 %zu / %zu 条目(当前缓存大小:%zu)\n",
|
SDL_Log("缓存清理:删除 %zu / %zu 条目(当前缓存大小:%zu)\n",
|
||||||
itemsToRemove, m_cache.size(), m_cache.size());
|
itemsToRemove, m_cache.size(), m_cache.size());
|
||||||
|
*/
|
||||||
// 删除最旧的缓存项
|
// 删除最旧的缓存项
|
||||||
for (size_t i = 0; i < itemsToRemove && i < cacheItems.size(); ++i) {
|
for (size_t i = 0; i < itemsToRemove && i < cacheItems.size(); ++i) {
|
||||||
|
|
||||||
@@ -262,5 +262,5 @@ void TextRenderer::autoCleanCache(size_t keepKey) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_Log("缓存清理完成,当前缓存大小:%zu\n", m_cache.size());
|
//SDL_Log("缓存清理完成,当前缓存大小:%zu\n", m_cache.size());
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,34 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
enum class NetDataType {
|
||||||
|
CLICK_POSITION,
|
||||||
|
GAME_START
|
||||||
|
};
|
||||||
|
|
||||||
struct NetData {
|
struct NetData {
|
||||||
std::pair<int, int> clickPosition = {0, 0};
|
std::pair<int, int> clickPosition = {0, 0};
|
||||||
|
int firstPlayer = 1;
|
||||||
|
NetDataType type = NetDataType::CLICK_POSITION;
|
||||||
// 序列化,转换成字节数组
|
// 序列化,转换成字节数组
|
||||||
void serialize(char* buffer) const {
|
void serialize(char* buffer) const {
|
||||||
// 暴力转换
|
// 暴力转换
|
||||||
int* ptr = reinterpret_cast<int*>(buffer);
|
int* ptr = reinterpret_cast<int*>(buffer);
|
||||||
ptr[0] = clickPosition.first;
|
|
||||||
ptr[1] = clickPosition.second;
|
ptr[0] = static_cast<int>(type);
|
||||||
|
ptr[1] = clickPosition.first;
|
||||||
|
ptr[2] = clickPosition.second;
|
||||||
|
ptr[3] = firstPlayer;
|
||||||
}
|
}
|
||||||
// 反序列化,从字节数组恢复
|
// 反序列化,从字节数组恢复
|
||||||
static NetData deserialize(const char* buffer) {
|
static NetData deserialize(const char* buffer) {
|
||||||
// 暴力转换
|
// 暴力转换
|
||||||
const int* ptr = reinterpret_cast<const int*>(buffer);
|
const int* ptr = reinterpret_cast<const int*>(buffer);
|
||||||
return NetData{{ptr[0], ptr[1]}};
|
NetData data;
|
||||||
|
data.type = static_cast<NetDataType>(ptr[0]);
|
||||||
|
data.clickPosition = {ptr[1], ptr[2]};
|
||||||
|
data.firstPlayer = ptr[3];
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
// 大小(固定16字节:4个int)
|
// 大小(固定16字节:4个int)
|
||||||
static constexpr size_t size() { return 4 * sizeof(int); }
|
static constexpr size_t size() { return 4 * sizeof(int); }
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ void NetworkManager::init(NetType type) {
|
|||||||
std::cout << "client started\n";
|
std::cout << "client started\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkManager::setClickEventCallback(ClickEventCallback callback) {
|
||||||
|
m_clickEventCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
void NetworkManager::init(NetType type) {
|
void NetworkManager::init(NetType type) {
|
||||||
// 先启动 io_context 线程
|
// 先启动 io_context 线程
|
||||||
@@ -68,12 +72,23 @@ void NetworkManager::startServer() {
|
|||||||
|
|
||||||
void NetworkManager::startClient() {
|
void NetworkManager::startClient() {
|
||||||
m_client->setCallbackes(
|
m_client->setCallbackes(
|
||||||
[](const NetData& click) {
|
[this](const NetData& click) {
|
||||||
/* 处理对手棋步 */
|
/* 处理对手棋步 */
|
||||||
|
if (m_clickEventCallback) {
|
||||||
|
std::cout << "Received opponent move: ("
|
||||||
|
<< click.clickPosition.first << ", "
|
||||||
|
<< click.clickPosition.second << ")\n";
|
||||||
|
m_clickEventCallback(click.clickPosition.first, click.clickPosition.second);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[]() {
|
[]() {
|
||||||
/* 提示用户走棋 */
|
/* 提示用户走棋 */
|
||||||
std::cout << "It's your turn now!\n";
|
std::cout << "NetworkManager:It's your turn now!\n";
|
||||||
|
},
|
||||||
|
[this]() {
|
||||||
|
/* 游戏开始回调 */
|
||||||
|
m_startGameCallback();
|
||||||
|
std::cout << "Game has started!\n";
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (m_netType == NetType::HOST) {
|
if (m_netType == NetType::HOST) {
|
||||||
@@ -100,4 +115,24 @@ void NetworkManager::startIOContextLoop() {
|
|||||||
});
|
});
|
||||||
std::cout << "IO context loop started on thread: "
|
std::cout << "IO context loop started on thread: "
|
||||||
<< m_ioThread.joinable() << std::endl;
|
<< m_ioThread.joinable() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkManager::postClickPosition(int logicalX, int logicalY, bool isChangeTurn) {
|
||||||
|
if (m_client) {
|
||||||
|
NetData data;
|
||||||
|
data.clickPosition = {logicalX, logicalY};
|
||||||
|
// 发送位置并告诉对手是否换回合
|
||||||
|
m_client->sentClickPosition(data, isChangeTurn);
|
||||||
|
std::cout << "Posted click position: ("
|
||||||
|
<< logicalX << ", " << logicalY << ")\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkManager::setIsMyTurn(bool isMyTurn) {
|
||||||
|
m_isMyTurn = isMyTurn;
|
||||||
|
if (m_client) {
|
||||||
|
// 如果不是我的回合,则客户端应该等待对手
|
||||||
|
m_client->setShouldWait(!isMyTurn);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
class NetworkManager {
|
class NetworkManager {
|
||||||
public:
|
public:
|
||||||
|
using ClickEventCallback = std::function<void(int logicalX, int logicalY)>;
|
||||||
|
using StartGameCallback = std::function<void()>;
|
||||||
NetworkManager();
|
NetworkManager();
|
||||||
|
|
||||||
|
|
||||||
@@ -13,7 +15,15 @@ public:
|
|||||||
|
|
||||||
void init(NetType type);
|
void init(NetType type);
|
||||||
|
|
||||||
|
void setClickEventCallback(ClickEventCallback callback);
|
||||||
|
|
||||||
|
void setStartGameCallback(StartGameCallback callback) {
|
||||||
|
m_startGameCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIsMyTurn(bool isMyTurn);
|
||||||
|
bool isMyTurn() const { return m_isMyTurn; }
|
||||||
|
void postClickPosition(int logicalX, int logicalY, bool isChangeTurn = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 一定要在最前面
|
// 一定要在最前面
|
||||||
@@ -28,7 +38,10 @@ private:
|
|||||||
asio::io_context::executor_type> m_workguard;
|
asio::io_context::executor_type> m_workguard;
|
||||||
std::thread m_ioThread;
|
std::thread m_ioThread;
|
||||||
|
|
||||||
|
ClickEventCallback m_clickEventCallback;
|
||||||
|
StartGameCallback m_startGameCallback;
|
||||||
|
|
||||||
|
bool m_isMyTurn = false; // 新增:当前是否是我的回合
|
||||||
void startServer();
|
void startServer();
|
||||||
|
|
||||||
void startClient();
|
void startClient();
|
||||||
|
|||||||
@@ -7,14 +7,22 @@ Client::Client(asio::io_context& ioContext):
|
|||||||
// 构造函数实现
|
// 构造函数实现
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::setCallbackes(MoveCallback onOpponentMove, TurnCallback onMyTurn) {
|
void Client::setCallbackes(MoveCallback onOpponentMove, TurnCallback onMyTurn, TurnCallback onGameStart) {
|
||||||
m_onOpponentMove = onOpponentMove;
|
m_onOpponentMove = onOpponentMove;
|
||||||
m_onMyTurn = onMyTurn;
|
m_onMyTurn = onMyTurn;
|
||||||
|
m_onGameStart = onGameStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::stopWaiting() {
|
||||||
|
m_shouldWait = false;
|
||||||
|
m_isWaiting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::connect(const std::string& host, int port, bool iAmFirst) {
|
void Client::connect(const std::string& host, int port, bool iAmFirst) {
|
||||||
m_host = host;
|
m_host = host;
|
||||||
m_port = port;
|
m_port = port;
|
||||||
|
m_isHost = iAmFirst;
|
||||||
|
m_shouldWait = true; // 连接后开始等待
|
||||||
//用shared_ptr保持对象存活
|
//用shared_ptr保持对象存活
|
||||||
auto self = shared_from_this();
|
auto self = shared_from_this();
|
||||||
|
|
||||||
@@ -40,28 +48,41 @@ void Client::connect(const std::string& host, int port, bool iAmFirst) {
|
|||||||
|
|
||||||
void Client::onConnected(bool iAmFirst) {
|
void Client::onConnected(bool iAmFirst) {
|
||||||
std::cout << "Connected to server " << m_host << ":" << m_port << std::endl;
|
std::cout << "Connected to server " << m_host << ":" << m_port << std::endl;
|
||||||
|
// 重置等待状态
|
||||||
// 如果是先手,触发回调
|
m_shouldWait = true;
|
||||||
if (iAmFirst && m_onMyTurn) {
|
m_isWaiting = false;
|
||||||
m_onMyTurn();
|
// 开始等待对手消息
|
||||||
} else {
|
if (m_shouldWait) {
|
||||||
// 等待对手动作
|
|
||||||
waitForOpponent();
|
waitForOpponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 发送点击位置数据给对手
|
// 发送点击位置数据给对手
|
||||||
|
|
||||||
void Client::sentClickPosition(const NetData& data) {
|
void Client::sentClickPosition(const NetData& data, bool isChangeTurn) {
|
||||||
auto self = shared_from_this();
|
auto self = shared_from_this();
|
||||||
|
|
||||||
|
NetData sendData = data;
|
||||||
|
sendData.type = NetDataType::CLICK_POSITION;
|
||||||
|
|
||||||
|
|
||||||
char buffer[NetData::size()];
|
char buffer[NetData::size()];
|
||||||
data.serialize(buffer);
|
sendData.serialize(buffer);
|
||||||
asio::async_write(m_socket, asio::buffer(buffer, NetData::size()),
|
asio::async_write(m_socket, asio::buffer(buffer, NetData::size()),
|
||||||
[this, self](const asio::error_code& ec, std::size_t /*bytesTransferred*/) {
|
[this, self, isChangeTurn](const asio::error_code& ec, std::size_t /*bytesTransferred*/) {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
// 发送成功,等待对手动作
|
// 如果需要转换回合,则开始等待对手
|
||||||
waitForOpponent();
|
if (isChangeTurn) {
|
||||||
|
m_isMyTurn = false;
|
||||||
|
m_shouldWait = true;
|
||||||
|
if (!m_isWaiting) {
|
||||||
|
waitForOpponent();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_isMyTurn = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "send failed: " << ec.message() << std::endl;
|
std::cerr << "send failed: " << ec.message() << std::endl;
|
||||||
}
|
}
|
||||||
@@ -69,6 +90,9 @@ void Client::sentClickPosition(const NetData& data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Client::waitForOpponent() {
|
void Client::waitForOpponent() {
|
||||||
|
if (!m_shouldWait || m_isWaiting) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto self = shared_from_this();
|
auto self = shared_from_this();
|
||||||
m_socket.async_read_some(
|
m_socket.async_read_some(
|
||||||
asio::buffer(m_readBuffer, NetData::size()),
|
asio::buffer(m_readBuffer, NetData::size()),
|
||||||
@@ -77,21 +101,69 @@ void Client::waitForOpponent() {
|
|||||||
|
|
||||||
if (bytesTransferred == NetData::size()) {
|
if (bytesTransferred == NetData::size()) {
|
||||||
NetData netData = NetData::deserialize(m_readBuffer);
|
NetData netData = NetData::deserialize(m_readBuffer);
|
||||||
// 触发对手移动回调
|
|
||||||
if (m_onOpponentMove) {
|
// 检查消息类型
|
||||||
m_onOpponentMove(netData);
|
if (netData.type == NetDataType::GAME_START) {
|
||||||
|
std::cout << "Game started! First player is: " << netData.firstPlayer << std::endl;
|
||||||
|
|
||||||
|
// 判断自己是否是先手
|
||||||
|
bool iAmFirst = (netData.firstPlayer == 1 && m_isHost) ||
|
||||||
|
(netData.firstPlayer == 2 && !m_isHost);
|
||||||
|
|
||||||
|
m_isMyTurn = iAmFirst;
|
||||||
|
if (m_onGameStart) {
|
||||||
|
m_onGameStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_isMyTurn && m_onMyTurn) {
|
||||||
|
std::cout << "It's your turn now! (You are first)\n";
|
||||||
|
m_onMyTurn();
|
||||||
|
} else if (!m_isMyTurn && m_onOpponentMove) {
|
||||||
|
// 如果不是先手,等待对手走棋
|
||||||
|
std::cout << "Waiting for opponent to move...\n";
|
||||||
|
// 可以在这里触发一个等待对手的回调,如果需要的话
|
||||||
|
if (m_shouldWait) {
|
||||||
|
waitForOpponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 轮到我了
|
else if (netData.type == NetDataType::CLICK_POSITION) {
|
||||||
if (m_onMyTurn) {
|
// 正常的对手移动
|
||||||
m_onMyTurn();
|
if (m_onOpponentMove) {
|
||||||
|
std::cout << "Received opponent move: ("
|
||||||
|
<< netData.clickPosition.first << ", "
|
||||||
|
<< netData.clickPosition.second << ")\n";
|
||||||
|
m_onOpponentMove(netData);
|
||||||
|
}
|
||||||
|
// 现在轮到我了
|
||||||
|
//m_isMyTurn = true;
|
||||||
|
|
||||||
|
|
||||||
|
if (m_isMyTurn) {
|
||||||
|
m_shouldWait = false;
|
||||||
|
if (m_onMyTurn) {
|
||||||
|
m_onMyTurn();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_shouldWait) {
|
||||||
|
waitForOpponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 重置读取缓冲区以准备下一次读取
|
// 重置读取缓冲区以准备下一次读取
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "Incomplete data received from opponent." << std::endl;
|
std::cerr << "Incomplete data received from opponent." << std::endl;
|
||||||
|
if (m_shouldWait) {
|
||||||
|
waitForOpponent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::cerr << "read failed: " << ec.message() << std::endl;
|
std::cerr << "read failed: " << ec.message() << std::endl;
|
||||||
|
// 发生错误时,可以选择重新等待对手
|
||||||
|
if (m_shouldWait) {
|
||||||
|
waitForOpponent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ public:
|
|||||||
|
|
||||||
Client(asio::io_context& ioContext);
|
Client(asio::io_context& ioContext);
|
||||||
~Client() = default;
|
~Client() = default;
|
||||||
|
// 设置等待状态
|
||||||
void setCallbackes(MoveCallback onOpponentMove, TurnCallback onMyTurn);
|
void setShouldWait(bool shouldWait) { m_shouldWait = shouldWait; }
|
||||||
|
void setCallbackes(MoveCallback onOpponentMove, TurnCallback onMyTurn, TurnCallback onGameStart);
|
||||||
|
|
||||||
void connect(const std::string& host, int port, bool iAmFirst = true);
|
void connect(const std::string& host, int port, bool iAmFirst = true);
|
||||||
|
|
||||||
void sentClickPosition(const NetData& data);
|
void sentClickPosition(const NetData& data, bool isChangeTurn = false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -30,13 +31,21 @@ private:
|
|||||||
asio::ip::tcp::socket m_socket;
|
asio::ip::tcp::socket m_socket;
|
||||||
std::string m_host;
|
std::string m_host;
|
||||||
int m_port;
|
int m_port;
|
||||||
|
bool m_isHost = false;
|
||||||
MoveCallback m_onOpponentMove;
|
MoveCallback m_onOpponentMove;
|
||||||
TurnCallback m_onMyTurn;
|
TurnCallback m_onMyTurn;
|
||||||
|
TurnCallback m_onGameStart;
|
||||||
char m_readBuffer[NetData::size()];
|
char m_readBuffer[NetData::size()];
|
||||||
|
|
||||||
|
|
||||||
|
// 新增状态控制
|
||||||
|
bool m_shouldWait = false; // 是否应该等待对手
|
||||||
|
bool m_isWaiting = false; // 当前是否正在等待
|
||||||
|
bool m_isMyTurn = false; // 是否是我的回合
|
||||||
|
|
||||||
void onConnected(bool iAmFirst);
|
void onConnected(bool iAmFirst);
|
||||||
void waitForOpponent();
|
void waitForOpponent();
|
||||||
|
void stopWaiting(); // 停止等待
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -83,6 +83,37 @@ void GameServer::waitForPlayers(int playerNum) {
|
|||||||
void GameServer::startGame() {
|
void GameServer::startGame() {
|
||||||
std::cout << "Gmae Start player1 is the first\n";
|
std::cout << "Gmae Start player1 is the first\n";
|
||||||
|
|
||||||
|
NetData gameStartMsg;
|
||||||
|
gameStartMsg.type = NetDataType::GAME_START;
|
||||||
|
gameStartMsg.firstPlayer = 1; // 玩家1先手
|
||||||
|
gameStartMsg.clickPosition = {-1, -1}; // 特殊值表示游戏开始
|
||||||
|
|
||||||
|
char buffer1[NetData::size()];
|
||||||
|
char buffer2[NetData::size()];
|
||||||
|
// player1
|
||||||
|
gameStartMsg.serialize(buffer1);
|
||||||
|
//player2
|
||||||
|
gameStartMsg.serialize(buffer2);
|
||||||
|
// 发送游戏开始消息给两个玩家
|
||||||
|
asio::async_write(m_player1, asio::buffer(buffer1, NetData::size()),
|
||||||
|
[](const asio::error_code& ec, size_t) {
|
||||||
|
if (ec) {
|
||||||
|
std::cerr << "Failed to send start message to player1: " << ec.message() << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Game start message sent to player1\n";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
asio::async_write(m_player2, asio::buffer(buffer2, NetData::size()),
|
||||||
|
[](const asio::error_code& ec, size_t) {
|
||||||
|
if (ec) {
|
||||||
|
std::cerr << "Failed to send start message to player2: " << ec.message() << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Game start message sent to player2\n";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
forwardMoves();
|
forwardMoves();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,10 +8,9 @@ GameScene::~GameScene() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameScene::onEnter(SDL_Renderer* renderer, int WIDTH, int HEIGHT, UIRenderer* uiRenderer){
|
std::unique_ptr<GameUIManager> GameScene::createUIManager() {
|
||||||
m_renderer = renderer;
|
// 默认创建普通的GameUIManager
|
||||||
m_uiRenderer = uiRenderer;
|
return std::make_unique<GameUIManager>(
|
||||||
m_gameUIManager = std::make_unique<GameUIManager>(
|
|
||||||
[this](const std::string& sceneName) {
|
[this](const std::string& sceneName) {
|
||||||
if (m_eventCallback) {
|
if (m_eventCallback) {
|
||||||
SceneEvent event{SceneEventType::ChangeScene, sceneName};
|
SceneEvent event{SceneEventType::ChangeScene, sceneName};
|
||||||
@@ -19,10 +18,50 @@ void GameScene::onEnter(SDL_Renderer* renderer, int WIDTH, int HEIGHT, UIRendere
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GameScene::preHandleClick(int logicalX, int logicalY) {
|
||||||
|
// 默认实现:先处理UI点击
|
||||||
|
if (m_gameUIManager && m_gameUIManager->handleClick(logicalX, logicalY)) {
|
||||||
|
return true; // UI已处理点击
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查游戏状态
|
||||||
|
if (m_gameSession->getGameState() != GameState::GAME_RUNING) {
|
||||||
|
SDL_Log("Game is not running, click ignored.");
|
||||||
|
return true; // 游戏未运行,不处理点击
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // 继续处理游戏点击
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameScene::postHandleClick() {
|
||||||
|
|
||||||
|
// 默认实现:更新UI和渲染器状态
|
||||||
|
m_gameUIManager->updateActionType(m_gameSession->getCurrentActionType());
|
||||||
|
m_boardRenderer->updateMovementRange(m_gameSession->getSelectedPiece(), m_gameSession->getCurrentActionType());
|
||||||
|
m_gameUIManager->updateGameState(m_gameSession->getGameState());
|
||||||
|
m_boardRenderer->setGameState(m_gameSession->getGameState());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameScene::handleBoardClick(int row, int col) {
|
||||||
|
// 处理棋盘点击逻辑
|
||||||
|
m_gameSession->handleCoordinateInput(row, col);
|
||||||
|
m_gameSession->printBoard();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameScene::onEnter(SDL_Renderer* renderer, int WIDTH, int HEIGHT, UIRenderer* uiRenderer){
|
||||||
|
m_renderer = renderer;
|
||||||
|
m_uiRenderer = uiRenderer;
|
||||||
|
|
||||||
|
// 使用工厂方法创建UIManager
|
||||||
|
m_gameUIManager = createUIManager();
|
||||||
m_gameUIManager->init();
|
m_gameUIManager->init();
|
||||||
m_gameUIManager->setCallback([this]() {
|
m_gameUIManager->setCallback([this]() {
|
||||||
this->restartGame();
|
this->restartGame();
|
||||||
});
|
});
|
||||||
|
|
||||||
m_boardRenderer = std::make_unique<BoardRenderer>(WIDTH, HEIGHT, renderer);
|
m_boardRenderer = std::make_unique<BoardRenderer>(WIDTH, HEIGHT, renderer);
|
||||||
m_gameSession = std::make_unique<GameSession>();
|
m_gameSession = std::make_unique<GameSession>();
|
||||||
m_CoordinateConverter = std::make_unique<CoordinateConverter>(renderer);
|
m_CoordinateConverter = std::make_unique<CoordinateConverter>(renderer);
|
||||||
@@ -56,7 +95,8 @@ void GameScene::renderUI() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameScene::handleClick(int logicalX, int logicalY) {
|
void GameScene::handleClick(int logicalX, int logicalY) {
|
||||||
if (m_gameUIManager && m_gameUIManager->handleClick(logicalX, logicalY)) {
|
// 1. 预处理(UI点击等)
|
||||||
|
if (preHandleClick(logicalX, logicalY)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,16 +107,18 @@ void GameScene::handleClick(int logicalX, int logicalY) {
|
|||||||
auto click = m_CoordinateConverter->ScreenToBoard(logicalX, logicalY, m_boardRenderer->getBoardArea());
|
auto click = m_CoordinateConverter->ScreenToBoard(logicalX, logicalY, m_boardRenderer->getBoardArea());
|
||||||
if (click) {
|
if (click) {
|
||||||
auto [row, col] = click.value();
|
auto [row, col] = click.value();
|
||||||
m_gameSession->handleCoordinateInput(row, col);
|
handleBoardClick(row, col);
|
||||||
m_gameSession->printBoard();
|
|
||||||
SDL_Log("try to updateActionType\n");
|
// 3. 后处理(更新UI状态等)
|
||||||
|
postHandleClick();
|
||||||
|
/*SDL_Log("try to updateActionType\n");
|
||||||
m_gameUIManager->updateActionType( m_gameSession->getCurrentActionType());
|
m_gameUIManager->updateActionType( m_gameSession->getCurrentActionType());
|
||||||
SDL_Log("tyr to updateMovementRange\n");
|
SDL_Log("tyr to updateMovementRange\n");
|
||||||
m_boardRenderer->updateMovementRange(m_gameSession->getSelectedPiece(), m_gameSession->getCurrentActionType());
|
m_boardRenderer->updateMovementRange(m_gameSession->getSelectedPiece(), m_gameSession->getCurrentActionType());
|
||||||
SDL_Log("tyr to updateGameState\n");
|
SDL_Log("tyr to updateGameState\n");
|
||||||
m_gameUIManager->updateGameState(m_gameSession->getGameState());
|
m_gameUIManager->updateGameState(m_gameSession->getGameState());
|
||||||
m_boardRenderer->setGameState(m_gameSession->getGameState());
|
m_boardRenderer->setGameState(m_gameSession->getGameState());
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
SDL_Log("invail cilck aera!");
|
SDL_Log("invail cilck aera!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,19 @@ public:
|
|||||||
|
|
||||||
void restartGame();
|
void restartGame();
|
||||||
protected:
|
protected:
|
||||||
|
// 创建UIManager的工厂方法,子类可以重写
|
||||||
|
virtual std::unique_ptr<GameUIManager> createUIManager();
|
||||||
|
|
||||||
|
// // 点击处理的钩子方法
|
||||||
|
virtual bool preHandleClick(int logicalX, int logicalY);
|
||||||
|
virtual void postHandleClick();
|
||||||
|
|
||||||
|
virtual void handleBoardClick(int row, int col);
|
||||||
|
|
||||||
|
// 公共成员,子类可以直接访问
|
||||||
std::unique_ptr<BoardRenderer> m_boardRenderer;
|
std::unique_ptr<BoardRenderer> m_boardRenderer;
|
||||||
std::unique_ptr<CoordinateConverter> m_CoordinateConverter;
|
std::unique_ptr<CoordinateConverter> m_CoordinateConverter;
|
||||||
std::unique_ptr<GameSession> m_gameSession;
|
std::unique_ptr<GameSession> m_gameSession;
|
||||||
private:
|
|
||||||
std::unique_ptr<GameUIManager> m_gameUIManager;
|
std::unique_ptr<GameUIManager> m_gameUIManager;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
#include "OnlineGameScene.h"
|
#include "OnlineGameScene.h"
|
||||||
#include "core/GameApplication.h"
|
#include "core/GameApplication.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
void OnlineGameScene::onEnter(SDL_Renderer* renderer, int WIDTH, int HEIGHT, UIRenderer* uiRenderer) {
|
|
||||||
m_renderer = renderer;
|
std::unique_ptr<GameUIManager> OnlineGameScene::createUIManager() {
|
||||||
m_uiRenderer = uiRenderer;
|
auto onlineUIManager = std::make_unique<OnlineGameUIManager>(
|
||||||
m_gameUIManager = std::make_unique<OnlineGameUIManager>(
|
|
||||||
[this](const std::string& sceneName) {
|
[this](const std::string& sceneName) {
|
||||||
if (m_eventCallback) {
|
if (m_eventCallback) {
|
||||||
SceneEvent event{SceneEventType::ChangeScene, sceneName};
|
SceneEvent event{SceneEventType::ChangeScene, sceneName};
|
||||||
@@ -12,49 +11,122 @@ void OnlineGameScene::onEnter(SDL_Renderer* renderer, int WIDTH, int HEIGHT, UIR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
m_networkManager = std::make_unique<NetworkManager>();
|
// 设置网络类型回调
|
||||||
|
onlineUIManager->setOnlineTypeCallback(
|
||||||
m_gameUIManager->init();
|
[this](NetType type) {
|
||||||
m_gameUIManager->setCallback([this]() {
|
if (m_networkManager) {
|
||||||
this->restartGame();
|
m_networkManager->init(type);
|
||||||
});
|
if (type == NetType::CLIENT) {
|
||||||
|
m_isMyTurn = false;
|
||||||
m_gameUIManager->setOnlineTypeCallback(
|
|
||||||
[this](NetType type){
|
m_myPlayerID = PlayerID::P2;
|
||||||
//std::cout << "try to init networkmanager\n";
|
} else if (type == NetType::HOST) {
|
||||||
if (!m_networkManager) {
|
m_isMyTurn = true;
|
||||||
std::cerr << "networkmanager is null\n";
|
m_myPlayerID = PlayerID::P1;
|
||||||
}
|
}
|
||||||
m_networkManager->init(type);
|
m_networkManager->setIsMyTurn(m_isMyTurn);
|
||||||
if (type == NetType::CLIENT) {
|
|
||||||
m_isMyTurn = false;
|
|
||||||
m_myPlayerID = PlayerID::P2;
|
|
||||||
}
|
|
||||||
if (type == NetType::HOST) {
|
|
||||||
m_isMyTurn = true;
|
|
||||||
m_myPlayerID = PlayerID::P1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
m_boardRenderer = std::make_unique<BoardRenderer>(WIDTH, HEIGHT, renderer);
|
|
||||||
m_gameSession = std::make_unique<GameSession>();
|
|
||||||
m_CoordinateConverter = std::make_unique<CoordinateConverter>(renderer);
|
|
||||||
m_gameSession->initialize();
|
|
||||||
|
|
||||||
m_boardRenderer->setBoard(m_gameSession->getBoard());
|
|
||||||
|
|
||||||
|
|
||||||
|
return onlineUIManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnlineGameScene::onEnter(SDL_Renderer* renderer, int WIDTH, int HEIGHT, UIRenderer* uiRenderer) {
|
||||||
|
// 先创建网络管理器
|
||||||
|
m_networkManager = std::make_unique<NetworkManager>();
|
||||||
|
m_networkManager->setClickEventCallback(
|
||||||
|
[this](int logicalX, int logicalY) {
|
||||||
|
this->handleNetworkClick(logicalX, logicalY);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_networkManager->setStartGameCallback(
|
||||||
|
[this]() {
|
||||||
|
auto onlineUIManager = dynamic_cast<OnlineGameUIManager*>(m_gameUIManager.get());
|
||||||
|
if (onlineUIManager) {
|
||||||
|
onlineUIManager->hideOnlineButtons();
|
||||||
|
}
|
||||||
|
m_currentGameState = GameState::GAME_RUNING;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
// 调用父类的onEnter(会调用我们重写的createUIManager)
|
||||||
|
GameScene::onEnter(renderer, WIDTH, HEIGHT, uiRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OnlineGameScene::preHandleClick(int logicalX, int logicalY) {
|
||||||
|
|
||||||
|
// 1. 先调用父类的UI处理
|
||||||
|
if (GameScene::preHandleClick(logicalX, logicalY)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 2. 检查是否是自己的回合
|
||||||
|
// 网络处理会使用这个函数来决定是否处理点击,但是因为不是自己的回合所以不会调用handleBoardClick,导致bug
|
||||||
|
/*if (!m_isMyTurn) {
|
||||||
|
std::cout << "It is not your turn\n";
|
||||||
|
return true; // 不是自己的回合,阻止处理
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return false; // 继续处理点击
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnlineGameScene::postHandleClick() {
|
||||||
|
// 调用父类的后处理
|
||||||
|
GameScene::postHandleClick();
|
||||||
|
|
||||||
|
// 在线游戏特有的后处理
|
||||||
|
if (m_gameSession->getCurrentPlayer() != m_myPlayerID) {
|
||||||
|
m_isMyTurn = false;
|
||||||
|
// 可以在这里发送网络消息给对手
|
||||||
|
m_networkManager->setIsMyTurn(false);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnlineGameScene::handleBoardClick(int row, int col) {
|
||||||
|
if (m_currentGameState != GameState::GAME_RUNING) {
|
||||||
|
std::cout << "Game is not running, board click ignored.\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 调用父类的处理逻辑
|
||||||
|
GameScene::handleBoardClick(row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnlineGameScene::handleClick(int logicalX, int logicalY) {
|
||||||
|
// 要阻止的是鼠标点击事件,但是网络事件可以处理
|
||||||
|
if (m_currentGameState == GameState::GAME_RUNING && !m_isMyTurn) {
|
||||||
|
std::cout << "It is not your turn, click ignored.\n";
|
||||||
|
return; // 不是自己的回合,忽略点击
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重用父类的逻辑
|
||||||
|
GameScene::handleClick(logicalX, logicalY);
|
||||||
|
if (m_currentGameState != GameState::GAME_RUNING) {
|
||||||
|
std::cout << "Game has not started yet, not sending click\n";
|
||||||
|
return; // 游戏未开始不发送点击
|
||||||
|
}
|
||||||
|
if (m_gameSession->getCurrentPlayer() != m_myPlayerID) {
|
||||||
|
m_isMyTurn = false;
|
||||||
|
m_networkManager->setIsMyTurn(false);
|
||||||
|
m_networkManager->postClickPosition(logicalX, logicalY, true);
|
||||||
|
} else {
|
||||||
|
m_networkManager->postClickPosition(logicalX, logicalY, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void OnlineGameScene::renderWorld() {
|
void OnlineGameScene::renderWorld() {
|
||||||
|
if (m_currentGameState != GameState::GAME_RUNING) {
|
||||||
|
// 渲染遮罩或提示
|
||||||
|
m_boardRenderer->renderBlackOverlay();
|
||||||
|
return;
|
||||||
|
}
|
||||||
GameScene::renderWorld();
|
GameScene::renderWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnlineGameScene::renderUI() {
|
void OnlineGameScene::renderUI() {
|
||||||
m_uiRenderer->renderUI(m_gameUIManager->getUIRenderData());
|
GameScene::renderUI();
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
void OnlineGameScene::handleClick(int logicalX, int logicalY) {
|
void OnlineGameScene::handleClick(int logicalX, int logicalY) {
|
||||||
if (m_gameUIManager && m_gameUIManager->handleClick(logicalX, logicalY)) {
|
if (m_gameUIManager && m_gameUIManager->handleClick(logicalX, logicalY)) {
|
||||||
return;
|
return;
|
||||||
@@ -70,13 +142,21 @@ void OnlineGameScene::handleClick(int logicalX, int logicalY) {
|
|||||||
m_isMyTurn = false;
|
m_isMyTurn = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
void OnlineGameScene::handleNetworkClick(int logicalX, int logicalY) {
|
void OnlineGameScene::handleNetworkClick(int logicalX, int logicalY) {
|
||||||
|
std::cout << "Handling network click at (" << logicalX << ", " << logicalY << ")\n";
|
||||||
|
// 处理来自网络的点击
|
||||||
if (m_isMyTurn) {
|
if (m_isMyTurn) {
|
||||||
return;
|
return; // 如果是自己的回合,忽略网络点击
|
||||||
}
|
}
|
||||||
|
// 调用父类的基础点击处理
|
||||||
GameScene::handleClick(logicalX, logicalY);
|
GameScene::handleClick(logicalX, logicalY);
|
||||||
|
std::cout << "After handling network click, current player: "
|
||||||
|
<< (m_gameSession->getCurrentPlayer() == PlayerID::P1 ? "P1" : "P2") << "\n";
|
||||||
|
// 更新回合状态
|
||||||
if (m_gameSession->getCurrentPlayer() == m_myPlayerID) {
|
if (m_gameSession->getCurrentPlayer() == m_myPlayerID) {
|
||||||
|
std::cout << "OnlineGameScene: It is now my turn.\n";
|
||||||
m_isMyTurn = true;
|
m_isMyTurn = true;
|
||||||
|
m_networkManager->setIsMyTurn(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,9 +14,15 @@ public:
|
|||||||
void handleNetworkClick(int logicalX, int logicalY);
|
void handleNetworkClick(int logicalX, int logicalY);
|
||||||
|
|
||||||
void renderUI() override;
|
void renderUI() override;
|
||||||
|
protected:
|
||||||
|
std::unique_ptr<GameUIManager> createUIManager() override;
|
||||||
|
bool preHandleClick(int logicalX, int logicalY) override;
|
||||||
|
void postHandleClick() override;
|
||||||
|
|
||||||
|
void handleBoardClick(int row, int col) override;
|
||||||
private:
|
private:
|
||||||
PlayerID m_myPlayerID;
|
PlayerID m_myPlayerID = PlayerID::P1;
|
||||||
bool m_isMyTurn;
|
bool m_isMyTurn = true;
|
||||||
std::unique_ptr<NetworkManager> m_networkManager;
|
std::unique_ptr<NetworkManager> m_networkManager;
|
||||||
std::unique_ptr<OnlineGameUIManager> m_gameUIManager;
|
GameState m_currentGameState = GameState::GAME_PREGAME;
|
||||||
};
|
};
|
||||||
@@ -49,3 +49,15 @@ void OnlineGameUIManager::setOnlineTypeCallback(OnlineTypeEvent onlineTypeEvent)
|
|||||||
m_onlineTypeEvent = onlineTypeEvent;
|
m_onlineTypeEvent = onlineTypeEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnlineGameUIManager::hideOnlineButtons() {
|
||||||
|
auto hostIt = m_buttons.find(makeHash("OnlineHostButton"));
|
||||||
|
if (hostIt != m_buttons.end()) {
|
||||||
|
hostIt->second->setVisible(false);
|
||||||
|
hostIt->second->setEnabled(false);
|
||||||
|
}
|
||||||
|
auto joinIt = m_buttons.find(makeHash("OnlineJoinButton"));
|
||||||
|
if (joinIt != m_buttons.end()) {
|
||||||
|
joinIt->second->setVisible(false);
|
||||||
|
joinIt->second->setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ public:
|
|||||||
~OnlineGameUIManager();
|
~OnlineGameUIManager();
|
||||||
void init() override;
|
void init() override;
|
||||||
void setOnlineTypeCallback(OnlineTypeEvent type);
|
void setOnlineTypeCallback(OnlineTypeEvent type);
|
||||||
|
|
||||||
|
void hideOnlineButtons();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OnlineTypeEvent m_onlineTypeEvent;
|
OnlineTypeEvent m_onlineTypeEvent;
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user