Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0a72040110 | |||
| 1dcdf10d6a | |||
|
|
ed746891b7 | ||
| 3bd3202bf8 | |||
| b7f5f43777 | |||
| 2ad6ebf38d | |||
| 96deb8b393 | |||
| 47fe0c4719 | |||
| da8946e9ef |
@ -154,8 +154,8 @@
|
||||
{
|
||||
"type": "Button",
|
||||
"name": "shootButton",
|
||||
"x": 100,
|
||||
"y": 100,
|
||||
"x": 1115,
|
||||
"y": 0,
|
||||
"width": 100,
|
||||
"height": 100,
|
||||
"textures": {
|
||||
|
||||
BIN
resources/joystick_base.png
(Stored with Git LFS)
Normal file
BIN
resources/joystick_base.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/joystick_knob.png
(Stored with Git LFS)
Normal file
BIN
resources/joystick_knob.png
(Stored with Git LFS)
Normal file
Binary file not shown.
148
src/Game.cpp
148
src/Game.cpp
@ -1,4 +1,4 @@
|
||||
#include "Game.h"
|
||||
#include "Game.h"
|
||||
#include "AnimatedModel.h"
|
||||
#include "BoneAnimatedModel.h"
|
||||
#include "planet/PlanetData.h"
|
||||
@ -243,6 +243,20 @@ 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),
|
||||
@ -273,7 +287,13 @@ 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{ 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 });
|
||||
|
||||
|
||||
spaceship.AssignFrom(spaceshipBase);
|
||||
spaceship.RefreshVBO();
|
||||
@ -397,10 +417,15 @@ 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());
|
||||
@ -643,24 +668,79 @@ namespace ZL
|
||||
sparkEmitter.update(static_cast<float>(delta));
|
||||
planetObject.update(static_cast<float>(delta));
|
||||
|
||||
static float pingTimer = 0.0f;
|
||||
pingTimer += delta;
|
||||
if (pingTimer >= 1000.0f) {
|
||||
std::string pingMsg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent();
|
||||
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;
|
||||
|
||||
networkClient->Send(pingMsg);
|
||||
std::cout << "Sending: " << pingMsg << std::endl;
|
||||
pingTimer = 0.0f;
|
||||
}
|
||||
|
||||
//Handle input:
|
||||
|
||||
if (newShipVelocity != Environment::shipState.selectedVelocity)
|
||||
|
||||
|
||||
//<<<<<<< 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())
|
||||
{
|
||||
Environment::shipState.selectedVelocity = newShipVelocity;
|
||||
float diffx = Environment::tapDownCurrentPos(0) - Environment::tapDownStartPos(0);
|
||||
float diffy = Environment::tapDownCurrentPos(1) - Environment::tapDownStartPos(1);
|
||||
|
||||
std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent();
|
||||
networkClient->Send(msg);
|
||||
// Только управление камерой через 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float discreteMag;
|
||||
@ -695,7 +775,8 @@ namespace ZL
|
||||
{
|
||||
discreteAngle = -1;
|
||||
discreteMag = 0.0f;
|
||||
}
|
||||
>>>>>>> main*/
|
||||
//}
|
||||
|
||||
|
||||
if (discreteAngle != Environment::shipState.discreteAngle || discreteMag != Environment::shipState.discreteMag) {
|
||||
@ -1107,13 +1188,10 @@ namespace ZL
|
||||
}();
|
||||
|
||||
if (!uiManager.isUiInteraction()) {
|
||||
Environment::tapDownHold = true;
|
||||
|
||||
Environment::tapDownStartPos(0) = mx;
|
||||
Environment::tapDownStartPos(1) = my;
|
||||
|
||||
Environment::tapDownCurrentPos(0) = mx;
|
||||
Environment::tapDownCurrentPos(1) = my;
|
||||
// Джойстик обрабатывает управление кораблём, поэтому
|
||||
// любое нажатие вне UI элементов - это управление камерой
|
||||
isDraggingShip = false;
|
||||
isDraggingCamera = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1122,11 +1200,33 @@ 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)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include "render/Renderer.h"
|
||||
#include "Environment.h"
|
||||
@ -93,6 +93,12 @@ 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;
|
||||
|
||||
@ -167,6 +167,91 @@ 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 {
|
||||
@ -446,6 +531,57 @@ 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;
|
||||
@ -526,6 +662,9 @@ namespace ZL {
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
|
||||
for (const auto& j : joysticks) {
|
||||
j->draw(renderer);
|
||||
}
|
||||
for (const auto& b : buttons) {
|
||||
b->draw(renderer);
|
||||
}
|
||||
@ -724,6 +863,22 @@ 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) {
|
||||
@ -752,6 +907,27 @@ 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) {
|
||||
@ -771,6 +947,14 @@ 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) {
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@ -71,6 +73,47 @@ 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;
|
||||
@ -108,7 +151,7 @@ namespace ZL {
|
||||
void onMouseUp(int x, int y);
|
||||
|
||||
bool isUiInteraction() const {
|
||||
return pressedButton != nullptr || pressedSlider != nullptr;
|
||||
return pressedButton != nullptr || pressedSlider != nullptr || pressedJoystick != nullptr;
|
||||
}
|
||||
|
||||
void stopAllAnimations() {
|
||||
@ -135,6 +178,12 @@ 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();
|
||||
@ -176,12 +225,14 @@ 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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user