Initial commit
This commit is contained in:
commit
b37727ae66
|
|
@ -0,0 +1,11 @@
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Копируем файлы игры в директорию nginx
|
||||||
|
COPY index.html /usr/share/nginx/html/index.html
|
||||||
|
COPY style.css /usr/share/nginx/html/style.css
|
||||||
|
COPY game.js /usr/share/nginx/html/game.js
|
||||||
|
|
||||||
|
# Используем конфигурацию nginx по умолчанию
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,215 @@
|
||||||
|
# GrechkaCraft: Multiplayer
|
||||||
|
|
||||||
|
2D песочница в стиле Minecraft с мультиплеером. Исследуйте, стройте, добывайте ресурсы и сражайтесь с мобами!
|
||||||
|
|
||||||
|
## 🎮 Управление
|
||||||
|
|
||||||
|
### Клавиатура (ПК)
|
||||||
|
- **A / ←** - движение влево
|
||||||
|
- **D / →** - движение вправо
|
||||||
|
- **W / ↑ / Пробел** - прыжок
|
||||||
|
- **S / ↓** - спуск вниз (на лестницах)
|
||||||
|
- **ЛКМ** - взаимодействие (добыча/строительство/атака)
|
||||||
|
|
||||||
|
### Сенсорное управление (мобильные устройства)
|
||||||
|
На мобильных устройствах (экраны шириной до 768px) отображается панель управления внизу экрана:
|
||||||
|
- **⬅️** - движение влево
|
||||||
|
- **⬆️** - прыжок
|
||||||
|
- **⬇️** - спуск вниз
|
||||||
|
- **➡️** - движение вправо
|
||||||
|
|
||||||
|
## 🎯 Режимы игры
|
||||||
|
|
||||||
|
Переключайте режимы кнопкой **🏃** в правом верхнем углу:
|
||||||
|
|
||||||
|
1. **🏃 Движение** - стандартный режим для передвижения
|
||||||
|
2. **⛏️ Добыча** - ломайте блоки и атакуйте мобов
|
||||||
|
3. **🧱 Строительство** - ставьте блоки
|
||||||
|
|
||||||
|
## 📦 Инвентарь и крафт
|
||||||
|
|
||||||
|
### Инвентарь
|
||||||
|
- Откройте инвентарь кнопкой **📦** в правом верхнем углу
|
||||||
|
- Выберите предмет для использования
|
||||||
|
- Инвентарь отображается поверх кнопок управления на мобильных устройствах
|
||||||
|
|
||||||
|
### Крафт
|
||||||
|
- Откройте панель крафта кнопкой **🔨** в правом верхнем углу
|
||||||
|
- Выбирайте рецепты из списка
|
||||||
|
- Кнопка "Создать" активна только если достаточно ресурсов
|
||||||
|
|
||||||
|
## 🧱 Блоки
|
||||||
|
|
||||||
|
### Базовые блоки
|
||||||
|
- **Трава** - основной блок поверхности
|
||||||
|
- **Грязь** - подповерхностный слой
|
||||||
|
- **Камень** - прочный блок для строительства
|
||||||
|
- **Песок** - падает при отсутствии опоры
|
||||||
|
- **Гравий** - падает при отсутствии опоры
|
||||||
|
- **Глина** - добывается в песчаных берегах
|
||||||
|
|
||||||
|
### Деревянные блоки
|
||||||
|
- **Дерево** - добывается из деревьев
|
||||||
|
- **Доски** - создаются из дерева
|
||||||
|
- **Лестница** - позволяет подниматься и спускаться
|
||||||
|
|
||||||
|
### Руды
|
||||||
|
- **Уголь** - топливо для костров
|
||||||
|
- **Медь** - редкая руда
|
||||||
|
- **Железо** - средняя редкость
|
||||||
|
- **Золото** - редкая руда
|
||||||
|
- **Алмаз** - очень редкая руда
|
||||||
|
|
||||||
|
### Декоративные и специальные блоки
|
||||||
|
- **Листва** - декоративный блок
|
||||||
|
- **Стекло** - прозрачный блок
|
||||||
|
- **Вода** - жидкость, можно плавать
|
||||||
|
- **Кирпич** - прочный строительный блок
|
||||||
|
- **Цветок** - декоративный элемент
|
||||||
|
- **Факел** - освещение ночью
|
||||||
|
- **Костёр** - освещение + жарка мяса
|
||||||
|
- **TNT** - взрывчатка
|
||||||
|
- **Кровать** - позволяет спать и пропускать ночь
|
||||||
|
- **Лодка** - для передвижения по воде
|
||||||
|
|
||||||
|
## 🍖 Предметы и инструменты
|
||||||
|
|
||||||
|
### Еда
|
||||||
|
- **Сырое мясо** - добывается из животных, восстанавливает 15 голода и 15 HP
|
||||||
|
- **Жареное мясо** - жарится на костре, восстанавливает 45 голода и 15 HP
|
||||||
|
|
||||||
|
### Инструменты
|
||||||
|
- **Деревянная кирка** - 60 прочности, mining power 1
|
||||||
|
- **Каменная кирка** - 130 прочности, mining power 2
|
||||||
|
- **Железная кирка** - 250 прочности, mining power 3
|
||||||
|
- **Деревянный меч** - 40 прочности, 5 урона
|
||||||
|
- **Каменный меч** - 100 прочности, 8 урона
|
||||||
|
- **Железный меч** - 200 прочности, 12 урона
|
||||||
|
|
||||||
|
## 👾 Мобы
|
||||||
|
|
||||||
|
### Дружественные (днём)
|
||||||
|
- **Свинья** - даёт 2 сырого мяса
|
||||||
|
- **Курица** - даёт 1 сырое мясо
|
||||||
|
|
||||||
|
### Враждебные (ночью)
|
||||||
|
- **Зомби** - атакует игрока, наносит 15 урона
|
||||||
|
- **Крипер** - взрывается рядом с игроком
|
||||||
|
- **Скелет** - стреляет стрелами издалека
|
||||||
|
|
||||||
|
## 🌍 Мир
|
||||||
|
|
||||||
|
### Генерация
|
||||||
|
- Детерминированная генерация на основе seed
|
||||||
|
- Автоматическая генерация при движении
|
||||||
|
- Разнообразные биомы: горы, равнины, пляжи
|
||||||
|
|
||||||
|
### День и ночь
|
||||||
|
- Автоматический цикл дня и ночи
|
||||||
|
- Ночью появляются враждебные мобы
|
||||||
|
- Нажмите на часы в UI для переключения на ночь
|
||||||
|
- Спите на кровати для пропуска ночи
|
||||||
|
|
||||||
|
### Физика
|
||||||
|
- Гравитация и коллизии
|
||||||
|
- Плавание в воде
|
||||||
|
- Лестницы для вертикального движения
|
||||||
|
- Урон от падения
|
||||||
|
|
||||||
|
## 💾 Сохранение
|
||||||
|
|
||||||
|
### Автосохранение
|
||||||
|
- Игра сохраняется автоматически при скрытии страницы
|
||||||
|
- Игра сохраняется перед закрытием страницы
|
||||||
|
- Игра сохраняется при отходе ко сну
|
||||||
|
|
||||||
|
### Ручное сохранение
|
||||||
|
- Кнопка **💾** в правом верхнем углу (только в одиночном режиме)
|
||||||
|
- Сохраняется в localStorage браузера
|
||||||
|
|
||||||
|
### Сброс игры
|
||||||
|
- Кнопка **🔄** удаляет сохранение и начинает новую игру
|
||||||
|
- Генерируется новый worldId
|
||||||
|
|
||||||
|
## 🌐 Мультиплеер
|
||||||
|
|
||||||
|
### Подключение
|
||||||
|
- Автоматическое подключение к серверу при запуске
|
||||||
|
- World ID отображается в левом верхнем углу
|
||||||
|
- Кликните на World ID для копирования ссылки
|
||||||
|
|
||||||
|
### Совместная игра
|
||||||
|
- Видите других игроков в реальном времени
|
||||||
|
- Общие изменения блоков
|
||||||
|
- Общий день/ночь
|
||||||
|
- Чат (временно скрыт)
|
||||||
|
|
||||||
|
### Синхронизация
|
||||||
|
- Позиции игроков синхронизируются 20 раз в секунду
|
||||||
|
- Изменения блоков мгновенно передаются всем игрокам
|
||||||
|
|
||||||
|
## 🛠️ Развертывание
|
||||||
|
|
||||||
|
### Локальный запуск
|
||||||
|
```bash
|
||||||
|
# Клонирование репозитория
|
||||||
|
git clone <repository-url>
|
||||||
|
cd grechka-game
|
||||||
|
|
||||||
|
# Запуск через Docker Compose
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Игра доступна на порту 80
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
```bash
|
||||||
|
# Сборка образа
|
||||||
|
docker build -t grechka-game .
|
||||||
|
|
||||||
|
# Запуск контейнера
|
||||||
|
docker run -p 80:80 grechka-game
|
||||||
|
```
|
||||||
|
|
||||||
|
### Структура файлов
|
||||||
|
- `index.html` - основной HTML файл
|
||||||
|
- `game.js` - игровой движок
|
||||||
|
- `style.css` - стили интерфейса
|
||||||
|
- `Dockerfile` - конфигурация Docker образа
|
||||||
|
- `docker-compose.yml` - конфигурация Docker Compose
|
||||||
|
|
||||||
|
## 📝 Недавние изменения
|
||||||
|
|
||||||
|
### Версия 1.3 (2026-01-03)
|
||||||
|
- ✅ Добавлена кнопка "вниз" для мобильных устройств
|
||||||
|
- ✅ Исправлен z-index для инвентаря и крафта (теперь поверх кнопок управления)
|
||||||
|
- ✅ Скрыт чат из интерфейса
|
||||||
|
- ✅ Добавлены проверки на null для предотвращения крашей JavaScript
|
||||||
|
|
||||||
|
### Предыдущие версии
|
||||||
|
- Мультиплеер через Socket.IO
|
||||||
|
- Система сохранения в localStorage
|
||||||
|
- Автоматический цикл дня и ночи
|
||||||
|
- Система крафта и инструментов
|
||||||
|
- Разнообразные мобы и блоки
|
||||||
|
|
||||||
|
## 🐛 Известные проблемы
|
||||||
|
|
||||||
|
- Чат временно скрыт
|
||||||
|
- На мобильных устройствах кнопки управления могут перекрывать hotbar
|
||||||
|
|
||||||
|
## 📄 Лицензия
|
||||||
|
|
||||||
|
Проект распространяется как есть.
|
||||||
|
|
||||||
|
## 🤝 Участие
|
||||||
|
|
||||||
|
Для внесения изменений:
|
||||||
|
1. Форкните репозиторий
|
||||||
|
2. Создайте ветку для новой функции
|
||||||
|
3. Внесите изменения
|
||||||
|
4. Отправьте pull request
|
||||||
|
|
||||||
|
## 📞 Контакты
|
||||||
|
|
||||||
|
По вопросам и предложениям обращайтесь к разработчику.
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Копируем файлы игры в директорию nginx
|
||||||
|
COPY index.html /usr/share/nginx/html/index.html
|
||||||
|
COPY style.css /usr/share/nginx/html/style.css
|
||||||
|
COPY game.js /usr/share/nginx/html/game.js
|
||||||
|
|
||||||
|
# Используем конфигурацию nginx по умолчанию
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,11 @@
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Копируем файлы игры в директорию nginx
|
||||||
|
COPY index.html /usr/share/nginx/html/index.html
|
||||||
|
COPY style.css /usr/share/nginx/html/style.css
|
||||||
|
COPY game.js /usr/share/nginx/html/game.js
|
||||||
|
|
||||||
|
# Используем конфигурацию nginx по умолчанию
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,27 @@
|
||||||
|
name: grechka-game
|
||||||
|
services:
|
||||||
|
grechka-game:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: grechka-game
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- shared_network
|
||||||
|
labels:
|
||||||
|
# Включаем Traefik для этого сервиса
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=shared_network"
|
||||||
|
|
||||||
|
# HTTPS роутер
|
||||||
|
- "traefik.http.routers.grechka-game.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.grechka-game.rule=Host(`grechka.mkn8n.ru`)"
|
||||||
|
- "traefik.http.routers.grechka-game.tls=true"
|
||||||
|
- "traefik.http.routers.grechka-game.tls.certresolver=mytlschallenge"
|
||||||
|
|
||||||
|
# Сервис
|
||||||
|
- "traefik.http.services.grechka-game.loadbalancer.server.port=80"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
shared_network:
|
||||||
|
external: true
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,79 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
|
<title>GrechkaCraft: Multiplayer</title>
|
||||||
|
<!-- Socket.io Client -->
|
||||||
|
<script src="https://cdn.socket.io/4.7.4/socket.io.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="game">
|
||||||
|
<canvas id="c"></canvas>
|
||||||
|
|
||||||
|
<div class="ui">
|
||||||
|
<div id="stats">
|
||||||
|
<div class="row">❤️ <span id="hp">100</span> 🍗 <span id="food">100</span></div>
|
||||||
|
<div class="row">🫁 <span id="o2">100</span></div>
|
||||||
|
<div class="row">📍 X:<span id="sx">0</span> Y:<span id="sy">0</span></div>
|
||||||
|
<div class="row">🕒 <span id="tod">День</span></div>
|
||||||
|
<div class="row">🌐 <span id="worldId" style="cursor:pointer; text-decoration:underline;" title="Нажмите, чтобы скопировать ссылку">default</span></div>
|
||||||
|
<div class="row" id="multiplayerStatus" style="display:none;">👥 <span id="playerCount">0</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modeBtn" class="rbtn pe">🏃</div>
|
||||||
|
<div id="saveBtn" class="rbtn pe">💾</div>
|
||||||
|
<div id="craftBtn" class="rbtn pe">🔨</div>
|
||||||
|
<div id="resetBtn" class="rbtn pe">🔄</div>
|
||||||
|
|
||||||
|
<div id="craftPanel">
|
||||||
|
<div class="top">
|
||||||
|
<div style="font-weight:900;font-size:18px;">Крафт</div>
|
||||||
|
<button class="close" id="craftClose">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
<div id="recipes"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="inventoryPanel">
|
||||||
|
<div class="top">
|
||||||
|
<div style="font-weight:900;font-size:18px;">Инвентарь</div>
|
||||||
|
<button class="close" id="inventoryClose">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
<div id="inventoryGrid"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="death">
|
||||||
|
<div style="font-size:22px;font-weight:900;">ВЫ ПОГИБЛИ</div>
|
||||||
|
<button id="respawnBtn">ВОЗРОДИТЬСЯ</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="hotbar" class="pe"></div>
|
||||||
|
<div id="invToggle" class="rbtn pe" style="bottom:10px; left:10px; background:#3498db;">🎒</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Chat UI -->
|
||||||
|
<div id="chatPanel" style="display:none; position:absolute; left:10px; right:10px; top:60px; bottom:160px; background:rgba(0,0,0,0.85); border:2px solid rgba(255,255,255,0.8); border-radius:12px; pointer-events:auto; z-index:50; padding:10px; overflow:hidden;">
|
||||||
|
<div style="display:flex; justify-content:space-between; align-items:center; color:#fff; margin-bottom:10px;">
|
||||||
|
<div style="font-weight:900;font-size:18px;">💬 Чат</div>
|
||||||
|
<button id="chatClose" style="background:#c0392b; border:none; color:#fff; font-weight:900; padding:6px 10px; border-radius:8px; cursor:pointer;">✕</button>
|
||||||
|
</div>
|
||||||
|
<div id="chatMessages" style="flex:1; overflow-y:auto; color:#fff; font-size:13px; margin-bottom:8px; max-height:calc(100% - 40px);"></div>
|
||||||
|
<div style="display:flex; gap:6px;">
|
||||||
|
<input id="chatInput" type="text" placeholder="Введите сообщение..." style="flex:1; padding:8px; border:2px solid rgba(255,255,255,0.5); border-radius:8px; background:rgba(255,255,255,0.1); color:#fff; font-size:13px;" />
|
||||||
|
<button id="chatSend" style="background:#2ecc71; border:none; color:#fff; font-weight:900; padding:8px 16px; border-radius:8px; cursor:pointer;">➤</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="chatToggle" class="rbtn pe">💬</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="controls">
|
||||||
|
<div id="left" class="cbtn">←</div>
|
||||||
|
<div id="right" class="cbtn">→</div>
|
||||||
|
<div id="jump" class="cbtn">↑</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="game.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* Minegrechka Game Styles - v1.2 */
|
||||||
|
html, body { margin:0; padding:0; width:100%; height:100%; overflow:hidden; background:#111; font-family: system-ui, sans-serif; user-select:none; -webkit-user-select:none; touch-action:none; }
|
||||||
|
#game { position:absolute; top:0; left:0; right:0; bottom:140px; background:#87CEEB; overflow:hidden; }
|
||||||
|
canvas { display:block; width:100%; height:100%; image-rendering:pixelated; }
|
||||||
|
#controls { position:absolute; left:0; right:0; bottom:0; height:140px; background:#222; border-top:4px solid #444; z-index:10; }
|
||||||
|
|
||||||
|
.ui { position:absolute; inset:0; pointer-events:none; z-index:20; }
|
||||||
|
.pe { pointer-events:auto; }
|
||||||
|
|
||||||
|
#stats { position:absolute; left:10px; top:10px; color:#fff; font-weight:800; font-size:14px;
|
||||||
|
background: rgba(0,0,0,0.55); padding:8px; border-radius:10px; text-shadow:1px 1px 0 #000; }
|
||||||
|
#stats .row{ display:flex; gap:10px; align-items:center; }
|
||||||
|
|
||||||
|
.rbtn { position:absolute; right:10px; width:52px; height:52px; border-radius:12px;
|
||||||
|
display:flex; align-items:center; justify-content:center; border:2px solid rgba(255,255,255,0.9);
|
||||||
|
font-size:24px; cursor:pointer; pointer-events:auto; box-shadow:0 4px 0 rgba(0,0,0,0.5); }
|
||||||
|
.rbtn:active { transform: translateY(4px); box-shadow:none; }
|
||||||
|
#modeBtn { top:10px; background:#f39c12; }
|
||||||
|
#saveBtn { top:10px; right:70px !important; background:#27ae60; }
|
||||||
|
#resetBtn { top:10px; right:130px !important; background:#e74c3c; }
|
||||||
|
#craftBtn { top:74px; right:10px !important; background:#9b59b6; }
|
||||||
|
#chatToggle { top:10px; right:190px !important; background:#9b59b6; }
|
||||||
|
|
||||||
|
#hotbar { position:absolute; left:50%; transform:translateX(-50%); bottom:10px; display:flex; gap:6px;
|
||||||
|
background: rgba(0,0,0,0.60); padding:6px; border-radius:12px; pointer-events:auto;
|
||||||
|
overflow-x: auto; overflow-y: hidden; max-width: 80%; }
|
||||||
|
.slot { width:38px; height:38px; border:2px solid rgba(255,255,255,0.22); border-radius:10px;
|
||||||
|
position:relative; overflow:hidden; cursor:pointer; background: rgba(255,255,255,0.07);
|
||||||
|
display:flex; align-items:center; justify-content:center; font-size:18px; }
|
||||||
|
.slot.sel { border-color:#f1c40f; box-shadow: 0 0 0 2px rgba(241,196,15,0.18) inset; }
|
||||||
|
.count { position:absolute; right:3px; bottom:1px; font-size:10px; color:#fff; font-weight:900; text-shadow:1px 1px 0 #000; }
|
||||||
|
|
||||||
|
/* Craft modal */
|
||||||
|
#craftPanel { display:none; position:absolute; left:14px; right:14px; top:14px; bottom:14px;
|
||||||
|
background: rgba(10,10,12,0.92); border:2px solid rgba(255,255,255,0.85); border-radius:14px;
|
||||||
|
pointer-events:auto; padding:12px; overflow:auto; }
|
||||||
|
|
||||||
|
/* Inventory modal */
|
||||||
|
#inventoryPanel { display:none; position:absolute; left:50%; top:50%; transform: translate(-50%, -50%);
|
||||||
|
width: 420px; max-width: 90%; background: rgba(10,10,12,0.92); border:2px solid rgba(255,255,255,0.85);
|
||||||
|
border-radius:14px; pointer-events:auto; padding:12px; z-index: 100; }
|
||||||
|
#inventoryPanel .top { display:flex; justify-content:space-between; align-items:center; color:#fff; margin-bottom:10px; }
|
||||||
|
#inventoryGrid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; margin-top: 10px; }
|
||||||
|
.inv-slot { width: 48px; height: 48px; border: 2px solid rgba(255,255,255,0.22); border-radius: 8px;
|
||||||
|
position: relative; overflow: hidden; cursor: pointer; background: rgba(255,255,255,0.07);
|
||||||
|
display: flex; align-items: center; justify-content: center; font-size: 24px; }
|
||||||
|
.inv-slot.sel { border-color: #f1c40f; box-shadow: 0 0 0 2px rgba(241,196,15,0.18) inset; }
|
||||||
|
.inv-count { position: absolute; right: 3px; bottom: 1px; font-size: 12px; color: #fff;
|
||||||
|
font-weight: 900; text-shadow: 1px 1px 0 #000; background: rgba(0,0,0,0.5); padding: 1px 3px; border-radius: 4px; }
|
||||||
|
#craftPanel .top { display:flex; justify-content:space-between; align-items:center; color:#fff; margin-bottom:10px; }
|
||||||
|
#craftPanel .close { background:#c0392b; border:none; color:#fff; font-weight:900; padding:8px 10px; border-radius:10px; cursor:pointer; }
|
||||||
|
.recipe { display:flex; align-items:center; gap:10px; padding:10px; border-radius:12px;
|
||||||
|
background: rgba(255,255,255,0.06); border:1px solid rgba(255,255,255,0.10); margin-bottom:8px; }
|
||||||
|
.ricon { width:32px; height:32px; border-radius:8px; background-size:cover; image-rendering:pixelated; }
|
||||||
|
.rinfo { flex:1; }
|
||||||
|
.rname { color:#fff; font-weight:900; font-size:14px; }
|
||||||
|
.rcost { color:#bbb; font-size:11px; line-height:1.25; }
|
||||||
|
.rcraft { background:#2ecc71; border:none; color:#fff; font-weight:900; padding:8px 10px; border-radius:10px; cursor:pointer; }
|
||||||
|
.rcraft:disabled { background:#444; color:#888; cursor:not-allowed; }
|
||||||
|
|
||||||
|
/* Controls buttons */
|
||||||
|
.cbtn { position:absolute; top:50%; transform:translateY(-50%); width:74px; height:74px; border-radius:14px;
|
||||||
|
background:#333; border:3px solid #555; color:#fff; font-size:32px; display:flex; align-items:center; justify-content:center;
|
||||||
|
box-shadow:0 7px 0 #111; pointer-events:auto; }
|
||||||
|
.cbtn:active { transform:translateY(-46%); box-shadow:0 3px 0 #111; background:#444; }
|
||||||
|
#left { left:18px; }
|
||||||
|
#right { left:102px; }
|
||||||
|
#jump { right:18px; background:#d35400; border-color:#e67e22; }
|
||||||
|
|
||||||
|
#death { display:none; position:absolute; inset:0; background: rgba(60,0,0,0.88);
|
||||||
|
z-index:200; color:#fff; pointer-events:auto; align-items:center; justify-content:center; flex-direction:column; gap:12px; }
|
||||||
|
#death button { padding:12px 18px; font-size:18px; font-weight:900; border:none; border-radius:12px; cursor:pointer; }
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
name: grechka-game
|
||||||
|
services:
|
||||||
|
grechka-game:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: grechka-game
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- shared_network
|
||||||
|
labels:
|
||||||
|
# Включаем Traefik для этого сервиса
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=shared_network"
|
||||||
|
|
||||||
|
# HTTPS роутер
|
||||||
|
- "traefik.http.routers.grechka-game.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.grechka-game.rule=Host(`grechka.mkn8n.ru`)"
|
||||||
|
- "traefik.http.routers.grechka-game.tls=true"
|
||||||
|
- "traefik.http.routers.grechka-game.tls.certresolver=mytlschallenge"
|
||||||
|
|
||||||
|
# Сервис
|
||||||
|
- "traefik.http.services.grechka-game.loadbalancer.server.port=80"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
shared_network:
|
||||||
|
external: true
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,79 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
|
<title>GrechkaCraft: Multiplayer</title>
|
||||||
|
<!-- Socket.io Client -->
|
||||||
|
<script src="https://cdn.socket.io/4.7.4/socket.io.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="game">
|
||||||
|
<canvas id="c"></canvas>
|
||||||
|
|
||||||
|
<div class="ui">
|
||||||
|
<div id="stats">
|
||||||
|
<div class="row">❤️ <span id="hp">100</span> 🍗 <span id="food">100</span></div>
|
||||||
|
<div class="row">🫁 <span id="o2">100</span></div>
|
||||||
|
<div class="row">📍 X:<span id="sx">0</span> Y:<span id="sy">0</span></div>
|
||||||
|
<div class="row">🕒 <span id="tod">День</span></div>
|
||||||
|
<div class="row">🌐 <span id="worldId" style="cursor:pointer; text-decoration:underline;" title="Нажмите, чтобы скопировать ссылку">default</span></div>
|
||||||
|
<div class="row" id="multiplayerStatus" style="display:none;">👥 <span id="playerCount">0</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modeBtn" class="rbtn pe">🏃</div>
|
||||||
|
<div id="saveBtn" class="rbtn pe">💾</div>
|
||||||
|
<div id="craftBtn" class="rbtn pe">🔨</div>
|
||||||
|
<div id="resetBtn" class="rbtn pe">🔄</div>
|
||||||
|
|
||||||
|
<div id="craftPanel">
|
||||||
|
<div class="top">
|
||||||
|
<div style="font-weight:900;font-size:18px;">Крафт</div>
|
||||||
|
<button class="close" id="craftClose">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
<div id="recipes"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="inventoryPanel">
|
||||||
|
<div class="top">
|
||||||
|
<div style="font-weight:900;font-size:18px;">Инвентарь</div>
|
||||||
|
<button class="close" id="inventoryClose">Закрыть</button>
|
||||||
|
</div>
|
||||||
|
<div id="inventoryGrid"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="death">
|
||||||
|
<div style="font-size:22px;font-weight:900;">ВЫ ПОГИБЛИ</div>
|
||||||
|
<button id="respawnBtn">ВОЗРОДИТЬСЯ</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="hotbar" class="pe"></div>
|
||||||
|
<div id="invToggle" class="rbtn pe" style="bottom:10px; left:10px; background:#3498db;">🎒</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Chat UI -->
|
||||||
|
<div id="chatPanel" style="display:none; position:absolute; left:10px; right:10px; top:60px; bottom:160px; background:rgba(0,0,0,0.85); border:2px solid rgba(255,255,255,0.8); border-radius:12px; pointer-events:auto; z-index:50; padding:10px; overflow:hidden;">
|
||||||
|
<div style="display:flex; justify-content:space-between; align-items:center; color:#fff; margin-bottom:10px;">
|
||||||
|
<div style="font-weight:900;font-size:18px;">💬 Чат</div>
|
||||||
|
<button id="chatClose" style="background:#c0392b; border:none; color:#fff; font-weight:900; padding:6px 10px; border-radius:8px; cursor:pointer;">✕</button>
|
||||||
|
</div>
|
||||||
|
<div id="chatMessages" style="flex:1; overflow-y:auto; color:#fff; font-size:13px; margin-bottom:8px; max-height:calc(100% - 40px);"></div>
|
||||||
|
<div style="display:flex; gap:6px;">
|
||||||
|
<input id="chatInput" type="text" placeholder="Введите сообщение..." style="flex:1; padding:8px; border:2px solid rgba(255,255,255,0.5); border-radius:8px; background:rgba(255,255,255,0.1); color:#fff; font-size:13px;" />
|
||||||
|
<button id="chatSend" style="background:#2ecc71; border:none; color:#fff; font-weight:900; padding:8px 16px; border-radius:8px; cursor:pointer;">➤</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="chatToggle" class="rbtn pe">💬</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="controls">
|
||||||
|
<div id="left" class="cbtn">←</div>
|
||||||
|
<div id="right" class="cbtn">→</div>
|
||||||
|
<div id="jump" class="cbtn">↑</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="game.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* Minegrechka Game Styles - v1.2 */
|
||||||
|
html, body { margin:0; padding:0; width:100%; height:100%; overflow:hidden; background:#111; font-family: system-ui, sans-serif; user-select:none; -webkit-user-select:none; touch-action:none; }
|
||||||
|
#game { position:absolute; top:0; left:0; right:0; bottom:140px; background:#87CEEB; overflow:hidden; }
|
||||||
|
canvas { display:block; width:100%; height:100%; image-rendering:pixelated; }
|
||||||
|
#controls { position:absolute; left:0; right:0; bottom:0; height:140px; background:#222; border-top:4px solid #444; z-index:10; }
|
||||||
|
|
||||||
|
.ui { position:absolute; inset:0; pointer-events:none; z-index:20; }
|
||||||
|
.pe { pointer-events:auto; }
|
||||||
|
|
||||||
|
#stats { position:absolute; left:10px; top:10px; color:#fff; font-weight:800; font-size:14px;
|
||||||
|
background: rgba(0,0,0,0.55); padding:8px; border-radius:10px; text-shadow:1px 1px 0 #000; }
|
||||||
|
#stats .row{ display:flex; gap:10px; align-items:center; }
|
||||||
|
|
||||||
|
.rbtn { position:absolute; right:10px; width:52px; height:52px; border-radius:12px;
|
||||||
|
display:flex; align-items:center; justify-content:center; border:2px solid rgba(255,255,255,0.9);
|
||||||
|
font-size:24px; cursor:pointer; pointer-events:auto; box-shadow:0 4px 0 rgba(0,0,0,0.5); }
|
||||||
|
.rbtn:active { transform: translateY(4px); box-shadow:none; }
|
||||||
|
#modeBtn { top:10px; background:#f39c12; }
|
||||||
|
#saveBtn { top:10px; right:70px !important; background:#27ae60; }
|
||||||
|
#resetBtn { top:10px; right:130px !important; background:#e74c3c; }
|
||||||
|
#craftBtn { top:74px; right:10px !important; background:#9b59b6; }
|
||||||
|
#chatToggle { top:10px; right:190px !important; background:#9b59b6; }
|
||||||
|
|
||||||
|
#hotbar { position:absolute; left:50%; transform:translateX(-50%); bottom:10px; display:flex; gap:6px;
|
||||||
|
background: rgba(0,0,0,0.60); padding:6px; border-radius:12px; pointer-events:auto;
|
||||||
|
overflow-x: auto; overflow-y: hidden; max-width: 80%; }
|
||||||
|
.slot { width:38px; height:38px; border:2px solid rgba(255,255,255,0.22); border-radius:10px;
|
||||||
|
position:relative; overflow:hidden; cursor:pointer; background: rgba(255,255,255,0.07);
|
||||||
|
display:flex; align-items:center; justify-content:center; font-size:18px; }
|
||||||
|
.slot.sel { border-color:#f1c40f; box-shadow: 0 0 0 2px rgba(241,196,15,0.18) inset; }
|
||||||
|
.count { position:absolute; right:3px; bottom:1px; font-size:10px; color:#fff; font-weight:900; text-shadow:1px 1px 0 #000; }
|
||||||
|
|
||||||
|
/* Craft modal */
|
||||||
|
#craftPanel { display:none; position:absolute; left:14px; right:14px; top:14px; bottom:14px;
|
||||||
|
background: rgba(10,10,12,0.92); border:2px solid rgba(255,255,255,0.85); border-radius:14px;
|
||||||
|
pointer-events:auto; padding:12px; overflow:auto; }
|
||||||
|
|
||||||
|
/* Inventory modal */
|
||||||
|
#inventoryPanel { display:none; position:absolute; left:50%; top:50%; transform: translate(-50%, -50%);
|
||||||
|
width: 420px; max-width: 90%; background: rgba(10,10,12,0.92); border:2px solid rgba(255,255,255,0.85);
|
||||||
|
border-radius:14px; pointer-events:auto; padding:12px; z-index: 100; }
|
||||||
|
#inventoryPanel .top { display:flex; justify-content:space-between; align-items:center; color:#fff; margin-bottom:10px; }
|
||||||
|
#inventoryGrid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; margin-top: 10px; }
|
||||||
|
.inv-slot { width: 48px; height: 48px; border: 2px solid rgba(255,255,255,0.22); border-radius: 8px;
|
||||||
|
position: relative; overflow: hidden; cursor: pointer; background: rgba(255,255,255,0.07);
|
||||||
|
display: flex; align-items: center; justify-content: center; font-size: 24px; }
|
||||||
|
.inv-slot.sel { border-color: #f1c40f; box-shadow: 0 0 0 2px rgba(241,196,15,0.18) inset; }
|
||||||
|
.inv-count { position: absolute; right: 3px; bottom: 1px; font-size: 12px; color: #fff;
|
||||||
|
font-weight: 900; text-shadow: 1px 1px 0 #000; background: rgba(0,0,0,0.5); padding: 1px 3px; border-radius: 4px; }
|
||||||
|
#craftPanel .top { display:flex; justify-content:space-between; align-items:center; color:#fff; margin-bottom:10px; }
|
||||||
|
#craftPanel .close { background:#c0392b; border:none; color:#fff; font-weight:900; padding:8px 10px; border-radius:10px; cursor:pointer; }
|
||||||
|
.recipe { display:flex; align-items:center; gap:10px; padding:10px; border-radius:12px;
|
||||||
|
background: rgba(255,255,255,0.06); border:1px solid rgba(255,255,255,0.10); margin-bottom:8px; }
|
||||||
|
.ricon { width:32px; height:32px; border-radius:8px; background-size:cover; image-rendering:pixelated; }
|
||||||
|
.rinfo { flex:1; }
|
||||||
|
.rname { color:#fff; font-weight:900; font-size:14px; }
|
||||||
|
.rcost { color:#bbb; font-size:11px; line-height:1.25; }
|
||||||
|
.rcraft { background:#2ecc71; border:none; color:#fff; font-weight:900; padding:8px 10px; border-radius:10px; cursor:pointer; }
|
||||||
|
.rcraft:disabled { background:#444; color:#888; cursor:not-allowed; }
|
||||||
|
|
||||||
|
/* Controls buttons */
|
||||||
|
.cbtn { position:absolute; top:50%; transform:translateY(-50%); width:74px; height:74px; border-radius:14px;
|
||||||
|
background:#333; border:3px solid #555; color:#fff; font-size:32px; display:flex; align-items:center; justify-content:center;
|
||||||
|
box-shadow:0 7px 0 #111; pointer-events:auto; }
|
||||||
|
.cbtn:active { transform:translateY(-46%); box-shadow:0 3px 0 #111; background:#444; }
|
||||||
|
#left { left:18px; }
|
||||||
|
#right { left:102px; }
|
||||||
|
#jump { right:18px; background:#d35400; border-color:#e67e22; }
|
||||||
|
|
||||||
|
#death { display:none; position:absolute; inset:0; background: rgba(60,0,0,0.88);
|
||||||
|
z-index:200; color:#fff; pointer-events:auto; align-items:center; justify-content:center; flex-direction:column; gap:12px; }
|
||||||
|
#death button { padding:12px 18px; font-size:18px; font-weight:900; border:none; border-radius:12px; cursor:pointer; }
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
name: grechka-game
|
||||||
|
services:
|
||||||
|
grechka-game:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: grechka-game
|
||||||
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- shared_network
|
||||||
|
labels:
|
||||||
|
# Включаем Traefik для этого сервиса
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.docker.network=shared_network"
|
||||||
|
|
||||||
|
# HTTPS роутер
|
||||||
|
- "traefik.http.routers.grechka-game.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.grechka-game.rule=Host(`grechka.mkn8n.ru`)"
|
||||||
|
- "traefik.http.routers.grechka-game.tls=true"
|
||||||
|
- "traefik.http.routers.grechka-game.tls.certresolver=mytlschallenge"
|
||||||
|
|
||||||
|
# Сервис
|
||||||
|
- "traefik.http.services.grechka-game.loadbalancer.server.port=80"
|
||||||
|
|
||||||
|
networks:
|
||||||
|
shared_network:
|
||||||
|
external: true
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
|
|
@ -0,0 +1,82 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ru">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||||
|
<title>GrechkaCraft: Multiplayer</title>
|
||||||
|
<!-- Socket.io Client -->
|
||||||
|
<script src="https://cdn.socket.io/4.7.4/socket.io.min.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="game">
|
||||||
|
<canvas id="c"></canvas>
|
||||||
|
|
||||||
|
<div class="ui">
|
||||||
|
<div id="stats">
|
||||||
|
<div class="row">❤️ <span id="hp">100</span> 🍗 <span id="food">100</span></div>
|
||||||
|
<div class="row">🫁 <span id="o2">100</span></div>
|
||||||
|
<div class="row">📍 X:<span id="sx">0</span> Y:<span id="sy">0</span></div>
|
||||||
|
<div class="row">🕒 <span id="tod">День</span></div>
|
||||||
|
<div class="row">🌐 <span id="worldId" style="cursor:pointer; text-decoration:underline;" title="Нажмите, чтобы скопировать ссылку">default</span></div>
|
||||||
|
<div class="row" id="multiplayerStatus" style="display:none;">👥 <span id="playerCount">0</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modeBtn" class="rbtn pe">🏃</div>
|
||||||
|
<div id="saveBtn" class="rbtn pe">💾</div>
|
||||||
|
<div id="craftBtn" class="rbtn pe">🔨</div>
|
||||||
|
<div id="resetBtn" class="rbtn pe">🔄</div>
|
||||||
|
|
||||||
|
<div id="chatToggle" class="rbtn pe">💬</div>
|
||||||
|
<div id="invToggle" class="rbtn pe">📦</div>
|
||||||
|
<div id="hotbar" class="pe"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="controls">
|
||||||
|
<div id="left" class="btn pe">⬅️</div>
|
||||||
|
<div id="jump" class="btn pe">⬆️</div>
|
||||||
|
<div id="down" class="btn pe">⬇️</div>
|
||||||
|
<div id="right" class="btn pe">➡️</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="craftPanel" class="panel" style="display:none;">
|
||||||
|
<div class="panel-header">
|
||||||
|
<span>Крафт</span>
|
||||||
|
<span id="craftClose" class="close" style="cursor:pointer;">✕</span>
|
||||||
|
</div>
|
||||||
|
<div id="recipes"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="inventoryPanel" class="panel" style="display:none;">
|
||||||
|
<div class="panel-header">
|
||||||
|
<span>Инвентарь</span>
|
||||||
|
<span id="inventoryClose" class="close" style="cursor:pointer;">✕</span>
|
||||||
|
</div>
|
||||||
|
<div id="inventoryGrid"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="chatPanel" class="panel" style="display:none;">
|
||||||
|
<div class="panel-header">
|
||||||
|
<span>Чат</span>
|
||||||
|
<span id="chatClose" class="close" style="cursor:pointer;">✕</span>
|
||||||
|
</div>
|
||||||
|
<div id="chatMessages"></div>
|
||||||
|
<div class="chat-input">
|
||||||
|
<input type="text" id="chatInput" placeholder="Введите сообщение...">
|
||||||
|
<button id="chatSend">Отправить</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="death" class="death-screen" style="display:none;">
|
||||||
|
<div class="death-content">
|
||||||
|
<h1>💀 Вы погибли!</h1>
|
||||||
|
<button id="respawnBtn" class="respawn-btn">Возродиться</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="game.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,92 @@
|
||||||
|
/* Minegrechka Game Styles - v1.2 */
|
||||||
|
html, body { margin:0; padding:0; width:100%; height:100%; overflow:hidden; background:#111; font-family: system-ui, sans-serif; user-select:none; -webkit-user-select:none; touch-action:none; }
|
||||||
|
#game { position:absolute; top:0; left:0; right:0; bottom:0; background:#87CEEB; overflow:hidden; }
|
||||||
|
canvas { display:block; width:100%; height:100%; image-rendering:pixelated; }
|
||||||
|
#controls { position:absolute; left:0; right:0; bottom:0; height:140px; background:#222; border-top:4px solid #444; z-index:100; display:none; }
|
||||||
|
|
||||||
|
/* Стили для кнопок управления (.btn вместо .cbtn для совместимости с index.html) */
|
||||||
|
.btn { position:absolute; top:50%; transform:translateY(-50%); width:74px; height:74px; border-radius:14px;
|
||||||
|
background:#333; border:3px solid #555; color:#fff; font-size:32px; display:flex; align-items:center; justify-content:center;
|
||||||
|
box-shadow:0 7px 0 #111; pointer-events:auto; z-index:101; }
|
||||||
|
.btn:active { transform:translateY(-46%); box-shadow:0 3px 0 #111; background:#444; }
|
||||||
|
#left { left:18px; }
|
||||||
|
#right { left:102px; }
|
||||||
|
#down { left:186px; background:#2980b9; border-color:#3498db; }
|
||||||
|
#jump { right:18px; background:#d35400; border-color:#e67e22; }
|
||||||
|
|
||||||
|
/* Скрываем панель на десктопе (широкие экраны) */
|
||||||
|
@media (min-width: 769px) {
|
||||||
|
#controls { display: none !important; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Показываем панель на мобильных устройствах (узкие экраны) */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
#controls { display: block !important; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui { position:absolute; inset:0; pointer-events:none; z-index:20; }
|
||||||
|
.pe { pointer-events:auto; }
|
||||||
|
|
||||||
|
#stats { position:absolute; left:10px; top:10px; color:#fff; font-weight:800; font-size:14px;
|
||||||
|
background: rgba(0,0,0,0.55); padding:8px; border-radius:10px; text-shadow:1px 1px 0 #000; }
|
||||||
|
#stats .row{ display:flex; gap:10px; align-items:center; }
|
||||||
|
|
||||||
|
.rbtn { position:absolute; right:10px; width:52px; height:52px; border-radius:12px;
|
||||||
|
display:flex; align-items:center; justify-content:center; border:2px solid rgba(255,255,255,0.9);
|
||||||
|
font-size:24px; cursor:pointer; pointer-events:auto; box-shadow:0 4px 0 rgba(0,0,0,0.5); }
|
||||||
|
.rbtn:active { transform: translateY(4px); box-shadow:none; }
|
||||||
|
#modeBtn { top:10px; background:#f39c12; }
|
||||||
|
#saveBtn { top:10px; right:70px !important; background:#27ae60; }
|
||||||
|
#resetBtn { top:10px; right:130px !important; background:#e74c3c; }
|
||||||
|
#craftBtn { top:74px; right:10px !important; background:#9b59b6; }
|
||||||
|
#invToggle { top:74px; right:70px !important; background:#3498db; }
|
||||||
|
#chatToggle { display: none !important; }
|
||||||
|
#chatPanel { display: none !important; }
|
||||||
|
|
||||||
|
#hotbar { position:absolute; left:50%; transform:translateX(-50%); bottom:10px; display:flex; gap:6px;
|
||||||
|
background: rgba(0,0,0,0.60); padding:6px; border-radius:12px; pointer-events:auto;
|
||||||
|
overflow-x: auto; overflow-y: hidden; max-width: 80%; }
|
||||||
|
|
||||||
|
/* Поднимаем hotbar на тач-устройствах, чтобы не перекрывать кнопки */
|
||||||
|
body.touch-device #hotbar {
|
||||||
|
bottom: 150px;
|
||||||
|
}
|
||||||
|
.slot { width:38px; height:38px; border:2px solid rgba(255,255,255,0.22); border-radius:10px;
|
||||||
|
position:relative; overflow:hidden; cursor:pointer; background: rgba(255,255,255,0.07);
|
||||||
|
display:flex; align-items:center; justify-content:center; font-size:18px; }
|
||||||
|
.slot.sel { border-color:#f1c40f; box-shadow: 0 0 0 2px rgba(241,196,15,0.18) inset; }
|
||||||
|
.count { position:absolute; right:3px; bottom:1px; font-size:10px; color:#fff; font-weight:900; text-shadow:1px 1px 0 #000; }
|
||||||
|
|
||||||
|
/* Craft modal */
|
||||||
|
#craftPanel { display:none; position:absolute; left:14px; right:14px; top:14px; bottom:14px;
|
||||||
|
background: rgba(10,10,12,0.92); border:2px solid rgba(255,255,255,0.85); border-radius:14px;
|
||||||
|
pointer-events:auto; padding:12px; overflow:auto; z-index: 200; }
|
||||||
|
|
||||||
|
/* Inventory modal */
|
||||||
|
#inventoryPanel { display:none; position:absolute; left:50%; top:50%; transform: translate(-50%, -50%);
|
||||||
|
width: 420px; max-width: 90%; background: rgba(10,10,12,0.92); border:2px solid rgba(255,255,255,0.85);
|
||||||
|
border-radius:14px; pointer-events:auto; padding:12px; z-index: 200; }
|
||||||
|
#inventoryPanel .top { display:flex; justify-content:space-between; align-items:center; color:#fff; margin-bottom:10px; }
|
||||||
|
#inventoryGrid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; margin-top: 10px; }
|
||||||
|
.inv-slot { width: 48px; height: 48px; border: 2px solid rgba(255,255,255,0.22); border-radius: 8px;
|
||||||
|
position: relative; overflow: hidden; cursor: pointer; background: rgba(255,255,255,0.07);
|
||||||
|
display: flex; align-items: center; justify-content: center; font-size: 24px; }
|
||||||
|
.inv-slot.sel { border-color: #f1c40f; box-shadow: 0 0 0 2px rgba(241,196,15,0.18) inset; }
|
||||||
|
.inv-count { position: absolute; right: 3px; bottom: 1px; font-size: 12px; color: #fff;
|
||||||
|
font-weight: 900; text-shadow: 1px 1px 0 #000; background: rgba(0,0,0,0.5); padding: 1px 3px; border-radius: 4px; }
|
||||||
|
.equipped-indicator { position: absolute; top: 2px; right: 2px; font-size: 14px; color: #2ecc71; font-weight: 900; text-shadow: 1px 1px 0 #000; }
|
||||||
|
#craftPanel .top { display:flex; justify-content:space-between; align-items:center; color:#fff; margin-bottom:10px; }
|
||||||
|
#craftPanel .close { background:#c0392b; border:none; color:#fff; font-weight:900; padding:8px 10px; border-radius:10px; cursor:pointer; }
|
||||||
|
#inventoryPanel .close { background:#c0392b; border:none; color:#fff; font-weight:900; padding:8px 10px; border-radius:10px; cursor:pointer; }
|
||||||
|
.recipe { display:flex; align-items:center; gap:10px; padding:10px; border-radius:12px;
|
||||||
|
background: rgba(255,255,255,0.06); border:1px solid rgba(255,255,255,0.10); margin-bottom:8px; }
|
||||||
|
.ricon { width:32px; height:32px; border-radius:8px; background-size:cover; image-rendering:pixelated; }
|
||||||
|
.rinfo { flex:1; }
|
||||||
|
.rname { color:#fff; font-weight:900; font-size:14px; }
|
||||||
|
.rcost { color:#bbb; font-size:11px; line-height:1.25; }
|
||||||
|
.rcraft { background:#2ecc71; border:none; color:#fff; font-weight:900; padding:8px 10px; border-radius:10px; cursor:pointer; }
|
||||||
|
.rcraft:disabled { background:#444; color:#888; cursor:not-allowed; }
|
||||||
|
|
||||||
|
#death { display:none; position:absolute; inset:0; background: rgba(60,0,0,0.88);
|
||||||
|
z-index:200; color:#fff; pointer-events:auto; align-items:center; justify-content:center; flex-direction:column; gap:12px; }
|
||||||
|
#death button { padding:12px 18px; font-size:18px; font-weight:900; border:none; border-radius:12px; cursor:pointer; }
|
||||||
Loading…
Reference in New Issue