Compare commits

..

No commits in common. "camera2" and "main" have entirely different histories.

7 changed files with 28 additions and 375 deletions

View File

@ -154,8 +154,8 @@
{
"type": "Button",
"name": "shootButton",
"x": 1115,
"y": 0,
"x": 100,
"y": 100,
"width": 100,
"height": 100,
"textures": {

BIN
resources/joystick_base.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/joystick_knob.png (Stored with Git LFS)

Binary file not shown.

View File

@ -1,4 +1,4 @@
#include "Game.h"
#include "Game.h"
#include "AnimatedModel.h"
#include "BoneAnimatedModel.h"
#include "planet/PlanetData.h"
@ -243,20 +243,6 @@ namespace ZL
}
});
// Добавляем джойстик для управления кораблём
// centerX=150, centerY=150 (от левого нижнего угла в UI координатах)
// baseRadius=120, knobRadius=50
uiManager.addJoystick("shipJoystick", 150.0f, 150.0f, 120.0f, 50.0f,
renderer, CONST_ZIP_FILE,
"resources/joystick_base.png", "resources/joystick_knob.png");
/*uiManager.setSliderCallback("musicVolumeSlider", [this](const std::string& name, float value) {
std::cerr << "Music volume slider changed to: " << value << std::endl;
musicVolume = value;
Environment::shipVelocity = musicVolume * 20.0f;
});
//#endif*/
cubemapTexture = std::make_shared<Texture>(
std::array<TextureDataStruct, 6>{
CreateTextureDataFromPng("resources/sky/space1.png", CONST_ZIP_FILE),
@ -287,13 +273,7 @@ namespace ZL
spaceshipBase = LoadFromTextFile02("resources/spaceshipnew001.txt", CONST_ZIP_FILE);
spaceshipBase.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY())).toRotationMatrix());// QuatFromRotateAroundY(M_PI / 2.0).toRotationMatrix());
//spaceshipBase.Move(Vector3f{ 1.2, 0, -5 });
//spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 });
spaceshipBase.Move(Vector3f{ -0.52998, 0, -10 });
//spaceshipBase.Move(Vector3f{ 1.2, 0, -5 });
spaceshipBase.Move(Vector3f{ 1.2, 0, -5 });
spaceship.AssignFrom(spaceshipBase);
spaceship.RefreshVBO();
@ -417,15 +397,10 @@ namespace ZL
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
renderer.TranslateMatrix({ 0, -6.f, 0 }); //Ship camera offset
// Корабль рисуется с учётом разницы между его ориентацией и камерой
// shipWorldOrientation - куда смотрит корабль в мире
// Environment::inverseShipMatrix - обратная матрица камеры
Matrix3f shipRelativeToCamera = Environment::inverseShipMatrix * shipWorldOrientation;
renderer.RotateMatrix(shipRelativeToCamera);
if (shipAlive) {
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
@ -668,79 +643,24 @@ namespace ZL
sparkEmitter.update(static_cast<float>(delta));
planetObject.update(static_cast<float>(delta));
int discreteAngle = -1;
float discreteMag = 0;
auto joystick = uiManager.findJoystick("shipJoystick");
if (joystick && joystick->isActive) {
float joyX = joystick->getDirectionX(); // -1..1
float joyY = joystick->getDirectionY(); // -1..1
float magnitude = joystick->getMagnitude(); // 0..1
discreteMag = roundf(magnitude * 10) * 0.1f;
float angleY = std::atan2(-joyX, -joyY);
discreteAngle = static_cast<int>(angleY * 180.0f / M_PI);
if (discreteAngle < 0) discreteAngle += 360;
static float pingTimer = 0.0f;
pingTimer += delta;
if (pingTimer >= 1000.0f) {
std::string pingMsg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent();
networkClient->Send(pingMsg);
std::cout << "Sending: " << pingMsg << std::endl;
pingTimer = 0.0f;
}
//Handle input:
//<<<<<<< HEAD
// Управление кораблём через джойстик
/*auto joystick = uiManager.findJoystick("shipJoystick");
if (joystick && joystick->isActive) {
float joyX = joystick->getDirectionX(); // -1..1
float joyY = joystick->getDirectionY(); // -1..1
float magnitude = joystick->getMagnitude(); // 0..1
if (magnitude > 0.1f) {
// Скорость пропорциональна отклонению джойстика
Environment::shipState.velocity = magnitude * 500.0f * static_cast<float>(delta) / 100.0f;
// Направление джойстика относительно камеры
// joyY отрицательный = вперёд, joyX = влево/вправо
float angleY = std::atan2(-joyX, -joyY);
// Локальный поворот в пространстве камеры
Eigen::Quaternionf localRotation(Eigen::AngleAxisf(angleY, Eigen::Vector3f::UnitY()));
Matrix3f localRotMat = localRotation.toRotationMatrix();
// Преобразуем в мировую ориентацию: камера * локальный_поворот
shipWorldOrientation = Environment::shipState.rotation * localRotMat;
}
else {
Environment::shipState.velocity = 0.0f;
}
}
else if (Environment::tapDownHold && !uiManager.isUiInteraction())
if (newShipVelocity != Environment::shipState.selectedVelocity)
{
float diffx = Environment::tapDownCurrentPos(0) - Environment::tapDownStartPos(0);
float diffy = Environment::tapDownCurrentPos(1) - Environment::tapDownStartPos(1);
Environment::shipState.selectedVelocity = newShipVelocity;
// Только управление камерой через drag (вне зоны джойстика)
if (isDraggingCamera) {
if (std::abs(diffy) > 5.0f || std::abs(diffx) > 5.0f)
{
float rotationPower = std::sqrt(diffx * diffx + diffy * diffy);
float deltaAlpha = rotationPower * static_cast<float>(delta) * static_cast<float>(M_PI) / 15000.f;
Eigen::Vector3f rotationDirection(diffy, diffx, 0.0f);
rotationDirection.normalize();
Eigen::Quaternionf rotateQuat(Eigen::AngleAxisf(deltaAlpha, rotationDirection));
Matrix3f rotateMat = rotateQuat.toRotationMatrix();
Environment::shipState.rotation = Environment::shipState.rotation * rotateMat;
Environment::inverseShipMatrix = Environment::shipState.rotation.inverse();
// плавное вращение (ВАЖНО!)
Environment::tapDownStartPos = Environment::tapDownCurrentPos;
}
}
std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent();
networkClient->Send(msg);
}
float discreteMag;
@ -775,8 +695,7 @@ namespace ZL
{
discreteAngle = -1;
discreteMag = 0.0f;
>>>>>>> main*/
//}
}
if (discreteAngle != Environment::shipState.discreteAngle || discreteMag != Environment::shipState.discreteMag) {
@ -1188,10 +1107,13 @@ namespace ZL
}();
if (!uiManager.isUiInteraction()) {
// Джойстик обрабатывает управление кораблём, поэтому
// любое нажатие вне UI элементов - это управление камерой
isDraggingShip = false;
isDraggingCamera = true;
Environment::tapDownHold = true;
Environment::tapDownStartPos(0) = mx;
Environment::tapDownStartPos(1) = my;
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
}
}
@ -1200,33 +1122,11 @@ namespace ZL
int uiX = mx;
int uiY = Environment::height - my;
// Проверяем был ли активен джойстик до отпускания
auto joystick = uiManager.findJoystick("shipJoystick");
bool wasJoystickActive = joystick && joystick->isActive;
uiManager.onMouseUp(uiX, uiY);
// Сбрасываем состояние если отпустили джойстик
/*
if (wasJoystickActive) {
Environment::shipVelocity = 0.0f;
shipMoveLockActive = false;
rotateShipMat = Matrix3f::Identity();
}
if (!uiManager.isUiInteraction()) {
Environment::tapDownHold = false;
Environment::shipVelocity = 0.0f;
shipMoveLockActive = false;
if (isDraggingCamera) {
rotateShipMat = Matrix3f::Identity();
}
isDraggingShip = false;
isDraggingCamera = false;
}*/
}
}
void Game::handleMotion(int mx, int my)

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "render/Renderer.h"
#include "Environment.h"
@ -93,12 +93,6 @@ namespace ZL {
int maxProjectiles = 32;
std::vector<Vector3f> shipLocalEmissionPoints;
bool isDraggingShip = false;
bool isDraggingCamera = false;
Matrix3f rotateShipMat = Matrix3f::Identity(); // Локальный поворот от джойстика
Matrix3f shipWorldOrientation = Matrix3f::Identity(); // Ориентация корабля в мире (независимо от камеры)
bool shipMoveLockActive = false;
Matrix3f lockedCameraMat = Matrix3f::Identity();
bool shipAlive = true;
bool gameOver = false;

View File

@ -167,91 +167,6 @@ namespace ZL {
renderer.DisableVertexAttribArray(vTexCoordName);
}
void UiJoystick::buildBaseMesh() {
baseMesh.data.PositionData.clear();
baseMesh.data.TexCoordData.clear();
float x0 = centerX - baseRadius;
float y0 = centerY - baseRadius;
float x1 = centerX + baseRadius;
float y1 = centerY + baseRadius;
baseMesh.data.PositionData.push_back({ x0, y0, 0 });
baseMesh.data.TexCoordData.push_back({ 0, 0 });
baseMesh.data.PositionData.push_back({ x0, y1, 0 });
baseMesh.data.TexCoordData.push_back({ 0, 1 });
baseMesh.data.PositionData.push_back({ x1, y1, 0 });
baseMesh.data.TexCoordData.push_back({ 1, 1 });
baseMesh.data.PositionData.push_back({ x0, y0, 0 });
baseMesh.data.TexCoordData.push_back({ 0, 0 });
baseMesh.data.PositionData.push_back({ x1, y1, 0 });
baseMesh.data.TexCoordData.push_back({ 1, 1 });
baseMesh.data.PositionData.push_back({ x1, y0, 0 });
baseMesh.data.TexCoordData.push_back({ 1, 0 });
baseMesh.RefreshVBO();
}
void UiJoystick::buildKnobMesh() {
knobMesh.data.PositionData.clear();
knobMesh.data.TexCoordData.clear();
float cx = centerX + knobOffsetX;
float cy = centerY + knobOffsetY;
float x0 = cx - knobRadius;
float y0 = cy - knobRadius;
float x1 = cx + knobRadius;
float y1 = cy + knobRadius;
knobMesh.data.PositionData.push_back({ x0, y0, 0 });
knobMesh.data.TexCoordData.push_back({ 0, 0 });
knobMesh.data.PositionData.push_back({ x0, y1, 0 });
knobMesh.data.TexCoordData.push_back({ 0, 1 });
knobMesh.data.PositionData.push_back({ x1, y1, 0 });
knobMesh.data.TexCoordData.push_back({ 1, 1 });
knobMesh.data.PositionData.push_back({ x0, y0, 0 });
knobMesh.data.TexCoordData.push_back({ 0, 0 });
knobMesh.data.PositionData.push_back({ x1, y1, 0 });
knobMesh.data.TexCoordData.push_back({ 1, 1 });
knobMesh.data.PositionData.push_back({ x1, y0, 0 });
knobMesh.data.TexCoordData.push_back({ 1, 0 });
knobMesh.RefreshVBO();
}
void UiJoystick::draw(Renderer& renderer) const {
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
if (texBase) {
glBindTexture(GL_TEXTURE_2D, texBase->getTexID());
renderer.DrawVertexRenderStruct(baseMesh);
}
if (texKnob) {
glBindTexture(GL_TEXTURE_2D, texKnob->getTexID());
renderer.DrawVertexRenderStruct(knobMesh);
}
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
}
void UiManager::loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile) {
std::string content;
try {
@ -531,57 +446,6 @@ namespace ZL {
return true;
}
bool UiManager::addJoystick(const std::string& name, float centerX, float centerY, float baseRadius, float knobRadius,
Renderer& renderer, const std::string& zipFile,
const std::string& basePath, const std::string& knobPath) {
auto j = std::make_shared<UiJoystick>();
j->name = name;
j->centerX = centerX;
j->centerY = centerY;
j->baseRadius = baseRadius;
j->knobRadius = knobRadius;
j->knobOffsetX = 0;
j->knobOffsetY = 0;
j->isActive = false;
try {
if (!basePath.empty()) {
auto data = CreateTextureDataFromPng(basePath.c_str(), zipFile.c_str());
j->texBase = std::make_shared<Texture>(data);
}
if (!knobPath.empty()) {
auto data = CreateTextureDataFromPng(knobPath.c_str(), zipFile.c_str());
j->texKnob = std::make_shared<Texture>(data);
}
}
catch (const std::exception& e) {
std::cerr << "UiManager: addJoystick failed to load textures: " << e.what() << std::endl;
return false;
}
j->buildBaseMesh();
j->buildKnobMesh();
joysticks.push_back(j);
return true;
}
std::shared_ptr<UiJoystick> UiManager::findJoystick(const std::string& name) {
for (auto& j : joysticks) if (j->name == name) return j;
return nullptr;
}
void UiManager::resetJoystick(const std::string& name) {
auto j = findJoystick(name);
if (j) {
j->knobOffsetX = 0;
j->knobOffsetY = 0;
j->isActive = false;
j->buildKnobMesh();
}
}
bool UiManager::pushMenuFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile) {
MenuState prev;
prev.root = root;
@ -662,9 +526,6 @@ namespace ZL {
renderer.PushMatrix();
renderer.LoadIdentity();
for (const auto& j : joysticks) {
j->draw(renderer);
}
for (const auto& b : buttons) {
b->draw(renderer);
}
@ -863,22 +724,6 @@ namespace ZL {
s->buildKnobMesh();
if (s->onValueChanged) s->onValueChanged(s->name, s->value);
}
if (pressedJoystick) {
auto j = pressedJoystick;
float dx = (float)x - j->centerX;
float dy = (float)y - j->centerY;
float dist = std::sqrt(dx * dx + dy * dy);
if (dist > j->baseRadius) {
dx = dx / dist * j->baseRadius;
dy = dy / dist * j->baseRadius;
}
j->knobOffsetX = dx;
j->knobOffsetY = dy;
j->buildKnobMesh();
}
}
void UiManager::onMouseDown(int x, int y) {
@ -907,27 +752,6 @@ namespace ZL {
break;
}
}
for (auto& j : joysticks) {
if (j->contains((float)x, (float)y)) {
pressedJoystick = j;
j->isActive = true;
float dx = (float)x - j->centerX;
float dy = (float)y - j->centerY;
float dist = std::sqrt(dx * dx + dy * dy);
if (dist > j->baseRadius) {
dx = dx / dist * j->baseRadius;
dy = dy / dist * j->baseRadius;
}
j->knobOffsetX = dx;
j->knobOffsetY = dy;
j->buildKnobMesh();
break;
}
}
}
void UiManager::onMouseUp(int x, int y) {
@ -947,14 +771,6 @@ namespace ZL {
if (pressedSlider) {
pressedSlider.reset();
}
if (pressedJoystick) {
pressedJoystick->knobOffsetX = 0;
pressedJoystick->knobOffsetY = 0;
pressedJoystick->isActive = false;
pressedJoystick->buildKnobMesh();
pressedJoystick.reset();
}
}
std::shared_ptr<UiButton> UiManager::findButton(const std::string& name) {

View File

@ -9,8 +9,6 @@
#include <memory>
#include <functional>
#include <map>
#include <cmath>
#include <algorithm>
namespace ZL {
@ -73,47 +71,6 @@ namespace ZL {
void draw(Renderer& renderer) const;
};
struct UiJoystick {
std::string name;
float centerX = 0; // центр джойстика (UI координаты)
float centerY = 0;
float baseRadius = 100; // радиус основания
float knobRadius = 40; // радиус ручки
float knobOffsetX = 0; // смещение ручки от центра
float knobOffsetY = 0;
bool isActive = false; // нажат ли джойстик
std::shared_ptr<Texture> texBase; // текстура основания
std::shared_ptr<Texture> texKnob; // текстура ручки
VertexRenderStruct baseMesh;
VertexRenderStruct knobMesh;
// Возвращает направление -1..1 по каждой оси
float getDirectionX() const { return baseRadius > 0 ? knobOffsetX / baseRadius : 0; }
float getDirectionY() const { return baseRadius > 0 ? -knobOffsetY / baseRadius : 0; }
// Возвращает силу 0..1
float getMagnitude() const {
if (baseRadius <= 0) return 0;
float dist = std::sqrt(knobOffsetX * knobOffsetX + knobOffsetY * knobOffsetY);
float ratio = dist / baseRadius;
return ratio < 1.0f ? ratio : 1.0f;
}
bool contains(float px, float py) const {
float dx = px - centerX;
float dy = py - centerY;
return (dx * dx + dy * dy) <= (baseRadius * baseRadius);
}
void buildBaseMesh();
void buildKnobMesh();
void draw(Renderer& renderer) const;
};
struct UiNode {
std::string type;
UiRect rect;
@ -151,7 +108,7 @@ namespace ZL {
void onMouseUp(int x, int y);
bool isUiInteraction() const {
return pressedButton != nullptr || pressedSlider != nullptr || pressedJoystick != nullptr;
return pressedButton != nullptr || pressedSlider != nullptr;
}
void stopAllAnimations() {
@ -178,12 +135,6 @@ namespace ZL {
bool setSliderCallback(const std::string& name, std::function<void(const std::string&, float)> cb);
bool setSliderValue(const std::string& name, float value); // programmatic set (clamped 0..1)
bool addJoystick(const std::string& name, float centerX, float centerY, float baseRadius, float knobRadius,
Renderer& renderer, const std::string& zipFile,
const std::string& basePath, const std::string& knobPath);
std::shared_ptr<UiJoystick> findJoystick(const std::string& name);
void resetJoystick(const std::string& name); // сбросить ручку в центр
bool pushMenuFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
bool popMenu();
void clearMenuStack();
@ -225,14 +176,12 @@ namespace ZL {
std::shared_ptr<UiNode> root;
std::vector<std::shared_ptr<UiButton>> buttons;
std::vector<std::shared_ptr<UiSlider>> sliders;
std::vector<std::shared_ptr<UiJoystick>> joysticks;
std::map<std::shared_ptr<UiNode>, std::vector<ActiveAnim>> nodeActiveAnims;
std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks; // key: (nodeName, animName)
std::shared_ptr<UiButton> pressedButton;
std::shared_ptr<UiSlider> pressedSlider;
std::shared_ptr<UiJoystick> pressedJoystick;
struct MenuState {
std::shared_ptr<UiNode> root;