mirror of
https://github.com/zhenyan121/SporeBG-Conid.git
synced 2026-04-10 06:14:08 +08:00
Added NetworkManager Client and GameServer class
This commit is contained in:
@@ -46,6 +46,11 @@ set(SOURCE_FILES
|
|||||||
src/core/DebugManager.cpp
|
src/core/DebugManager.cpp
|
||||||
src/ui/managers/debug/DebugOverlay.cpp
|
src/ui/managers/debug/DebugOverlay.cpp
|
||||||
src/core/Time.cpp
|
src/core/Time.cpp
|
||||||
|
src/scenes/gameplay/OnlineGameScene.cpp
|
||||||
|
src/ui/managers/OnlineGameUIManager.cpp
|
||||||
|
src/network/client/Client.cpp
|
||||||
|
src/network/server/GameServer.cpp
|
||||||
|
src/network/NetworkManager.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -56,10 +61,11 @@ target_include_directories(${PROJECT_NAME} PRIVATE
|
|||||||
${asio_SOURCE_DIR}/asio/include
|
${asio_SOURCE_DIR}/asio/include
|
||||||
|
|
||||||
)
|
)
|
||||||
|
# ========== Windows: 定义宏 & 链接库 ==========
|
||||||
|
if (WIN32)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
target_compile_definitions(${PROJECT_NAME} PRIVATE
|
||||||
ASIO_STANDALONE
|
ASIO_STANDALONE
|
||||||
|
_WIN32_WINNT=0x0A00
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME}
|
target_link_libraries(${PROJECT_NAME}
|
||||||
@@ -68,8 +74,11 @@ target_link_libraries(${PROJECT_NAME}
|
|||||||
SDL3_ttf::SDL3_ttf
|
SDL3_ttf::SDL3_ttf
|
||||||
SDL3_image::SDL3_image
|
SDL3_image::SDL3_image
|
||||||
nlohmann_json::nlohmann_json
|
nlohmann_json::nlohmann_json
|
||||||
|
ws2_32
|
||||||
|
mswsock
|
||||||
|
advapi32
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
# ========== Windows: 复制 DLL ==========
|
# ========== Windows: 复制 DLL ==========
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
# 查找 MinGW 运行时库
|
# 查找 MinGW 运行时库
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
一个棋类游戏,与孢子分裂有关,本为**cpp重构版**,游戏核心主要玩法由**cold1840**制定的,可以看他的[python版本](https://github.com/cold1840/SporeBG),这个版本旨在用**cpp**完全重写这个游戏,**注意本项目并未使用到里面的代码,核心逻辑实现是不一样的**,且本项目打算加入许多功能,**整体玩法也是完全不一样的**,同时**cold1840**也在一定程度上参与项目的开发与维护
|
一个棋类游戏,与孢子分裂有关,本为**cpp重构版**,游戏核心主要玩法由**cold1840**制定的,可以看他的[python版本](https://github.com/cold1840/SporeBG),这个版本旨在用**cpp**完全重写这个游戏,**注意本项目并未使用到里面的代码,核心逻辑实现是不一样的**,且本项目打算加入许多功能,**整体玩法也是完全不一样的**,同时**cold1840**也在一定程度上参与项目的开发与维护
|
||||||
|
|
||||||
## 构建指南
|
## 构建指南
|
||||||
|
**mingw老版本有重大问题,导致asio内部状态损坏,引起段错误,如果是mingw请使用最新版本**
|
||||||
确保电脑安装了`cmake`和`ninja`,使用`gcc`与`g++`:
|
确保电脑安装了`cmake`和`ninja`,使用`gcc`与`g++`:
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/zhenyan121/SporeBG-Conid.git
|
git clone https://github.com/zhenyan121/SporeBG-Conid.git
|
||||||
|
|||||||
26
src/network/NetData.h
Normal file
26
src/network/NetData.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <utility>
|
||||||
|
struct NetData {
|
||||||
|
std::pair<int, int> clickPosition = {0, 0};
|
||||||
|
// 序列化,转换成字节数组
|
||||||
|
void serialize(char* buffer) const {
|
||||||
|
// 暴力转换
|
||||||
|
int* ptr = reinterpret_cast<int*>(buffer);
|
||||||
|
ptr[0] = clickPosition.first;
|
||||||
|
ptr[1] = clickPosition.second;
|
||||||
|
}
|
||||||
|
// 反序列化,从字节数组恢复
|
||||||
|
static NetData deserialize(const char* buffer) {
|
||||||
|
// 暴力转换
|
||||||
|
const int* ptr = reinterpret_cast<const int*>(buffer);
|
||||||
|
return NetData{{ptr[0], ptr[1]}};
|
||||||
|
}
|
||||||
|
// 大小(固定16字节:4个int)
|
||||||
|
static constexpr size_t size() { return 4 * sizeof(int); }
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class NetType {
|
||||||
|
HOST,
|
||||||
|
CLIENT
|
||||||
|
|
||||||
|
};
|
||||||
74
src/network/NetworkManager.cpp
Normal file
74
src/network/NetworkManager.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "NetworkManager.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
NetworkManager::~NetworkManager() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkManager::init(NetType type) {
|
||||||
|
m_netType = type;
|
||||||
|
if (type == NetType::HOST) {
|
||||||
|
m_gameServer = std::make_shared<GameServer>(m_ioContext);
|
||||||
|
//std::cout << "try to start server\n";
|
||||||
|
startServer();
|
||||||
|
|
||||||
|
}
|
||||||
|
m_client = std::make_shared<Client>(m_ioContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void NetworkManager::init(NetType type) {
|
||||||
|
// 先启动 io_context 线程
|
||||||
|
m_ioThread = std::thread([this]() {
|
||||||
|
std::cout << "Network thread starting: "
|
||||||
|
<< std::this_thread::get_id() << std::endl;
|
||||||
|
m_ioContext.run();
|
||||||
|
});
|
||||||
|
std::cout << "Main thread after starting network thread: "
|
||||||
|
<< std::this_thread::get_id() << std::endl;
|
||||||
|
// 等待网络线程启动
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
std::cout << "Initializing NetworkManager on thread: "
|
||||||
|
<< std::this_thread::get_id() << std::endl;
|
||||||
|
// 在网络线程中初始化
|
||||||
|
asio::post(m_ioContext, [this, type]() {
|
||||||
|
std::cout << "NetworkManager init running on thread: "
|
||||||
|
<< std::this_thread::get_id() << std::endl;
|
||||||
|
// 在这里创建 GameServer 和调用 async_accept
|
||||||
|
if (type == NetType::HOST) {
|
||||||
|
m_gameServer = std::make_shared<GameServer>(m_ioContext);
|
||||||
|
m_gameServer->startServer(52025);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}*/
|
||||||
|
void NetworkManager::startServer() {
|
||||||
|
|
||||||
|
if (!m_gameServer) {
|
||||||
|
std::cerr << "gameServer is not esist\n";
|
||||||
|
}
|
||||||
|
m_gameServer->startServer(52025);
|
||||||
|
|
||||||
|
std::cout << "start server success\n";
|
||||||
|
m_ioContext.run();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkManager::startClient() {
|
||||||
|
m_client->setCallbackes(
|
||||||
|
[](const NetData& click) {
|
||||||
|
/* 处理对手棋步 */
|
||||||
|
},
|
||||||
|
[]() {
|
||||||
|
/* 提示用户走棋 */
|
||||||
|
std::cout << "It's your turn now!\n";
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (m_netType == NetType::HOST) {
|
||||||
|
m_client->connect("127.0.0.1", 52025, true);
|
||||||
|
}
|
||||||
|
if (m_netType == NetType::CLIENT) {
|
||||||
|
m_client->connect("127.0.0.1", 52025, false);
|
||||||
|
m_ioContext.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/network/NetworkManager.h
Normal file
32
src/network/NetworkManager.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "network/client/Client.h"
|
||||||
|
#include "network/server/GameServer.h"
|
||||||
|
|
||||||
|
class NetworkManager {
|
||||||
|
public:
|
||||||
|
NetworkManager() = default;
|
||||||
|
|
||||||
|
|
||||||
|
~NetworkManager();
|
||||||
|
|
||||||
|
|
||||||
|
void init(NetType type);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//asio::ip::tcp::acceptor m_acceptor;
|
||||||
|
|
||||||
|
std::shared_ptr<GameServer> m_gameServer = nullptr;
|
||||||
|
std::shared_ptr<Client> m_client = nullptr;
|
||||||
|
NetType m_netType;
|
||||||
|
|
||||||
|
std::thread m_ioThread;
|
||||||
|
|
||||||
|
asio::io_context m_ioContext;
|
||||||
|
void startServer();
|
||||||
|
|
||||||
|
void startClient();
|
||||||
|
};
|
||||||
99
src/network/client/Client.cpp
Normal file
99
src/network/client/Client.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include "Client.h"
|
||||||
|
#include <iostream>
|
||||||
|
Client::Client(asio::io_context& ioContext):
|
||||||
|
m_resolver(ioContext),
|
||||||
|
m_socket(ioContext)
|
||||||
|
{
|
||||||
|
// 构造函数实现
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::setCallbackes(MoveCallback onOpponentMove, TurnCallback onMyTurn) {
|
||||||
|
m_onOpponentMove = onOpponentMove;
|
||||||
|
m_onMyTurn = onMyTurn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::connect(const std::string& host, int port, bool iAmFirst) {
|
||||||
|
m_host = host;
|
||||||
|
m_port = port;
|
||||||
|
//用shared_ptr保持对象存活
|
||||||
|
auto self = shared_from_this();
|
||||||
|
|
||||||
|
std::cout << "try to resolve: " << host << ":" << port << std::endl;
|
||||||
|
// 屎山一样的lambda
|
||||||
|
m_resolver.async_resolve(host, std::to_string(port),
|
||||||
|
[this, self, iAmFirst](const asio::error_code& ec, asio::ip::tcp::resolver::results_type results) {
|
||||||
|
if (!ec) {
|
||||||
|
asio::async_connect(m_socket, results,
|
||||||
|
[this, self, iAmFirst](const asio::error_code& ec, const asio::ip::tcp::endpoint& /*endpoint*/) {
|
||||||
|
if (!ec) {
|
||||||
|
onConnected(iAmFirst);
|
||||||
|
} else {
|
||||||
|
// 处理连接错误
|
||||||
|
std::cerr << "connect failed: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
std::cerr << "resolve failed: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::onConnected(bool iAmFirst) {
|
||||||
|
std::cout << "Connected to server " << m_host << ":" << m_port << std::endl;
|
||||||
|
|
||||||
|
// 如果是先手,触发回调
|
||||||
|
if (iAmFirst && m_onMyTurn) {
|
||||||
|
m_onMyTurn();
|
||||||
|
} else {
|
||||||
|
// 等待对手动作
|
||||||
|
waitForOpponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 发送点击位置数据给对手
|
||||||
|
|
||||||
|
void Client::sentClickPosition(const NetData& data) {
|
||||||
|
auto self = shared_from_this();
|
||||||
|
char buffer[NetData::size()];
|
||||||
|
data.serialize(buffer);
|
||||||
|
asio::async_write(m_socket, asio::buffer(buffer, NetData::size()),
|
||||||
|
[this, self](const asio::error_code& ec, std::size_t /*bytesTransferred*/) {
|
||||||
|
if (!ec) {
|
||||||
|
// 发送成功,等待对手动作
|
||||||
|
waitForOpponent();
|
||||||
|
} else {
|
||||||
|
std::cerr << "send failed: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::waitForOpponent() {
|
||||||
|
auto self = shared_from_this();
|
||||||
|
m_socket.async_read_some(
|
||||||
|
asio::buffer(m_readBuffer, NetData::size()),
|
||||||
|
[this, self](const asio::error_code& ec, std::size_t bytesTransferred) {
|
||||||
|
if (!ec) {
|
||||||
|
|
||||||
|
if (bytesTransferred == NetData::size()) {
|
||||||
|
NetData netData = NetData::deserialize(m_readBuffer);
|
||||||
|
// 触发对手移动回调
|
||||||
|
if (m_onOpponentMove) {
|
||||||
|
m_onOpponentMove(netData);
|
||||||
|
}
|
||||||
|
// 轮到我了
|
||||||
|
if (m_onMyTurn) {
|
||||||
|
m_onMyTurn();
|
||||||
|
}
|
||||||
|
// 重置读取缓冲区以准备下一次读取
|
||||||
|
|
||||||
|
} else {
|
||||||
|
std::cerr << "Incomplete data received from opponent." << std::endl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cerr << "read failed: " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
42
src/network/client/Client.h
Normal file
42
src/network/client/Client.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <asio.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "network/NetData.h"
|
||||||
|
|
||||||
|
class Client : public std::enable_shared_from_this<Client> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
// 事件回调类型
|
||||||
|
using MoveCallback = std::function<void(const NetData&)>;
|
||||||
|
using TurnCallback = std::function<void()>;
|
||||||
|
|
||||||
|
Client(asio::io_context& ioContext);
|
||||||
|
~Client() = default;
|
||||||
|
|
||||||
|
void setCallbackes(MoveCallback onOpponentMove, TurnCallback onMyTurn);
|
||||||
|
|
||||||
|
void connect(const std::string& host, int port, bool iAmFirst = true);
|
||||||
|
|
||||||
|
void sentClickPosition(const NetData& data);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
asio::ip::tcp::resolver m_resolver;
|
||||||
|
asio::ip::tcp::socket m_socket;
|
||||||
|
std::string m_host;
|
||||||
|
int m_port;
|
||||||
|
MoveCallback m_onOpponentMove;
|
||||||
|
TurnCallback m_onMyTurn;
|
||||||
|
char m_readBuffer[NetData::size()];
|
||||||
|
|
||||||
|
|
||||||
|
void onConnected(bool iAmFirst);
|
||||||
|
void waitForOpponent();
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
116
src/network/server/GameServer.cpp
Normal file
116
src/network/server/GameServer.cpp
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#include "GameServer.h"
|
||||||
|
#include <iostream>
|
||||||
|
//#include <sstream>
|
||||||
|
GameServer::GameServer(asio::io_context& ioContext)
|
||||||
|
: m_ioContext(ioContext),
|
||||||
|
m_player1(ioContext),
|
||||||
|
m_player2(ioContext),
|
||||||
|
m_acceptor(ioContext)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameServer::startServer(int port) {
|
||||||
|
|
||||||
|
std::cout << "Starting server on port " << port << std::endl;
|
||||||
|
//std::cout << "startServer called on thread: "
|
||||||
|
// << std::this_thread::get_id() << std::endl;
|
||||||
|
// 同步初始化(通常这部分是同步的)
|
||||||
|
asio::ip::tcp::endpoint endpoint(asio::ip::tcp::v4(), port);
|
||||||
|
m_acceptor.open(endpoint.protocol());
|
||||||
|
m_acceptor.set_option(asio::ip::tcp::acceptor::reuse_address(true));
|
||||||
|
m_acceptor.bind(endpoint);
|
||||||
|
m_acceptor.listen();
|
||||||
|
|
||||||
|
// 开始异步接受连接
|
||||||
|
waitForPlayers(1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameServer::waitForPlayers(int playerNum) {
|
||||||
|
|
||||||
|
/*if (!m_acceptor) {
|
||||||
|
std::cerr << "ERROR: m_acceptor is null in waitForPlayers!" << std::endl;
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
std::cout << "waitForPlayers called for player " << playerNum << std::endl;
|
||||||
|
|
||||||
|
//auto& socket = (playerNum == 1) ? m_player1 : m_player2;
|
||||||
|
std::cout << "accepting player " << playerNum << std::endl;
|
||||||
|
// 捕获 shared_ptr 确保对象存活
|
||||||
|
//auto self = shared_from_this();
|
||||||
|
try {
|
||||||
|
std::cout << "Before async_accept for player " << playerNum << std::endl;
|
||||||
|
|
||||||
|
/*if (!m_acceptor || !m_acceptor->is_open()) {
|
||||||
|
std::cerr << "Acceptor is not open!" << std::endl;
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
// 保存当前对象的原始指针(用于调试)
|
||||||
|
/*static std::atomic<void*> lastThisPtr = nullptr;
|
||||||
|
lastThisPtr = this;
|
||||||
|
std::cout << "waitForPlayers: this=" << this
|
||||||
|
<< ", playerNum=" << playerNum << std::endl;*/
|
||||||
|
//std::cout << "acceptor open: " << m_acceptor->is_open() << "\n";
|
||||||
|
//std::cout << "socket open: " << socket.is_open() << "\n";
|
||||||
|
// mingw老版本有重大问题,导致asio内部状态损坏,引起段错误!!!
|
||||||
|
m_acceptor.async_accept(
|
||||||
|
[this, playerNum](const asio::error_code& ec, asio::ip::tcp::socket peerSocket) {
|
||||||
|
if (!ec) {
|
||||||
|
std::cout << "player" << playerNum << " connect successfully\n";
|
||||||
|
if (playerNum == 1) {
|
||||||
|
m_player1 = std::move(peerSocket);
|
||||||
|
std::cout << "try to accept player2\n";
|
||||||
|
waitForPlayers(2);
|
||||||
|
} else {
|
||||||
|
m_player2 = std::move(peerSocket);
|
||||||
|
startGame();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cerr << "Error accepting player " << playerNum << ": " << ec.message() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
std::cout << "After async_accept for player " << playerNum << std::endl;
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Exception in waitForPlayers: " << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameServer::startGame() {
|
||||||
|
std::cout << "Gmae Start player1 is the first\n";
|
||||||
|
|
||||||
|
forwardMoves();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameServer::forwardMoves() {
|
||||||
|
listenPlayer(m_player1, m_player2);
|
||||||
|
listenPlayer(m_player2, m_player1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameServer::listenPlayer(asio::ip::tcp::socket& fromPlayer, asio::ip::tcp::socket& toPlayer) {
|
||||||
|
auto self = shared_from_this();
|
||||||
|
|
||||||
|
fromPlayer.async_read_some(
|
||||||
|
asio::buffer(m_buffer, NetData::size()),
|
||||||
|
[this, self, &fromPlayer, &toPlayer](const asio::error_code& ec, size_t bytes) {
|
||||||
|
if (!ec) {
|
||||||
|
if (bytes == NetData::size()) {
|
||||||
|
// 转发给对手
|
||||||
|
asio::async_write(
|
||||||
|
toPlayer,
|
||||||
|
asio::buffer(m_buffer, bytes),
|
||||||
|
[](const asio::error_code& ec, size_t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
);
|
||||||
|
listenPlayer(fromPlayer, toPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
30
src/network/server/GameServer.h
Normal file
30
src/network/server/GameServer.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <asio.hpp>
|
||||||
|
#include "network/NetData.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class GameServer : public std::enable_shared_from_this<GameServer> {
|
||||||
|
public:
|
||||||
|
GameServer(asio::io_context& ioContext);
|
||||||
|
~GameServer() = default;
|
||||||
|
|
||||||
|
void startServer( int port);
|
||||||
|
|
||||||
|
private:
|
||||||
|
asio::io_context& m_ioContext;
|
||||||
|
//std::unique_ptr<asio::ip::tcp::acceptor> m_acceptor;
|
||||||
|
asio::ip::tcp::acceptor m_acceptor;
|
||||||
|
asio::ip::tcp::socket m_player1;
|
||||||
|
asio::ip::tcp::socket m_player2;
|
||||||
|
char m_buffer[NetData::size()];
|
||||||
|
|
||||||
|
void waitForPlayers(int playerNumber);
|
||||||
|
|
||||||
|
void startGame();
|
||||||
|
|
||||||
|
void forwardMoves();
|
||||||
|
|
||||||
|
void listenPlayer(asio::ip::tcp::socket& fromPlayer, asio::ip::tcp::socket& toPlayer);
|
||||||
|
};
|
||||||
51
src/ui/managers/OnlineGameUIManager.cpp
Normal file
51
src/ui/managers/OnlineGameUIManager.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include "OnlineGameUIManager.h"
|
||||||
|
#include "ui/base/UIWidgetFactory.h"
|
||||||
|
OnlineGameUIManager::OnlineGameUIManager(SceneEventCallback eventCallback)
|
||||||
|
: GameUIManager(eventCallback) {
|
||||||
|
}
|
||||||
|
|
||||||
|
OnlineGameUIManager::~OnlineGameUIManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnlineGameUIManager::init() {
|
||||||
|
GameUIManager::init();
|
||||||
|
// 在这里可以添加在线游戏特有的UI组件
|
||||||
|
|
||||||
|
auto it = m_buttons.find(makeHash("ActionButton"));
|
||||||
|
if (it != m_buttons.end()) {
|
||||||
|
auto& actionButton = it->second;
|
||||||
|
actionButton->setEnabled(false); // 在线游戏中初始禁用
|
||||||
|
}
|
||||||
|
|
||||||
|
auto onlineHostButton = UIWidgetFactory::createStandardButton(
|
||||||
|
"OnlineHostButton",
|
||||||
|
"Host Game",
|
||||||
|
200,
|
||||||
|
100,
|
||||||
|
[this]() {
|
||||||
|
// host 模式
|
||||||
|
if(m_onlineTypeEvent) {
|
||||||
|
m_onlineTypeEvent(NetType::HOST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_buttons.emplace(onlineHostButton->getNameHash(), std::move(onlineHostButton));
|
||||||
|
auto onlineJoinButton = UIWidgetFactory::createStandardButton(
|
||||||
|
"OnlineJoinButton",
|
||||||
|
"Join Game",
|
||||||
|
400,
|
||||||
|
100,
|
||||||
|
[this]() {
|
||||||
|
|
||||||
|
if(m_onlineTypeEvent) {
|
||||||
|
m_onlineTypeEvent(NetType::CLIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_buttons.emplace(onlineJoinButton->getNameHash(), std::move(onlineJoinButton));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnlineGameUIManager::setOnlineTypeCallback(OnlineTypeEvent onlineTypeEvent) {
|
||||||
|
m_onlineTypeEvent = onlineTypeEvent;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user