Звук (Web Audio API) + несколько раскладок coop-карты

Клиент: audio.js синтезирует эффекты без внешних файлов (выстрел,
взрыв, разрушение кирпича, победа/поражение) — вписывается в
"чистый HTML/CSS/JS" стек. AudioContext разблокируется по клику
"готов" (браузеры блокируют автовоспроизведение без жеста).

Сервер: 3 варианта раскладки coop-карты (случайный выбор при старте
матча) вместо одной фиксированной.

Fix: сервер разрушал кирпичи в своей копии карты, но никогда не сообщал
об этом клиенту — стена оставалась видимой навсегда, хотя сквозь неё уже
можно было стрелять. Теперь game.state включает destroyed_tiles,
клиент убирает соответствующий спрайт стены.
This commit is contained in:
2026-08-06 12:42:52 +05:00
parent 79aa4a0c48
commit f2a5657740
5 changed files with 150 additions and 13 deletions
+33 -6
View File
@@ -88,7 +88,7 @@ void Game::buildCoopMap() {
}
}
// немного укрытий по полю
// немного укрытий по полю — несколько вариантов раскладки для разнообразия
auto block = [this](int x, int y, int w, int h, int tile) {
for (int dy = 0; dy < h; dy++) {
for (int dx = 0; dx < w; dx++) {
@@ -96,11 +96,29 @@ void Game::buildCoopMap() {
}
}
};
block(2, 5, 2, 2, kBrick);
block(11, 5, 2, 2, kBrick);
block(6, 4, 3, 1, kSteel);
block(4, 8, 2, 2, kBrick);
block(9, 8, 2, 2, kBrick);
switch (std::rand() % 3) {
case 0:
block(2, 5, 2, 2, kBrick);
block(11, 5, 2, 2, kBrick);
block(6, 4, 3, 1, kSteel);
block(4, 8, 2, 2, kBrick);
block(9, 8, 2, 2, kBrick);
break;
case 1:
block(1, 4, 3, 1, kSteel);
block(11, 4, 3, 1, kSteel);
block(6, 6, 3, 3, kBrick);
block(2, 9, 2, 2, kBrick);
block(11, 9, 2, 2, kBrick);
break;
default:
block(4, 3, 1, 4, kBrick);
block(10, 3, 1, 4, kBrick);
block(6, 5, 3, 2, kSteel);
block(3, 9, 3, 1, kBrick);
block(9, 9, 3, 1, kBrick);
break;
}
// база внизу по центру, укрыта кирпичом с трёх сторон
int bx = kMapWidth / 2;
@@ -320,6 +338,7 @@ void Game::fireBullet(Tank &tank) {
}
void Game::updateBullets() {
destroyed_tiles_.clear();
double step = kBulletSpeed * kDt;
for (auto &b : bullets_) {
@@ -361,6 +380,7 @@ void Game::updateBullets() {
}
if (map_[ty][tx] == kBrick) {
map_[ty][tx] = kEmpty;
destroyed_tiles_.push_back({tx, ty});
dead[i] = true;
continue;
}
@@ -518,6 +538,13 @@ void Game::broadcastState() {
if (base_) {
payload["base"] = {{"x", base_->x}, {"y", base_->y}, {"alive", base_->alive}};
}
if (!destroyed_tiles_.empty()) {
json destroyed = json::array();
for (const auto &[tx, ty] : destroyed_tiles_) {
destroyed.push_back({tx, ty});
}
payload["destroyed_tiles"] = destroyed;
}
for (const auto &t : tanks_) {
if (!t.is_ai) {
sendTo(t.ws, "game.state", payload);
+1
View File
@@ -69,6 +69,7 @@ private:
std::vector<Bullet> bullets_;
std::optional<Base> base_;
std::vector<std::pair<double, double>> enemy_spawn_points_;
std::vector<std::pair<int, int>> destroyed_tiles_; // за последний тик — для звука/синка стен на клиенте
int enemies_spawned_total_ = 0;
int enemy_spawn_cooldown_ = 0;
int next_bullet_id_ = 1;