space-game001/Game.cpp
2026-01-12 14:41:24 +06:00

698 lines
30 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Game.h"
#include "AnimatedModel.h"
#include "BoneAnimatedModel.h"
#include "Utils.h"
#include "OpenGlExtensions.h"
#include <iostream>
#include "TextureManager.h"
#include "TextModel.h"
#include <random>
#include <cmath>
namespace ZL
{
#ifdef EMSCRIPTEN
const char* CONST_ZIP_FILE = "space-game001.zip";
#else
const char* CONST_ZIP_FILE = "";
#endif
Matrix3f rotateShipMat = Matrix3f::Identity();
Vector4f generateRandomQuaternion(std::mt19937& gen)
{
// Распределение для генерации случайных координат кватерниона
std::normal_distribution<> distrib(0.0, 1.0);
// Генерируем четыре случайных числа из нормального распределения N(0, 1).
// Нормализация этого вектора дает равномерное распределение по 4D-сфере (т.е. кватернион единичной длины).
Vector4f randomQuat = {
(float)distrib(gen),
(float)distrib(gen),
(float)distrib(gen),
(float)distrib(gen)
};
return randomQuat.normalized();
}
// --- Основная функция генерации ---
std::vector<BoxCoords> generateRandomBoxCoords(int N)
{
// Константы
const float MIN_DISTANCE = 3.0f;
const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; // Работаем с квадратом расстояния
const float MIN_COORD = -100.0f;
const float MAX_COORD = 100.0f;
const int MAX_ATTEMPTS = 1000; // Ограничение на количество попыток, чтобы избежать бесконечного цикла
std::vector<BoxCoords> boxCoordsArr;
boxCoordsArr.reserve(N); // Резервируем память
// 1. Инициализация генератора псевдослучайных чисел
// Используем Mersenne Twister (mt19937) как высококачественный генератор
std::random_device rd;
std::mt19937 gen(rd());
// 2. Определение равномерного распределения для координат [MIN_COORD, MAX_COORD]
std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD);
int generatedCount = 0;
while (generatedCount < N)
{
bool accepted = false;
int attempts = 0;
// Попытка найти подходящие координаты
while (!accepted && attempts < MAX_ATTEMPTS)
{
// Генерируем новые случайные координаты
Vector3f newPos(
(float)distrib(gen),
(float)distrib(gen),
(float)distrib(gen)
);
// Проверка расстояния до всех уже существующих объектов
accepted = true; // Предполагаем, что подходит, пока не доказано обратное
for (const auto& existingBox : boxCoordsArr)
{
// Расчет вектора разности
Vector3f diff = newPos - existingBox.pos;
// Расчет квадрата расстояния
float distanceSquared = diff.squaredNorm();
// Если квадрат расстояния меньше квадрата минимального расстояния
if (distanceSquared < MIN_DISTANCE_SQUARED)
{
accepted = false; // Отклоняем, слишком близко
break; // Нет смысла проверять дальше, если одно нарушение найдено
}
}
if (accepted)
{
// 2. Генерируем случайный кватернион
Vector4f randomQuat = generateRandomQuaternion(gen);
// 3. Преобразуем его в матрицу вращения
Matrix3f randomMatrix = QuatToMatrix(randomQuat);
// 4. Добавляем объект с новой случайной матрицей
boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix });
generatedCount++;
}
attempts++;
}
// Если превышено максимальное количество попыток, выходим из цикла,
// чтобы избежать зависания, если N слишком велико или диапазон слишком мал.
if (!accepted) {
std::cerr << "Предупреждение: Не удалось сгенерировать " << N << " объектов. Сгенерировано: " << generatedCount << std::endl;
break;
}
}
return boxCoordsArr;
}
Game::Game()
: window(nullptr)
, glContext(nullptr)
, newTickCount(0)
, lastTickCount(0)
{
}
Game::~Game() {
if (glContext) {
SDL_GL_DeleteContext(glContext);
}
if (window) {
SDL_DestroyWindow(window);
}
SDL_Quit();
}
void Game::setup() {
glContext = SDL_GL_CreateContext(ZL::Environment::window);
ZL::BindOpenGlFunctions();
ZL::CheckGlError();
// Initialize renderer
#ifdef EMSCRIPTEN
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE);
#else
renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE);
renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_desktop.fragment", CONST_ZIP_FILE);
#endif
cubemapTexture = std::make_shared<Texture>(
std::array<TextureDataStruct, 6>{
CreateTextureDataFromBmp24("./resources/sky/space_rt.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_lf.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_up.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_dn.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_bk.bmp", CONST_ZIP_FILE),
CreateTextureDataFromBmp24("./resources/sky/space_ft.bmp", CONST_ZIP_FILE)
});
cubemap.data = ZL::CreateCubemap(500);
cubemap.RefreshVBO();
//Load texture
spaceshipTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE));
spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE);
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 });
spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0)));
spaceship.AssignFrom(spaceshipBase);
spaceship.RefreshVBO();
//Boxes
boxTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE));
boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE);
boxCoordsArr = generateRandomBoxCoords(50);
boxRenderArr.resize(boxCoordsArr.size());
for (int i = 0; i < boxCoordsArr.size(); i++)
{
boxRenderArr[i].AssignFrom(boxBase);
boxRenderArr[i].RefreshVBO();
}
buttonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE));
button.data.PositionData.push_back({ 100, 100, 0 });
button.data.PositionData.push_back({ 100, 150, 0 });
button.data.PositionData.push_back({ 300, 150, 0 });
button.data.PositionData.push_back({ 100, 100, 0 });
button.data.PositionData.push_back({ 300, 150, 0 });
button.data.PositionData.push_back({ 300, 100, 0 });
button.data.TexCoordData.push_back({ 0,0 });
button.data.TexCoordData.push_back({ 0,1 });
button.data.TexCoordData.push_back({ 1,1 });
button.data.TexCoordData.push_back({ 0,0 });
button.data.TexCoordData.push_back({ 1,1 });
button.data.TexCoordData.push_back({ 1,0 });
button.RefreshVBO();
musicVolumeBarTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE));
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 });
musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 });
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
musicVolumeBar.data.TexCoordData.push_back({ 0,1 });
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
musicVolumeBar.data.TexCoordData.push_back({ 0,0 });
musicVolumeBar.data.TexCoordData.push_back({ 1,1 });
musicVolumeBar.data.TexCoordData.push_back({ 1,0 });
musicVolumeBar.RefreshVBO();
musicVolumeBarButtonTexture = std::make_unique<Texture>(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE));
float musicVolumeBarButtonButtonCenterY = 350.0f;
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 });
musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 });
musicVolumeBarButton.RefreshVBO();
renderer.InitOpenGL();
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
void Game::drawCubemap()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(envShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.RotateMatrix(Environment::inverseShipMatrix);
CheckGlError();
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture->getTexID());
renderer.DrawVertexRenderStruct(cubemap);
CheckGlError();
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::drawShip()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
// Используем зафиксированную камеру для отрисовки, если lock активен
// Это обеспечит правильную ориентацию модели относительно начальной позиции камеры
if (shipMoveLockActive) {
///Matrix3f inverseLockedCamera = InverseMatrix(lockedCameraMat);
renderer.RotateMatrix(lockedCameraMat);
} else {
renderer.RotateMatrix(Environment::inverseShipMatrix);
}
renderer.RotateMatrix(rotateShipMat);
// Компенсируем начальный поворот модели на 90° вокруг Y, чтобы модель смотрела в направлении движения
// Модель изначально повёрнута на M_PI / 2.0 вокруг Y, поэтому добавляем компенсацию
Vector4f correctionQuat = QuatFromRotateAroundY(M_PI / 2.0f);
renderer.RotateMatrix(correctionQuat);
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
renderer.DrawVertexRenderStruct(spaceship);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::drawBoxes()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
1, 1000);
for (int i = 0; i < boxCoordsArr.size(); i++)
{
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
renderer.RotateMatrix(Environment::inverseShipMatrix);
renderer.TranslateMatrix(-Environment::shipPosition);
renderer.TranslateMatrix(boxCoordsArr[i].pos);
renderer.RotateMatrix(boxCoordsArr[i].m);
glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
renderer.DrawVertexRenderStruct(boxRenderArr[i]);
renderer.PopMatrix();
}
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::UpdateVolumeKnob() {
float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY);
auto& pos = musicVolumeBarButton.data.PositionData;
pos[0] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
pos[1] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[2] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[3] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
pos[4] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 };
pos[5] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 };
musicVolumeBarButton.RefreshVBO();
}
void Game::UpdateVolumeFromMouse(int mouseX, int mouseY) {
int uiX = mouseX;
int uiY = Environment::height - mouseY;
Environment::shipVelocity = (musicVolume - 0.2) * (20.0);
if (uiY < volumeBarMinY || uiY > volumeBarMaxY)
{
return;
}
float t = (uiY - volumeBarMinY) / (volumeBarMaxY - volumeBarMinY);
if (t < 0.0f) t = 0.0f;
if (t > 1.0f) t = 1.0f;
musicVolume = t;
UpdateVolumeKnob();
}
void Game::drawUI()
{
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
glClear(GL_DEPTH_BUFFER_BIT);
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushProjectionMatrix(Environment::width, Environment::height, -1, 1);
renderer.PushMatrix();
renderer.LoadIdentity();
glBindTexture(GL_TEXTURE_2D, buttonTexture->getTexID());
renderer.DrawVertexRenderStruct(button);
glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID());
renderer.DrawVertexRenderStruct(musicVolumeBar);
glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID());
renderer.DrawVertexRenderStruct(musicVolumeBarButton);
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader();
CheckGlError();
}
void Game::drawScene() {
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
glClearColor(0.0f, 0.5f, 1.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glViewport(0, 0, Environment::width, Environment::height);
CheckGlError();
drawCubemap();
drawShip();
drawBoxes();
//drawUI();
CheckGlError();
}
void Game::processTickCount() {
if (lastTickCount == 0) {
lastTickCount = SDL_GetTicks64();
return;
}
newTickCount = SDL_GetTicks64();
if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) {
size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ?
CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount;
//gameObjects.updateScene(delta);
if (Environment::tapDownHold) {
float diffx = Environment::tapDownCurrentPos.v[0] - Environment::tapDownStartPos.v[0];
float diffy = Environment::tapDownCurrentPos.v[1] - Environment::tapDownStartPos.v[1];
if (isDraggingShip) {
// Движение корабля
if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold
{
float velocity = sqrtf(diffx * diffx + diffy * diffy);
Environment::shipVelocity = velocity * delta / 100;
// SDL screen Y направлен вниз, поэтому инвертируем diffy
// Движение по -Z (вперёд в локальных координатах камеры)
// diffx: вправо = положительное, влево = отрицательное
// diffy: вниз = положительное, вверх = отрицательное (в SDL)
// Для логики: вверх на экране (отрицательный diffy) = движение вперёд (-Z)
// Вправо на экране (положительный diffx) = поворот вправо (вокруг +Y)
// Вычисляем угол поворота вокруг Y (горизонтальный поворот)
// atan2(x, z) где x - это -diffx (инвертированное для правильного направления), z - это -diffy (вверх/вниз, инвертированное)
// Вверх (diffy < 0) должно давать угол 0 (вперёд), вправо (diffx > 0) должно давать правильное направление
float angleY = atan2(-diffx, -diffy); // угол поворота вокруг Y (инвертируем diffx для правильного направления)
// Создаём кватернион для поворота вокруг Y (горизонтальный поворот)
Vector4f quat = { 0, sin(angleY * 0.5f), 0, cos(angleY * 0.5f) };
rotateShipMat = QuatToMatrix(quat);
// Фиксируем ориентацию камеры при первом реальном движении
if (!shipMoveLockActive) {
lockedCameraMat = Environment::shipMatrix;
shipMoveLockActive = true;
}
}
else
{
Environment::shipVelocity = 0;
}
}
else if (isDraggingCamera) {
// Вращение камеры
if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold
{
float rotationPower = sqrtf(diffx * diffx + diffy * diffy);
float deltaAlpha = rotationPower * delta * M_PI / 500000.f;
Vector3f rotationDirection = { diffy, diffx, 0 };
rotationDirection = rotationDirection.normalized();
Vector4f rotateQuat = {
rotationDirection.v[0] * sin(deltaAlpha * 0.5f),
rotationDirection.v[1] * sin(deltaAlpha * 0.5f),
rotationDirection.v[2] * sin(deltaAlpha * 0.5f),
cos(deltaAlpha * 0.5f) };
Matrix3f rotateMat = QuatToMatrix(rotateQuat);
Environment::shipMatrix = MultMatrixMatrix(Environment::shipMatrix, rotateMat);
Environment::inverseShipMatrix = InverseMatrix(Environment::shipMatrix);
// Обновляем начальную позицию для плавного вращения
Environment::tapDownStartPos.v[0] = Environment::tapDownCurrentPos.v[0];
Environment::tapDownStartPos.v[1] = Environment::tapDownCurrentPos.v[1];
}
}
}
if (fabs(Environment::shipVelocity) > 0.01f)
{
// Получаем локальное перемещение в координатах камеры
Vector3f localMove = MultMatrixVector(rotateShipMat, Vector3f{0, 0, -Environment::shipVelocity * delta / 1000.f});
// Выбираем матрицу камеры: зафиксированную (если lock активен) или текущую
Matrix3f camMat = lockedCameraMat;//////shipMoveLockActive ? lockedCameraMat : Environment::shipMatrix;
// Переводим локальное перемещение в мировые координаты
Vector3f worldMove = MultMatrixVector(camMat, localMove);
Environment::shipPosition = Environment::shipPosition + worldMove;
}
lastTickCount = newTickCount;
}
}
void Game::render() {
SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
ZL::CheckGlError();
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene();
processTickCount();
SDL_GL_SwapWindow(ZL::Environment::window);
}
void Game::update() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
Environment::exitGameLoop = true;
}
else if (event.type == SDL_MOUSEBUTTONDOWN) {
// 1. Обработка нажатия кнопки мыши
int mx = event.button.x;
int my = event.button.y;
std::cout << mx << " " << my << '\n';
int uiX = mx;
int uiY = Environment::height - my;
if (mx < 400 && my > 400)
{
Environment::tapDownHold = true;
isDraggingShip = true;
isDraggingCamera = false;
// Сбрасываем lock при новом нажатии, чтобы новый drag снова фиксировал камеру при первом движении
shipMoveLockActive = false;
// Координаты начального нажатия
Environment::tapDownStartPos.v[0] = event.button.x;
Environment::tapDownStartPos.v[1] = event.button.y;
// Начальная позиция также становится текущей
Environment::tapDownCurrentPos.v[0] = event.button.x;
Environment::tapDownCurrentPos.v[1] = event.button.y;
}
else
{
Environment::tapDownHold = true;
isDraggingShip = false;
isDraggingCamera = true;
// Координаты начального нажатия
Environment::tapDownStartPos.v[0] = event.button.x;
Environment::tapDownStartPos.v[1] = event.button.y;
// Начальная позиция также становится текущей
Environment::tapDownCurrentPos.v[0] = event.button.x;
Environment::tapDownCurrentPos.v[1] = event.button.y;
}
}
else if (event.type == SDL_MOUSEBUTTONUP) {
// 2. Обработка отпускания кнопки мыши
isDraggingVolume = false;
Environment::tapDownHold = false;
Environment::shipVelocity = 0;
// Сбрасываем lock камеры при отпускании мыши
shipMoveLockActive = false;
// Если была повернута камера, синхронизируем ориентацию корабля с камерой
// Корабль должен смотреть в том же направлении, что и камера (без дополнительного вращения)
if (isDraggingCamera) {
rotateShipMat = Matrix3f::Identity();
}
isDraggingShip = false;
isDraggingCamera = false;
}
else if (event.type == SDL_MOUSEMOTION) {
// 3. Обработка перемещения мыши
int mx = event.motion.x;
int my = event.motion.y;
if (Environment::tapDownHold) {
// Обновление текущей позиции, если кнопка удерживается
Environment::tapDownCurrentPos.v[0] = event.motion.x;
Environment::tapDownCurrentPos.v[1] = event.motion.y;
}
}
else if (event.type == SDL_MOUSEWHEEL) {
static const float zoomstep = 2.0f;
if (event.wheel.y > 0) {
Environment::zoom -= zoomstep;
}
else if (event.wheel.y < 0) {
Environment::zoom += zoomstep;
}
if (Environment::zoom < zoomstep) {
Environment::zoom = zoomstep;
}
}
else if (event.type == SDL_KEYUP)
{
if (event.key.keysym.sym == SDLK_i)
{
Environment::shipVelocity += 1.f;
}
if (event.key.keysym.sym == SDLK_k)
{
Environment::shipVelocity -= 1.f;
}
}
}
render();
}
} // namespace ZL