Compare commits

..

5 Commits
linux ... main

Author SHA1 Message Date
Vladislav Khorev
5e7c050c68 Merge branch 'spark' 2026-03-10 11:39:02 +03:00
Vladislav Khorev
c88784a669 Added inverse, fixing server bug 2026-03-10 11:38:16 +03:00
Vlad
181132e092 merge 2026-03-10 14:36:35 +06:00
Vlad
6fe10eacfc Merge remote-tracking branch 'origin/main' into spark 2026-03-10 14:26:51 +06:00
Vlad
9e692c9ec3 added enter nicknamw 2026-03-10 14:25:00 +06:00
8 changed files with 276 additions and 28 deletions

View File

@ -323,7 +323,7 @@ set(_have_freetype TRUE)
foreach(cfg IN LISTS BUILD_CONFIGS)
if(NOT EXISTS "${FREETYPE_BASE_DIR}-${cfg}/lib/freetype.lib" AND
NOT EXISTS "${FREETYPE_BASE_DIR}-${cfg}/lib/freetyped.lib")
#set(_have_freetype FALSE)
set(_have_freetype FALSE)
endif()
endforeach()
@ -391,7 +391,7 @@ foreach(cand
endforeach()
if(_ft_debug_lib STREQUAL "" OR _ft_release_lib STREQUAL "")
# message(FATAL_ERROR "FreeType libs not found in ${FREETYPE_BASE_DIR}-Debug/Release")
message(FATAL_ERROR "FreeType libs not found in ${FREETYPE_BASE_DIR}-Debug/Release")
endif()
add_library(freetype_external_lib UNKNOWN IMPORTED GLOBAL)
@ -441,7 +441,7 @@ if(NOT _have_sdl2ttf)
endforeach()
if(_FT_LIB STREQUAL "")
# message(FATAL_ERROR "FreeType library not found for ${cfg}")
message(FATAL_ERROR "FreeType library not found for ${cfg}")
endif()
log("Configuring SDL_ttf (${cfg}) ...")
@ -462,7 +462,7 @@ if(NOT _have_sdl2ttf)
RESULT_VARIABLE _ttf_cfg_res
)
if(NOT _ttf_cfg_res EQUAL 0)
#message(FATAL_ERROR "SDL_ttf configure failed for ${cfg}")
message(FATAL_ERROR "SDL_ttf configure failed for ${cfg}")
endif()
log("Building SDL_ttf (${cfg}) ...")
@ -472,7 +472,7 @@ if(NOT _have_sdl2ttf)
RESULT_VARIABLE _ttf_build_res
)
if(NOT _ttf_build_res EQUAL 0)
#message(FATAL_ERROR "SDL_ttf build failed for ${cfg}")
message(FATAL_ERROR "SDL_ttf build failed for ${cfg}")
endif()
log("Installing SDL_ttf (${cfg}) ...")
@ -482,7 +482,7 @@ if(NOT _have_sdl2ttf)
RESULT_VARIABLE _ttf_inst_res
)
if(NOT _ttf_inst_res EQUAL 0)
#message(FATAL_ERROR "SDL_ttf install failed for ${cfg}")
message(FATAL_ERROR "SDL_ttf install failed for ${cfg}")
endif()
endforeach()
@ -510,7 +510,7 @@ foreach(cand
endforeach()
if(_ttf_debug_lib STREQUAL "" OR _ttf_release_lib STREQUAL "")
# message(FATAL_ERROR "SDL_ttf libs not found in install-Debug / install-Release")
message(FATAL_ERROR "SDL_ttf libs not found in install-Debug / install-Release")
endif()
add_library(SDL2_ttf_external_lib UNKNOWN IMPORTED GLOBAL)
@ -546,4 +546,4 @@ if(NOT TARGET boost_external_lib)
add_library(boost_external_lib INTERFACE)
# Boost заголовки находятся непосредственно в корне распакованной папки
target_include_directories(boost_external_lib INTERFACE "${BOOST_SRC_DIR}")
endif()
endif()

View File

@ -30,13 +30,52 @@
border-radius: 5px;
}
#status { color: white; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
/* Nick modal */
#nickOverlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0,0,0,0.85);
z-index: 9999;
}
#nickBox {
background: #111;
border: 1px solid #444;
padding: 24px;
width: 320px;
box-shadow: 0 8px 24px rgba(0,0,0,0.6);
text-align: center;
}
#nickBox h2 { margin: 0 0 12px 0; font-size: 18px; color: #eee; }
#nickBox input[type="text"] {
width: 100%;
padding: 10px;
font-size: 16px;
box-sizing: border-box;
margin-bottom: 12px;
border: 1px solid #333;
background: #000;
color: #fff;
}
#nickBox button {
padding: 10px 16px;
font-size: 16px;
background: #2a9fd6;
border: none;
color: #fff;
cursor: pointer;
}
#nickSkip { margin-left: 8px; background: #666; }
</style>
</head>
<body>
<button id="fs-button">Fullscreen</button>
<div id="status">Downloading...</div>
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1"></canvas>
<!--
<script>
var statusElement = document.getElementById("status");
var canvas = document.getElementById("canvas");
@ -66,6 +105,112 @@
});
</script>
<script async src="space-game001.js"></script>
<script async src="space-game001.js"></script>-->
<div id="nickOverlay" style="display:none;">
<div id="nickBox">
<h2>Enter your nickname</h2>
<input id="nickInput" type="text" maxlength="32" placeholder="Player" />
<div>
<button id="nickSubmit">Start</button>
</div>
</div>
</div>
<script>
// Utility: подготовить глобальный Module до загрузки Emscripten-скрипта
function prepareModuleEnvironment() {
window.Module = window.Module || {};
var canvasEl = document.getElementById('canvas');
// Устанавливаем canvas для Emscripten, чтобы createContext не падал
window.Module.canvas = canvasEl;
// Подготовим заглушку setStatus, если ещё нет
window.Module.setStatus = window.Module.setStatus || function (text) {
var statusElement = document.getElementById("status");
statusElement.innerHTML = text;
statusElement.style.display = text ? 'block' : 'none';
};
}
// Show overlay only if no nickname saved.
function loadGameScript() {
var s = document.createElement('script');
s.src = 'space-game001.js';
s.async = true;
document.body.appendChild(s);
}
function showNickOverlay() {
var overlay = document.getElementById('nickOverlay');
overlay.style.display = 'flex';
var input = document.getElementById('nickInput');
input.focus();
}
function hideNickOverlay() {
var overlay = document.getElementById('nickOverlay');
overlay.style.display = 'none';
}
function saveNickAndStart(nick) {
try {
if (!nick || nick.trim() === '') nick = 'Player';
localStorage.setItem('spacegame_nick', nick);
} catch (e) {
console.warn('localStorage not available', e);
}
hideNickOverlay();
// перед загрузкой скрипта гарантируем, что Module.canvas задан
prepareModuleEnvironment();
loadGameScript();
}
document.addEventListener('DOMContentLoaded', function() {
// Готовим Module сразу — даже если откроется модалка, поле canvas будет доступно для скрипта (если он загружается позже)
prepareModuleEnvironment();
var stored = null;
try {
stored = localStorage.getItem('spacegame_nick');
} catch (e) {
console.warn('localStorage not available', e);
}
if (stored && stored.trim() !== '') {
// Nick is present — start immediately
loadGameScript();
} else {
// Show modal to request nickname before loading WASM
showNickOverlay();
var submit = document.getElementById('nickSubmit');
var skip = document.getElementById('nickSkip');
var input = document.getElementById('nickInput');
submit.addEventListener('click', function() {
saveNickAndStart(input.value);
});
skip.addEventListener('click', function() {
saveNickAndStart('Player');
});
input.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
saveNickAndStart(input.value);
}
});
}
});
window.addEventListener("orientationchange", function() {
// Chrome на Android обновляет innerWidth/Height не мгновенно.
// Ждем завершения анимации поворота.
setTimeout(() => {
// В Emscripten это вызовет ваш onWindowResized в C++
window.dispatchEvent(new Event('resize'));
}, 200);
});
</script>
</body>
</html>

View File

@ -41,6 +41,22 @@
"disabled": "resources/button_players.png"
}
},
{
"type": "Button",
"name": "inverseMouseButton",
"x": 0,
"y": 100,
"width": 150,
"height": 150,
"horizontal_gravity": "right",
"vertical_gravity": "top",
"textures": {
"normal": "resources/fire.png",
"hover": "resources/fire.png",
"pressed": "resources/fire2.png",
"disabled": "resources/fire.png"
}
},
{
"type": "Button",
"name": "shootButton",

View File

@ -46,4 +46,4 @@ if(WIN32)
endif()
# Дополнительный макрос, чтобы Asio знал, что мы работаем без устаревших функций
target_compile_definitions(Server PRIVATE BOOST_ASIO_NO_DEPRECATED)
target_compile_definitions(Server PRIVATE BOOST_ASIO_NO_DEPRECATED)

View File

@ -125,8 +125,6 @@ void Session::sendBoxesToClient() {
void Session::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) {
@ -135,6 +133,8 @@ void Session::init()
uint64_t now_ms = static_cast<uint64_t>(
std::chrono::duration_cast<std::chrono::milliseconds>(now_tp.time_since_epoch()).count());
self->sendBoxesToClient();
self->send_message("ID:" + std::to_string(self->id_) + ":" + std::to_string(now_ms));
self->do_read();
}
@ -938,14 +938,14 @@ void Server::accept()
int main() {
try {
net::io_context ioc;
tcp::acceptor acceptor{ ioc, {tcp::v4(), 8010} };
tcp::acceptor acceptor{ ioc, {tcp::v4(), 8081} };
Server server(acceptor, ioc);
server.init();
server.accept();
std::cout << "Server started on port 8010...\n";
std::cout << "Server started on port 8081...\n";
server.update_world();
ioc.run();
@ -954,4 +954,4 @@ int main() {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
}

View File

@ -1,8 +1,15 @@
#include "MenuManager.h"
#include <iostream>
#ifdef EMSCRIPTEN
#include <emscripten.h>
#include <cstdlib>
#endif
namespace ZL {
extern bool inverseVertical;
MenuManager::MenuManager(Renderer& iRenderer) :
renderer(iRenderer)
{
@ -53,15 +60,39 @@ namespace ZL {
state = GameState::ShipSelectionSingle;
uiManager.replaceRoot(shipSelectionRoot);
uiManager.setButtonCallback("spaceshipButton", [this](const std::string&) {
std::string initialNick;
#ifdef EMSCRIPTEN
char* savedNickC = emscripten_run_script_string("localStorage.getItem('spacegame_nick') || ''");
if (savedNickC) {
initialNick = savedNickC;
free(savedNickC);
}
#endif
auto tf = uiManager.findTextField("nicknameInput");
if (tf) {
if (!initialNick.empty()) tf->text = initialNick;
#ifdef EMSCRIPTEN
uiManager.setTextFieldCallback("nicknameInput", [](const std::string&, const std::string& value) {
EM_ASM_({
try { localStorage.setItem('spacegame_nick', UTF8ToString($0)); } catch(e) {}
}, value.c_str());
});
#endif
}
uiManager.setButtonCallback("spaceshipButton", [this, initialNick](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = initialNick;
if (nick.empty()) nick = "Player";
enterGameplay();
if (onSingleplayerPressed) onSingleplayerPressed(nick, 0);
});
uiManager.setButtonCallback("cargoshipButton", [this](const std::string&) {
uiManager.setButtonCallback("cargoshipButton", [this, initialNick](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = initialNick;
if (nick.empty()) nick = "Player";
enterGameplay();
if (onSingleplayerPressed) onSingleplayerPressed(nick, 1);
@ -79,8 +110,31 @@ namespace ZL {
state = GameState::ShipSelectionMulti;
uiManager.replaceRoot(shipSelectionRoot);
uiManager.setButtonCallback("spaceshipButton", [this](const std::string&) {
std::string initialNick;
#ifdef EMSCRIPTEN
char* savedNickC = emscripten_run_script_string("localStorage.getItem('spacegame_nick') || ''");
if (savedNickC) {
initialNick = savedNickC;
free(savedNickC);
}
#endif
auto tf = uiManager.findTextField("nicknameInput");
if (tf) {
if (!initialNick.empty()) tf->text = initialNick;
#ifdef EMSCRIPTEN
uiManager.setTextFieldCallback("nicknameInput", [](const std::string&, const std::string& value) {
EM_ASM_({
try { localStorage.setItem('spacegame_nick', UTF8ToString($0)); } catch(e) {}
}, value.c_str());
});
#endif
}
uiManager.setButtonCallback("spaceshipButton", [this, initialNick](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = initialNick;
if (nick.empty()) nick = "Player";
pendingMultiNick = nick;
pendingMultiShipType = 0;
@ -88,8 +142,9 @@ namespace ZL {
if (onMultiplayerPressed) onMultiplayerPressed(nick, 0);
});
uiManager.setButtonCallback("cargoshipButton", [this](const std::string&) {
uiManager.setButtonCallback("cargoshipButton", [this, initialNick](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = initialNick;
if (nick.empty()) nick = "Player";
pendingMultiNick = nick;
pendingMultiShipType = 1;
@ -189,6 +244,14 @@ namespace ZL {
if (onShowPlayersPressed) onShowPlayersPressed();
});
//inverseMouseButton
uiManager.setButtonPressCallback("inverseMouseButton", [this](const std::string&) {
inverseVertical = !inverseVertical;
std::cout << "Inverse mouse: " << (inverseVertical ? "ON" : "OFF") << std::endl;
});
/*
uiManager.setSliderCallback("velocitySlider", [this](const std::string&, float value) {

View File

@ -36,6 +36,8 @@ namespace ZL
extern float y;
extern float z;
bool inverseVertical = true;
Eigen::Quaternionf generateRandomQuaternion(std::mt19937& gen)
{
@ -2079,11 +2081,22 @@ namespace ZL
Environment::tapDownHold = true;
Environment::tapDownStartPos(0) = mx;
Environment::tapDownStartPos(1) = my;
if (inverseVertical)
{
Environment::tapDownStartPos(0) = mx;
Environment::tapDownStartPos(1) = my;
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
}
else
{
Environment::tapDownStartPos(0) = mx;
Environment::tapDownStartPos(1) = -my;
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = -my;
}
}
void Space::handleUp(int mx, int my)
@ -2096,9 +2109,20 @@ namespace ZL
{
if (playerListVisible) return;
if (Environment::tapDownHold) {
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
if (inverseVertical)
{
if (Environment::tapDownHold) {
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = my;
}
}
else
{
if (Environment::tapDownHold) {
Environment::tapDownCurrentPos(0) = mx;
Environment::tapDownCurrentPos(1) = -my;
}
}
}

View File

@ -9,7 +9,7 @@ namespace ZL {
// Формируем URL. Обратите внимание, что в Web часто лучше использовать ws://localhost
//std::string url = "ws://" + host + ":" + std::to_string(port);
std::string url = "wss://api.spacegame.fishrungames.com";
//std::string url = "ws://localhost:8081";
EmscriptenWebSocketCreateAttributes attr = {
url.c_str(),
nullptr,