Merge branch 'sergey'
This commit is contained in:
commit
8effdd5dfa
@ -423,7 +423,7 @@ private:
|
|||||||
float len = worldForward.norm();
|
float len = worldForward.norm();
|
||||||
if (len > 1e-6f) worldForward /= len;
|
if (len > 1e-6f) worldForward /= len;
|
||||||
pr.vel = worldForward * velocity;
|
pr.vel = worldForward * velocity;
|
||||||
pr.lifeMs = 5000.0f;
|
pr.lifeMs = 15000.0f;
|
||||||
g_projectiles.push_back(pr);
|
g_projectiles.push_back(pr);
|
||||||
|
|
||||||
std::cout << "Server: Created projectile from player " << id_
|
std::cout << "Server: Created projectile from player " << id_
|
||||||
@ -526,9 +526,7 @@ void update_world(net::steady_timer& timer, net::io_context& ioc) {
|
|||||||
if (!session->fetchStateAtTime(now, targetState)) continue;
|
if (!session->fetchStateAtTime(now, targetState)) continue;
|
||||||
|
|
||||||
Eigen::Vector3f diff = pr.pos - targetState.position;
|
Eigen::Vector3f diff = pr.pos - targetState.position;
|
||||||
const float shipRadius = 15.0f;
|
float combinedRadius = shipCollisionRadius + projectileHitRadius;
|
||||||
const float projectileRadius = 1.5f;
|
|
||||||
float combinedRadius = shipRadius + projectileRadius;
|
|
||||||
|
|
||||||
if (diff.squaredNorm() <= combinedRadius * combinedRadius) {
|
if (diff.squaredNorm() <= combinedRadius * combinedRadius) {
|
||||||
DeathInfo death;
|
DeathInfo death;
|
||||||
|
|||||||
147
src/Space.cpp
147
src/Space.cpp
@ -1143,67 +1143,112 @@ namespace ZL
|
|||||||
Vector3f shooterPos = Environment::shipState.position + Environment::shipState.rotation * Vector3f{ 0.0f, 0.9f - 6.0f, 5.0f };
|
Vector3f shooterPos = Environment::shipState.position + Environment::shipState.rotation * Vector3f{ 0.0f, 0.9f - 6.0f, 5.0f };
|
||||||
|
|
||||||
// скорость цели в мире (вектор)
|
// скорость цели в мире (вектор)
|
||||||
Vector3f shooterVel = ForwardFromRotation(Environment::shipState.rotation) * Environment::shipState.velocity;
|
// Vector3f shooterVel = ForwardFromRotation(Environment::shipState.rotation) * Environment::shipState.velocity;
|
||||||
|
|
||||||
|
float shooterSpeed = std::abs(Environment::shipState.velocity);
|
||||||
|
// В нашей физике линейная скорость корабля всегда направлена по его forward (-Z)
|
||||||
|
// Когда игрок наводится на lead indicator, forward (и скорость) становятся сонаправлены с выстрелом
|
||||||
|
// поэтому эффективная скорость снаряда в мире ≈ muzzle + shipSpeed.
|
||||||
|
const float effectiveProjectileSpeed = projectileSpeed + shooterSpeed;
|
||||||
|
Vector3f shooterVel = Vector3f::Zero(); // скорость уже учтена в effectiveProjectileSpeed
|
||||||
Vector3f targetVel = ForwardFromRotation(st.rotation) * st.velocity;
|
Vector3f targetVel = ForwardFromRotation(st.rotation) * st.velocity;
|
||||||
|
|
||||||
|
// ВАЖНО: remote state берется на now_ms - CLIENT_DELAY
|
||||||
|
// Значит shipWorld - это позиция ~0.5 сек назад.
|
||||||
|
// Для корректного lead нужно предсказать положение цели на сейчас
|
||||||
|
const float clientDelaySec = (float)CLIENT_DELAY / 1000.0f;
|
||||||
|
Vector3f targetPosNow = shipWorld + targetVel * clientDelaySec;
|
||||||
|
|
||||||
const float minTargetSpeed = 0.5f; // подобрать (в твоих единицах)
|
const float minTargetSpeed = 0.5f; // подобрать (в твоих единицах)
|
||||||
bool targetMoving = (targetVel.norm() > minTargetSpeed);
|
bool targetMoving = (targetVel.norm() > minTargetSpeed);
|
||||||
|
|
||||||
// альфа круга
|
// альфа круга
|
||||||
float leadAlpha = targetMoving ? 1.0f : 0.5f;
|
float leadAlpha = targetMoving ? 1.0f : 0.5f;
|
||||||
|
|
||||||
Vector3f leadWorld = shipWorld;
|
Vector3f leadWorld = targetPosNow;
|
||||||
bool haveLead = false;
|
bool haveLead = false;
|
||||||
|
|
||||||
// чтобы круг не улетал далеко: максимум 4 секунды (подстроить под игру)
|
// Дистанцию лучше считать от реальной точки вылета
|
||||||
float distToTarget = (Environment::shipState.position - shipWorld).norm();
|
float distToTarget = (shooterPos - targetPosNow).norm();
|
||||||
float maxLeadTime = std::clamp((distToTarget / projectileSpeed) * 1.2f, 0.05f, 4.0f);
|
// Максимальное время перехвата ограничиваем жизнью пули
|
||||||
|
const float projectileLifeSec = (float)PROJECTILE_LIFE / 1000.0f;
|
||||||
|
float maxLeadTime = std::clamp((distToTarget / effectiveProjectileSpeed) * 1.25f, 0.01f, projectileLifeSec * 0.98f);
|
||||||
|
|
||||||
if (!targetMoving) {
|
if (!targetMoving) {
|
||||||
// Цель стоит: рисуем lead прямо на ней, но полупрозрачный
|
// Цель стоит: рисуем lead прямо на ней, но полупрозрачный
|
||||||
leadWorld = shipWorld;
|
leadWorld = targetPosNow;
|
||||||
haveLead = true;
|
haveLead = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
float tLead = 0.0f;
|
float tLead = 0.0f;
|
||||||
|
|
||||||
// 1) Пытаемся “правильное” решение перехвата
|
// 1) Пытаемся “правильное” решение перехвата
|
||||||
bool ok = SolveLeadInterceptTime(shooterPos, shooterVel, shipWorld, targetVel, projectileSpeed, tLead);
|
bool ok = SolveLeadInterceptTime(shooterPos, shooterVel, targetPosNow, targetVel, effectiveProjectileSpeed, tLead);
|
||||||
|
|
||||||
// 2) Если решения нет / оно плохое — fallback (чтобы круг не пропадал при пролёте "вбок")
|
// 2) Если решения нет / оно плохое — fallback (чтобы круг не пропадал при пролёте "вбок")
|
||||||
// Это ключевое изменение: lead всегда будет.
|
// Это ключевое изменение: lead всегда будет.
|
||||||
if (!ok || !(tLead > 0.0f) || tLead > maxLeadTime) {
|
if (!ok || !(tLead > 0.0f) || tLead > maxLeadTime) {
|
||||||
tLead = std::clamp(distToTarget / projectileSpeed, 0.05f, maxLeadTime);
|
tLead = std::clamp(distToTarget / effectiveProjectileSpeed, 0.05f, maxLeadTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
leadWorld = shipWorld + targetVel * tLead;
|
leadWorld = targetPosNow + targetVel * tLead;
|
||||||
haveLead = true;
|
haveLead = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) проекция
|
// Проекция цели (для рамок/стрелки)
|
||||||
float ndcX, ndcY, ndcZ, clipW;
|
float ndcX, ndcY, ndcZ, clipW;
|
||||||
if (!projectToNDC(shipWorld, ndcX, ndcY, ndcZ, clipW)) return;
|
if (!projectToNDC(shipWorld, ndcX, ndcY, ndcZ, clipW)) return;
|
||||||
|
|
||||||
// behind camera?
|
|
||||||
bool behind = (clipW <= 0.0f);
|
bool behind = (clipW <= 0.0f);
|
||||||
|
|
||||||
// on-screen check (NDC)
|
|
||||||
bool onScreen = (!behind &&
|
bool onScreen = (!behind &&
|
||||||
ndcX >= -1.0f && ndcX <= 1.0f &&
|
ndcX >= -1.0f && ndcX <= 1.0f &&
|
||||||
ndcY >= -1.0f && ndcY <= 1.0f);
|
ndcY >= -1.0f && ndcY <= 1.0f);
|
||||||
|
|
||||||
// 3) расстояние
|
|
||||||
float dist = (Environment::shipState.position - shipWorld).norm();
|
float dist = (Environment::shipState.position - shipWorld).norm();
|
||||||
|
|
||||||
// time for arrow bob
|
|
||||||
float t = static_cast<float>(SDL_GetTicks64()) * 0.001f;
|
float t = static_cast<float>(SDL_GetTicks64()) * 0.001f;
|
||||||
|
|
||||||
// 4) Настройки стиля
|
// Проекция Lead
|
||||||
|
float leadNdcX = 0.f, leadNdcY = 0.f, leadNdcZ = 0.f, leadClipW = 0.f;
|
||||||
|
bool leadOnScreen = false;
|
||||||
|
|
||||||
|
if (haveLead) {
|
||||||
|
if (projectToNDC(leadWorld, leadNdcX, leadNdcY, leadNdcZ, leadClipW) && leadClipW > 0.0f) {
|
||||||
|
leadOnScreen =
|
||||||
|
(leadNdcX >= -1.0f && leadNdcX <= 1.0f &&
|
||||||
|
leadNdcY >= -1.0f && leadNdcY <= 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Настройки HUD стилизация
|
||||||
Eigen::Vector4f enemyColor(1.f, 0.f, 0.f, 1.f); // красный
|
Eigen::Vector4f enemyColor(1.f, 0.f, 0.f, 1.f); // красный
|
||||||
float thickness = 2.0f; // толщина линий (px)
|
float thickness = 2.0f; // толщина линий (px)
|
||||||
float z = 0.0f; // 2D слой
|
float z = 0.0f; // 2D слой
|
||||||
|
|
||||||
// 5) Если цель в кадре: рисуем скобки
|
auto drawLeadRing2D = [&](float lx, float ly)
|
||||||
|
{
|
||||||
|
float distLead = (Environment::shipState.position - leadWorld).norm();
|
||||||
|
float r = 30.0f / (distLead * 0.01f + 1.0f);
|
||||||
|
r = std::clamp(r, 6.0f, 18.0f);
|
||||||
|
|
||||||
|
float thicknessPx = 2.5f;
|
||||||
|
float innerR = max(1.0f, r - thicknessPx);
|
||||||
|
float outerR = r + thicknessPx;
|
||||||
|
|
||||||
|
Eigen::Vector4f leadColor = enemyColor;
|
||||||
|
leadColor.w() = leadAlpha;
|
||||||
|
|
||||||
|
renderer.RenderUniform4fv("uColor", leadColor.data());
|
||||||
|
VertexDataStruct ring = MakeRing2D(lx, ly, innerR, outerR, 0.0f, 32, enemyColor);
|
||||||
|
hudTempMesh.AssignFrom(ring);
|
||||||
|
renderer.DrawVertexRenderStruct(hudTempMesh);
|
||||||
|
|
||||||
|
// вернуть цвет HUD обратно
|
||||||
|
renderer.RenderUniform4fv("uColor", enemyColor.data());
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Цель в кадре: рамки
|
||||||
if (onScreen)
|
if (onScreen)
|
||||||
{
|
{
|
||||||
// перевод NDC -> экран (в пикселях)
|
// перевод NDC -> экран (в пикселях)
|
||||||
@ -1252,40 +1297,9 @@ namespace ZL
|
|||||||
renderer.LoadIdentity();
|
renderer.LoadIdentity();
|
||||||
|
|
||||||
renderer.EnableVertexAttribArray("vPosition");
|
renderer.EnableVertexAttribArray("vPosition");
|
||||||
|
renderer.RenderUniform4fv("uColor", enemyColor.data());
|
||||||
|
|
||||||
Eigen::Vector4f hudColor = enemyColor;
|
// рамки
|
||||||
renderer.RenderUniform4fv("uColor", hudColor.data());
|
|
||||||
|
|
||||||
|
|
||||||
if (haveLead) {
|
|
||||||
float leadNdcX, leadNdcY, leadNdcZ, leadClipW;
|
|
||||||
if (projectToNDC(leadWorld, leadNdcX, leadNdcY, leadNdcZ, leadClipW) && leadClipW > 0.0f) {
|
|
||||||
if (leadNdcX >= -1 && leadNdcX <= 1 && leadNdcY >= -1 && leadNdcY <= 1) {
|
|
||||||
float lx = (leadNdcX * 0.5f + 0.5f) * Environment::projectionWidth;
|
|
||||||
float ly = (leadNdcY * 0.5f + 0.5f) * Environment::projectionHeight;
|
|
||||||
|
|
||||||
float distLead = (Environment::shipState.position - leadWorld).norm();
|
|
||||||
float r = 30.0f / (distLead * 0.01f + 1.0f);
|
|
||||||
r = std::clamp(r, 6.0f, 18.0f);
|
|
||||||
|
|
||||||
float thicknessPx = 2.5f;
|
|
||||||
float innerR = max(1.0f, r - thicknessPx);
|
|
||||||
float outerR = r + thicknessPx;
|
|
||||||
Eigen::Vector4f leadColor = enemyColor;
|
|
||||||
leadColor.w() = leadAlpha;
|
|
||||||
renderer.RenderUniform4fv("uColor", leadColor.data());
|
|
||||||
|
|
||||||
VertexDataStruct ring = MakeRing2D(lx, ly, innerR, outerR, 0.0f, 32, enemyColor);
|
|
||||||
hudTempMesh.AssignFrom(ring);
|
|
||||||
renderer.DrawVertexRenderStruct(hudTempMesh);
|
|
||||||
|
|
||||||
renderer.RenderUniform4fv("uColor", hudColor.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderer.EnableVertexAttribArray("vPosition");
|
|
||||||
|
|
||||||
drawBar(left + cornerLen * 0.5f, top, cornerLen, thickness);
|
drawBar(left + cornerLen * 0.5f, top, cornerLen, thickness);
|
||||||
drawBar(left, top - cornerLen * 0.5f, thickness, cornerLen);
|
drawBar(left, top - cornerLen * 0.5f, thickness, cornerLen);
|
||||||
|
|
||||||
@ -1298,9 +1312,14 @@ namespace ZL
|
|||||||
drawBar(right - cornerLen * 0.5f, bottom, cornerLen, thickness);
|
drawBar(right - cornerLen * 0.5f, bottom, cornerLen, thickness);
|
||||||
drawBar(right, bottom + cornerLen * 0.5f, thickness, cornerLen);
|
drawBar(right, bottom + cornerLen * 0.5f, thickness, cornerLen);
|
||||||
|
|
||||||
|
// LEAD — независимо от рамок: если его точка на экране, рисуем
|
||||||
|
if (haveLead && leadOnScreen) {
|
||||||
|
float lx = (leadNdcX * 0.5f + 0.5f) * Environment::projectionWidth;
|
||||||
|
float ly = (leadNdcY * 0.5f + 0.5f) * Environment::projectionHeight;
|
||||||
|
drawLeadRing2D(lx, ly);
|
||||||
|
}
|
||||||
|
|
||||||
renderer.DisableVertexAttribArray("vPosition");
|
renderer.DisableVertexAttribArray("vPosition");
|
||||||
|
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
@ -1312,6 +1331,8 @@ namespace ZL
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Цель вне экрана: стрелка
|
||||||
float dirX = ndcX;
|
float dirX = ndcX;
|
||||||
float dirY = ndcY;
|
float dirY = ndcY;
|
||||||
|
|
||||||
@ -1384,18 +1405,30 @@ namespace ZL
|
|||||||
renderer.PushMatrix();
|
renderer.PushMatrix();
|
||||||
renderer.LoadIdentity();
|
renderer.LoadIdentity();
|
||||||
|
|
||||||
|
renderer.EnableVertexAttribArray("vPosition");
|
||||||
|
renderer.RenderUniform4fv("uColor", enemyColor.data());
|
||||||
|
|
||||||
|
// стрелка
|
||||||
drawTri(tip, left, right);
|
drawTri(tip, left, right);
|
||||||
|
|
||||||
float tailLen = 14.0f;
|
float tailLen = 14.0f;
|
||||||
float tailX = edgeX - dirX * 6.0f;
|
float tailX = edgeX - dirX * 6.0f;
|
||||||
float tailY = edgeY - dirY * 6.0f;
|
float tailY = edgeY - dirY * 6.0f;
|
||||||
|
|
||||||
drawBar(tailX, tailY, max(thickness, tailLen), thickness);
|
drawBar(tailX, tailY, max(thickness, tailLen), thickness);
|
||||||
|
|
||||||
|
// LEAD — рисуем даже когда цель вне экрана (если lead точка на экране)
|
||||||
|
if (haveLead && leadOnScreen) {
|
||||||
|
float lx = (leadNdcX * 0.5f + 0.5f) * Environment::projectionWidth;
|
||||||
|
float ly = (leadNdcY * 0.5f + 0.5f) * Environment::projectionHeight;
|
||||||
|
drawLeadRing2D(lx, ly);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderer.DisableVertexAttribArray("vPosition");
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
// дистанция около стрелки
|
||||||
{
|
{
|
||||||
std::string d = std::to_string((int)dist) + "m";
|
std::string d = std::to_string((int)dist) + "m";
|
||||||
float tx = edgeX + px * 18.0f;
|
float tx = edgeX + px * 18.0f;
|
||||||
@ -1421,7 +1454,7 @@ namespace ZL
|
|||||||
firePressed = false;
|
firePressed = false;
|
||||||
if (now_ms - lastProjectileFireTime >= static_cast<uint64_t>(projectileCooldownMs)) {
|
if (now_ms - lastProjectileFireTime >= static_cast<uint64_t>(projectileCooldownMs)) {
|
||||||
lastProjectileFireTime = now_ms;
|
lastProjectileFireTime = now_ms;
|
||||||
const float projectileSpeed = 250.0f;
|
const float projectileSpeed = PROJECTILE_VELOCITY;
|
||||||
|
|
||||||
this->fireProjectiles();
|
this->fireProjectiles();
|
||||||
|
|
||||||
@ -1429,7 +1462,7 @@ namespace ZL
|
|||||||
Eigen::Vector3f worldForward = (Environment::shipState.rotation * localForward).normalized();
|
Eigen::Vector3f worldForward = (Environment::shipState.rotation * localForward).normalized();
|
||||||
|
|
||||||
Eigen::Vector3f centerPos = Environment::shipState.position +
|
Eigen::Vector3f centerPos = Environment::shipState.position +
|
||||||
Environment::shipState.rotation * Vector3f{ 0, 0.9f, 5.0f };
|
Environment::shipState.rotation * Vector3f{ 0, 0.9f - 6.0f, 5.0f };
|
||||||
|
|
||||||
Eigen::Quaternionf q(Environment::shipState.rotation);
|
Eigen::Quaternionf q(Environment::shipState.rotation);
|
||||||
float speedToSend = projectileSpeed + Environment::shipState.velocity;
|
float speedToSend = projectileSpeed + Environment::shipState.velocity;
|
||||||
@ -1743,8 +1776,8 @@ namespace ZL
|
|||||||
const float size = 0.5f;
|
const float size = 0.5f;
|
||||||
for (const auto& pi : pending) {
|
for (const auto& pi : pending) {
|
||||||
const std::vector<Vector3f> localOffsets = {
|
const std::vector<Vector3f> localOffsets = {
|
||||||
Vector3f{ -1.5f, 0.9f, 5.0f },
|
Vector3f{ -1.5f, 0.9f - 6.0f, 5.0f },
|
||||||
Vector3f{ 1.5f, 0.9f, 5.0f }
|
Vector3f{ 1.5f, 0.9f - 6.0f, 5.0f }
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector3f localForward = { 0, 0, -1 };
|
Vector3f localForward = { 0, 0, -1 };
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user