Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e799b4ec79 | ||
|
|
c8076b6018 | ||
|
|
204b79bf06 | ||
|
|
50232c0816 | ||
|
|
e8fb14b809 | ||
|
|
d425167dce | ||
|
|
cacc18dc7e |
No files matched your search
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
BIN
Binary file not shown.
+187
-18
@@ -11,6 +11,8 @@
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include "../src/network/ClientState.h"
|
||||
#include <random>
|
||||
#include <algorithm>
|
||||
|
||||
// Вспомогательный split
|
||||
std::vector<std::string> split(const std::string& s, char delimiter) {
|
||||
@@ -31,6 +33,16 @@ using tcp = net::ip::tcp;
|
||||
|
||||
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::mutex g_sessions_mutex;
|
||||
|
||||
@@ -38,38 +50,84 @@ class Session : public std::enable_shared_from_this<Session> {
|
||||
websocket::stream<beast::tcp_stream> ws_;
|
||||
beast::flat_buffer buffer_;
|
||||
int id_;
|
||||
bool is_writing_ = false;
|
||||
|
||||
ClientStateInterval timedClientStates;
|
||||
|
||||
void process_message(const std::string& msg) {
|
||||
auto now_server = std::chrono::system_clock::now();
|
||||
|
||||
auto parts = split(msg, ':');
|
||||
|
||||
if (parts.size() < 16)
|
||||
{
|
||||
throw std::runtime_error("Unknown message type received, too small");
|
||||
if (parts.empty()) {
|
||||
std::cerr << "Empty message received\n";
|
||||
return;
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
ClientState receivedState;
|
||||
|
||||
receivedState.id = id_;
|
||||
|
||||
std::chrono::system_clock::time_point uptime_timepoint{ std::chrono::duration_cast<std::chrono::system_clock::time_point::duration>(std::chrono::milliseconds(clientTimestamp)) };
|
||||
std::chrono::system_clock::time_point uptime_timepoint{
|
||||
std::chrono::milliseconds(clientTimestamp)
|
||||
};
|
||||
receivedState.lastUpdateServerTime = uptime_timepoint;
|
||||
|
||||
if (parts[0] == "UPD") {
|
||||
receivedState.handle_full_sync(parts, 2);
|
||||
retranslateMessage(msg);
|
||||
timedClientStates.add_state(receivedState);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unknown message type received: " + parts[0]);
|
||||
else if (parts[0] == "FIRE") {
|
||||
if (parts.size() < 8) {
|
||||
std::cerr << "Invalid FIRE: too few parts\n";
|
||||
return;
|
||||
}
|
||||
|
||||
timedClientStates.add_state(receivedState);
|
||||
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)
|
||||
@@ -84,6 +142,52 @@ 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:
|
||||
explicit Session(tcp::socket&& socket, int id)
|
||||
@@ -92,6 +196,16 @@ public:
|
||||
|
||||
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() {
|
||||
@@ -105,15 +219,15 @@ public:
|
||||
if (ec) return;
|
||||
std::cout << "Client " << self->id_ << " connected\n";
|
||||
self->init();
|
||||
self->send_message("ID:" + std::to_string(self->id_));
|
||||
self->do_read();
|
||||
// self->send_message("ID:" + std::to_string(self->id_));
|
||||
// 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));
|
||||
ws_.async_write(net::buffer(*ss), [ss](beast::error_code, std::size_t) {});
|
||||
}
|
||||
}*/
|
||||
|
||||
int get_id() const {
|
||||
return id_;
|
||||
@@ -151,8 +265,63 @@ 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() {
|
||||
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;
|
||||
tcp::acceptor acceptor{ ioc, {tcp::v4(), 8080} };
|
||||
int next_id = 0;
|
||||
|
||||
+136
-7
@@ -10,6 +10,7 @@
|
||||
#include <random>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#ifdef __ANDROID__
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
@@ -268,6 +269,10 @@ namespace ZL
|
||||
bool explosionCfgLoaded = explosionEmitter.loadFromJsonFile("resources/config/explosion_config.json", renderer, CONST_ZIP_FILE);
|
||||
explosionEmitter.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.startAnimationOnNode("backgroundNode", "bgScroll");
|
||||
@@ -296,10 +301,8 @@ namespace ZL
|
||||
g_exitBgAnimating = false;
|
||||
});
|
||||
|
||||
// Set UI button callbacks
|
||||
uiManager.setButtonCallback("playButton", [this](const std::string& name) {
|
||||
std::cerr << "Play button pressed: " << name << std::endl;
|
||||
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("settingsButton", [this](const std::string& name) {
|
||||
@@ -332,11 +335,31 @@ namespace ZL
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("shootButton", [this](const std::string& name) {
|
||||
uint64_t now = SDL_GetTicks64();
|
||||
if (now - lastProjectileFireTime >= static_cast<uint64_t>(projectileCooldownMs)) {
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -346,6 +369,20 @@ namespace ZL
|
||||
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>(
|
||||
std::array<TextureDataStruct, 6>{
|
||||
@@ -540,6 +577,9 @@ namespace ZL
|
||||
explosionEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
||||
}
|
||||
|
||||
//glBindTexture(GL_TEXTURE_2D, basePlatformTexture->getTexID());
|
||||
//renderer.DrawVertexRenderStruct(basePlatform);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
@@ -692,6 +732,27 @@ namespace ZL
|
||||
|
||||
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
|
||||
for (auto const& [id, remotePlayer] : latestRemotePlayers) {
|
||||
|
||||
@@ -770,7 +831,16 @@ namespace ZL
|
||||
continue;
|
||||
|
||||
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";
|
||||
@@ -1230,7 +1300,7 @@ namespace ZL
|
||||
handleMotion(mx, my);
|
||||
|
||||
}
|
||||
/*
|
||||
|
||||
if (event.type == SDL_MOUSEWHEEL) {
|
||||
static const float zoomstep = 2.0f;
|
||||
if (event.wheel.y > 0) {
|
||||
@@ -1247,14 +1317,73 @@ namespace ZL
|
||||
{
|
||||
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
|
||||
}
|
||||
render();
|
||||
mainThreadHandler.processMainThreadTasks();
|
||||
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)
|
||||
|
||||
+4
-1
@@ -86,6 +86,7 @@ namespace ZL {
|
||||
VertexDataStruct spaceshipBase;
|
||||
VertexRenderStruct spaceship;
|
||||
|
||||
|
||||
VertexRenderStruct cubemap;
|
||||
|
||||
std::shared_ptr<Texture> boxTexture;
|
||||
@@ -121,7 +122,9 @@ namespace ZL {
|
||||
static constexpr float BASE_SCALE = 140.f;
|
||||
static constexpr float PERSPECTIVE_K = 0.05f; // Tune
|
||||
static constexpr float MIN_SCALE = 0.4f;
|
||||
static constexpr float MAX_SCALE = 1.5f;
|
||||
static constexpr float MAX_SCALE = 0.8f;
|
||||
static constexpr float CLOSE_DIST = 600.0f;
|
||||
bool serverBoxesApplied = false;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -45,6 +45,69 @@ 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();
|
||||
if (speedScale > 0.0001f) {
|
||||
// Коэффициент чувствительности вращения
|
||||
|
||||
@@ -13,8 +13,14 @@ constexpr float ANGULAR_ACCEL = 0.005f * 1000.0f;
|
||||
constexpr float SHIP_ACCEL = 1.0f * 1000.0f;
|
||||
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 CLIENT_DELAY = 200; //ms
|
||||
constexpr long long CLIENT_DELAY = 1000; //ms
|
||||
constexpr long long CUTOFF_TIME = 5000; //ms
|
||||
|
||||
struct ClientState {
|
||||
|
||||
@@ -11,8 +11,10 @@ namespace ZL {
|
||||
}
|
||||
|
||||
void LocalClient::Send(const std::string& message) {
|
||||
|
||||
}
|
||||
|
||||
std::vector<ProjectileInfo> LocalClient::getPendingProjectiles() {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,9 +17,14 @@ namespace ZL {
|
||||
|
||||
bool IsConnected() const override { return true; }
|
||||
int GetClientId() const { return 1; }
|
||||
std::vector<ProjectileInfo> getPendingProjectiles();
|
||||
|
||||
std::unordered_map<int, ClientStateInterval> getRemotePlayers() override {
|
||||
return std::unordered_map<int, ClientStateInterval>();
|
||||
}
|
||||
|
||||
std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> getServerBoxes() override {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -7,6 +7,13 @@
|
||||
// NetworkInterface.h - »нтерфейс дл¤ разных типов соединений
|
||||
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 {
|
||||
public:
|
||||
virtual ~INetworkClient() = default;
|
||||
@@ -15,5 +22,9 @@ namespace ZL {
|
||||
virtual bool IsConnected() const = 0;
|
||||
virtual void Poll() = 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,6 +64,13 @@ namespace ZL {
|
||||
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() {
|
||||
std::lock_guard<std::mutex> lock(queueMutex);
|
||||
|
||||
@@ -83,6 +90,68 @@ namespace ZL {
|
||||
std::string msg = messageQueue.front();
|
||||
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) {
|
||||
auto parts = split(msg, ':');
|
||||
if (parts.size() < 5) continue; // EVENT:ID:TYPE:TIME:DATA...
|
||||
|
||||
@@ -34,6 +34,13 @@ namespace ZL {
|
||||
std::unordered_map<int, ClientStateInterval> remotePlayers;
|
||||
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 processIncomingMessage(const std::string& msg);
|
||||
|
||||
@@ -54,6 +61,13 @@ namespace ZL {
|
||||
std::lock_guard<std::mutex> lock(playersMutex);
|
||||
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
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
namespace ZL {
|
||||
|
||||
Matrix3f GetRotationForTriangle(const Triangle& tri);
|
||||
|
||||
const float PlanetData::PLANET_RADIUS = 20000.f;
|
||||
const Vector3f PlanetData::PLANET_CENTER_OFFSET = Vector3f{ 0.f, 0.f, 0.0f };
|
||||
@@ -29,9 +30,9 @@ namespace ZL {
|
||||
PlanetData::PlanetData()
|
||||
: perlin(77777)
|
||||
, colorPerlin(123123)
|
||||
, currentLod(0)
|
||||
//, currentLod(0)
|
||||
{
|
||||
currentLod = planetMeshLods.size() - 1; // Start with max LOD
|
||||
// currentLod = planetMeshLods.size() - 1; // Start with max LOD
|
||||
/*
|
||||
initialVertexMap = {
|
||||
{{ 0.0f, 1.0f, 0.0f}, "A"},
|
||||
@@ -54,10 +55,29 @@ namespace ZL {
|
||||
planetAtmosphereLod = generateSphere(5, 0);
|
||||
planetAtmosphereLod.Scale(PLANET_RADIUS * 1.03);
|
||||
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(int level) const {
|
||||
return planetMeshLods.at(level);
|
||||
const LodLevel& PlanetData::getLodLevel() const {
|
||||
return planetMeshLods.at(MAX_LOD_LEVELS-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,13 +85,14 @@ namespace ZL {
|
||||
return planetAtmosphereLod;
|
||||
}
|
||||
|
||||
/*
|
||||
int PlanetData::getCurrentLodIndex() const {
|
||||
return currentLod;
|
||||
}
|
||||
|
||||
int PlanetData::getMaxLodIndex() const {
|
||||
return static_cast<int>(planetMeshLods.size() - 1);
|
||||
}
|
||||
}*/
|
||||
|
||||
std::pair<float, float> PlanetData::calculateZRange(float dToPlanetSurface) {
|
||||
|
||||
@@ -138,7 +159,7 @@ namespace ZL {
|
||||
|
||||
|
||||
std::vector<int> PlanetData::getBestTriangleUnderCamera(const Vector3f& viewerPosition) {
|
||||
const LodLevel& finalLod = planetMeshLods[currentLod]; // Работаем с текущим активным LOD
|
||||
const LodLevel& finalLod = planetMeshLods[MAX_LOD_LEVELS - 1]; // Работаем с текущим активным LOD
|
||||
Vector3f targetDir = (viewerPosition - PLANET_CENTER_OFFSET).normalized();
|
||||
|
||||
int bestTriangle = -1;
|
||||
@@ -167,7 +188,7 @@ namespace ZL {
|
||||
}
|
||||
|
||||
std::vector<int> PlanetData::getTrianglesUnderCameraNew2(const Vector3f& viewerPosition) {
|
||||
const LodLevel& finalLod = planetMeshLods[currentLod];
|
||||
const LodLevel& finalLod = planetMeshLods[MAX_LOD_LEVELS - 1];
|
||||
Vector3f shipLocal = viewerPosition - PLANET_CENTER_OFFSET;
|
||||
float currentDist = shipLocal.norm();
|
||||
Vector3f targetDir = shipLocal.normalized();
|
||||
|
||||
+19
-6
@@ -75,6 +75,20 @@ 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 {
|
||||
public:
|
||||
static const float PLANET_RADIUS;
|
||||
@@ -87,7 +101,7 @@ namespace ZL {
|
||||
std::array<LodLevel, MAX_LOD_LEVELS> planetMeshLods;
|
||||
LodLevel planetAtmosphereLod;
|
||||
|
||||
int currentLod; // Логический текущий уровень детализации
|
||||
//int currentLod; // Логический текущий уровень детализации
|
||||
|
||||
//std::map<Vector3f, VertexID, Vector3fComparator> initialVertexMap;
|
||||
|
||||
@@ -100,12 +114,8 @@ namespace ZL {
|
||||
PlanetData();
|
||||
|
||||
void init();
|
||||
|
||||
// Методы доступа к данным (для рендерера)
|
||||
const LodLevel& getLodLevel(int level) const;
|
||||
const LodLevel& getLodLevel() const;
|
||||
const LodLevel& getAtmosphereLod() const;
|
||||
int getCurrentLodIndex() const;
|
||||
int getMaxLodIndex() const;
|
||||
|
||||
// Логика
|
||||
std::pair<float, float> calculateZRange(float distanceToSurface);
|
||||
@@ -116,6 +126,9 @@ namespace ZL {
|
||||
std::vector<int> getTrianglesUnderCameraNew2(const Vector3f& viewerPosition);
|
||||
|
||||
void applySphericalRelaxation(LodLevel& lod, int iterations);
|
||||
|
||||
std::vector<PlanetCampObject> campObjects;
|
||||
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
+103
-6
@@ -5,9 +5,12 @@
|
||||
#include "Environment.h"
|
||||
#include "StoneObject.h"
|
||||
#include "utils/TaskManager.h"
|
||||
#include "TextModel.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
extern float x;
|
||||
|
||||
#if defined EMSCRIPTEN || defined __ANDROID__
|
||||
using std::min;
|
||||
using std::max;
|
||||
@@ -70,8 +73,7 @@ namespace ZL {
|
||||
|
||||
// 2. Забираем данные для VBO
|
||||
// Берем максимальный LOD для начальной отрисовки
|
||||
int lodIndex = planetData.getMaxLodIndex();
|
||||
planetRenderStruct.data = planetData.getLodLevel(lodIndex).vertexData;
|
||||
planetRenderStruct.data = planetData.getLodLevel().vertexData;
|
||||
|
||||
//planetRenderStruct.data.PositionData.resize(9);
|
||||
planetRenderStruct.RefreshVBO();
|
||||
@@ -87,13 +89,20 @@ namespace ZL {
|
||||
planetAtmosphereRenderStruct.RefreshVBO();
|
||||
}
|
||||
|
||||
planetStones = CreateStoneGroupData(778, planetData.getLodLevel(lodIndex));
|
||||
planetStones = CreateStoneGroupData(778, planetData.getLodLevel());
|
||||
|
||||
//stonesToRender = planetStones.inflate(planetStones.allInstances.size());
|
||||
stonesToRender.resize(planetStones.allInstances.size());
|
||||
planetStones.initStatuses();
|
||||
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +196,7 @@ namespace ZL {
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0];
|
||||
Triangle tr = planetData.getLodLevel().triangles[0];
|
||||
|
||||
// 1. Получаем матрицу вращения (оси в столбцах)
|
||||
Matrix3f mr = GetRotationForTriangle(tr);
|
||||
@@ -282,6 +291,8 @@ namespace ZL {
|
||||
|
||||
drawPlanet(renderer);
|
||||
drawStones(renderer);
|
||||
drawCamp(renderer);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
drawAtmosphere(renderer);
|
||||
}
|
||||
|
||||
@@ -328,7 +339,7 @@ namespace ZL {
|
||||
renderer.RenderUniform1i("BakedTexture", 1);
|
||||
|
||||
|
||||
Triangle tr = planetData.getLodLevel(planetData.getCurrentLodIndex()).triangles[0]; // Берем базовый треугольник
|
||||
Triangle tr = planetData.getLodLevel().triangles[0]; // Берем базовый треугольник
|
||||
Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании
|
||||
|
||||
// Позиция камеры (корабля) в мире
|
||||
@@ -464,7 +475,7 @@ namespace ZL {
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
}
|
||||
|
||||
void PlanetObject::drawAtmosphere(Renderer& renderer) {
|
||||
@@ -568,6 +579,92 @@ 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)
|
||||
{
|
||||
return planetData.distanceToPlanetSurfaceFast(viewerPosition);
|
||||
|
||||
@@ -41,6 +41,10 @@ namespace ZL {
|
||||
|
||||
std::unique_ptr<FrameBuffer> stoneMapFB;
|
||||
|
||||
|
||||
VertexRenderStruct campPlatform;
|
||||
std::shared_ptr<Texture> campPlatformTexture;
|
||||
|
||||
Vector3f lastUpdatePos;
|
||||
|
||||
// External items, set outside
|
||||
@@ -57,6 +61,7 @@ namespace ZL {
|
||||
void drawStones(Renderer& renderer);
|
||||
void drawPlanet(Renderer& renderer);
|
||||
void drawAtmosphere(Renderer& renderer);
|
||||
void drawCamp(Renderer& renderer);
|
||||
|
||||
float distanceToPlanetSurface(const Vector3f& viewerPosition);
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user