|
|
4 weeks ago | |
|---|---|---|
| .. | ||
| solution | 3 months ago | |
| your-work | 3 months ago | |
| README.md | 4 weeks ago | |
| assignment.md | 1 month ago | |
README.md
Створення космічної гри, частина 6: завершення та перезапуск
journey
title Your Game Completion Journey
section End Conditions
Define win/lose states: 3: Student
Implement condition checking: 4: Student
Handle state transitions: 4: Student
section Player Experience
Design feedback systems: 4: Student
Create restart mechanics: 5: Student
Polish user interface: 5: Student
section System Integration
Manage game lifecycle: 5: Student
Handle memory cleanup: 5: Student
Create complete experience: 5: Student
Кожна чудова гра потребує чітких умов завершення та зручного механізму перезапуску. Ви створили вражаючу космічну гру з рухом, боєм і системою очок — тепер час додати фінальні елементи, які зроблять її завершеною.
Ваша гра наразі працює безкінечно, як зонди Voyager, які NASA запустила у 1977 році — вони досі мандрують космосом десятиліття потому. Хоча це чудово для космічних досліджень, ігри потребують визначених кінцевих точок, щоб створити задовільний досвід.
Сьогодні ми реалізуємо правильні умови перемоги/поразки та систему перезапуску. До кінця цього уроку у вас буде відшліфована гра, яку гравці зможуть завершити та переграти, як класичні аркадні ігри, що визначили цей жанр.
mindmap
root((Game Completion))
End Conditions
Victory States
Defeat Conditions
Progress Tracking
State Validation
Player Feedback
Visual Messages
Color Psychology
Clear Communication
Emotional Response
State Management
Game Loop Control
Memory Cleanup
Object Lifecycle
Event Handling
Restart Systems
Input Handling
State Reset
Fresh Initialization
User Experience
Polish Elements
Message Display
Smooth Transitions
Error Prevention
Accessibility
Тест перед лекцією
Розуміння умов завершення гри
Коли ваша гра має завершитися? Це фундаментальне питання формувало дизайн ігор ще з часів ранньої аркадної ери. Pac-Man завершується, коли вас ловлять привиди або ви очищаєте всі точки, а Space Invaders завершується, коли прибульці досягають низу або ви знищуєте їх усіх.
Як творець гри, ви визначаєте умови перемоги та поразки. Для нашої космічної гри ось перевірені підходи, які створюють захоплюючий ігровий процес:
flowchart TD
A["🎮 Game Start"] --> B{"Check Conditions"}
B --> C["Enemy Count"]
B --> D["Hero Lives"]
B --> E["Score Threshold"]
B --> F["Level Progress"]
C --> C1{"Enemies = 0?"}
D --> D1{"Lives = 0?"}
E --> E1{"Score ≥ Target?"}
F --> F1{"Objectives Complete?"}
C1 -->|Yes| G["🏆 Victory"]
D1 -->|Yes| H["💀 Defeat"]
E1 -->|Yes| G
F1 -->|Yes| G
C1 -->|No| B
D1 -->|No| B
E1 -->|No| B
F1 -->|No| B
G --> I["🔄 Restart Option"]
H --> I
style G fill:#e8f5e8
style H fill:#ffebee
style I fill:#e3f2fd
- Знищено
Nворожих кораблів: Це досить поширено, якщо ви розділяєте гру на різні рівні, де потрібно знищитиNворожих кораблів, щоб завершити рівень. - Ваш корабель знищено: Є ігри, де ви програєте, якщо ваш корабель знищено. Інший поширений підхід — концепція життів. Кожного разу, коли ваш корабель знищується, це зменшує кількість життів. Коли всі життя втрачені, ви програєте.
- Зібрано
Nочок: Ще одна поширена умова завершення — це збір очок. Як ви отримуєте очки — залежить від вас, але часто очки присвоюються за різні дії, як-от знищення ворожого корабля або збір предметів, які випадають, коли вони знищені. - Завершення рівня: Це може включати кілька умов, таких як знищення
Xворожих кораблів, збірYочок або, можливо, збір конкретного предмета.
Реалізація функціоналу перезапуску гри
Хороші ігри заохочують повторне проходження через зручні механізми перезапуску. Коли гравці завершують гру (або зазнають поразки), вони часто хочуть спробувати знову негайно — щоб побити свій результат або покращити свої навички.
stateDiagram-v2
[*] --> Playing: Game Start
Playing --> Victory: All enemies destroyed
Playing --> Defeat: Lives = 0
Victory --> MessageDisplay: Show win message
Defeat --> MessageDisplay: Show lose message
MessageDisplay --> WaitingRestart: Press Enter prompt
WaitingRestart --> Resetting: Enter key pressed
Resetting --> CleanupMemory: Clear intervals
CleanupMemory --> ClearEvents: Remove listeners
ClearEvents --> InitializeGame: Fresh start
InitializeGame --> Playing: New game begins
note right of MessageDisplay
Color-coded feedback:
Green = Victory
Red = Defeat
end note
note right of Resetting
Complete state reset
prevents memory leaks
end note
Tetris ідеально демонструє це: коли ваші блоки досягають верху, ви можете миттєво почати нову гру без складних меню. Ми створимо схожу систему перезапуску, яка чисто скидає стан гри та швидко повертає гравців до дії.
✅ Рефлексія: Згадайте ігри, в які ви грали. За яких умов вони завершуються, і як вас спонукають до перезапуску? Що робить досвід перезапуску плавним, а що — дратівливим?
Що ви створите
Ви реалізуєте фінальні функції, які перетворять ваш проект на завершену ігрову систему. Ці елементи відрізняють відшліфовані ігри від базових прототипів.
Ось що ми додаємо сьогодні:
- Умова перемоги: Знищіть усіх ворогів і отримайте належне святкування (ви це заслужили!)
- Умова поразки: Втратьте всі життя і побачте екран поразки
- Механізм перезапуску: Натисніть Enter, щоб одразу повернутися до гри — адже однієї гри ніколи не достатньо
- Управління станом: Чистий аркуш кожного разу — без залишкових ворогів чи дивних глюків з попередньої гри
Початок роботи
Давайте підготуємо ваше середовище розробки. У вас мають бути всі файли вашої космічної гри з попередніх уроків.
Ваш проект має виглядати приблизно так:
-| assets
-| enemyShip.png
-| player.png
-| laserRed.png
-| life.png
-| index.html
-| app.js
-| package.json
Запустіть сервер розробки:
cd your-work
npm start
Ця команда:
- Запускає локальний сервер на
http://localhost:5000 - Правильно обслуговує ваші файли
- Автоматично оновлює сторінку при внесенні змін
Відкрийте http://localhost:5000 у вашому браузері та переконайтеся, що ваша гра працює. Ви маєте змогу рухатися, стріляти та взаємодіяти з ворогами. Після підтвердження ми можемо перейти до реалізації.
💡 Корисна порада: Щоб уникнути попереджень у Visual Studio Code, оголосіть
gameLoopIdна початку вашого файлу якlet gameLoopId;, а не всередині функціїwindow.onload. Це відповідає сучасним практикам оголошення змінних у JavaScript.
flowchart TD
A["1. Condition Tracking"] --> B["2. Event Handlers"]
B --> C["3. Message Constants"]
C --> D["4. Restart Controls"]
D --> E["5. Message Display"]
E --> F["6. Reset System"]
G["isHeroDead()\nisEnemiesDead()"] --> A
H["Collision Events\nEnd Game Events"] --> B
I["GAME_END_WIN\nGAME_END_LOSS"] --> C
J["Enter Key\nRestart Trigger"] --> D
K["Victory/Defeat\nColor-coded Text"] --> E
L["State Cleanup\nFresh Initialization"] --> F
F --> M["🎮 Complete Game"]
style A fill:#e3f2fd
style B fill:#e8f5e8
style C fill:#fff3e0
style D fill:#f3e5f5
style E fill:#e0f2f1
style F fill:#fce4ec
style M fill:#e1f5fe
Кроки реалізації
Крок 1: Створення функцій відстеження умов завершення
Нам потрібні функції для моніторингу, коли гра має завершитися. Як датчики на Міжнародній космічній станції, які постійно контролюють критичні системи, ці функції будуть безперервно перевіряти стан гри.
function isHeroDead() {
return hero.life <= 0;
}
function isEnemiesDead() {
const enemies = gameObjects.filter((go) => go.type === "Enemy" && !go.dead);
return enemies.length === 0;
}
Ось що відбувається за лаштунками:
- Перевіряє, чи герой втратив всі життя (ой!)
- Рахує, скільки ворогів ще живі та активні
- Повертає
true, коли поле бою очищене від ворогів - Використовує просту логіку true/false для зручності
- Фільтрує всі об'єкти гри, щоб знайти тих, хто вижив
Крок 2: Оновлення обробників подій для умов завершення
Тепер ми зв'яжемо ці перевірки умов із системою подій гри. Кожного разу, коли відбувається зіткнення, гра буде оцінювати, чи це викликає умову завершення. Це створює миттєвий зворотний зв'язок для критичних подій гри.
sequenceDiagram
participant Collision
participant GameLogic
participant Conditions
participant EventSystem
participant Display
Collision->>GameLogic: Laser hits enemy
GameLogic->>GameLogic: Destroy objects
GameLogic->>Conditions: Check isEnemiesDead()
alt All enemies defeated
Conditions->>EventSystem: Emit GAME_END_WIN
EventSystem->>Display: Show victory message
else Enemies remain
Conditions->>GameLogic: Continue game
end
Collision->>GameLogic: Enemy hits hero
GameLogic->>GameLogic: Decrease lives
GameLogic->>Conditions: Check isHeroDead()
alt Lives = 0
Conditions->>EventSystem: Emit GAME_END_LOSS
EventSystem->>Display: Show defeat message
else Lives remain
GameLogic->>Conditions: Check isEnemiesDead()
alt All enemies defeated
Conditions->>EventSystem: Emit GAME_END_WIN
end
end
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
first.dead = true;
second.dead = true;
hero.incrementPoints();
if (isEnemiesDead()) {
eventEmitter.emit(Messages.GAME_END_WIN);
}
});
eventEmitter.on(Messages.COLLISION_ENEMY_HERO, (_, { enemy }) => {
enemy.dead = true;
hero.decrementLife();
if (isHeroDead()) {
eventEmitter.emit(Messages.GAME_END_LOSS);
return; // loss before victory
}
if (isEnemiesDead()) {
eventEmitter.emit(Messages.GAME_END_WIN);
}
});
eventEmitter.on(Messages.GAME_END_WIN, () => {
endGame(true);
});
eventEmitter.on(Messages.GAME_END_LOSS, () => {
endGame(false);
});
Що тут відбувається:
- Лазер влучає у ворога: Обидва зникають, ви отримуєте очки, і ми перевіряємо, чи ви перемогли
- Ворог влучає у вас: Ви втрачаєте життя, і ми перевіряємо, чи ви ще живі
- Розумний порядок: Спочатку перевіряємо на поразку (ніхто не хоче одночасно виграти і програти!)
- Миттєві реакції: Як тільки щось важливе трапляється, гра про це знає
Крок 3: Додати нові константи повідомлень
Вам потрібно додати нові типи повідомлень до вашого об'єкта Messages. Ці константи допомагають підтримувати узгодженість і запобігати помилкам у системі подій.
GAME_END_LOSS: "GAME_END_LOSS",
GAME_END_WIN: "GAME_END_WIN",
У наведеному вище ми:
- Додали константи для подій завершення гри для підтримки узгодженості
- Використовували описові назви, які чітко вказують на призначення події
- Дотримувалися існуючої конвенції іменування типів повідомлень
Крок 4: Реалізація контролю перезапуску
Тепер ви додасте клавіатурні контролі, які дозволяють гравцям перезапустити гру. Клавіша Enter — це природний вибір, оскільки вона зазвичай асоціюється з підтвердженням дій і початком нових ігор.
Додайте виявлення клавіші Enter до вашого існуючого обробника подій keydown:
else if(evt.key === "Enter") {
eventEmitter.emit(Messages.KEY_EVENT_ENTER);
}
Додайте нову константу повідомлення:
KEY_EVENT_ENTER: "KEY_EVENT_ENTER",
Що вам потрібно знати:
- Розширює вашу існуючу систему обробки подій клавіатури
- Використовує клавішу Enter як тригер перезапуску для інтуїтивного досвіду користувача
- Випромінює спеціальну подію, яку можуть слухати інші частини вашої гри
- Підтримує той самий шаблон, що й ваші інші клавіатурні контролі
Крок 5: Створення системи відображення повідомлень
Ваша гра повинна чітко повідомляти результати гравцям. Ми створимо систему повідомлень, яка відображає стани перемоги та поразки за допомогою тексту з кольоровим кодуванням, схожого на інтерфейси терміналів ранніх комп'ютерних систем, де зелений означав успіх, а червоний — помилки.
Створіть функцію displayMessage():
function displayMessage(message, color = "red") {
ctx.font = "30px Arial";
ctx.fillStyle = color;
ctx.textAlign = "center";
ctx.fillText(message, canvas.width / 2, canvas.height / 2);
}
Крок за кроком, ось що відбувається:
- Встановлює розмір і сімейство шрифту для чіткого, читабельного тексту
- Застосовує параметр кольору з "червоним" за замовчуванням для попереджень
- Центрує текст горизонтально та вертикально на полотні
- Використовує сучасні параметри за замовчуванням у JavaScript для гнучких варіантів кольору
- Використовує контекст 2D полотна для прямого рендерингу тексту
Створіть функцію endGame():
function endGame(win) {
clearInterval(gameLoopId);
// Set a delay to ensure any pending renders complete
setTimeout(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (win) {
displayMessage(
"Victory!!! Pew Pew... - Press [Enter] to start a new game Captain Pew Pew",
"green"
);
} else {
displayMessage(
"You died !!! Press [Enter] to start a new game Captain Pew Pew"
);
}
}, 200)
}
Що робить ця функція:
- Заморожує все на місці — більше ніяких рухів кораблів чи лазерів
- Робить невелику паузу (200 мс), щоб останній кадр завершив малювання
- Очищає екран і фарбує його в чорний для драматичного ефекту
- Показує різні повідомлення для переможців і переможених
- Кодує кольори новин — зелений для хороших, червоний для... ну, не дуже хороших
- Повідомляє гравцям, як саме повернутися до гри
🔄 Педагогічна перевірка
Управління станом гри: Перед реалізацією функціоналу скидання переконайтеся, що ви розумієте:
- ✅ Як умови завершення створюють чіткі ігрові цілі
- ✅ Чому візуальний зворотний зв'язок важливий для розуміння гравцем
- ✅ Важливість правильного очищення для запобігання витокам пам'яті
- ✅ Як архітектура, заснована на подіях, дозволяє чисті переходи стану
Швидкий самотест: Що станеться, якщо ви не очистите слухачів подій під час скидання? Відповідь: Витоки пам'яті та дублювання обробників подій, що спричиняє непередбачувану поведінку
Принципи дизайну гри: Ви зараз реалізуєте:
- Чіткі цілі: Гравці точно знають, що визначає успіх і невдачу
- Миттєвий зворотний зв'язок: Зміни стану гри повідомляються негайно
- Контроль користувача: Гравці можуть перезапустити гру, коли вони готові
- Надійність системи: Правильне очищення запобігає помилкам і проблемам продуктивності
Крок 6: Реалізація функціоналу скидання гри
Система скидання повинна повністю очистити поточний стан гри та ініціалізувати нову сесію гри. Це гарантує, що гравці отримають чистий старт без залишкових даних з попередньої гри.
Створіть функцію resetGame():
function resetGame() {
if (gameLoopId) {
clearInterval(gameLoopId);
eventEmitter.clear();
initGame();
gameLoopId = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.fillRect(0, 0, canvas.width, canvas.height);
drawPoints();
drawLife();
updateGameObjects();
drawGameObjects(ctx);
}, 100);
}
}
Давайте розберемо кожну частину:
- Перевіряє, чи поточний цикл гри працює перед скиданням
- Очищає існуючий цикл гри, щоб зупинити всю поточну активність гри
- Видаляє всі слухачі подій, щоб запобігти витокам пам'яті
- Реініціалізує стан гри з новими об'єктами та змінними
- Запускає новий цикл гри з усіма необхідними функціями гри
- Підтримує той самий інтервал у 100 мс для стабільної продуктивності гри
Додайте обробник подій клавіші Enter до вашої функції initGame():
eventEmitter.on(Messages.KEY_EVENT_ENTER, () => {
resetGame();
});
Додайте метод clear() до вашого класу EventEmitter:
clear() {
this.listeners = {};
}
Основні моменти, які слід пам'ятати:
- З'єднує натискання клавіші Enter з функціоналом скидання гри
- Реєструє цей слухач подій під час ініціалізації гри
- Забезпечує чистий спосіб видалення всіх слухачів подій під час скидання
- Запобігає витокам пам'яті, очищаючи обробники подій між іграми
- Скидає об'єкт слухачів до порожнього стану для нової ініціалізації
Вітаємо! 🎉
👽 💥 🚀 Ви успішно створили завершену гру з нуля. Як програмісти, які створили перші відеоігри у 1970-х роках, ви перетворили рядки коду на інтерактивний досвід із правильними ігровими механіками та зворотним зв'язком для користувача. 🚀 💥 👽
Ви досягли:
- Реалізували повні умови перемоги та поразки з зворотним зв'язком для користувача
- Створили плавну систему перезапуску для безперервного ігрового процесу
- Розробили чітке візуальне спілкування для станів гри
- Управляли складними переходами стану гри та очищенням
- Зібрали всі компоненти в цілісну, іграбельну гру
🔄 Педагогічна перевірка
Завершена система розробки гри: Святкуйте своє оволодіння повним циклом розробки гри:
- ✅ Як умови завершення створюють задовільний досвід гравця?
- ✅ Чому правильне управління станом критично важливе для стабільності гри?
- ✅ Як візуальний зворотний зв'язок покращує розуміння гравцем?
- ✅ Яку роль відіграє система перезапуску в утриманні гравця?
Майстерність системи: Ваша завершена гра демонструє:
- Повноцінну розробку гри: Від графіки до введення до управління станом
- Професійну архітектуру: Системи, засновані на подіях, із правильним очищенням
- Дизайн користувацького досвіду: Чіткий зворотний зв'язок та інтуїтивні контролі
- Оптимізацію продуктивності: Ефективне рендеринг та управління пам'яттю
- Полірування та завершеність: Усі деталі, які роблять гру завершено
🌟 Ваш місяць у кар'єрі розробника ігор
- Створіть кілька завершених ігор, досліджуючи різні жанри та механіки
- Вивчіть просунуті фреймворки для розробки ігор, такі як Phaser або Three.js
- Внесіть свій вклад у проєкти з відкритим кодом у сфері розробки ігор
- Вивчіть принципи дизайну ігор та психологію гравців
- Створіть портфоліо, яке демонструє ваші навички розробки ігор
- Зв'яжіться з спільнотою розробників ігор та продовжуйте навчання
🎯 Повна хронологія вашого шляху до майстерності в розробці ігор
timeline
title Complete Game Development Learning Progression
section Foundation (Lessons 1-2)
Game Architecture: Project structure
: Asset management
: Canvas basics
: Event systems
section Interaction Systems (Lessons 3-4)
Player Control: Input handling
: Movement mechanics
: Collision detection
: Physics simulation
section Game Mechanics (Lesson 5)
Feedback Systems: Scoring mechanisms
: Life management
: Visual communication
: Player motivation
section Game Completion (Lesson 6)
Polish & Flow: End conditions
: State management
: Restart systems
: User experience
section Advanced Features (1 week)
Enhancement Skills: Audio integration
: Visual effects
: Level progression
: Performance optimization
section Professional Development (1 month)
Industry Readiness: Framework mastery
: Team collaboration
: Portfolio development
: Community engagement
section Career Advancement (3 months)
Specialization: Advanced game engines
: Platform deployment
: Monetization strategies
: Industry networking
🛠️ Підсумок вашого повного набору інструментів для розробки ігор
Після завершення цієї серії космічних ігор ви опанували:
- Архітектуру ігор: Системи, що керуються подіями, ігрові цикли та управління станами
- Програмування графіки: Canvas API, рендеринг спрайтів та візуальні ефекти
- Системи введення: Обробка клавіатури, виявлення зіткнень та чутливе управління
- Дизайн ігор: Зворотний зв'язок з гравцем, системи прогресу та механіки залучення
- Оптимізація продуктивності: Ефективний рендеринг, управління пам'яттю та контроль частоти кадрів
- Користувацький досвід: Чітка комунікація, інтуїтивне управління та увага до деталей
- Професійні шаблони: Чистий код, техніки налагодження та організація проєктів
Застосування в реальному світі: Ваші навички розробки ігор безпосередньо застосовуються до:
- Інтерактивних веб-додатків: Динамічні інтерфейси та системи в реальному часі
- Візуалізації даних: Анімовані графіки та інтерактивна графіка
- Освітніх технологій: Гейміфікація та захоплюючі навчальні досвіди
- Мобільної розробки: Взаємодія через сенсорний екран та оптимізація продуктивності
- Симуляційного програмного забезпечення: Фізичні двигуни та моделювання в реальному часі
- Креативних індустрій: Інтерактивне мистецтво, розваги та цифрові досвіди
Професійні навички, які ви здобули: Тепер ви можете:
- Проєктувати складні інтерактивні системи з нуля
- Налагоджувати додатки в реальному часі, використовуючи систематичні підходи
- Оптимізувати продуктивність для плавного користувацького досвіду
- Дизайнити захоплюючі інтерфейси та шаблони взаємодії
- Співпрацювати ефективно над технічними проєктами з правильною організацією коду
Опановані концепції розробки ігор:
- Системи в реальному часі: Ігрові цикли, управління частотою кадрів та продуктивність
- Архітектура, що керується подіями: Розділені системи та передача повідомлень
- Управління станами: Складна обробка даних та управління життєвим циклом
- Програмування користувацького інтерфейсу: Графіка Canvas та адаптивний дизайн
- Теорія дизайну ігор: Психологія гравців та механіки залучення
Наступний рівень: Ви готові досліджувати просунуті фреймворки для ігор, 3D-графіку, багатокористувацькі системи або перейти до професійних ролей у розробці ігор!
🌟 Досягнення розблоковано: Ви завершили повний шлях розробки ігор та створили інтерактивний досвід професійної якості з нуля!
Ласкаво просимо до спільноти розробників ігор! 🎮✨
Виклик GitHub Copilot Agent 🚀
Використовуйте режим Agent, щоб виконати наступний виклик:
Опис: Покращіть космічну гру, реалізувавши систему прогресу рівнів зі зростаючою складністю та бонусними функціями.
Завдання: Створіть систему багаторівневої космічної гри, де кожен рівень має більше ворожих кораблів із підвищеною швидкістю та здоров'ям. Додайте множник очок, який збільшується з кожним рівнем, та реалізуйте бонуси (наприклад, швидкий вогонь або щит), які випадково з'являються при знищенні ворогів. Включіть бонус за завершення рівня та відображайте поточний рівень на екрані поряд із існуючими очками та життями.
Дізнайтеся більше про режим Agent тут.
🚀 Додатковий виклик для покращення
Додайте аудіо до вашої гри: Покращіть ігровий досвід, реалізувавши звукові ефекти! Розгляньте додавання звуку для:
- Лазерних пострілів, коли гравець стріляє
- Знищення ворогів, коли кораблі вражені
- Ураження героя, коли гравець отримує удари
- Переможної музики, коли гра виграна
- Звуку поразки, коли гра програна
Приклад реалізації аудіо:
// Create audio objects
const laserSound = new Audio('assets/laser.wav');
const explosionSound = new Audio('assets/explosion.wav');
// Play sounds during game events
function playLaserSound() {
laserSound.currentTime = 0; // Reset to beginning
laserSound.play();
}
Що потрібно знати:
- Створює об'єкти Audio для різних звукових ефектів
- Скидає
currentTime, щоб дозволити швидкі звукові ефекти - Обробляє політики автозапуску браузера, активуючи звуки через взаємодію користувача
- Керує гучністю та часом аудіо для кращого ігрового досвіду
💡 Ресурс для навчання: Досліджуйте цей аудіо-пісочницю, щоб дізнатися більше про реалізацію аудіо в іграх на JavaScript.
Післялекційний тест
Огляд та самостійне навчання
Ваше завдання — створити нову пробну гру, тому досліджуйте деякі цікаві ігри, щоб побачити, яку гру ви могли б створити.
Завдання
Відмова від відповідальності:
Цей документ був перекладений за допомогою сервісу автоматичного перекладу Co-op Translator. Хоча ми прагнемо до точності, будь ласка, майте на увазі, що автоматичні переклади можуть містити помилки або неточності. Оригінальний документ на його рідній мові слід вважати авторитетним джерелом. Для критичної інформації рекомендується професійний людський переклад. Ми не несемо відповідальності за будь-які непорозуміння або неправильні тлумачення, що виникають внаслідок використання цього перекладу.