Compare commits
No commits in common. "e799b4ec79e5e22778e1c6ab5b04da2ef7a39743" and "d249f17d22a774495ba7b93222af4667241ea2cf" have entirely different histories.
e799b4ec79
...
d249f17d22
@ -1,128 +0,0 @@
|
|||||||
{
|
|
||||||
"root": {
|
|
||||||
"type": "FrameLayout",
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 1280,
|
|
||||||
"height": 720,
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"type": "LinearLayout",
|
|
||||||
"name": "settingsButtons",
|
|
||||||
"orientation": "vertical",
|
|
||||||
"spacing": 10,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
"width": 300,
|
|
||||||
"height": 300,
|
|
||||||
"children": [
|
|
||||||
{
|
|
||||||
"type": "Button",
|
|
||||||
"name": "langButton",
|
|
||||||
"x": 1100,
|
|
||||||
"y": 580,
|
|
||||||
"width": 142,
|
|
||||||
"height": 96,
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/main_menu/lang.png",
|
|
||||||
"hover": "resources/main_menu/lang.png",
|
|
||||||
"pressed": "resources/main_menu/lang.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Button",
|
|
||||||
"name": "titleBtn",
|
|
||||||
"x": 473,
|
|
||||||
"y": 500,
|
|
||||||
"width": 254,
|
|
||||||
"height": 35,
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/main_menu/title.png",
|
|
||||||
"hover": "resources/main_menu/title.png",
|
|
||||||
"pressed": "resources/main_menu/title.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Button",
|
|
||||||
"name": "underlineBtn",
|
|
||||||
"x": 516,
|
|
||||||
"y": 465,
|
|
||||||
"width": 168,
|
|
||||||
"height": 44,
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/main_menu/line.png",
|
|
||||||
"hover": "resources/main_menu/line.png",
|
|
||||||
"pressed": "resources/main_menu/line.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Button",
|
|
||||||
"name": "subtitleBtn",
|
|
||||||
"x": 528,
|
|
||||||
"y": 455,
|
|
||||||
"width": 144,
|
|
||||||
"height": 11,
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/main_menu/subtitle.png",
|
|
||||||
"hover": "resources/main_menu/subtitle.png",
|
|
||||||
"pressed": "resources/main_menu/subtitle.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Button",
|
|
||||||
"name": "singleButton",
|
|
||||||
"x": 409,
|
|
||||||
"y": 360,
|
|
||||||
"width": 382,
|
|
||||||
"height": 56,
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/main_menu/single.png",
|
|
||||||
"hover": "resources/main_menu/single.png",
|
|
||||||
"pressed": "resources/main_menu/single.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Button",
|
|
||||||
"name": "multiplayerButton",
|
|
||||||
"x": 409,
|
|
||||||
"y": 289,
|
|
||||||
"width": 382,
|
|
||||||
"height": 56,
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/main_menu/multi.png",
|
|
||||||
"hover": "resources/main_menu/multi.png",
|
|
||||||
"pressed": "resources/main_menu/multi.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Button",
|
|
||||||
"name": "exitButton",
|
|
||||||
"x": 409,
|
|
||||||
"y": 218,
|
|
||||||
"width": 382,
|
|
||||||
"height": 56,
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/main_menu/exit.png",
|
|
||||||
"hover": "resources/main_menu/exit.png",
|
|
||||||
"pressed": "resources/main_menu/exit.png"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Button",
|
|
||||||
"name": "versionLabel",
|
|
||||||
"x": 559.5,
|
|
||||||
"y": 170,
|
|
||||||
"width": 81,
|
|
||||||
"height": 9,
|
|
||||||
"textures": {
|
|
||||||
"normal": "resources/main_menu/version.png",
|
|
||||||
"hover": "resources/main_menu/version.png",
|
|
||||||
"pressed": "resources/main_menu/version.png"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BIN
resources/main_menu/exit.png
(Stored with Git LFS)
BIN
resources/main_menu/exit.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/main_menu/lang.png
(Stored with Git LFS)
BIN
resources/main_menu/lang.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/main_menu/line.png
(Stored with Git LFS)
BIN
resources/main_menu/line.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/main_menu/multi.png
(Stored with Git LFS)
BIN
resources/main_menu/multi.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/main_menu/single.png
(Stored with Git LFS)
BIN
resources/main_menu/single.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/main_menu/subtitle.png
(Stored with Git LFS)
BIN
resources/main_menu/subtitle.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/main_menu/title.png
(Stored with Git LFS)
BIN
resources/main_menu/title.png
(Stored with Git LFS)
Binary file not shown.
BIN
resources/main_menu/version.png
(Stored with Git LFS)
BIN
resources/main_menu/version.png
(Stored with Git LFS)
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
resources/platform_base.png
(Stored with Git LFS)
BIN
resources/platform_base.png
(Stored with Git LFS)
Binary file not shown.
@ -11,8 +11,6 @@
|
|||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "../src/network/ClientState.h"
|
#include "../src/network/ClientState.h"
|
||||||
#include <random>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
// Вспомогательный split
|
// Вспомогательный split
|
||||||
std::vector<std::string> split(const std::string& s, char delimiter) {
|
std::vector<std::string> split(const std::string& s, char delimiter) {
|
||||||
@ -33,16 +31,6 @@ using tcp = net::ip::tcp;
|
|||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
|
|
||||||
struct ServerBox {
|
|
||||||
Eigen::Vector3f position;
|
|
||||||
Eigen::Matrix3f rotation;
|
|
||||||
float collisionRadius = 2.0f;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<ServerBox> g_serverBoxes;
|
|
||||||
std::mutex g_boxes_mutex;
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Session>> g_sessions;
|
std::vector<std::shared_ptr<Session>> g_sessions;
|
||||||
std::mutex g_sessions_mutex;
|
std::mutex g_sessions_mutex;
|
||||||
|
|
||||||
@ -50,85 +38,39 @@ class Session : public std::enable_shared_from_this<Session> {
|
|||||||
websocket::stream<beast::tcp_stream> ws_;
|
websocket::stream<beast::tcp_stream> ws_;
|
||||||
beast::flat_buffer buffer_;
|
beast::flat_buffer buffer_;
|
||||||
int id_;
|
int id_;
|
||||||
bool is_writing_ = false;
|
|
||||||
|
|
||||||
ClientStateInterval timedClientStates;
|
ClientStateInterval timedClientStates;
|
||||||
|
|
||||||
void process_message(const std::string& msg) {
|
void process_message(const std::string& msg) {
|
||||||
auto now_server = std::chrono::system_clock::now();
|
auto now_server = std::chrono::system_clock::now();
|
||||||
|
|
||||||
auto parts = split(msg, ':');
|
auto parts = split(msg, ':');
|
||||||
|
|
||||||
if (parts.empty()) {
|
if (parts.size() < 16)
|
||||||
std::cerr << "Empty message received\n";
|
{
|
||||||
return;
|
throw std::runtime_error("Unknown message type received, too small");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string type = parts[0];
|
|
||||||
|
|
||||||
if (type == "UPD") {
|
|
||||||
if (parts.size() < 16) {
|
|
||||||
std::cerr << "Invalid UPD message: too few parts (" << parts.size() << ")\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint64_t clientTimestamp = std::stoull(parts[1]);
|
uint64_t clientTimestamp = std::stoull(parts[1]);
|
||||||
|
|
||||||
ClientState receivedState;
|
ClientState receivedState;
|
||||||
|
|
||||||
receivedState.id = id_;
|
receivedState.id = id_;
|
||||||
std::chrono::system_clock::time_point uptime_timepoint{
|
|
||||||
std::chrono::milliseconds(clientTimestamp)
|
std::chrono::system_clock::time_point uptime_timepoint{ std::chrono::duration_cast<std::chrono::system_clock::time_point::duration>(std::chrono::milliseconds(clientTimestamp)) };
|
||||||
};
|
|
||||||
receivedState.lastUpdateServerTime = uptime_timepoint;
|
receivedState.lastUpdateServerTime = uptime_timepoint;
|
||||||
|
|
||||||
|
if (parts[0] == "UPD") {
|
||||||
receivedState.handle_full_sync(parts, 2);
|
receivedState.handle_full_sync(parts, 2);
|
||||||
retranslateMessage(msg);
|
retranslateMessage(msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unknown message type received: " + parts[0]);
|
||||||
|
}
|
||||||
|
|
||||||
timedClientStates.add_state(receivedState);
|
timedClientStates.add_state(receivedState);
|
||||||
}
|
}
|
||||||
else if (parts[0] == "FIRE") {
|
|
||||||
if (parts.size() < 8) {
|
|
||||||
std::cerr << "Invalid FIRE: too few parts\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t clientTime = std::stoull(parts[1]);
|
|
||||||
Eigen::Vector3f pos{
|
|
||||||
std::stof(parts[2]), std::stof(parts[3]), std::stof(parts[4])
|
|
||||||
};
|
|
||||||
Eigen::Vector3f dir{
|
|
||||||
std::stof(parts[5]), std::stof(parts[6]), std::stof(parts[7])
|
|
||||||
};
|
|
||||||
|
|
||||||
int shotCount = 1;
|
|
||||||
if (parts.size() >= 9) {
|
|
||||||
try {
|
|
||||||
shotCount = std::stoi(parts[8]);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
shotCount = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string broadcast = "PROJECTILE:" +
|
|
||||||
std::to_string(id_) + ":" +
|
|
||||||
std::to_string(clientTime) + ":" +
|
|
||||||
std::to_string(pos.x()) + ":" +
|
|
||||||
std::to_string(pos.y()) + ":" +
|
|
||||||
std::to_string(pos.z()) + ":" +
|
|
||||||
std::to_string(dir.x()) + ":" +
|
|
||||||
std::to_string(dir.y()) + ":" +
|
|
||||||
std::to_string(dir.z()) + ":" +
|
|
||||||
std::to_string(shotCount);
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(g_sessions_mutex);
|
|
||||||
std::cout << "Player " << id_ << " fired " << shotCount << " shots → broadcasting\n";
|
|
||||||
|
|
||||||
for (auto& session : g_sessions) {
|
|
||||||
if (session->get_id() != id_) {
|
|
||||||
session->send_message(broadcast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::cerr << "Unknown message type: " << type << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void retranslateMessage(const std::string& msg)
|
void retranslateMessage(const std::string& msg)
|
||||||
{
|
{
|
||||||
@ -142,52 +84,6 @@ class Session : public std::enable_shared_from_this<Session> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendBoxesToClient() {
|
|
||||||
std::lock_guard<std::mutex> lock(g_boxes_mutex);
|
|
||||||
|
|
||||||
std::string boxMsg = "BOXES:";
|
|
||||||
for (const auto& box : g_serverBoxes) {
|
|
||||||
Eigen::Quaternionf q(box.rotation);
|
|
||||||
boxMsg += std::to_string(box.position.x()) + ":" +
|
|
||||||
std::to_string(box.position.y()) + ":" +
|
|
||||||
std::to_string(box.position.z()) + ":" +
|
|
||||||
std::to_string(q.w()) + ":" +
|
|
||||||
std::to_string(q.x()) + ":" +
|
|
||||||
std::to_string(q.y()) + ":" +
|
|
||||||
std::to_string(q.z()) + "|";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!boxMsg.empty() && boxMsg.back() == '|') {
|
|
||||||
boxMsg.pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
send_message(boxMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_message(std::string msg) {
|
|
||||||
auto ss = std::make_shared<std::string>(std::move(msg));
|
|
||||||
|
|
||||||
if (is_writing_) {
|
|
||||||
|
|
||||||
ws_.async_write(net::buffer(*ss),
|
|
||||||
[self = shared_from_this(), ss](beast::error_code ec, std::size_t) {
|
|
||||||
if (ec) {
|
|
||||||
std::cerr << "Write error: " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
is_writing_ = true;
|
|
||||||
ws_.async_write(net::buffer(*ss),
|
|
||||||
[self = shared_from_this(), ss](beast::error_code ec, std::size_t) {
|
|
||||||
self->is_writing_ = false;
|
|
||||||
if (ec) {
|
|
||||||
std::cerr << "Write error: " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Session(tcp::socket&& socket, int id)
|
explicit Session(tcp::socket&& socket, int id)
|
||||||
@ -196,16 +92,6 @@ public:
|
|||||||
|
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
sendBoxesToClient();
|
|
||||||
|
|
||||||
auto timer = std::make_shared<net::steady_timer>(ws_.get_executor());
|
|
||||||
timer->expires_after(std::chrono::milliseconds(100));
|
|
||||||
timer->async_wait([self = shared_from_this(), timer](const boost::system::error_code& ec) {
|
|
||||||
if (!ec) {
|
|
||||||
self->send_message("ID:" + std::to_string(self->id_));
|
|
||||||
self->do_read();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() {
|
void run() {
|
||||||
@ -219,15 +105,15 @@ public:
|
|||||||
if (ec) return;
|
if (ec) return;
|
||||||
std::cout << "Client " << self->id_ << " connected\n";
|
std::cout << "Client " << self->id_ << " connected\n";
|
||||||
self->init();
|
self->init();
|
||||||
// self->send_message("ID:" + std::to_string(self->id_));
|
self->send_message("ID:" + std::to_string(self->id_));
|
||||||
// self->do_read();
|
self->do_read();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void send_message(std::string msg) {
|
void send_message(std::string msg) {
|
||||||
auto ss = std::make_shared<std::string>(std::move(msg));
|
auto ss = std::make_shared<std::string>(std::move(msg));
|
||||||
ws_.async_write(net::buffer(*ss), [ss](beast::error_code, std::size_t) {});
|
ws_.async_write(net::buffer(*ss), [ss](beast::error_code, std::size_t) {});
|
||||||
}*/
|
}
|
||||||
|
|
||||||
int get_id() const {
|
int get_id() const {
|
||||||
return id_;
|
return id_;
|
||||||
@ -265,63 +151,8 @@ void update_world(net::steady_timer& timer, net::io_context& ioc) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ServerBox> generateServerBoxes(int count) {
|
|
||||||
std::vector<ServerBox> boxes;
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 gen(rd());
|
|
||||||
|
|
||||||
const float MIN_COORD = -100.0f;
|
|
||||||
const float MAX_COORD = 100.0f;
|
|
||||||
const float MIN_DISTANCE = 3.0f;
|
|
||||||
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE;
|
|
||||||
const int MAX_ATTEMPTS = 1000;
|
|
||||||
|
|
||||||
std::uniform_real_distribution<> posDistrib(MIN_COORD, MAX_COORD);
|
|
||||||
std::uniform_real_distribution<> angleDistrib(0.0, M_PI * 2.0);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
bool accepted = false;
|
|
||||||
int attempts = 0;
|
|
||||||
|
|
||||||
while (!accepted && attempts < MAX_ATTEMPTS) {
|
|
||||||
ServerBox box;
|
|
||||||
box.position = Eigen::Vector3f(
|
|
||||||
(float)posDistrib(gen),
|
|
||||||
(float)posDistrib(gen),
|
|
||||||
(float)posDistrib(gen)
|
|
||||||
);
|
|
||||||
|
|
||||||
accepted = true;
|
|
||||||
for (const auto& existingBox : boxes) {
|
|
||||||
Eigen::Vector3f diff = box.position - existingBox.position;
|
|
||||||
if (diff.squaredNorm() < MIN_DISTANCE_SQUARED) {
|
|
||||||
accepted = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (accepted) {
|
|
||||||
float randomAngle = (float)angleDistrib(gen);
|
|
||||||
Eigen::Vector3f axis = Eigen::Vector3f::Random().normalized();
|
|
||||||
box.rotation = Eigen::AngleAxisf(randomAngle, axis).toRotationMatrix();
|
|
||||||
boxes.push_back(box);
|
|
||||||
}
|
|
||||||
|
|
||||||
attempts++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return boxes;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
try {
|
try {
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(g_boxes_mutex);
|
|
||||||
g_serverBoxes = generateServerBoxes(50);
|
|
||||||
std::cout << "Generated " << g_serverBoxes.size() << " boxes on server\n";
|
|
||||||
}
|
|
||||||
net::io_context ioc;
|
net::io_context ioc;
|
||||||
tcp::acceptor acceptor{ ioc, {tcp::v4(), 8080} };
|
tcp::acceptor acceptor{ ioc, {tcp::v4(), 8080} };
|
||||||
int next_id = 0;
|
int next_id = 0;
|
||||||
|
|||||||
143
src/Game.cpp
143
src/Game.cpp
@ -10,7 +10,6 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#endif
|
#endif
|
||||||
@ -269,10 +268,6 @@ namespace ZL
|
|||||||
bool explosionCfgLoaded = explosionEmitter.loadFromJsonFile("resources/config/explosion_config.json", renderer, CONST_ZIP_FILE);
|
bool explosionCfgLoaded = explosionEmitter.loadFromJsonFile("resources/config/explosion_config.json", renderer, CONST_ZIP_FILE);
|
||||||
explosionEmitter.setEmissionPoints(std::vector<Vector3f>());
|
explosionEmitter.setEmissionPoints(std::vector<Vector3f>());
|
||||||
projectileEmitter.setEmissionPoints(std::vector<Vector3f>());
|
projectileEmitter.setEmissionPoints(std::vector<Vector3f>());
|
||||||
|
|
||||||
uiManager.loadFromFile("resources/config/main_menu.json", renderer, CONST_ZIP_FILE);
|
|
||||||
std::function<void()> loadGameplayUI;
|
|
||||||
loadGameplayUI = [this]() {
|
|
||||||
uiManager.loadFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE);
|
uiManager.loadFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE);
|
||||||
|
|
||||||
uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
|
uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
|
||||||
@ -301,8 +296,10 @@ namespace ZL
|
|||||||
g_exitBgAnimating = false;
|
g_exitBgAnimating = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set UI button callbacks
|
||||||
uiManager.setButtonCallback("playButton", [this](const std::string& name) {
|
uiManager.setButtonCallback("playButton", [this](const std::string& name) {
|
||||||
std::cerr << "Play button pressed: " << name << std::endl;
|
std::cerr << "Play button pressed: " << name << std::endl;
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
uiManager.setButtonCallback("settingsButton", [this](const std::string& name) {
|
uiManager.setButtonCallback("settingsButton", [this](const std::string& name) {
|
||||||
@ -335,31 +332,11 @@ namespace ZL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
uiManager.setButtonCallback("shootButton", [this](const std::string& name) {
|
uiManager.setButtonCallback("shootButton", [this](const std::string& name) {
|
||||||
uint64_t now = SDL_GetTicks64();
|
uint64_t now = SDL_GetTicks64();
|
||||||
if (now - lastProjectileFireTime >= static_cast<uint64_t>(projectileCooldownMs)) {
|
if (now - lastProjectileFireTime >= static_cast<uint64_t>(projectileCooldownMs)) {
|
||||||
lastProjectileFireTime = now;
|
lastProjectileFireTime = now;
|
||||||
|
fireProjectiles();
|
||||||
this->fireProjectiles();
|
|
||||||
|
|
||||||
Eigen::Vector3f localForward = { 0, 0, -1 };
|
|
||||||
Eigen::Vector3f worldForward = (Environment::shipState.rotation * localForward).normalized();
|
|
||||||
|
|
||||||
Eigen::Vector3f centerPos = Environment::shipState.position +
|
|
||||||
Environment::shipState.rotation * Vector3f{ 0, 0.9f, 5.0f };
|
|
||||||
|
|
||||||
std::string fireMsg = "FIRE:" +
|
|
||||||
std::to_string(now) + ":" +
|
|
||||||
std::to_string(centerPos.x()) + ":" +
|
|
||||||
std::to_string(centerPos.y()) + ":" +
|
|
||||||
std::to_string(centerPos.z()) + ":" +
|
|
||||||
std::to_string(worldForward.x()) + ":" +
|
|
||||||
std::to_string(worldForward.y()) + ":" +
|
|
||||||
std::to_string(worldForward.z()) + ":" +
|
|
||||||
"2";
|
|
||||||
|
|
||||||
networkClient->Send(fireMsg);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -369,20 +346,6 @@ namespace ZL
|
|||||||
newShipVelocity = newVel;
|
newShipVelocity = newVel;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
uiManager.setButtonCallback("singleButton", [loadGameplayUI](const std::string& name) {
|
|
||||||
std::cerr << "Single button pressed: " << name << " -> load gameplay UI\n";
|
|
||||||
loadGameplayUI();
|
|
||||||
});
|
|
||||||
uiManager.setButtonCallback("multiplayerButton", [loadGameplayUI](const std::string& name) {
|
|
||||||
std::cerr << "Multiplayer button pressed: " << name << " -> load gameplay UI\n";
|
|
||||||
loadGameplayUI();
|
|
||||||
});
|
|
||||||
uiManager.setButtonCallback("exitButton", [](const std::string& name) {
|
|
||||||
std::cerr << "Exit from main menu pressed: " << name << " -> exiting\n";
|
|
||||||
Environment::exitGameLoop = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
cubemapTexture = std::make_shared<Texture>(
|
cubemapTexture = std::make_shared<Texture>(
|
||||||
std::array<TextureDataStruct, 6>{
|
std::array<TextureDataStruct, 6>{
|
||||||
@ -577,9 +540,6 @@ namespace ZL
|
|||||||
explosionEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
explosionEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
||||||
}
|
}
|
||||||
|
|
||||||
//glBindTexture(GL_TEXTURE_2D, basePlatformTexture->getTexID());
|
|
||||||
//renderer.DrawVertexRenderStruct(basePlatform);
|
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
@ -732,27 +692,6 @@ namespace ZL
|
|||||||
|
|
||||||
latestRemotePlayers = networkClient->getRemotePlayers();
|
latestRemotePlayers = networkClient->getRemotePlayers();
|
||||||
|
|
||||||
// Если сервер прислал коробки, применяем их однократно вместо локальной генерации
|
|
||||||
if (!serverBoxesApplied && networkClient) {
|
|
||||||
auto sboxes = networkClient->getServerBoxes();
|
|
||||||
if (!sboxes.empty()) {
|
|
||||||
boxCoordsArr.clear();
|
|
||||||
for (auto& b : sboxes) {
|
|
||||||
BoxCoords bc;
|
|
||||||
bc.pos = b.first;
|
|
||||||
bc.m = b.second;
|
|
||||||
boxCoordsArr.push_back(bc);
|
|
||||||
}
|
|
||||||
boxRenderArr.resize(boxCoordsArr.size());
|
|
||||||
for (int i = 0; i < (int)boxCoordsArr.size(); ++i) {
|
|
||||||
boxRenderArr[i].AssignFrom(boxBase);
|
|
||||||
boxRenderArr[i].RefreshVBO();
|
|
||||||
}
|
|
||||||
boxAlive.assign(boxCoordsArr.size(), true);
|
|
||||||
serverBoxesApplied = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Итерируемся по актуальным данным из extrapolateRemotePlayers
|
// Итерируемся по актуальным данным из extrapolateRemotePlayers
|
||||||
for (auto const& [id, remotePlayer] : latestRemotePlayers) {
|
for (auto const& [id, remotePlayer] : latestRemotePlayers) {
|
||||||
|
|
||||||
@ -831,16 +770,7 @@ namespace ZL
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
float uiX = sx, uiY = sy;
|
float uiX = sx, uiY = sy;
|
||||||
//float scale = std::clamp(BASE_SCALE / (dist * PERSPECTIVE_K + 1.f), MIN_SCALE, MAX_SCALE);
|
float scale = std::clamp(BASE_SCALE / (dist * PERSPECTIVE_K + 1.f), MIN_SCALE, MAX_SCALE);
|
||||||
float scale;
|
|
||||||
if (dist > CLOSE_DIST) {
|
|
||||||
scale = 0.4f;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
float t = 1.0f - (dist / CLOSE_DIST);
|
|
||||||
scale = 0.4f + (MAX_SCALE - 0.4f) * t;
|
|
||||||
}
|
|
||||||
scale = std::clamp(scale, MIN_SCALE, MAX_SCALE);
|
|
||||||
|
|
||||||
// Дефолтный лейбл
|
// Дефолтный лейбл
|
||||||
std::string label = "Player (" + std::to_string(st.id) + ") " + std::to_string((int)dist) + "m";
|
std::string label = "Player (" + std::to_string(st.id) + ") " + std::to_string((int)dist) + "m";
|
||||||
@ -1300,7 +1230,7 @@ namespace ZL
|
|||||||
handleMotion(mx, my);
|
handleMotion(mx, my);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
if (event.type == SDL_MOUSEWHEEL) {
|
if (event.type == SDL_MOUSEWHEEL) {
|
||||||
static const float zoomstep = 2.0f;
|
static const float zoomstep = 2.0f;
|
||||||
if (event.wheel.y > 0) {
|
if (event.wheel.y > 0) {
|
||||||
@ -1317,73 +1247,14 @@ namespace ZL
|
|||||||
{
|
{
|
||||||
if (event.key.keysym.sym == SDLK_i)
|
if (event.key.keysym.sym == SDLK_i)
|
||||||
{
|
{
|
||||||
x = x + 1;
|
|
||||||
}
|
|
||||||
if (event.key.keysym.sym == SDLK_k)
|
|
||||||
{
|
|
||||||
x = x - 1;
|
|
||||||
}
|
|
||||||
if (event.key.keysym.sym == SDLK_a)
|
|
||||||
{
|
|
||||||
Environment::shipState.position = { 9466.15820, 1046.00159, 18531.2090 };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
render();
|
render();
|
||||||
mainThreadHandler.processMainThreadTasks();
|
mainThreadHandler.processMainThreadTasks();
|
||||||
networkClient->Poll();
|
networkClient->Poll();
|
||||||
|
|
||||||
if (networkClient) {
|
|
||||||
auto pending = networkClient->getPendingProjectiles();
|
|
||||||
if (!pending.empty()) {
|
|
||||||
const float projectileSpeed = 60.0f;
|
|
||||||
const float lifeMs = 5000.0f;
|
|
||||||
const float size = 0.5f;
|
|
||||||
|
|
||||||
auto remotePlayersSnapshot = networkClient->getRemotePlayers();
|
|
||||||
for (const auto& pi : pending) {
|
|
||||||
Eigen::Vector3f dir = pi.direction;
|
|
||||||
float len = dir.norm();
|
|
||||||
if (len <= 1e-6f) continue;
|
|
||||||
dir /= len;
|
|
||||||
|
|
||||||
Eigen::Matrix3f shooterRot = Eigen::Matrix3f::Identity();
|
|
||||||
float shooterVel = 0.0f;
|
|
||||||
auto it = remotePlayersSnapshot.find(pi.shooterId);
|
|
||||||
if (it != remotePlayersSnapshot.end()) {
|
|
||||||
std::chrono::system_clock::time_point pktTime{ std::chrono::milliseconds(pi.clientTime) };
|
|
||||||
if (it->second.canFetchClientStateAtTime(pktTime)) {
|
|
||||||
ClientState shooterState = it->second.fetchClientStateAtTime(pktTime);
|
|
||||||
shooterRot = shooterState.rotation;
|
|
||||||
shooterVel = shooterState.velocity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float speedWithOwner = projectileSpeed + shooterVel;
|
|
||||||
Eigen::Vector3f baseVel = dir * speedWithOwner;
|
|
||||||
|
|
||||||
int shotCount = 2;
|
|
||||||
|
|
||||||
std::vector<Eigen::Vector3f> localOffsets = {
|
|
||||||
{-1.5f, 0.9f, 5.0f},
|
|
||||||
{ 1.5f, 0.9f, 5.0f}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; i < shotCount; ++i) {
|
|
||||||
Eigen::Vector3f rotatedOffset = shooterRot * localOffsets[i];
|
|
||||||
Eigen::Vector3f shotPos = pi.position + rotatedOffset;
|
|
||||||
|
|
||||||
for (auto& p : projectiles) {
|
|
||||||
if (!p->isActive()) {
|
|
||||||
p->init(shotPos, baseVel, lifeMs, size, projectileTexture, renderer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Game::handleDown(int mx, int my)
|
void Game::handleDown(int mx, int my)
|
||||||
|
|||||||
@ -86,7 +86,6 @@ namespace ZL {
|
|||||||
VertexDataStruct spaceshipBase;
|
VertexDataStruct spaceshipBase;
|
||||||
VertexRenderStruct spaceship;
|
VertexRenderStruct spaceship;
|
||||||
|
|
||||||
|
|
||||||
VertexRenderStruct cubemap;
|
VertexRenderStruct cubemap;
|
||||||
|
|
||||||
std::shared_ptr<Texture> boxTexture;
|
std::shared_ptr<Texture> boxTexture;
|
||||||
@ -122,9 +121,7 @@ namespace ZL {
|
|||||||
static constexpr float BASE_SCALE = 140.f;
|
static constexpr float BASE_SCALE = 140.f;
|
||||||
static constexpr float PERSPECTIVE_K = 0.05f; // Tune
|
static constexpr float PERSPECTIVE_K = 0.05f; // Tune
|
||||||
static constexpr float MIN_SCALE = 0.4f;
|
static constexpr float MIN_SCALE = 0.4f;
|
||||||
static constexpr float MAX_SCALE = 0.8f;
|
static constexpr float MAX_SCALE = 1.5f;
|
||||||
static constexpr float CLOSE_DIST = 600.0f;
|
|
||||||
bool serverBoxesApplied = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -45,69 +45,6 @@ void ClientState::simulate_physics(size_t delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
float distToCenter = position.norm(); // Расстояние до {0,0,0}
|
|
||||||
float landingZone = PLANET_RADIUS * PLANET_ALIGN_ZONE;
|
|
||||||
|
|
||||||
if (distToCenter <= landingZone) {
|
|
||||||
Eigen::Vector3f planetNormal = position.normalized();
|
|
||||||
|
|
||||||
// --- 1. ВЫРАВНИВАНИЕ КРЕНА (Roll - ось Z) ---
|
|
||||||
Eigen::Vector3f localX = rotation.col(0);
|
|
||||||
float rollError = localX.dot(planetNormal);
|
|
||||||
|
|
||||||
if (std::abs(rollError) > 0.001f) {
|
|
||||||
currentAngularVelocity.z() -= rollError * PLANET_ANGULAR_ACCEL * delta;
|
|
||||||
currentAngularVelocity.z() = std::max(-PLANET_MAX_ANGULAR_VELOCITY,
|
|
||||||
std::min(currentAngularVelocity.z(), PLANET_MAX_ANGULAR_VELOCITY));
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- 2. ОГРАНИЧЕНИЕ ТАНГАЖА (Pitch - ось X) ---
|
|
||||||
// Нос корабля в локальных координатах — это -Z (третий столбец матрицы)
|
|
||||||
Eigen::Vector3f forwardDir = -rotation.col(2);
|
|
||||||
|
|
||||||
// В твоем случае dot < 0 означает, что нос направлен К планете
|
|
||||||
float pitchSin = forwardDir.dot(planetNormal);
|
|
||||||
float currentPitchAngle = asinf(std::clamp(pitchSin, -1.0f, 1.0f));
|
|
||||||
|
|
||||||
// Лимит у нас M_PI / 6.0 (примерно 0.523)
|
|
||||||
// По твоим данным: -0.89 < -0.523, значит мы превысили наклон вниз
|
|
||||||
if (currentPitchAngle < -PITCH_LIMIT) {
|
|
||||||
// Вычисляем ошибку (насколько мы ушли "ниже" лимита)
|
|
||||||
// -0.89 - (-0.52) = -0.37
|
|
||||||
float pitchError = currentPitchAngle + PITCH_LIMIT;
|
|
||||||
|
|
||||||
// Теперь важно: нам нужно ПОДНЯТЬ нос.
|
|
||||||
// Если pitchError отрицательный, а нам нужно уменьшить вращение,
|
|
||||||
// пробуем прибавлять или вычитать в зависимости от твоей оси X.
|
|
||||||
// Судя по стандартной логике Eigen, нам нужно ПЛЮСОВАТЬ:
|
|
||||||
currentAngularVelocity.x() -= pitchError * PLANET_ANGULAR_ACCEL * delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Вне зоны: тормозим Z (крен) И X (тангаж), если они были активны
|
|
||||||
float drop = ANGULAR_ACCEL * delta;
|
|
||||||
|
|
||||||
if (std::abs(currentAngularVelocity[2]) > 0.0001f) {
|
|
||||||
if (std::abs(currentAngularVelocity[2]) <= drop) {
|
|
||||||
currentAngularVelocity[2] = 0.0f;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
currentAngularVelocity[2] -= (currentAngularVelocity[2] > 0 ? 1.0f : -1.0f) * drop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ограничение скорости
|
|
||||||
currentAngularVelocity.x() = std::max(-PLANET_MAX_ANGULAR_VELOCITY,
|
|
||||||
std::min(currentAngularVelocity.x(), PLANET_MAX_ANGULAR_VELOCITY));
|
|
||||||
// Ограничение скорости
|
|
||||||
currentAngularVelocity.y() = std::max(-PLANET_MAX_ANGULAR_VELOCITY,
|
|
||||||
std::min(currentAngularVelocity.y(), PLANET_MAX_ANGULAR_VELOCITY));
|
|
||||||
// Ограничение скорости
|
|
||||||
currentAngularVelocity.z() = std::max(-PLANET_MAX_ANGULAR_VELOCITY,
|
|
||||||
std::min(currentAngularVelocity.z(), PLANET_MAX_ANGULAR_VELOCITY));
|
|
||||||
|
|
||||||
float speedScale = currentAngularVelocity.norm();
|
float speedScale = currentAngularVelocity.norm();
|
||||||
if (speedScale > 0.0001f) {
|
if (speedScale > 0.0001f) {
|
||||||
// Коэффициент чувствительности вращения
|
// Коэффициент чувствительности вращения
|
||||||
|
|||||||
@ -13,14 +13,8 @@ constexpr float ANGULAR_ACCEL = 0.005f * 1000.0f;
|
|||||||
constexpr float SHIP_ACCEL = 1.0f * 1000.0f;
|
constexpr float SHIP_ACCEL = 1.0f * 1000.0f;
|
||||||
constexpr float ROTATION_SENSITIVITY = 0.002f;
|
constexpr float ROTATION_SENSITIVITY = 0.002f;
|
||||||
|
|
||||||
constexpr float PLANET_RADIUS = 20000.f;
|
|
||||||
constexpr float PLANET_ALIGN_ZONE = 1.05f;
|
|
||||||
constexpr float PLANET_ANGULAR_ACCEL = 0.01f; // Подбери под динамику
|
|
||||||
constexpr float PLANET_MAX_ANGULAR_VELOCITY = 10.f;
|
|
||||||
constexpr float PITCH_LIMIT = static_cast<float>(M_PI) / 9.f;//18.0f;
|
|
||||||
|
|
||||||
constexpr long long SERVER_DELAY = 0; //ms
|
constexpr long long SERVER_DELAY = 0; //ms
|
||||||
constexpr long long CLIENT_DELAY = 1000; //ms
|
constexpr long long CLIENT_DELAY = 200; //ms
|
||||||
constexpr long long CUTOFF_TIME = 5000; //ms
|
constexpr long long CUTOFF_TIME = 5000; //ms
|
||||||
|
|
||||||
struct ClientState {
|
struct ClientState {
|
||||||
|
|||||||
@ -11,10 +11,8 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void LocalClient::Send(const std::string& message) {
|
void LocalClient::Send(const std::string& message) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ProjectileInfo> LocalClient::getPendingProjectiles() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -17,14 +17,9 @@ namespace ZL {
|
|||||||
|
|
||||||
bool IsConnected() const override { return true; }
|
bool IsConnected() const override { return true; }
|
||||||
int GetClientId() const { return 1; }
|
int GetClientId() const { return 1; }
|
||||||
std::vector<ProjectileInfo> getPendingProjectiles();
|
|
||||||
|
|
||||||
std::unordered_map<int, ClientStateInterval> getRemotePlayers() override {
|
std::unordered_map<int, ClientStateInterval> getRemotePlayers() override {
|
||||||
return std::unordered_map<int, ClientStateInterval>();
|
return std::unordered_map<int, ClientStateInterval>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> getServerBoxes() override {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -7,13 +7,6 @@
|
|||||||
// NetworkInterface.h - »нтерфейс дл¤ разных типов соединений
|
// NetworkInterface.h - »нтерфейс дл¤ разных типов соединений
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
struct ProjectileInfo {
|
|
||||||
int shooterId = -1;
|
|
||||||
uint64_t clientTime = 0;
|
|
||||||
Eigen::Vector3f position = Eigen::Vector3f::Zero();
|
|
||||||
Eigen::Vector3f direction = Eigen::Vector3f::Zero();
|
|
||||||
};
|
|
||||||
|
|
||||||
class INetworkClient {
|
class INetworkClient {
|
||||||
public:
|
public:
|
||||||
virtual ~INetworkClient() = default;
|
virtual ~INetworkClient() = default;
|
||||||
@ -22,9 +15,5 @@ namespace ZL {
|
|||||||
virtual bool IsConnected() const = 0;
|
virtual bool IsConnected() const = 0;
|
||||||
virtual void Poll() = 0; // ƒл¤ обработки вход¤щих пакетов
|
virtual void Poll() = 0; // ƒл¤ обработки вход¤щих пакетов
|
||||||
virtual std::unordered_map<int, ClientStateInterval> getRemotePlayers() = 0;
|
virtual std::unordered_map<int, ClientStateInterval> getRemotePlayers() = 0;
|
||||||
|
|
||||||
virtual std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> getServerBoxes() = 0;
|
|
||||||
|
|
||||||
virtual std::vector<ProjectileInfo> getPendingProjectiles() = 0;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,13 +64,6 @@ namespace ZL {
|
|||||||
messageQueue.push(msg);
|
messageQueue.push(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ProjectileInfo> WebSocketClient::getPendingProjectiles() {
|
|
||||||
std::lock_guard<std::mutex> lock(projMutex_);
|
|
||||||
auto copy = pendingProjectiles_;
|
|
||||||
pendingProjectiles_.clear();
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebSocketClient::Poll() {
|
void WebSocketClient::Poll() {
|
||||||
std::lock_guard<std::mutex> lock(queueMutex);
|
std::lock_guard<std::mutex> lock(queueMutex);
|
||||||
|
|
||||||
@ -90,68 +83,6 @@ namespace ZL {
|
|||||||
std::string msg = messageQueue.front();
|
std::string msg = messageQueue.front();
|
||||||
messageQueue.pop();
|
messageQueue.pop();
|
||||||
|
|
||||||
// Обработка списка коробок от сервера
|
|
||||||
if (msg.rfind("BOXES:", 0) == 0) {
|
|
||||||
std::string payload = msg.substr(6); // после "BOXES:"
|
|
||||||
std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> parsedBoxes;
|
|
||||||
if (!payload.empty()) {
|
|
||||||
auto items = split(payload, '|');
|
|
||||||
for (auto& item : items) {
|
|
||||||
if (item.empty()) continue;
|
|
||||||
auto parts = split(item, ':');
|
|
||||||
if (parts.size() < 7) continue;
|
|
||||||
try {
|
|
||||||
float px = std::stof(parts[0]);
|
|
||||||
float py = std::stof(parts[1]);
|
|
||||||
float pz = std::stof(parts[2]);
|
|
||||||
Eigen::Quaternionf q(
|
|
||||||
std::stof(parts[3]),
|
|
||||||
std::stof(parts[4]),
|
|
||||||
std::stof(parts[5]),
|
|
||||||
std::stof(parts[6])
|
|
||||||
);
|
|
||||||
Eigen::Matrix3f rot = q.toRotationMatrix();
|
|
||||||
parsedBoxes.emplace_back(Eigen::Vector3f{ px, py, pz }, rot);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
// пропускаем некорректную запись
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> bLock(boxesMutex);
|
|
||||||
serverBoxes_ = std::move(parsedBoxes);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.rfind("PROJECTILE:", 0) == 0) {
|
|
||||||
auto parts = split(msg, ':');
|
|
||||||
if (parts.size() >= 9) {
|
|
||||||
try {
|
|
||||||
ProjectileInfo pi;
|
|
||||||
pi.shooterId = std::stoi(parts[1]);
|
|
||||||
pi.clientTime = std::stoull(parts[2]);
|
|
||||||
pi.position = Eigen::Vector3f(
|
|
||||||
std::stof(parts[3]),
|
|
||||||
std::stof(parts[4]),
|
|
||||||
std::stof(parts[5])
|
|
||||||
);
|
|
||||||
pi.direction = Eigen::Vector3f(
|
|
||||||
std::stof(parts[6]),
|
|
||||||
std::stof(parts[7]),
|
|
||||||
std::stof(parts[8])
|
|
||||||
);
|
|
||||||
std::lock_guard<std::mutex> pl(projMutex_);
|
|
||||||
pendingProjectiles_.push_back(pi);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.rfind("EVENT:", 0) == 0) {
|
if (msg.rfind("EVENT:", 0) == 0) {
|
||||||
auto parts = split(msg, ':');
|
auto parts = split(msg, ':');
|
||||||
if (parts.size() < 5) continue; // EVENT:ID:TYPE:TIME:DATA...
|
if (parts.size() < 5) continue; // EVENT:ID:TYPE:TIME:DATA...
|
||||||
|
|||||||
@ -34,13 +34,6 @@ namespace ZL {
|
|||||||
std::unordered_map<int, ClientStateInterval> remotePlayers;
|
std::unordered_map<int, ClientStateInterval> remotePlayers;
|
||||||
std::mutex playersMutex;
|
std::mutex playersMutex;
|
||||||
|
|
||||||
// Серверные коробки
|
|
||||||
std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> serverBoxes_;
|
|
||||||
std::mutex boxesMutex;
|
|
||||||
|
|
||||||
std::vector<ProjectileInfo> pendingProjectiles_;
|
|
||||||
std::mutex projMutex_;
|
|
||||||
|
|
||||||
void startAsyncRead();
|
void startAsyncRead();
|
||||||
void processIncomingMessage(const std::string& msg);
|
void processIncomingMessage(const std::string& msg);
|
||||||
|
|
||||||
@ -61,13 +54,6 @@ namespace ZL {
|
|||||||
std::lock_guard<std::mutex> lock(playersMutex);
|
std::lock_guard<std::mutex> lock(playersMutex);
|
||||||
return remotePlayers;
|
return remotePlayers;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> getServerBoxes() override {
|
|
||||||
std::lock_guard<std::mutex> lock(boxesMutex);
|
|
||||||
return serverBoxes_;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<ProjectileInfo> getPendingProjectiles() override;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
Matrix3f GetRotationForTriangle(const Triangle& tri);
|
|
||||||
|
|
||||||
const float PlanetData::PLANET_RADIUS = 20000.f;
|
const float PlanetData::PLANET_RADIUS = 20000.f;
|
||||||
const Vector3f PlanetData::PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, 0.0f };
|
const Vector3f PlanetData::PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, 0.0f };
|
||||||
@ -30,9 +29,9 @@ namespace ZL {
|
|||||||
PlanetData::PlanetData()
|
PlanetData::PlanetData()
|
||||||
: perlin(77777)
|
: perlin(77777)
|
||||||
, colorPerlin(123123)
|
, colorPerlin(123123)
|
||||||
//, currentLod(0)
|
, currentLod(0)
|
||||||
{
|
{
|
||||||
// currentLod = planetMeshLods.size() - 1; // Start with max LOD
|
currentLod = planetMeshLods.size() - 1; // Start with max LOD
|
||||||
/*
|
/*
|
||||||
initialVertexMap = {
|
initialVertexMap = {
|
||||||
{{ 0.0f, 1.0f, 0.0f}, "A"},
|
{{ 0.0f, 1.0f, 0.0f}, "A"},
|
||||||
@ -55,29 +54,10 @@ namespace ZL {
|
|||||||
planetAtmosphereLod = generateSphere(5, 0);
|
planetAtmosphereLod = generateSphere(5, 0);
|
||||||
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
||||||
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
planetAtmosphereLod.Move(PLANET_CENTER_OFFSET);
|
||||||
|
|
||||||
const auto& lodLevel = getLodLevel();
|
|
||||||
|
|
||||||
for (size_t i = 0; i < lodLevel.triangles.size(); i++)
|
|
||||||
{
|
|
||||||
if (i % 100 == 0)
|
|
||||||
{
|
|
||||||
PlanetCampObject campObject;
|
|
||||||
|
|
||||||
campObject.position = (lodLevel.triangles[i].data[0] +
|
|
||||||
lodLevel.triangles[i].data[1] +
|
|
||||||
lodLevel.triangles[i].data[2]) / 3.0f;
|
|
||||||
|
|
||||||
auto newM = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI * 0.5, Eigen::Vector3f::UnitX())).toRotationMatrix();
|
|
||||||
|
|
||||||
campObject.rotation = GetRotationForTriangle(lodLevel.triangles[i]).inverse() * newM;
|
|
||||||
campObjects.push_back(campObject);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const LodLevel& PlanetData::getLodLevel() const {
|
const LodLevel& PlanetData::getLodLevel(int level) const {
|
||||||
return planetMeshLods.at(MAX_LOD_LEVELS-1);
|
return planetMeshLods.at(level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -85,14 +65,13 @@ namespace ZL {
|
|||||||
return planetAtmosphereLod;
|
return planetAtmosphereLod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
int PlanetData::getCurrentLodIndex() const {
|
int PlanetData::getCurrentLodIndex() const {
|
||||||
return currentLod;
|
return currentLod;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlanetData::getMaxLodIndex() const {
|
int PlanetData::getMaxLodIndex() const {
|
||||||
return static_cast<int>(planetMeshLods.size() - 1);
|
return static_cast<int>(planetMeshLods.size() - 1);
|
||||||
}*/
|
}
|
||||||
|
|
||||||
std::pair<float, float> PlanetData::calculateZRange(float dToPlanetSurface) {
|
std::pair<float, float> PlanetData::calculateZRange(float dToPlanetSurface) {
|
||||||
|
|
||||||
@ -159,7 +138,7 @@ namespace ZL {
|
|||||||
|
|
||||||
|
|
||||||
std::vector<int> PlanetData::getBestTriangleUnderCamera(const Vector3f& viewerPosition) {
|
std::vector<int> PlanetData::getBestTriangleUnderCamera(const Vector3f& viewerPosition) {
|
||||||
const LodLevel& finalLod = planetMeshLods[MAX_LOD_LEVELS - 1]; // Работаем с текущим активным LOD
|
const LodLevel& finalLod = planetMeshLods[currentLod]; // Работаем с текущим активным LOD
|
||||||
Vector3f targetDir = (viewerPosition - PLANET_CENTER_OFFSET).normalized();
|
Vector3f targetDir = (viewerPosition - PLANET_CENTER_OFFSET).normalized();
|
||||||
|
|
||||||
int bestTriangle = -1;
|
int bestTriangle = -1;
|
||||||
@ -188,7 +167,7 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> PlanetData::getTrianglesUnderCameraNew2(const Vector3f& viewerPosition) {
|
std::vector<int> PlanetData::getTrianglesUnderCameraNew2(const Vector3f& viewerPosition) {
|
||||||
const LodLevel& finalLod = planetMeshLods[MAX_LOD_LEVELS - 1];
|
const LodLevel& finalLod = planetMeshLods[currentLod];
|
||||||
Vector3f shipLocal = viewerPosition - PLANET_CENTER_OFFSET;
|
Vector3f shipLocal = viewerPosition - PLANET_CENTER_OFFSET;
|
||||||
float currentDist = shipLocal.norm();
|
float currentDist = shipLocal.norm();
|
||||||
Vector3f targetDir = shipLocal.normalized();
|
Vector3f targetDir = shipLocal.normalized();
|
||||||
|
|||||||
@ -75,20 +75,6 @@ namespace ZL {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PlanetCampObject
|
|
||||||
{
|
|
||||||
Vector3f position;
|
|
||||||
Matrix3f rotation;
|
|
||||||
|
|
||||||
std::array<Vector3f, 5> platformPos = {
|
|
||||||
Vector3f{ 0.f, 0.f,-38.f },
|
|
||||||
Vector3f{ 20.f, 0.f,-18.f },
|
|
||||||
Vector3f{ 20.f, 0.f,-58.f },
|
|
||||||
Vector3f{ -20.f, 0.f,-58.f },
|
|
||||||
Vector3f{ -20.f, 0.f,-18.f }
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class PlanetData {
|
class PlanetData {
|
||||||
public:
|
public:
|
||||||
static const float PLANET_RADIUS;
|
static const float PLANET_RADIUS;
|
||||||
@ -101,7 +87,7 @@ namespace ZL {
|
|||||||
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLods;
|
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLods;
|
||||||
LodLevel planetAtmosphereLod;
|
LodLevel planetAtmosphereLod;
|
||||||
|
|
||||||
//int currentLod; // Логический текущий уровень детализации
|
int currentLod; // Логический текущий уровень детализации
|
||||||
|
|
||||||
//std::map<Vector3f, VertexID, Vector3fComparator> initialVertexMap;
|
//std::map<Vector3f, VertexID, Vector3fComparator> initialVertexMap;
|
||||||
|
|
||||||
@ -114,8 +100,12 @@ namespace ZL {
|
|||||||
PlanetData();
|
PlanetData();
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
const LodLevel& getLodLevel() const;
|
|
||||||
|
// Методы доступа к данным (для рендерера)
|
||||||
|
const LodLevel& getLodLevel(int level) const;
|
||||||
const LodLevel& getAtmosphereLod() const;
|
const LodLevel& getAtmosphereLod() const;
|
||||||
|
int getCurrentLodIndex() const;
|
||||||
|
int getMaxLodIndex() const;
|
||||||
|
|
||||||
// Логика
|
// Логика
|
||||||
std::pair<float, float> calculateZRange(float distanceToSurface);
|
std::pair<float, float> calculateZRange(float distanceToSurface);
|
||||||
@ -126,9 +116,6 @@ namespace ZL {
|
|||||||
std::vector<int> getTrianglesUnderCameraNew2(const Vector3f& viewerPosition);
|
std::vector<int> getTrianglesUnderCameraNew2(const Vector3f& viewerPosition);
|
||||||
|
|
||||||
void applySphericalRelaxation(LodLevel& lod, int iterations);
|
void applySphericalRelaxation(LodLevel& lod, int iterations);
|
||||||
|
|
||||||
std::vector<PlanetCampObject> campObjects;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZL
|
} // namespace ZL
|
||||||
@ -5,12 +5,9 @@
|
|||||||
#include "Environment.h"
|
#include "Environment.h"
|
||||||
#include "StoneObject.h"
|
#include "StoneObject.h"
|
||||||
#include "utils/TaskManager.h"
|
#include "utils/TaskManager.h"
|
||||||
#include "TextModel.h"
|
|
||||||
|
|
||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
extern float x;
|
|
||||||
|
|
||||||
#if defined EMSCRIPTEN || defined __ANDROID__
|
#if defined EMSCRIPTEN || defined __ANDROID__
|
||||||
using std::min;
|
using std::min;
|
||||||
using std::max;
|
using std::max;
|
||||||
@ -73,7 +70,8 @@ namespace ZL {
|
|||||||
|
|
||||||
// 2. Забираем данные для VBO
|
// 2. Забираем данные для VBO
|
||||||
// Берем максимальный LOD для начальной отрисовки
|
// Берем максимальный LOD для начальной отрисовки
|
||||||
planetRenderStruct.data = planetData.getLodLevel().vertexData;
|
int lodIndex = planetData.getMaxLodIndex();
|
||||||
|
planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData;
|
||||||
|
|
||||||
//planetRenderStruct.data.PositionData.resize(9);
|
//planetRenderStruct.data.PositionData.resize(9);
|
||||||
planetRenderStruct.RefreshVBO();
|
planetRenderStruct.RefreshVBO();
|
||||||
@ -89,20 +87,13 @@ namespace ZL {
|
|||||||
planetAtmosphereRenderStruct.RefreshVBO();
|
planetAtmosphereRenderStruct.RefreshVBO();
|
||||||
}
|
}
|
||||||
|
|
||||||
planetStones = CreateStoneGroupData(778, planetData.getLodLevel());
|
planetStones = CreateStoneGroupData(778, planetData.getLodLevel(lodIndex));
|
||||||
|
|
||||||
//stonesToRender = planetStones.inflate(planetStones.allInstances.size());
|
//stonesToRender = planetStones.inflate(planetStones.allInstances.size());
|
||||||
stonesToRender.resize(planetStones.allInstances.size());
|
stonesToRender.resize(planetStones.allInstances.size());
|
||||||
planetStones.initStatuses();
|
planetStones.initStatuses();
|
||||||
|
|
||||||
stoneToBake = planetStones.inflateOne(0, 0.75);
|
stoneToBake = planetStones.inflateOne(0, 0.75);
|
||||||
|
|
||||||
|
|
||||||
campPlatform.data = LoadFromTextFile02("resources/platform1.txt", CONST_ZIP_FILE);
|
|
||||||
campPlatform.RefreshVBO();
|
|
||||||
|
|
||||||
campPlatformTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/platform_base.png", CONST_ZIP_FILE));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -196,7 +187,7 @@ namespace ZL {
|
|||||||
renderer.EnableVertexAttribArray(vPositionName);
|
renderer.EnableVertexAttribArray(vPositionName);
|
||||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||||
|
|
||||||
Triangle tr = planetData.getLodLevel().triangles[0];
|
Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0];
|
||||||
|
|
||||||
// 1. Получаем матрицу вращения (оси в столбцах)
|
// 1. Получаем матрицу вращения (оси в столбцах)
|
||||||
Matrix3f mr = GetRotationForTriangle(tr);
|
Matrix3f mr = GetRotationForTriangle(tr);
|
||||||
@ -291,8 +282,6 @@ namespace ZL {
|
|||||||
|
|
||||||
drawPlanet(renderer);
|
drawPlanet(renderer);
|
||||||
drawStones(renderer);
|
drawStones(renderer);
|
||||||
drawCamp(renderer);
|
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
|
||||||
drawAtmosphere(renderer);
|
drawAtmosphere(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +328,7 @@ namespace ZL {
|
|||||||
renderer.RenderUniform1i("BakedTexture", 1);
|
renderer.RenderUniform1i("BakedTexture", 1);
|
||||||
|
|
||||||
|
|
||||||
Triangle tr = planetData.getLodLevel().triangles[0]; // Берем базовый треугольник
|
Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0]; // Берем базовый треугольник
|
||||||
Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании
|
Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании
|
||||||
|
|
||||||
// Позиция камеры (корабля) в мире
|
// Позиция камеры (корабля) в мире
|
||||||
@ -475,7 +464,7 @@ namespace ZL {
|
|||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
CheckGlError();
|
CheckGlError();
|
||||||
|
|
||||||
|
glClear(GL_DEPTH_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetObject::drawAtmosphere(Renderer& renderer) {
|
void PlanetObject::drawAtmosphere(Renderer& renderer) {
|
||||||
@ -579,92 +568,6 @@ namespace ZL {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlanetObject::drawCamp(Renderer& renderer)
|
|
||||||
{
|
|
||||||
static const std::string defaultShaderName2 = "default";
|
|
||||||
static const std::string vPositionName = "vPosition";
|
|
||||||
static const std::string vColorName = "vColor";
|
|
||||||
static const std::string vNormalName = "vNormal";
|
|
||||||
static const std::string vTexCoordName = "vTexCoord";
|
|
||||||
static const std::string textureUniformName = "Texture";
|
|
||||||
|
|
||||||
renderer.shaderManager.PushShader(defaultShaderName2);
|
|
||||||
renderer.RenderUniform1i(textureUniformName, 0);
|
|
||||||
renderer.EnableVertexAttribArray(vPositionName);
|
|
||||||
renderer.EnableVertexAttribArray(vColorName);
|
|
||||||
renderer.EnableVertexAttribArray(vNormalName);
|
|
||||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
|
||||||
|
|
||||||
|
|
||||||
float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position);
|
|
||||||
auto zRange = planetData.calculateZRange(dist);
|
|
||||||
const float currentZNear = zRange.first;
|
|
||||||
const float currentZFar = zRange.second;
|
|
||||||
|
|
||||||
|
|
||||||
// 2. Применяем динамическую матрицу проекции
|
|
||||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
|
||||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
|
||||||
currentZNear, currentZFar);
|
|
||||||
|
|
||||||
renderer.PushMatrix();
|
|
||||||
renderer.LoadIdentity();
|
|
||||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
|
||||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
|
||||||
renderer.TranslateMatrix(-Environment::shipState.position);
|
|
||||||
|
|
||||||
renderer.RenderUniform1f("uDistanceToPlanetSurface", dist);
|
|
||||||
renderer.RenderUniform1f("uCurrentZFar", currentZFar);
|
|
||||||
renderer.RenderUniform3fv("uViewPos", Environment::shipState.position.data());
|
|
||||||
//std::cout << "uViewPos" << Environment::shipState.position << std::endl;
|
|
||||||
// PlanetObject.cpp, метод drawStones
|
|
||||||
Vector3f sunDirWorld = Vector3f(1.0f, -1.0f, -1.0f).normalized();
|
|
||||||
renderer.RenderUniform3fv("uLightDirWorld", sunDirWorld.data());
|
|
||||||
|
|
||||||
Vector3f playerDirWorld = Environment::shipState.position.normalized();
|
|
||||||
float playerLightFactor = max(0.0f, (playerDirWorld.dot(-sunDirWorld) + 0.2f) / 1.2f);
|
|
||||||
renderer.RenderUniform1f("uPlayerLightFactor", playerLightFactor);
|
|
||||||
|
|
||||||
glEnable(GL_CULL_FACE);
|
|
||||||
glCullFace(GL_BACK);
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
|
|
||||||
for (int i = 0; i < planetData.campObjects.size(); i++)
|
|
||||||
{
|
|
||||||
|
|
||||||
renderer.PushMatrix();
|
|
||||||
for (int j = 0; j < 5; j++)
|
|
||||||
{
|
|
||||||
renderer.PushMatrix();
|
|
||||||
renderer.TranslateMatrix(planetData.campObjects[i].position);
|
|
||||||
renderer.RotateMatrix(planetData.campObjects[i].rotation);
|
|
||||||
renderer.ScaleMatrix(Vector3f{ 2.0f, 2.0f, 2.0f });
|
|
||||||
renderer.TranslateMatrix(planetData.campObjects[i].platformPos[j]);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, campPlatformTexture->getTexID());
|
|
||||||
renderer.DrawVertexRenderStruct(campPlatform);
|
|
||||||
renderer.PopMatrix();
|
|
||||||
}
|
|
||||||
renderer.PopMatrix();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckGlError();
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
glDisable(GL_CULL_FACE);
|
|
||||||
|
|
||||||
renderer.PopMatrix();
|
|
||||||
renderer.PopProjectionMatrix();
|
|
||||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
|
||||||
renderer.DisableVertexAttribArray(vNormalName);
|
|
||||||
renderer.DisableVertexAttribArray(vColorName);
|
|
||||||
renderer.DisableVertexAttribArray(vPositionName);
|
|
||||||
renderer.shaderManager.PopShader();
|
|
||||||
CheckGlError();
|
|
||||||
|
|
||||||
glClear(GL_DEPTH_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
float PlanetObject::distanceToPlanetSurface(const Vector3f& viewerPosition)
|
float PlanetObject::distanceToPlanetSurface(const Vector3f& viewerPosition)
|
||||||
{
|
{
|
||||||
return planetData.distanceToPlanetSurfaceFast(viewerPosition);
|
return planetData.distanceToPlanetSurfaceFast(viewerPosition);
|
||||||
|
|||||||
@ -41,10 +41,6 @@ namespace ZL {
|
|||||||
|
|
||||||
std::unique_ptr<FrameBuffer> stoneMapFB;
|
std::unique_ptr<FrameBuffer> stoneMapFB;
|
||||||
|
|
||||||
|
|
||||||
VertexRenderStruct campPlatform;
|
|
||||||
std::shared_ptr<Texture> campPlatformTexture;
|
|
||||||
|
|
||||||
Vector3f lastUpdatePos;
|
Vector3f lastUpdatePos;
|
||||||
|
|
||||||
// External items, set outside
|
// External items, set outside
|
||||||
@ -61,7 +57,6 @@ namespace ZL {
|
|||||||
void drawStones(Renderer& renderer);
|
void drawStones(Renderer& renderer);
|
||||||
void drawPlanet(Renderer& renderer);
|
void drawPlanet(Renderer& renderer);
|
||||||
void drawAtmosphere(Renderer& renderer);
|
void drawAtmosphere(Renderer& renderer);
|
||||||
void drawCamp(Renderer& renderer);
|
|
||||||
|
|
||||||
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user