init
This commit is contained in:
4
.editorconfig
Normal file
4
.editorconfig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Normalize EOL for all files that Git considers text files.
|
||||||
|
* text=auto eol=lf
|
||||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
/android/
|
||||||
3
docs/Action Rog/.obsidian/app.json
vendored
Normal file
3
docs/Action Rog/.obsidian/app.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"alwaysUpdateLinks": true
|
||||||
|
}
|
||||||
1
docs/Action Rog/.obsidian/appearance.json
vendored
Normal file
1
docs/Action Rog/.obsidian/appearance.json
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
3
docs/Action Rog/.obsidian/community-plugins.json
vendored
Normal file
3
docs/Action Rog/.obsidian/community-plugins.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[
|
||||||
|
"table-editor-obsidian"
|
||||||
|
]
|
||||||
33
docs/Action Rog/.obsidian/core-plugins.json
vendored
Normal file
33
docs/Action Rog/.obsidian/core-plugins.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"file-explorer": true,
|
||||||
|
"global-search": true,
|
||||||
|
"switcher": true,
|
||||||
|
"graph": true,
|
||||||
|
"backlink": true,
|
||||||
|
"canvas": true,
|
||||||
|
"outgoing-link": true,
|
||||||
|
"tag-pane": true,
|
||||||
|
"footnotes": false,
|
||||||
|
"properties": true,
|
||||||
|
"page-preview": true,
|
||||||
|
"daily-notes": true,
|
||||||
|
"templates": true,
|
||||||
|
"note-composer": true,
|
||||||
|
"command-palette": true,
|
||||||
|
"slash-command": false,
|
||||||
|
"editor-status": true,
|
||||||
|
"bookmarks": true,
|
||||||
|
"markdown-importer": false,
|
||||||
|
"zk-prefixer": false,
|
||||||
|
"random-note": false,
|
||||||
|
"outline": true,
|
||||||
|
"word-count": true,
|
||||||
|
"slides": false,
|
||||||
|
"audio-recorder": false,
|
||||||
|
"workspaces": false,
|
||||||
|
"file-recovery": true,
|
||||||
|
"publish": false,
|
||||||
|
"sync": true,
|
||||||
|
"bases": true,
|
||||||
|
"webviewer": false
|
||||||
|
}
|
||||||
22
docs/Action Rog/.obsidian/graph.json
vendored
Normal file
22
docs/Action Rog/.obsidian/graph.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"collapse-filter": false,
|
||||||
|
"search": "",
|
||||||
|
"showTags": true,
|
||||||
|
"showAttachments": true,
|
||||||
|
"hideUnresolved": false,
|
||||||
|
"showOrphans": true,
|
||||||
|
"collapse-color-groups": false,
|
||||||
|
"colorGroups": [],
|
||||||
|
"collapse-display": false,
|
||||||
|
"showArrow": false,
|
||||||
|
"textFadeMultiplier": 0,
|
||||||
|
"nodeSizeMultiplier": 1,
|
||||||
|
"lineSizeMultiplier": 1,
|
||||||
|
"collapse-forces": false,
|
||||||
|
"centerStrength": 0.518713248970312,
|
||||||
|
"repelStrength": 10,
|
||||||
|
"linkStrength": 1,
|
||||||
|
"linkDistance": 250,
|
||||||
|
"scale": 1,
|
||||||
|
"close": true
|
||||||
|
}
|
||||||
504
docs/Action Rog/.obsidian/plugins/obsidian-tasks-plugin/main.js
vendored
Normal file
504
docs/Action Rog/.obsidian/plugins/obsidian-tasks-plugin/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
12
docs/Action Rog/.obsidian/plugins/obsidian-tasks-plugin/manifest.json
vendored
Normal file
12
docs/Action Rog/.obsidian/plugins/obsidian-tasks-plugin/manifest.json
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"id": "obsidian-tasks-plugin",
|
||||||
|
"name": "Tasks",
|
||||||
|
"version": "7.22.0",
|
||||||
|
"minAppVersion": "1.4.0",
|
||||||
|
"description": "Track tasks across your vault. Supports due dates, recurring tasks, done dates, sub-set of checklist items, and filtering.",
|
||||||
|
"helpUrl": "https://publish.obsidian.md/tasks/",
|
||||||
|
"author": "Clare Macrae and Ilyas Landikov (created by Martin Schenck)",
|
||||||
|
"authorUrl": "https://github.com/obsidian-tasks-group",
|
||||||
|
"fundingUrl": "https://github.com/sponsors/claremacrae",
|
||||||
|
"isDesktopOnly": false
|
||||||
|
}
|
||||||
1
docs/Action Rog/.obsidian/plugins/obsidian-tasks-plugin/styles.css
vendored
Normal file
1
docs/Action Rog/.obsidian/plugins/obsidian-tasks-plugin/styles.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
docs/Action Rog/.obsidian/plugins/table-editor-obsidian/data.json
vendored
Normal file
6
docs/Action Rog/.obsidian/plugins/table-editor-obsidian/data.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"formatType": "normal",
|
||||||
|
"showRibbonIcon": true,
|
||||||
|
"bindEnter": true,
|
||||||
|
"bindTab": true
|
||||||
|
}
|
||||||
236
docs/Action Rog/.obsidian/plugins/table-editor-obsidian/main.js
vendored
Normal file
236
docs/Action Rog/.obsidian/plugins/table-editor-obsidian/main.js
vendored
Normal file
File diff suppressed because one or more lines are too long
17
docs/Action Rog/.obsidian/plugins/table-editor-obsidian/manifest.json
vendored
Normal file
17
docs/Action Rog/.obsidian/plugins/table-editor-obsidian/manifest.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"id": "table-editor-obsidian",
|
||||||
|
"name": "Advanced Tables",
|
||||||
|
"author": "Tony Grosinger",
|
||||||
|
"authorUrl": "https://grosinger.net",
|
||||||
|
"description": "Improved table navigation, formatting, manipulation, and formulas",
|
||||||
|
"isDesktopOnly": false,
|
||||||
|
"minAppVersion": "1.0.0",
|
||||||
|
"version": "0.22.1",
|
||||||
|
"js": "main.js",
|
||||||
|
"fundingUrl": {
|
||||||
|
"Github Sponsor": "https://github.com/sponsors/tgrosinger",
|
||||||
|
"Buy me a Coffee": "https://buymeacoffee.com/tgrosinger",
|
||||||
|
"Paypal": "https://paypal.me/tgrosinger"
|
||||||
|
},
|
||||||
|
"donation": "https://buymeacoffee.com/tgrosinger"
|
||||||
|
}
|
||||||
78
docs/Action Rog/.obsidian/plugins/table-editor-obsidian/styles.css
vendored
Normal file
78
docs/Action Rog/.obsidian/plugins/table-editor-obsidian/styles.css
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
:root {
|
||||||
|
--advanced-tables-helper-size: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.HyperMD-table-row span.cm-inline-code {
|
||||||
|
font-size: 100%;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-tables-buttons>div>.title {
|
||||||
|
font-weight: var(--font-medium);
|
||||||
|
font-size: var(--nav-item-size);
|
||||||
|
color: var(--nav-item-color);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-type="advanced-tables-toolbar"] .nav-buttons-container {
|
||||||
|
column-gap: 0.2rem;
|
||||||
|
margin: 0.2rem 0 0.2rem 0;
|
||||||
|
justify-content: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-type="advanced-tables-toolbar"] .nav-buttons-container::before {
|
||||||
|
min-width: 2.6rem;
|
||||||
|
line-height: var(--advanced-tables-helper-size);
|
||||||
|
font-size: var(--nav-item-size);
|
||||||
|
font-weight: var(--nav-item-weight);
|
||||||
|
color: var(--nav-item-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-type="advanced-tables-toolbar"] .nav-buttons-container>* {
|
||||||
|
height: var(--advanced-tables-helper-size);
|
||||||
|
line-height: var(--advanced-tables-helper-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-type="advanced-tables-toolbar"] .nav-buttons-container .nav-action-button {
|
||||||
|
width: var(--advanced-tables-helper-size);
|
||||||
|
height: var(--advanced-tables-helper-size);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: var(--radius-s);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-type="advanced-tables-toolbar"] .nav-buttons-container .nav-action-button:hover {
|
||||||
|
background-color: var(--nav-item-background-hover);
|
||||||
|
color: var(--nav-item-color-hover);
|
||||||
|
font-weight: var(--nav-item-weight-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-tables-row-label {
|
||||||
|
width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
fill: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.widget-icon:hover {
|
||||||
|
fill: var(--text-normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-tables-csv-export textarea {
|
||||||
|
height: 200px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-tables-donation {
|
||||||
|
width: 70%;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-tables-donate-button {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
224
docs/Action Rog/.obsidian/workspace.json
vendored
Normal file
224
docs/Action Rog/.obsidian/workspace.json
vendored
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
{
|
||||||
|
"main": {
|
||||||
|
"id": "9d84761fdc521e48",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "56870b1a5abc8bc3",
|
||||||
|
"type": "tabs",
|
||||||
|
"dimension": 52.76162790697675,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "fae3dd60da6746c9",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "markdown",
|
||||||
|
"state": {
|
||||||
|
"file": "Спелы/Начинания/Начинания.md",
|
||||||
|
"mode": "source",
|
||||||
|
"source": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-file",
|
||||||
|
"title": "Начинания"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "693c8197b2393835",
|
||||||
|
"type": "tabs",
|
||||||
|
"dimension": 47.23837209302326,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "41a43fa3fff1d73f",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "graph",
|
||||||
|
"state": {},
|
||||||
|
"icon": "lucide-git-fork",
|
||||||
|
"title": "Граф"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "vertical"
|
||||||
|
},
|
||||||
|
"left": {
|
||||||
|
"id": "c0e70ec8604f67da",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "b11845e247b44591",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "9a81516dc6c65404",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "file-explorer",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"autoReveal": false
|
||||||
|
},
|
||||||
|
"icon": "lucide-folder-closed",
|
||||||
|
"title": "Файловый менеджер"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6f4075d7a5920333",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "search",
|
||||||
|
"state": {
|
||||||
|
"query": "",
|
||||||
|
"matchingCase": false,
|
||||||
|
"explainSearch": false,
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical"
|
||||||
|
},
|
||||||
|
"icon": "lucide-search",
|
||||||
|
"title": "Поиск"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "f0a6202fc12fc4af",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "bookmarks",
|
||||||
|
"state": {},
|
||||||
|
"icon": "lucide-bookmark",
|
||||||
|
"title": "Закладки"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"id": "feabda6c3d6801d3",
|
||||||
|
"type": "split",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "cd27a52bffd0262b",
|
||||||
|
"type": "tabs",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "b0383d0fcbd61458",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "backlink",
|
||||||
|
"state": {
|
||||||
|
"file": "Спелы/Начинания/Начинания.md",
|
||||||
|
"collapseAll": false,
|
||||||
|
"extraContext": false,
|
||||||
|
"sortOrder": "alphabetical",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": "",
|
||||||
|
"backlinkCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
},
|
||||||
|
"icon": "links-coming-in",
|
||||||
|
"title": "Обратные ссылки для Начинания"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "609b4502709daf5e",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outgoing-link",
|
||||||
|
"state": {
|
||||||
|
"file": "Спелы/Начинания/Начинания.md",
|
||||||
|
"linksCollapsed": false,
|
||||||
|
"unlinkedCollapsed": true
|
||||||
|
},
|
||||||
|
"icon": "links-going-out",
|
||||||
|
"title": "Исходящие ссылки из Начинания"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2d8db340c9660aae",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "tag",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"useHierarchy": true,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-tags",
|
||||||
|
"title": "Теги"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dff9a1d15096e8ab",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "all-properties",
|
||||||
|
"state": {
|
||||||
|
"sortOrder": "frequency",
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-archive",
|
||||||
|
"title": "Все свойства"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1591bf739b0cab13",
|
||||||
|
"type": "leaf",
|
||||||
|
"state": {
|
||||||
|
"type": "outline",
|
||||||
|
"state": {
|
||||||
|
"file": "Спелы/Начинания/Начинания.md",
|
||||||
|
"followCursor": false,
|
||||||
|
"showSearch": false,
|
||||||
|
"searchQuery": ""
|
||||||
|
},
|
||||||
|
"icon": "lucide-list",
|
||||||
|
"title": "Структура Начинания"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"direction": "horizontal",
|
||||||
|
"width": 300,
|
||||||
|
"collapsed": true
|
||||||
|
},
|
||||||
|
"left-ribbon": {
|
||||||
|
"hiddenItems": {
|
||||||
|
"switcher:Меню быстрого перехода": false,
|
||||||
|
"graph:Граф": false,
|
||||||
|
"canvas:Создать новый холст": false,
|
||||||
|
"daily-notes:Сегодняшняя заметка": false,
|
||||||
|
"templates:Вставить шаблон": false,
|
||||||
|
"command-palette:Открыть палитру команд": false,
|
||||||
|
"bases:Создать новую базу": false,
|
||||||
|
"table-editor-obsidian:Advanced Tables Toolbar": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"active": "fae3dd60da6746c9",
|
||||||
|
"lastOpenFiles": [
|
||||||
|
"Спелы/Начинания/Первичные/Вода.md",
|
||||||
|
"Вода.md",
|
||||||
|
"Спелы/Начинания/Начинания.md",
|
||||||
|
"Спелы/Начинания/Первичные/Огонь.md",
|
||||||
|
"Спелы/Начинания/Вторичные",
|
||||||
|
"Спелы/Начинания/Первичные",
|
||||||
|
"Спелы/Лужа.md",
|
||||||
|
"Спелы/Начинания/Первичные/Смерть.md",
|
||||||
|
"Спелы/Начинания/Первичные/Жизнь.md",
|
||||||
|
"Спелы/Начинания/Первичные/Тьма.md",
|
||||||
|
"Спелы/Начинания/Первичные/Свет.md",
|
||||||
|
"Спелы/Начинания/Первичные/Воздух.md",
|
||||||
|
"Спелы/Начинания/Первичные/Земля.md",
|
||||||
|
"Спелы/Начинания",
|
||||||
|
"Добро пожаловать.md",
|
||||||
|
"Спелы"
|
||||||
|
]
|
||||||
|
}
|
||||||
0
docs/Action Rog/Вода.md
Normal file
0
docs/Action Rog/Вода.md
Normal file
1
docs/Action Rog/Спелы/Лужа.md
Normal file
1
docs/Action Rog/Спелы/Лужа.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
#мокрый
|
||||||
31
docs/Action Rog/Спелы/Начинания/Начинания.md
Normal file
31
docs/Action Rog/Спелы/Начинания/Начинания.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# Общее
|
||||||
|
Есть первичные начинания и вторичные.
|
||||||
|
Первичные доступны сразу, до вторичных нужно дойти.
|
||||||
|
Начинания - кирпичики из которых складываются спелы.
|
||||||
|
|
||||||
|
# Первичные начинания
|
||||||
|
1. [[Огонь]]
|
||||||
|
2. [[Вода]]
|
||||||
|
3. [[Земля]]
|
||||||
|
4. [[Воздух]]
|
||||||
|
5. [[Свет]]
|
||||||
|
6. [[Тьма]]
|
||||||
|
7. [[Жизнь]]
|
||||||
|
8. [[Смерть]]
|
||||||
|
|
||||||
|
Первичные начинания доступны сразу и могут
|
||||||
|
|
||||||
|
# Вторичные
|
||||||
|
Доступны как комбинации первичных
|
||||||
|
|
||||||
|
1. Паладин ([[Огонь]] + [[Свет]])
|
||||||
|
2. Бладмаг ([[Огонь]] + [[Жизнь]])
|
||||||
|
3. Растения ([[Жизнь]] + [[Земля]])
|
||||||
|
4. Сталь ([[Земля]] + [[Тьма]])
|
||||||
|
5. Лед ([[Тьма]] + [[Спелы/Начинания/Первичные/Вода]])
|
||||||
|
6. Яд ([[Спелы/Начинания/Первичные/Вода]] + [[Смерть]])
|
||||||
|
7. Чума ([[Смерть]] + [[Воздух]])
|
||||||
|
8. Молния ([[Воздух]] + [[Свет]])
|
||||||
|
|
||||||
5
docs/Action Rog/Спелы/Начинания/Первичные/Вода.md
Normal file
5
docs/Action Rog/Спелы/Начинания/Первичные/Вода.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#мокрый
|
||||||
|
|
||||||
0
docs/Action Rog/Спелы/Начинания/Первичные/Воздух.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Воздух.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Жизнь.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Жизнь.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Земля.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Земля.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Огонь.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Огонь.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Свет.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Свет.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Смерть.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Смерть.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Тьма.md
Normal file
0
docs/Action Rog/Спелы/Начинания/Первичные/Тьма.md
Normal file
1
icon.svg
Normal file
1
icon.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128"><rect width="124" height="124" x="2" y="2" fill="#363d52" stroke="#212532" stroke-width="4" rx="14"/><g fill="#fff" transform="translate(12.322 12.322)scale(.101)"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042" transform="translate(12.322 12.322)scale(.101)"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 995 B |
43
icon.svg.import
Normal file
43
icon.svg.import
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dn3m6ec8rak21"
|
||||||
|
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://icon.svg"
|
||||||
|
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Blender 4.4.0 MTL File: 'None'
|
||||||
|
# www.blender.org
|
||||||
|
|
||||||
|
newmtl Material.001
|
||||||
|
Ns 250.000000
|
||||||
|
Ka 1.000000 1.000000 1.000000
|
||||||
|
Ks 0.500000 0.500000 0.500000
|
||||||
|
Ke 0.000000 0.000000 0.000000
|
||||||
|
Ni 1.500000
|
||||||
|
d 1.000000
|
||||||
|
illum 2
|
||||||
|
map_Kd Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.png
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wavefront_obj"
|
||||||
|
importer_version=1
|
||||||
|
type="Mesh"
|
||||||
|
uid="uid://c82de86x4ho25"
|
||||||
|
path="res://.godot/imported/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.obj-272c3e26cc8a388ddaff3599002a085b.mesh"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
files=["res://.godot/imported/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.obj-272c3e26cc8a388ddaff3599002a085b.mesh"]
|
||||||
|
|
||||||
|
source_file="res://models/Crystal Golem Behemot/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.obj"
|
||||||
|
dest_files=["res://.godot/imported/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.obj-272c3e26cc8a388ddaff3599002a085b.mesh", "res://.godot/imported/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.obj-272c3e26cc8a388ddaff3599002a085b.mesh"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
generate_tangents=true
|
||||||
|
generate_lods=true
|
||||||
|
generate_shadow_mesh=true
|
||||||
|
generate_lightmap_uv2=false
|
||||||
|
generate_lightmap_uv2_texel_size=0.2
|
||||||
|
scale_mesh=Vector3(1, 1, 1)
|
||||||
|
offset_mesh=Vector3(0, 0, 0)
|
||||||
|
force_disable_mesh_compression=false
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 6.2 MiB |
@@ -0,0 +1,41 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://jyix4ilr67uk"
|
||||||
|
path.s3tc="res://.godot/imported/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.png-68db2fcac524e74c59fbe9360f7bc6f0.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://models/Crystal Golem Behemot/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.png"
|
||||||
|
dest_files=["res://.godot/imported/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.png-68db2fcac524e74c59fbe9360f7bc6f0.s3tc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 5.8 MiB |
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://x4734mds7b74"
|
||||||
|
path.s3tc="res://.godot/imported/Meshy_AI_Meshy_Merged_Animations_0.png-afda3fedb942079159108d0b652b7e94.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "7bd9bbed46ac9e0d5bf50f774da896f3"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://models/Crystal Golem Behemot/Meshy_AI_Meshy_Merged_Animations_0.png"
|
||||||
|
dest_files=["res://.godot/imported/Meshy_AI_Meshy_Merged_Animations_0.png-afda3fedb942079159108d0b652b7e94.s3tc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
BIN
models/Crystal Golem Behemot/Mutant Walking.fbx
Normal file
BIN
models/Crystal Golem Behemot/Mutant Walking.fbx
Normal file
Binary file not shown.
50
models/Crystal Golem Behemot/Mutant Walking.fbx.import
Normal file
50
models/Crystal Golem Behemot/Mutant Walking.fbx.import
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://fruqpocnluu4"
|
||||||
|
path="res://.godot/imported/Mutant Walking.fbx-044ace83349eaaf9d031cd571d61e9b3.scn"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://models/Crystal Golem Behemot/Mutant Walking.fbx"
|
||||||
|
dest_files=["res://.godot/imported/Mutant Walking.fbx-044ace83349eaaf9d031cd571d61e9b3.scn"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/root_script=null
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
nodes/use_name_suffixes=true
|
||||||
|
nodes/use_node_type_suffixes=true
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=true
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
materials/extract=0
|
||||||
|
materials/extract_format=0
|
||||||
|
materials/extract_path=""
|
||||||
|
_subresources={
|
||||||
|
"nodes": {
|
||||||
|
"PATH:Skeleton3D": {
|
||||||
|
"rest_pose/selected_animation": "mixamo_com"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fbx/importer=0
|
||||||
|
fbx/allow_geometry_helper_nodes=false
|
||||||
|
fbx/embedded_image_handling=1
|
||||||
|
fbx/naming_version=2
|
||||||
BIN
models/Crystal Golem Behemot/Mutant Walking_0.png
Normal file
BIN
models/Crystal Golem Behemot/Mutant Walking_0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 MiB |
44
models/Crystal Golem Behemot/Mutant Walking_0.png.import
Normal file
44
models/Crystal Golem Behemot/Mutant Walking_0.png.import
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cgxy3uivyomg"
|
||||||
|
path.s3tc="res://.godot/imported/Mutant Walking_0.png-5ddbf6c8fdd4c9c6cc7d81ed05a731ad.s3tc.ctex"
|
||||||
|
metadata={
|
||||||
|
"imported_formats": ["s3tc_bptc"],
|
||||||
|
"vram_texture": true
|
||||||
|
}
|
||||||
|
generator_parameters={
|
||||||
|
"md5": "9f199a31179af6f4a0995373751c7d0f"
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://models/Crystal Golem Behemot/Mutant Walking_0.png"
|
||||||
|
dest_files=["res://.godot/imported/Mutant Walking_0.png-5ddbf6c8fdd4c9c6cc7d81ed05a731ad.s3tc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=2
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=0
|
||||||
44
project.godot
Normal file
44
project.godot
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=5
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="ActionRog"
|
||||||
|
run/main_scene="res://scenes/main_menu.tscn"
|
||||||
|
config/features=PackedStringArray("4.5", "Forward Plus")
|
||||||
|
config/icon="res://icon.svg"
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
move_forward={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
move_back={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
move_left={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
move_right={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
dash={
|
||||||
|
"deadzone": 0.5,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
61
scenes/enemy.tscn
Normal file
61
scenes/enemy.tscn
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://dcyxfspptvuqn"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://8vuywuv7ebsl" path="res://scripts/enemy.gd" id="1_enemy"]
|
||||||
|
[ext_resource type="Script" path="res://scripts/enemy_health_bar.gd" id="2_health_bar"]
|
||||||
|
[ext_resource type="ArrayMesh" uid="uid://c82de86x4ho25" path="res://models/Crystal Golem Behemot/Meshy_AI_Crystal_Golem_Behemot_0110152107_texture.obj" id="3_enemy"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1"]
|
||||||
|
radius = 1.5
|
||||||
|
height = 5.0
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_1"]
|
||||||
|
size = Vector3(3, 0.2, 0.05)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"]
|
||||||
|
albedo_color = Color(0.5, 0, 0, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0.8, 0, 0, 1)
|
||||||
|
emission_energy_multiplier = 2.0
|
||||||
|
shading_mode = 0
|
||||||
|
flags_unshaded = true
|
||||||
|
flags_transparent = false
|
||||||
|
depth_draw_mode = 2
|
||||||
|
render_priority = 1
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_2"]
|
||||||
|
size = Vector3(3, 0.2, 0.05)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_2"]
|
||||||
|
albedo_color = Color(0, 1, 0, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0, 1, 0, 1)
|
||||||
|
emission_energy_multiplier = 2.0
|
||||||
|
shading_mode = 0
|
||||||
|
flags_unshaded = true
|
||||||
|
flags_transparent = false
|
||||||
|
depth_draw_mode = 2
|
||||||
|
render_priority = 2
|
||||||
|
|
||||||
|
[node name="Enemy" type="CharacterBody3D"]
|
||||||
|
script = ExtResource("1_enemy")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(2.5, 0, 0, 0, 2.5, 0, 0, 0, 2.5, 0, 2.6208835, 0)
|
||||||
|
mesh = ExtResource("3_enemy")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2.5, 0)
|
||||||
|
shape = SubResource("CapsuleShape3D_1")
|
||||||
|
|
||||||
|
[node name="HealthBarContainer" type="Node3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 5.5, 0)
|
||||||
|
script = ExtResource("2_health_bar")
|
||||||
|
|
||||||
|
[node name="BackgroundBar" type="MeshInstance3D" parent="HealthBarContainer"]
|
||||||
|
mesh = SubResource("BoxMesh_1")
|
||||||
|
material_override = SubResource("StandardMaterial3D_1")
|
||||||
|
|
||||||
|
[node name="HealthBar" type="MeshInstance3D" parent="HealthBarContainer"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.01)
|
||||||
|
mesh = SubResource("BoxMesh_2")
|
||||||
|
material_override = SubResource("StandardMaterial3D_2")
|
||||||
104
scenes/hud.tscn
Normal file
104
scenes/hud.tscn
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://hud"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/hud.gd" id="1_hud"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1"]
|
||||||
|
bg_color = Color(0.2, 0, 0, 0.8)
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_2"]
|
||||||
|
bg_color = Color(0, 0.8, 0, 0.8)
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3"]
|
||||||
|
bg_color = Color(0.2, 0.2, 0.2, 0.8)
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_4"]
|
||||||
|
bg_color = Color(0.2, 0.6, 1, 0.8)
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
|
||||||
|
[node name="HUD" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 2
|
||||||
|
script = ExtResource("1_hud")
|
||||||
|
|
||||||
|
[node name="HealthBar" type="ProgressBar" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 2
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 20.0
|
||||||
|
offset_top = -60.0
|
||||||
|
offset_right = 320.0
|
||||||
|
offset_bottom = -20.0
|
||||||
|
grow_vertical = 0
|
||||||
|
max_value = 100.0
|
||||||
|
value = 100.0
|
||||||
|
show_percentage = false
|
||||||
|
theme_override_styles/background = SubResource("StyleBoxFlat_1")
|
||||||
|
theme_override_styles/fill = SubResource("StyleBoxFlat_2")
|
||||||
|
|
||||||
|
[node name="HealthLabel" type="Label" parent="HealthBar"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/shadow_offset_x = 2
|
||||||
|
theme_override_constants/shadow_offset_y = 2
|
||||||
|
text = "HP: 100 / 100"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
|
[node name="DashCooldownBar" type="ProgressBar" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 2
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = 20.0
|
||||||
|
offset_top = -120.0
|
||||||
|
offset_right = 320.0
|
||||||
|
offset_bottom = -80.0
|
||||||
|
grow_vertical = 0
|
||||||
|
max_value = 100.0
|
||||||
|
value = 100.0
|
||||||
|
show_percentage = false
|
||||||
|
theme_override_styles/background = SubResource("StyleBoxFlat_3")
|
||||||
|
theme_override_styles/fill = SubResource("StyleBoxFlat_4")
|
||||||
|
|
||||||
|
[node name="DashCooldownLabel" type="Label" parent="DashCooldownBar"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
|
||||||
|
theme_override_constants/shadow_offset_x = 2
|
||||||
|
theme_override_constants/shadow_offset_y = 2
|
||||||
|
text = "Рывок: готов (Пробел)"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
vertical_alignment = 1
|
||||||
|
|
||||||
60
scenes/main.tscn
Normal file
60
scenes/main.tscn
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
[gd_scene load_steps=8 format=3 uid="uid://c64bxmqeaaaku"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://player" path="res://scenes/player.tscn" id="1_main"]
|
||||||
|
[ext_resource type="PackedScene" path="res://scenes/enemy.tscn" id="2_main"]
|
||||||
|
[ext_resource type="Script" uid="uid://28onm6d36qbo" path="res://scripts/camera_controller.gd" id="3_main"]
|
||||||
|
[ext_resource type="PackedScene" path="res://scenes/hud.tscn" id="4_main"]
|
||||||
|
|
||||||
|
[sub_resource type="PlaneMesh" id="PlaneMesh_1"]
|
||||||
|
size = Vector2(50, 50)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"]
|
||||||
|
albedo_color = Color(0.2, 0.2, 0.2, 1)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_1"]
|
||||||
|
size = Vector3(50, 0.1, 50)
|
||||||
|
|
||||||
|
[node name="Main" type="Node3D"]
|
||||||
|
|
||||||
|
[node name="Ground" type="StaticBody3D" parent="."]
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"]
|
||||||
|
mesh = SubResource("PlaneMesh_1")
|
||||||
|
surface_material_override/0 = SubResource("StandardMaterial3D_1")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"]
|
||||||
|
shape = SubResource("BoxShape3D_1")
|
||||||
|
|
||||||
|
[node name="Player" parent="." instance=ExtResource("1_main")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.2521453, 1, 12.966181)
|
||||||
|
|
||||||
|
[node name="Enemies" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="Enemy1" parent="Enemies" instance=ExtResource("2_main")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 13.720226, 1, 5)
|
||||||
|
|
||||||
|
[node name="Enemy2" parent="Enemies" instance=ExtResource("2_main")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 1, 5)
|
||||||
|
|
||||||
|
[node name="Enemy3" parent="Enemies" instance=ExtResource("2_main")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 1, -5)
|
||||||
|
|
||||||
|
[node name="Enemy4" parent="Enemies" instance=ExtResource("2_main")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 1, -5)
|
||||||
|
|
||||||
|
[node name="Enemy5" parent="Enemies" instance=ExtResource("2_main")]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 8)
|
||||||
|
|
||||||
|
[node name="CameraController" type="Node3D" parent="."]
|
||||||
|
script = ExtResource("3_main")
|
||||||
|
|
||||||
|
[node name="Camera3D" type="Camera3D" parent="CameraController"]
|
||||||
|
transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 0, 15, 15)
|
||||||
|
current = true
|
||||||
|
fov = 60.0
|
||||||
|
|
||||||
|
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||||
|
transform = Transform3D(0.866025, -0.433013, 0.25, 0, 0.5, 0.866025, -0.5, -0.75, 0.433013, 0, 10, 0)
|
||||||
|
shadow_enabled = true
|
||||||
|
|
||||||
|
[node name="HUD" parent="." instance=ExtResource("4_main")]
|
||||||
99
scenes/main_menu.tscn
Normal file
99
scenes/main_menu.tscn
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
[gd_scene load_steps=5 format=3 uid="uid://main_menu"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scripts/main_menu.gd" id="1_menu"]
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_1"]
|
||||||
|
bg_color = Color(0.2, 0.2, 0.2, 0.8)
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_2"]
|
||||||
|
bg_color = Color(0.3, 0.3, 0.4, 0.9)
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
|
||||||
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3"]
|
||||||
|
bg_color = Color(0.15, 0.15, 0.25, 0.9)
|
||||||
|
corner_radius_top_left = 5
|
||||||
|
corner_radius_top_right = 5
|
||||||
|
corner_radius_bottom_right = 5
|
||||||
|
corner_radius_bottom_left = 5
|
||||||
|
|
||||||
|
[node name="MainMenu" type="Control"]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_menu")
|
||||||
|
|
||||||
|
[node name="Background" type="ColorRect" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
color = Color(0.1, 0.1, 0.15, 1)
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 8
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 0.5
|
||||||
|
offset_left = -150.0
|
||||||
|
offset_top = -120.0
|
||||||
|
offset_right = 150.0
|
||||||
|
offset_bottom = 120.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
|
[node name="Title" type="Label" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_font_sizes/font_size = 48
|
||||||
|
text = "Action Rog"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="StartButton" type="Button" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
custom_minimum_size = Vector2(200, 40)
|
||||||
|
theme_override_styles/normal = SubResource("StyleBoxFlat_1")
|
||||||
|
theme_override_styles/hover = SubResource("StyleBoxFlat_2")
|
||||||
|
theme_override_styles/pressed = SubResource("StyleBoxFlat_3")
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_hover_color = Color(0.9, 0.9, 1, 1)
|
||||||
|
theme_override_colors/font_pressed_color = Color(0.7, 0.7, 0.9, 1)
|
||||||
|
text = "Начать игру"
|
||||||
|
|
||||||
|
[node name="SettingsButton" type="Button" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
custom_minimum_size = Vector2(200, 40)
|
||||||
|
theme_override_styles/normal = SubResource("StyleBoxFlat_1")
|
||||||
|
theme_override_styles/hover = SubResource("StyleBoxFlat_2")
|
||||||
|
theme_override_styles/pressed = SubResource("StyleBoxFlat_3")
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_hover_color = Color(0.9, 0.9, 1, 1)
|
||||||
|
theme_override_colors/font_pressed_color = Color(0.7, 0.7, 0.9, 1)
|
||||||
|
text = "Настройки"
|
||||||
|
|
||||||
|
[node name="QuitButton" type="Button" parent="VBoxContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
custom_minimum_size = Vector2(200, 40)
|
||||||
|
theme_override_styles/normal = SubResource("StyleBoxFlat_1")
|
||||||
|
theme_override_styles/hover = SubResource("StyleBoxFlat_2")
|
||||||
|
theme_override_styles/pressed = SubResource("StyleBoxFlat_3")
|
||||||
|
theme_override_colors/font_color = Color(1, 1, 1, 1)
|
||||||
|
theme_override_colors/font_hover_color = Color(0.9, 0.9, 1, 1)
|
||||||
|
theme_override_colors/font_pressed_color = Color(0.7, 0.7, 0.9, 1)
|
||||||
|
text = "Выход"
|
||||||
|
|
||||||
113
scenes/parabolic_projectile.tscn
Normal file
113
scenes/parabolic_projectile.tscn
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
[gd_scene load_steps=10 format=3 uid="uid://cwte6nc4bxak0"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://d3c5g160kh3vv" path="res://scripts/parabolic_projectile.gd" id="1_parabolic"]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"]
|
||||||
|
albedo_color = Color(1, 0.4, 0.1, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(1, 0.3, 0, 1)
|
||||||
|
emission_energy_multiplier = 4.0
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_1"]
|
||||||
|
radius = 0.3
|
||||||
|
height = 0.6
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1"]
|
||||||
|
radius = 0.3
|
||||||
|
height = 0.6
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_1"]
|
||||||
|
direction = Vector3(0, 0, -1)
|
||||||
|
initial_velocity_min = 2.0
|
||||||
|
initial_velocity_max = 5.0
|
||||||
|
gravity = Vector3(0, -2, 0)
|
||||||
|
scale_min = 0.15
|
||||||
|
scale_max = 0.25
|
||||||
|
color = Color(1, 0.5, 0, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_2"]
|
||||||
|
direction = Vector3(0, 0, -1)
|
||||||
|
initial_velocity_min = 1.0
|
||||||
|
initial_velocity_max = 3.0
|
||||||
|
gravity = Vector3(0, -1, 0)
|
||||||
|
scale_min = 0.08
|
||||||
|
scale_max = 0.18
|
||||||
|
color = Color(1, 0.3, 0, 0.8)
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_3"]
|
||||||
|
direction = Vector3(0, 1, 0)
|
||||||
|
spread = 180.0
|
||||||
|
initial_velocity_min = 5.0
|
||||||
|
initial_velocity_max = 10.0
|
||||||
|
gravity = Vector3(0, -5, 0)
|
||||||
|
scale_min = 0.1
|
||||||
|
scale_max = 0.25
|
||||||
|
scale_over_velocity_min = 0.05
|
||||||
|
scale_over_velocity_max = 0.15
|
||||||
|
color = Color(1, 0.6, 0.1, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_4"]
|
||||||
|
direction = Vector3(0, 1, 0)
|
||||||
|
initial_velocity_min = 1.5
|
||||||
|
initial_velocity_max = 3.0
|
||||||
|
gravity = Vector3(0, -2, 0)
|
||||||
|
scale_min = 0.15
|
||||||
|
scale_max = 0.3
|
||||||
|
color = Color(1, 0.8, 0.2, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_5"]
|
||||||
|
direction = Vector3(0, 1, 0)
|
||||||
|
spread = 90.0
|
||||||
|
initial_velocity_min = 2.0
|
||||||
|
initial_velocity_max = 4.0
|
||||||
|
gravity = Vector3(0, -1, 0)
|
||||||
|
scale_min = 0.2
|
||||||
|
scale_max = 0.4
|
||||||
|
color = Color(0.3, 0.3, 0.3, 0.6)
|
||||||
|
|
||||||
|
[node name="ParabolicProjectile" type="Area3D"]
|
||||||
|
script = ExtResource("1_parabolic")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
material_override = SubResource("StandardMaterial3D_1")
|
||||||
|
mesh = SubResource("SphereMesh_1")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("CapsuleShape3D_1")
|
||||||
|
|
||||||
|
[node name="FireParticles" type="GPUParticles3D" parent="."]
|
||||||
|
amount = 40
|
||||||
|
lifetime = 0.4
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_1")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_1")
|
||||||
|
|
||||||
|
[node name="TrailParticles" type="GPUParticles3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.4)
|
||||||
|
amount = 60
|
||||||
|
lifetime = 0.6
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_2")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_1")
|
||||||
|
|
||||||
|
[node name="ExplosionParticles" type="GPUParticles3D" parent="."]
|
||||||
|
emitting = false
|
||||||
|
amount = 80
|
||||||
|
lifetime = 0.5
|
||||||
|
one_shot = true
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_3")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_1")
|
||||||
|
|
||||||
|
[node name="ExplosionCore" type="GPUParticles3D" parent="."]
|
||||||
|
emitting = false
|
||||||
|
amount = 30
|
||||||
|
lifetime = 0.4
|
||||||
|
one_shot = true
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_4")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_1")
|
||||||
|
|
||||||
|
[node name="ExplosionSmoke" type="GPUParticles3D" parent="."]
|
||||||
|
emitting = false
|
||||||
|
amount = 40
|
||||||
|
lifetime = 0.5
|
||||||
|
one_shot = true
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_5")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_1")
|
||||||
23
scenes/player.tscn
Normal file
23
scenes/player.tscn
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://player"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://bt4nfjnngh21i" path="res://scripts/player.gd" id="1_player"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://q46fjntx43e2" path="res://scenes/straight_projectile.tscn" id="2_player"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cwte6nc4bxak0" path="res://scenes/parabolic_projectile.tscn" id="3_player"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_1"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_1"]
|
||||||
|
|
||||||
|
[node name="Player" type="CharacterBody3D" groups=["player"]]
|
||||||
|
script = ExtResource("1_player")
|
||||||
|
straight_projectile_scene = ExtResource("2_player")
|
||||||
|
parabolic_projectile_scene = ExtResource("3_player")
|
||||||
|
speed = 15.0
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||||
|
mesh = SubResource("BoxMesh_1")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||||
|
shape = SubResource("BoxShape3D_1")
|
||||||
57
scenes/straight_projectile.tscn
Normal file
57
scenes/straight_projectile.tscn
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
[gd_scene load_steps=7 format=3 uid="uid://q46fjntx43e2"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://crsltf0vxq1xd" path="res://scripts/straight_projectile.gd" id="1_straight"]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_1"]
|
||||||
|
albedo_color = Color(1, 0.6, 0.2, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(1, 0.4, 0, 1)
|
||||||
|
emission_energy_multiplier = 3.0
|
||||||
|
|
||||||
|
[sub_resource type="SphereMesh" id="SphereMesh_1"]
|
||||||
|
radius = 0.2
|
||||||
|
height = 0.6
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_1"]
|
||||||
|
radius = 0.2
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_1"]
|
||||||
|
direction = Vector3(0, 0, -1)
|
||||||
|
initial_velocity_min = 2.0
|
||||||
|
initial_velocity_max = 4.0
|
||||||
|
gravity = Vector3(0, -2, 0)
|
||||||
|
scale_min = 0.1
|
||||||
|
scale_max = 0.2
|
||||||
|
color = Color(1, 0.5, 0, 1)
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_2"]
|
||||||
|
direction = Vector3(0, 0, -1)
|
||||||
|
initial_velocity_min = 1.0
|
||||||
|
initial_velocity_max = 2.0
|
||||||
|
gravity = Vector3(0, -1, 0)
|
||||||
|
scale_min = 0.05
|
||||||
|
scale_max = 0.15
|
||||||
|
color = Color(1, 0.3, 0, 0.8)
|
||||||
|
|
||||||
|
[node name="StraightProjectile" type="Area3D"]
|
||||||
|
script = ExtResource("1_straight")
|
||||||
|
|
||||||
|
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
|
||||||
|
material_override = SubResource("StandardMaterial3D_1")
|
||||||
|
mesh = SubResource("SphereMesh_1")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("SphereShape3D_1")
|
||||||
|
|
||||||
|
[node name="FireParticles" type="GPUParticles3D" parent="."]
|
||||||
|
amount = 30
|
||||||
|
lifetime = 0.3
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_1")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_1")
|
||||||
|
|
||||||
|
[node name="TrailParticles" type="GPUParticles3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.3)
|
||||||
|
amount = 50
|
||||||
|
lifetime = 0.5
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_2")
|
||||||
|
draw_pass_1 = SubResource("SphereMesh_1")
|
||||||
46
scripts/camera_controller.gd
Normal file
46
scripts/camera_controller.gd
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
extends Node3D
|
||||||
|
class_name CameraController
|
||||||
|
|
||||||
|
# Контроллер камеры в стиле Path of Exile 2
|
||||||
|
# Изометрическая камера, которая следует за игроком
|
||||||
|
|
||||||
|
@export var target: Node3D = null
|
||||||
|
@export var camera_distance: float = 20.0
|
||||||
|
@export var camera_height: float = 15.0
|
||||||
|
@export var camera_angle: float = 45.0 # Угол наклона камеры
|
||||||
|
@export var follow_speed: float = 5.0
|
||||||
|
|
||||||
|
var camera: Camera3D
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
camera = get_node_or_null("Camera3D")
|
||||||
|
if not camera:
|
||||||
|
camera = Camera3D.new()
|
||||||
|
add_child(camera)
|
||||||
|
|
||||||
|
# Находим игрока если цель не установлена
|
||||||
|
if not target:
|
||||||
|
var players = get_tree().get_nodes_in_group("player")
|
||||||
|
if players.size() > 0:
|
||||||
|
target = players[0]
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
if not target or not is_instance_valid(target):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Вычисляем позицию камеры
|
||||||
|
var target_pos = target.global_position
|
||||||
|
var angle_rad = deg_to_rad(camera_angle)
|
||||||
|
|
||||||
|
# Изометрическая позиция камеры (диагональный вид сверху, как в POE 2)
|
||||||
|
# Камера находится под углом 45 градусов по диагонали
|
||||||
|
var offset_x = camera_distance * 0.707 # cos(45) = 0.707
|
||||||
|
var offset_z = camera_distance * 0.707 # sin(45) = 0.707
|
||||||
|
var offset_y = camera_height
|
||||||
|
|
||||||
|
# Плавное следование за игроком
|
||||||
|
var desired_pos = target_pos + Vector3(offset_x, offset_y, offset_z)
|
||||||
|
global_position = global_position.lerp(desired_pos, follow_speed * delta)
|
||||||
|
|
||||||
|
# Камера всегда смотрит на игрока
|
||||||
|
camera.look_at(target_pos, Vector3.UP)
|
||||||
1
scripts/camera_controller.gd.uid
Normal file
1
scripts/camera_controller.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://28onm6d36qbo
|
||||||
77
scripts/enemy.gd
Normal file
77
scripts/enemy.gd
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
extends Unit
|
||||||
|
class_name Enemy
|
||||||
|
|
||||||
|
# Класс противника
|
||||||
|
|
||||||
|
@export var detection_range: float = 10.0
|
||||||
|
@export var attack_range: float = 2.0
|
||||||
|
@export var attack_damage: float = 10.0
|
||||||
|
@export var attack_cooldown: float = 1.0
|
||||||
|
|
||||||
|
var target: Node3D = null
|
||||||
|
var attack_timer: float = 0.0
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
super._ready()
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
attack_timer -= delta
|
||||||
|
|
||||||
|
# Поиск цели (игрока)
|
||||||
|
if target == null or not is_instance_valid(target):
|
||||||
|
find_target()
|
||||||
|
|
||||||
|
# Движение к цели
|
||||||
|
if target and is_instance_valid(target):
|
||||||
|
var distance = global_position.distance_to(target.global_position)
|
||||||
|
|
||||||
|
if distance <= attack_range:
|
||||||
|
# Атака - поворачиваемся к цели
|
||||||
|
var look_direction = (target.global_position - global_position)
|
||||||
|
look_direction.y = 0
|
||||||
|
if look_direction.length() > 0.1:
|
||||||
|
var angle = atan2(look_direction.x, look_direction.z)
|
||||||
|
rotation.y = angle
|
||||||
|
|
||||||
|
if attack_timer <= 0:
|
||||||
|
attack(target)
|
||||||
|
attack_timer = attack_cooldown
|
||||||
|
elif distance <= detection_range:
|
||||||
|
# Преследование - поворачиваемся и бежим к цели
|
||||||
|
var direction = (target.global_position - global_position).normalized()
|
||||||
|
velocity.x = direction.x * speed
|
||||||
|
velocity.z = direction.z * speed
|
||||||
|
|
||||||
|
# Поворачиваем врага в сторону цели
|
||||||
|
var look_direction = (target.global_position - global_position)
|
||||||
|
look_direction.y = 0
|
||||||
|
if look_direction.length() > 0.1:
|
||||||
|
var angle = atan2(look_direction.x, look_direction.z)
|
||||||
|
rotation.y = angle
|
||||||
|
else:
|
||||||
|
# Остановка - не поворачиваемся
|
||||||
|
velocity.x = move_toward(velocity.x, 0, speed)
|
||||||
|
velocity.z = move_toward(velocity.z, 0, speed)
|
||||||
|
else:
|
||||||
|
# Остановка если нет цели
|
||||||
|
velocity.x = move_toward(velocity.x, 0, speed)
|
||||||
|
velocity.z = move_toward(velocity.z, 0, speed)
|
||||||
|
|
||||||
|
# Применяем гравитацию
|
||||||
|
if not is_on_floor():
|
||||||
|
velocity.y -= 9.8 * delta
|
||||||
|
else:
|
||||||
|
velocity.y = 0
|
||||||
|
|
||||||
|
super._physics_process(delta)
|
||||||
|
|
||||||
|
func find_target():
|
||||||
|
# Ищем игрока в сцене
|
||||||
|
var players = get_tree().get_nodes_in_group("player")
|
||||||
|
if players.size() > 0:
|
||||||
|
target = players[0]
|
||||||
|
|
||||||
|
func attack(target_unit: Node3D):
|
||||||
|
# Атака цели
|
||||||
|
if target_unit.has_method("take_damage"):
|
||||||
|
target_unit.take_damage(attack_damage)
|
||||||
1
scripts/enemy.gd.uid
Normal file
1
scripts/enemy.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://8vuywuv7ebsl
|
||||||
87
scripts/enemy_health_bar.gd
Normal file
87
scripts/enemy_health_bar.gd
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
extends Node3D
|
||||||
|
class_name EnemyHealthBar
|
||||||
|
|
||||||
|
# Скрипт для отображения полоски здоровья над врагом
|
||||||
|
|
||||||
|
@onready var background_bar: MeshInstance3D = $BackgroundBar
|
||||||
|
@onready var health_bar: MeshInstance3D = $HealthBar
|
||||||
|
|
||||||
|
var unit: Unit = null
|
||||||
|
var bar_width: float = 3.0
|
||||||
|
var bar_height: float = 0.2
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# Находим родительский Unit (враг)
|
||||||
|
unit = get_parent() as Unit
|
||||||
|
if unit:
|
||||||
|
# Подключаемся к сигналу изменения здоровья
|
||||||
|
unit.health_changed.connect(_on_health_changed)
|
||||||
|
# Изначально скрываем полоску (если здоровье 100%)
|
||||||
|
update_visibility()
|
||||||
|
update_health_bar()
|
||||||
|
else:
|
||||||
|
print("EnemyHealthBar: Не найден Unit!")
|
||||||
|
|
||||||
|
# Убеждаемся, что узлы найдены
|
||||||
|
if not background_bar:
|
||||||
|
print("EnemyHealthBar: Не найден BackgroundBar!")
|
||||||
|
if not health_bar:
|
||||||
|
print("EnemyHealthBar: Не найден HealthBar!")
|
||||||
|
|
||||||
|
func _process(_delta):
|
||||||
|
# Поворачиваем полоску к камере
|
||||||
|
var camera = get_viewport().get_camera_3d()
|
||||||
|
if camera and visible:
|
||||||
|
# BoxMesh по умолчанию ориентирован правильно
|
||||||
|
# Поворачиваем полоску так, чтобы она была обращена к камере
|
||||||
|
# Используем только горизонтальный поворот (по оси Y), чтобы полоска оставалась горизонтальной
|
||||||
|
var direction_to_camera = (camera.global_position - global_position).normalized()
|
||||||
|
if direction_to_camera.length() > 0.01:
|
||||||
|
var horizontal_direction = direction_to_camera
|
||||||
|
horizontal_direction.y = 0
|
||||||
|
horizontal_direction = horizontal_direction.normalized()
|
||||||
|
if horizontal_direction.length() > 0.01:
|
||||||
|
# Поворачиваем только по оси Y
|
||||||
|
var angle = atan2(horizontal_direction.x, horizontal_direction.z)
|
||||||
|
rotation.y = angle
|
||||||
|
|
||||||
|
# Обновляем полоску после поворота (чтобы позиция была правильной)
|
||||||
|
if unit:
|
||||||
|
update_health_bar()
|
||||||
|
|
||||||
|
func _on_health_changed(new_health: float):
|
||||||
|
update_health_bar()
|
||||||
|
update_visibility()
|
||||||
|
|
||||||
|
func update_health_bar():
|
||||||
|
if not unit or not health_bar:
|
||||||
|
return
|
||||||
|
|
||||||
|
var health_percent = clamp(unit.health / unit.max_health, 0.0, 1.0)
|
||||||
|
|
||||||
|
# Масштабируем полоску здоровья в зависимости от процента
|
||||||
|
# Убеждаемся, что масштаб всегда положительный и достаточно большой для видимости
|
||||||
|
var scale_x = max(health_percent, 0.05) # Минимум 0.05 для лучшей видимости
|
||||||
|
health_bar.scale.x = scale_x
|
||||||
|
|
||||||
|
# Смещаем полоску влево, чтобы она уменьшалась справа налево
|
||||||
|
# Используем локальные координаты относительно центра
|
||||||
|
# Центр полоски должен быть в центре, поэтому смещаем на половину разницы
|
||||||
|
var offset = -(bar_width * (1.0 - health_percent)) / 2.0
|
||||||
|
health_bar.position.x = offset
|
||||||
|
# Убеждаемся, что зеленая полоска немного впереди красной для правильного отображения
|
||||||
|
health_bar.position.z = 0.01
|
||||||
|
|
||||||
|
func update_visibility():
|
||||||
|
if not unit:
|
||||||
|
visible = false
|
||||||
|
return
|
||||||
|
|
||||||
|
# Показываем полоску только если здоровье меньше 100%
|
||||||
|
var should_show = unit.health < unit.max_health
|
||||||
|
visible = should_show
|
||||||
|
if background_bar:
|
||||||
|
background_bar.visible = should_show
|
||||||
|
if health_bar:
|
||||||
|
health_bar.visible = should_show
|
||||||
|
|
||||||
1
scripts/enemy_health_bar.gd.uid
Normal file
1
scripts/enemy_health_bar.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c7bnw4xa03juj
|
||||||
53
scripts/hud.gd
Normal file
53
scripts/hud.gd
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
extends Control
|
||||||
|
class_name HUD
|
||||||
|
|
||||||
|
# HUD для отображения информации об игроке
|
||||||
|
|
||||||
|
@onready var health_bar: ProgressBar = $HealthBar
|
||||||
|
@onready var health_label: Label = $HealthBar/HealthLabel
|
||||||
|
@onready var dash_cooldown_bar: ProgressBar = $DashCooldownBar
|
||||||
|
@onready var dash_cooldown_label: Label = $DashCooldownBar/DashCooldownLabel
|
||||||
|
|
||||||
|
var player: Player = null
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# Находим игрока в сцене
|
||||||
|
call_deferred("find_player")
|
||||||
|
|
||||||
|
func find_player():
|
||||||
|
var players = get_tree().get_nodes_in_group("player")
|
||||||
|
if players.size() > 0:
|
||||||
|
player = players[0] as Player
|
||||||
|
if player:
|
||||||
|
# Подключаемся к сигналам
|
||||||
|
player.health_changed.connect(_on_player_health_changed)
|
||||||
|
player.dash_cooldown_changed.connect(_on_dash_cooldown_changed)
|
||||||
|
# Обновляем отображение
|
||||||
|
update_health_display()
|
||||||
|
update_dash_cooldown_display()
|
||||||
|
|
||||||
|
func _on_player_health_changed(new_health: float):
|
||||||
|
update_health_display()
|
||||||
|
|
||||||
|
func _on_dash_cooldown_changed(remaining_time: float):
|
||||||
|
update_dash_cooldown_display()
|
||||||
|
|
||||||
|
func update_health_display():
|
||||||
|
if not player:
|
||||||
|
return
|
||||||
|
|
||||||
|
var health_percent = (player.health / player.max_health) * 100.0
|
||||||
|
health_bar.value = health_percent
|
||||||
|
health_label.text = "HP: %d / %d" % [int(player.health), int(player.max_health)]
|
||||||
|
|
||||||
|
func update_dash_cooldown_display():
|
||||||
|
if not player:
|
||||||
|
return
|
||||||
|
|
||||||
|
var cooldown_percent = (player.dash_cooldown_timer / player.dash_cooldown) * 100.0
|
||||||
|
dash_cooldown_bar.value = cooldown_percent
|
||||||
|
|
||||||
|
if player.dash_cooldown_timer > 0.0:
|
||||||
|
dash_cooldown_label.text = "Рывок: %.1f" % player.dash_cooldown_timer
|
||||||
|
else:
|
||||||
|
dash_cooldown_label.text = "Рывок: готов (Пробел)"
|
||||||
1
scripts/hud.gd.uid
Normal file
1
scripts/hud.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://buc8nflhbd2kx
|
||||||
29
scripts/main_menu.gd
Normal file
29
scripts/main_menu.gd
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
# Скрипт главного меню
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
# Подключаем сигналы кнопок
|
||||||
|
var start_button = get_node_or_null("VBoxContainer/StartButton")
|
||||||
|
var settings_button = get_node_or_null("VBoxContainer/SettingsButton")
|
||||||
|
var quit_button = get_node_or_null("VBoxContainer/QuitButton")
|
||||||
|
|
||||||
|
if start_button:
|
||||||
|
start_button.pressed.connect(_on_start_button_pressed)
|
||||||
|
if settings_button:
|
||||||
|
settings_button.pressed.connect(_on_settings_button_pressed)
|
||||||
|
if quit_button:
|
||||||
|
quit_button.pressed.connect(_on_quit_button_pressed)
|
||||||
|
|
||||||
|
func _on_start_button_pressed():
|
||||||
|
# Переход к игре
|
||||||
|
get_tree().change_scene_to_file("res://scenes/main.tscn")
|
||||||
|
|
||||||
|
func _on_settings_button_pressed():
|
||||||
|
# TODO: Открыть меню настроек
|
||||||
|
print("Настройки (пока не реализовано)")
|
||||||
|
|
||||||
|
func _on_quit_button_pressed():
|
||||||
|
# Выход из игры
|
||||||
|
get_tree().quit()
|
||||||
|
|
||||||
1
scripts/main_menu.gd.uid
Normal file
1
scripts/main_menu.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dpfj2k2b4353w
|
||||||
124
scripts/parabolic_projectile.gd
Normal file
124
scripts/parabolic_projectile.gd
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
extends Projectile
|
||||||
|
class_name ParabolicProjectile
|
||||||
|
|
||||||
|
# Параболический снаряд для броска
|
||||||
|
|
||||||
|
@export var projectile_gravity: float = 200
|
||||||
|
@export var arc_height: float = 15.0 # Увеличена высота параболы
|
||||||
|
|
||||||
|
var target_position: Vector3 = Vector3.ZERO
|
||||||
|
var start_position: Vector3 = Vector3.ZERO
|
||||||
|
var travel_time: float = 0.0
|
||||||
|
var total_time: float = 0.0
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
start_position = global_position
|
||||||
|
|
||||||
|
# Проверяем, что target_position установлен
|
||||||
|
if target_position == Vector3.ZERO:
|
||||||
|
# Если не установлен, используем направление вперед
|
||||||
|
target_position = start_position + Vector3(0, 0, -10.0)
|
||||||
|
target_position.y = start_position.y
|
||||||
|
|
||||||
|
# Вычисляем горизонтальное расстояние
|
||||||
|
var horizontal_distance = Vector3(start_position.x, 0, start_position.z).distance_to(Vector3(target_position.x, 0, target_position.z))
|
||||||
|
|
||||||
|
# Вычисляем правильную траекторию для попадания в цель
|
||||||
|
var horizontal_dir = (target_position - start_position)
|
||||||
|
horizontal_dir.y = 0
|
||||||
|
|
||||||
|
# Если цель слишком близко (включая клик на самого игрока), устанавливаем минимальное расстояние и направление
|
||||||
|
if horizontal_distance < 1.0:
|
||||||
|
# Если направление нулевое или очень маленькое, используем направление вперед от игрока
|
||||||
|
if horizontal_dir.length() < 0.1:
|
||||||
|
# Используем направление камеры или направление вперед
|
||||||
|
var camera = get_viewport().get_camera_3d()
|
||||||
|
if camera:
|
||||||
|
var forward = -camera.global_transform.basis.z
|
||||||
|
forward.y = 0
|
||||||
|
horizontal_dir = forward.normalized()
|
||||||
|
else:
|
||||||
|
horizontal_dir = Vector3(0, 0, -1) # Направление по умолчанию
|
||||||
|
else:
|
||||||
|
horizontal_dir = horizontal_dir.normalized()
|
||||||
|
|
||||||
|
# Устанавливаем минимальное расстояние
|
||||||
|
horizontal_distance = 1.0
|
||||||
|
# Обновляем target_position на минимальном расстоянии от стартовой позиции
|
||||||
|
target_position = start_position + horizontal_dir * horizontal_distance
|
||||||
|
target_position.y = 0.0
|
||||||
|
else:
|
||||||
|
horizontal_dir = horizontal_dir.normalized()
|
||||||
|
|
||||||
|
# Время подъема до максимальной высоты
|
||||||
|
var time_to_peak = sqrt(2 * arc_height / projectile_gravity)
|
||||||
|
# Время полета вниз (примерно такое же)
|
||||||
|
var time_to_fall = time_to_peak
|
||||||
|
# Общее время полета по вертикали
|
||||||
|
var vertical_time = time_to_peak + time_to_fall
|
||||||
|
|
||||||
|
# Горизонтальная скорость должна обеспечить попадание в цель за время полета
|
||||||
|
var horizontal_speed = horizontal_distance / vertical_time
|
||||||
|
|
||||||
|
# Начальная вертикальная скорость для достижения нужной высоты
|
||||||
|
var vertical_speed = sqrt(2 * projectile_gravity * arc_height)
|
||||||
|
|
||||||
|
# Общее время полета
|
||||||
|
total_time = vertical_time
|
||||||
|
|
||||||
|
# Устанавливаем начальную скорость
|
||||||
|
velocity = horizontal_dir * horizontal_speed + Vector3.UP * vertical_speed
|
||||||
|
|
||||||
|
# Вызываем super._ready() после установки velocity
|
||||||
|
super._ready()
|
||||||
|
|
||||||
|
# Отключаем мониторинг коллизий при полете
|
||||||
|
monitoring = false
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
if has_hit:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Если velocity не установлена, не двигаемся
|
||||||
|
if velocity == Vector3.ZERO:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Проверяем время жизни
|
||||||
|
lifetime_timer -= delta
|
||||||
|
if lifetime_timer <= 0:
|
||||||
|
if is_explosive:
|
||||||
|
explode(global_position)
|
||||||
|
else:
|
||||||
|
queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
travel_time += delta
|
||||||
|
|
||||||
|
# Сохраняем предыдущую позицию для raycast (если понадобится)
|
||||||
|
previous_position = global_position
|
||||||
|
|
||||||
|
# Применяем гравитацию
|
||||||
|
velocity.y -= projectile_gravity * delta
|
||||||
|
|
||||||
|
# Движение снаряда
|
||||||
|
global_position += velocity * delta
|
||||||
|
|
||||||
|
# Проверяем, достигли ли цели
|
||||||
|
# Проверяем по Y координате (приземление) и по времени полета
|
||||||
|
# НЕ проверяем горизонтальное расстояние, так как это может сработать сразу при близких целях
|
||||||
|
if (global_position.y <= target_position.y + 0.3) and (travel_time >= total_time * 0.5):
|
||||||
|
# Включаем коллизию только при приземлении
|
||||||
|
monitoring = true
|
||||||
|
# Устанавливаем позицию точно в целевую точку
|
||||||
|
global_position = target_position
|
||||||
|
on_hit(target_position)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Дополнительная проверка по времени полета (на случай, если снаряд не достиг земли)
|
||||||
|
if travel_time >= total_time * 1.2:
|
||||||
|
monitoring = true
|
||||||
|
global_position = target_position
|
||||||
|
on_hit(target_position)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Не проверяем столкновения при полете - только движение
|
||||||
1
scripts/parabolic_projectile.gd.uid
Normal file
1
scripts/parabolic_projectile.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://d3c5g160kh3vv
|
||||||
249
scripts/player.gd
Normal file
249
scripts/player.gd
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
extends Unit
|
||||||
|
class_name Player
|
||||||
|
|
||||||
|
# Класс игрока с управлением WASD
|
||||||
|
|
||||||
|
@export var mouse_sensitivity: float = 0.003
|
||||||
|
@export var dash_speed: float = 25.0 # Скорость рывка
|
||||||
|
@export var dash_duration: float = 0.2 # Длительность рывка
|
||||||
|
@export var dash_cooldown: float = 1.0 # Перезарядка рывка
|
||||||
|
@export var straight_projectile_scene: PackedScene = null # Сцена прямого снаряда
|
||||||
|
@export var parabolic_projectile_scene: PackedScene = null # Сцена параболического снаряда
|
||||||
|
@export var projectile_damage: float = 20.0
|
||||||
|
@export var projectile_speed: float = 20.0
|
||||||
|
@export var explosion_radius: float = 3.0
|
||||||
|
|
||||||
|
var camera_angle: float = 0.0
|
||||||
|
var is_dashing: bool = false
|
||||||
|
var dash_timer: float = 0.0
|
||||||
|
var dash_cooldown_timer: float = 0.0
|
||||||
|
var dash_direction: Vector3 = Vector3.ZERO
|
||||||
|
|
||||||
|
signal dash_started
|
||||||
|
signal dash_ended
|
||||||
|
signal dash_cooldown_changed(remaining_time: float)
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
super._ready()
|
||||||
|
# Игрок белый
|
||||||
|
var mesh_instance = get_node_or_null("MeshInstance3D")
|
||||||
|
if mesh_instance:
|
||||||
|
var material = StandardMaterial3D.new()
|
||||||
|
material.albedo_color = Color.WHITE
|
||||||
|
mesh_instance.material_override = material
|
||||||
|
|
||||||
|
func _input(event):
|
||||||
|
# Обработка рывка
|
||||||
|
if event.is_action_pressed("dash") and dash_cooldown_timer <= 0.0 and not is_dashing:
|
||||||
|
perform_dash()
|
||||||
|
|
||||||
|
# Обработка стрельбы (левая кнопка мыши)
|
||||||
|
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||||
|
shoot_straight_projectile()
|
||||||
|
|
||||||
|
# Обработка броска (правая кнопка мыши)
|
||||||
|
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
|
||||||
|
throw_parabolic_projectile()
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
# Обновляем таймеры
|
||||||
|
var previous_cooldown = dash_cooldown_timer
|
||||||
|
if dash_cooldown_timer > 0.0:
|
||||||
|
dash_cooldown_timer -= delta
|
||||||
|
dash_cooldown_timer = max(0.0, dash_cooldown_timer)
|
||||||
|
# Эмитим сигнал только если значение изменилось
|
||||||
|
if abs(previous_cooldown - dash_cooldown_timer) > 0.01:
|
||||||
|
dash_cooldown_changed.emit(dash_cooldown_timer)
|
||||||
|
|
||||||
|
# Поворачиваем игрока в сторону курсора мыши
|
||||||
|
update_rotation_to_mouse()
|
||||||
|
|
||||||
|
# Получаем направление движения от клавиатуры
|
||||||
|
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
||||||
|
var direction = Vector3(input_dir.x, 0, input_dir.y)
|
||||||
|
|
||||||
|
# Обработка рывка
|
||||||
|
if is_dashing:
|
||||||
|
dash_timer -= delta
|
||||||
|
if dash_timer <= 0.0:
|
||||||
|
end_dash()
|
||||||
|
else:
|
||||||
|
# Во время рывка двигаемся с увеличенной скоростью
|
||||||
|
velocity.x = dash_direction.x * dash_speed
|
||||||
|
velocity.z = dash_direction.z * dash_speed
|
||||||
|
else:
|
||||||
|
# Обычное движение
|
||||||
|
if direction.length() > 0:
|
||||||
|
velocity.x = direction.x * speed
|
||||||
|
velocity.z = direction.z * speed
|
||||||
|
else:
|
||||||
|
velocity.x = move_toward(velocity.x, 0, speed)
|
||||||
|
velocity.z = move_toward(velocity.z, 0, speed)
|
||||||
|
|
||||||
|
# Применяем гравитацию
|
||||||
|
if not is_on_floor():
|
||||||
|
velocity.y -= 9.8 * delta
|
||||||
|
else:
|
||||||
|
velocity.y = 0
|
||||||
|
|
||||||
|
super._physics_process(delta)
|
||||||
|
|
||||||
|
func update_rotation_to_mouse():
|
||||||
|
# Получаем камеру из сцены
|
||||||
|
var camera = get_viewport().get_camera_3d()
|
||||||
|
if not camera:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Получаем позицию курсора мыши на экране
|
||||||
|
var mouse_pos = get_viewport().get_mouse_position()
|
||||||
|
|
||||||
|
# Создаем луч от камеры через позицию курсора
|
||||||
|
var from = camera.project_ray_origin(mouse_pos)
|
||||||
|
var to = from + camera.project_ray_normal(mouse_pos) * 1000.0
|
||||||
|
|
||||||
|
# Создаем запрос для raycast
|
||||||
|
var space_state = get_world_3d().direct_space_state
|
||||||
|
var query = PhysicsRayQueryParameters3D.create(from, to)
|
||||||
|
query.collision_mask = 1 # Слой земли
|
||||||
|
|
||||||
|
# Выполняем raycast
|
||||||
|
var result = space_state.intersect_ray(query)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
# Получаем точку пересечения
|
||||||
|
var target_point = result.position
|
||||||
|
# Поворачиваем игрока в сторону курсора (только по оси Y)
|
||||||
|
var look_direction = (target_point - global_position)
|
||||||
|
look_direction.y = 0 # Игнорируем вертикальную составляющую
|
||||||
|
if look_direction.length() > 0.1:
|
||||||
|
look_at(global_position + look_direction, Vector3.UP)
|
||||||
|
|
||||||
|
func perform_dash():
|
||||||
|
# Получаем направление движения
|
||||||
|
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
|
||||||
|
var direction = Vector3(input_dir.x, 0, input_dir.y)
|
||||||
|
|
||||||
|
# Если игрок не двигается, рывок вперед (по направлению взгляда или вверх)
|
||||||
|
if direction.length() < 0.1:
|
||||||
|
direction = Vector3(0, 0, -1) # Вперед по умолчанию
|
||||||
|
|
||||||
|
# Нормализуем направление
|
||||||
|
dash_direction = direction.normalized()
|
||||||
|
|
||||||
|
# Запускаем рывок
|
||||||
|
is_dashing = true
|
||||||
|
dash_timer = dash_duration
|
||||||
|
dash_cooldown_timer = dash_cooldown
|
||||||
|
dash_started.emit()
|
||||||
|
|
||||||
|
func end_dash():
|
||||||
|
is_dashing = false
|
||||||
|
dash_timer = 0.0
|
||||||
|
dash_ended.emit()
|
||||||
|
|
||||||
|
func shoot_straight_projectile():
|
||||||
|
if not straight_projectile_scene:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Получаем точку прицеливания через raycast
|
||||||
|
var target_point = get_mouse_target_point()
|
||||||
|
if not target_point:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Создаем снаряд
|
||||||
|
var projectile = straight_projectile_scene.instantiate() as StraightProjectile
|
||||||
|
if not projectile:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Устанавливаем параметры
|
||||||
|
projectile.owner_unit = self
|
||||||
|
projectile.damage = projectile_damage
|
||||||
|
projectile.speed = projectile_speed
|
||||||
|
projectile.is_explosive = false
|
||||||
|
|
||||||
|
# Направление полета
|
||||||
|
var shoot_position = global_position + Vector3.UP * 1.0 # Немного выше игрока
|
||||||
|
var direction = (target_point - shoot_position).normalized()
|
||||||
|
projectile.direction = direction
|
||||||
|
|
||||||
|
# Позиция и поворот
|
||||||
|
projectile.global_position = shoot_position
|
||||||
|
projectile.look_at(shoot_position + direction, Vector3.UP)
|
||||||
|
|
||||||
|
# Добавляем в сцену
|
||||||
|
var scene_root = get_tree().current_scene
|
||||||
|
if not scene_root:
|
||||||
|
scene_root = get_tree().root.get_child(get_tree().root.get_child_count() - 1)
|
||||||
|
scene_root.add_child(projectile)
|
||||||
|
|
||||||
|
func throw_parabolic_projectile():
|
||||||
|
if not parabolic_projectile_scene:
|
||||||
|
# Пробуем загрузить вручную
|
||||||
|
parabolic_projectile_scene = load("res://scenes/parabolic_projectile.tscn") as PackedScene
|
||||||
|
if not parabolic_projectile_scene:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Получаем точку прицеливания через raycast (на плоскости)
|
||||||
|
var target_point = get_mouse_target_point()
|
||||||
|
|
||||||
|
# Убеждаемся, что целевая точка на уровне земли (Y = 0)
|
||||||
|
# Если кликнули на противника или другой объект, используем его X и Z, но Y ставим на землю
|
||||||
|
target_point.y = 0.0
|
||||||
|
|
||||||
|
# Позиция запуска
|
||||||
|
var throw_position = global_position + Vector3.UP * 1.0
|
||||||
|
|
||||||
|
# Создаем снаряд
|
||||||
|
var projectile = parabolic_projectile_scene.instantiate()
|
||||||
|
if not projectile:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Устанавливаем параметры ДО добавления в сцену
|
||||||
|
projectile.owner_unit = self
|
||||||
|
projectile.damage = projectile_damage
|
||||||
|
projectile.speed = projectile_speed
|
||||||
|
projectile.is_explosive = true
|
||||||
|
projectile.explosion_radius = explosion_radius
|
||||||
|
|
||||||
|
# Устанавливаем позицию
|
||||||
|
projectile.global_position = throw_position
|
||||||
|
|
||||||
|
# Целевая позиция (на уровне земли) - устанавливаем ДО _ready()
|
||||||
|
projectile.target_position = target_point
|
||||||
|
|
||||||
|
# Добавляем в сцену (после установки всех параметров)
|
||||||
|
var scene_root = get_tree().current_scene
|
||||||
|
if not scene_root:
|
||||||
|
scene_root = get_tree().root.get_child(get_tree().root.get_child_count() - 1)
|
||||||
|
scene_root.add_child(projectile)
|
||||||
|
|
||||||
|
func get_mouse_target_point() -> Vector3:
|
||||||
|
# Получаем камеру
|
||||||
|
var camera = get_viewport().get_camera_3d()
|
||||||
|
if not camera:
|
||||||
|
return global_position + transform.basis.z * -10.0
|
||||||
|
|
||||||
|
# Получаем позицию курсора мыши
|
||||||
|
var mouse_pos = get_viewport().get_mouse_position()
|
||||||
|
|
||||||
|
# Создаем луч от камеры
|
||||||
|
var from = camera.project_ray_origin(mouse_pos)
|
||||||
|
var ray_dir = camera.project_ray_normal(mouse_pos)
|
||||||
|
var to = from + ray_dir * 1000.0
|
||||||
|
|
||||||
|
# Raycast
|
||||||
|
var space_state = get_world_3d().direct_space_state
|
||||||
|
var query = PhysicsRayQueryParameters3D.create(from, to)
|
||||||
|
query.collision_mask = 1
|
||||||
|
|
||||||
|
var result = space_state.intersect_ray(query)
|
||||||
|
if result:
|
||||||
|
return result.position
|
||||||
|
|
||||||
|
# Если не попали ни во что, вычисляем точку на плоскости земли
|
||||||
|
if ray_dir.y < -0.01: # Луч направлен вниз
|
||||||
|
var t = -from.y / ray_dir.y
|
||||||
|
return from + ray_dir * t
|
||||||
|
|
||||||
|
# Если луч не направлен вниз, используем точку перед игроком
|
||||||
|
return global_position + transform.basis.z * -10.0
|
||||||
1
scripts/player.gd.uid
Normal file
1
scripts/player.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bt4nfjnngh21i
|
||||||
182
scripts/projectile.gd
Normal file
182
scripts/projectile.gd
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
extends Area3D
|
||||||
|
class_name Projectile
|
||||||
|
|
||||||
|
# Базовый класс для снарядов
|
||||||
|
|
||||||
|
@export var speed: float = 120.0
|
||||||
|
@export var damage: float = 20.0
|
||||||
|
@export var lifetime: float = 5.0
|
||||||
|
@export var is_explosive: bool = false
|
||||||
|
@export var explosion_radius: float = 3.0
|
||||||
|
|
||||||
|
var direction: Vector3 = Vector3.ZERO
|
||||||
|
var velocity: Vector3 = Vector3.ZERO
|
||||||
|
var owner_unit: Node3D = null
|
||||||
|
var lifetime_timer: float = 0.0
|
||||||
|
var has_hit: bool = false
|
||||||
|
var previous_position: Vector3 = Vector3.ZERO
|
||||||
|
|
||||||
|
signal hit(target: Node3D, position: Vector3)
|
||||||
|
signal exploded(position: Vector3)
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
lifetime_timer = lifetime
|
||||||
|
previous_position = global_position
|
||||||
|
# Настраиваем Area3D для обнаружения целей
|
||||||
|
body_entered.connect(_on_body_entered)
|
||||||
|
# Отключаем мониторинг по умолчанию для параболических
|
||||||
|
monitoring = true
|
||||||
|
monitorable = false
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
if has_hit:
|
||||||
|
return
|
||||||
|
|
||||||
|
lifetime_timer -= delta
|
||||||
|
if lifetime_timer <= 0:
|
||||||
|
if is_explosive:
|
||||||
|
explode(global_position)
|
||||||
|
else:
|
||||||
|
queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Сохраняем предыдущую позицию для raycast
|
||||||
|
previous_position = global_position
|
||||||
|
|
||||||
|
# Движение снаряда
|
||||||
|
global_position += velocity * delta
|
||||||
|
|
||||||
|
# Проверка столкновений через raycast
|
||||||
|
check_collisions_raycast()
|
||||||
|
|
||||||
|
func check_collisions_raycast():
|
||||||
|
# Используем raycast для проверки столкновений
|
||||||
|
var space_state = get_world_3d().direct_space_state
|
||||||
|
var query = PhysicsRayQueryParameters3D.create(previous_position, global_position)
|
||||||
|
query.exclude = [self, owner_unit] if owner_unit else [self]
|
||||||
|
query.collision_mask = 1 # Только слой земли и объектов
|
||||||
|
|
||||||
|
var result = space_state.intersect_ray(query)
|
||||||
|
if result:
|
||||||
|
var collider = result.collider
|
||||||
|
var hit_position = result.position
|
||||||
|
|
||||||
|
# Если это враг, наносим урон
|
||||||
|
if collider.has_method("take_damage"):
|
||||||
|
collider.take_damage(damage)
|
||||||
|
hit.emit(collider, hit_position)
|
||||||
|
|
||||||
|
on_hit(hit_position)
|
||||||
|
|
||||||
|
func _on_body_entered(body: Node3D):
|
||||||
|
# Дополнительная проверка через Area3D
|
||||||
|
if has_hit:
|
||||||
|
return
|
||||||
|
|
||||||
|
if body == owner_unit:
|
||||||
|
return
|
||||||
|
|
||||||
|
if body is Projectile:
|
||||||
|
return
|
||||||
|
|
||||||
|
if body.has_method("take_damage"):
|
||||||
|
body.take_damage(damage)
|
||||||
|
hit.emit(body, global_position)
|
||||||
|
|
||||||
|
on_hit(global_position)
|
||||||
|
|
||||||
|
func on_hit(position: Vector3):
|
||||||
|
if has_hit:
|
||||||
|
return
|
||||||
|
|
||||||
|
has_hit = true
|
||||||
|
velocity = Vector3.ZERO
|
||||||
|
# Останавливаем частицы
|
||||||
|
var fire_particles = get_node_or_null("FireParticles")
|
||||||
|
var trail_particles = get_node_or_null("TrailParticles")
|
||||||
|
if fire_particles:
|
||||||
|
fire_particles.emitting = false
|
||||||
|
if trail_particles:
|
||||||
|
trail_particles.emitting = false
|
||||||
|
|
||||||
|
if is_explosive:
|
||||||
|
explode(position)
|
||||||
|
else:
|
||||||
|
# Простое попадание
|
||||||
|
hit.emit(null, position)
|
||||||
|
# Воспроизводим анимацию попадания
|
||||||
|
play_hit_animation()
|
||||||
|
# Удаляем через небольшую задержку
|
||||||
|
await get_tree().create_timer(0.5).timeout
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func explode(position: Vector3):
|
||||||
|
# Находим все цели в радиусе взрыва
|
||||||
|
var space_state = get_world_3d().direct_space_state
|
||||||
|
var query = PhysicsShapeQueryParameters3D.new()
|
||||||
|
var sphere_shape = SphereShape3D.new()
|
||||||
|
sphere_shape.radius = explosion_radius
|
||||||
|
query.shape = sphere_shape
|
||||||
|
query.transform.origin = position
|
||||||
|
query.collision_mask = 1
|
||||||
|
|
||||||
|
var results = space_state.intersect_shape(query)
|
||||||
|
|
||||||
|
# Наносим урон всем в радиусе
|
||||||
|
for result in results:
|
||||||
|
var collider = result.collider
|
||||||
|
if collider != owner_unit and collider.has_method("take_damage"):
|
||||||
|
var distance = position.distance_to(collider.global_position)
|
||||||
|
var damage_multiplier = 1.0 - (distance / explosion_radius)
|
||||||
|
collider.take_damage(damage * damage_multiplier)
|
||||||
|
|
||||||
|
exploded.emit(position)
|
||||||
|
play_explosion_animation()
|
||||||
|
# Ждем, пока частицы взрыва отыграют (0.5 секунды)
|
||||||
|
await get_tree().create_timer(0.5).timeout
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func play_hit_animation():
|
||||||
|
# Создаем простой визуальный эффект попадания
|
||||||
|
var mesh = get_node_or_null("MeshInstance3D")
|
||||||
|
if mesh:
|
||||||
|
# Увеличиваем размер и скрываем
|
||||||
|
var tween = create_tween()
|
||||||
|
tween.tween_property(mesh, "scale", Vector3(2.0, 2.0, 2.0), 0.2)
|
||||||
|
tween.tween_callback(func(): mesh.visible = false)
|
||||||
|
|
||||||
|
func play_explosion_animation():
|
||||||
|
# Скрываем основной меш
|
||||||
|
var mesh = get_node_or_null("MeshInstance3D")
|
||||||
|
if mesh:
|
||||||
|
mesh.visible = false
|
||||||
|
|
||||||
|
# Останавливаем частицы полета
|
||||||
|
var fire_particles = get_node_or_null("FireParticles")
|
||||||
|
var trail_particles = get_node_or_null("TrailParticles")
|
||||||
|
if fire_particles:
|
||||||
|
fire_particles.emitting = false
|
||||||
|
if trail_particles:
|
||||||
|
trail_particles.emitting = false
|
||||||
|
|
||||||
|
# Воспроизводим частицы взрыва
|
||||||
|
var explosion_particles = get_node_or_null("ExplosionParticles")
|
||||||
|
var explosion_core = get_node_or_null("ExplosionCore")
|
||||||
|
var explosion_smoke = get_node_or_null("ExplosionSmoke")
|
||||||
|
|
||||||
|
# Масштабируем узлы частиц в зависимости от радиуса взрыва
|
||||||
|
# Это создаст визуальный эффект взрыва нужного размера
|
||||||
|
var scale_factor = explosion_radius / 3.0 # 3.0 - базовый радиус взрыва
|
||||||
|
|
||||||
|
if explosion_particles:
|
||||||
|
explosion_particles.scale = Vector3.ONE * scale_factor
|
||||||
|
explosion_particles.restart()
|
||||||
|
explosion_particles.emitting = true
|
||||||
|
if explosion_core:
|
||||||
|
explosion_core.scale = Vector3.ONE * scale_factor * 0.6
|
||||||
|
explosion_core.restart()
|
||||||
|
explosion_core.emitting = true
|
||||||
|
if explosion_smoke:
|
||||||
|
explosion_smoke.scale = Vector3.ONE * scale_factor * 1.2
|
||||||
|
explosion_smoke.restart()
|
||||||
|
explosion_smoke.emitting = true
|
||||||
1
scripts/projectile.gd.uid
Normal file
1
scripts/projectile.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bg1bpdny7eta6
|
||||||
13
scripts/straight_projectile.gd
Normal file
13
scripts/straight_projectile.gd
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
extends Projectile
|
||||||
|
class_name StraightProjectile
|
||||||
|
|
||||||
|
# Прямой снаряд для стрельбы
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
super._ready()
|
||||||
|
# Устанавливаем скорость только горизонтально (параллельно земле)
|
||||||
|
var horizontal_dir = direction
|
||||||
|
horizontal_dir.y = 0
|
||||||
|
horizontal_dir = horizontal_dir.normalized()
|
||||||
|
velocity = horizontal_dir * speed
|
||||||
|
|
||||||
1
scripts/straight_projectile.gd.uid
Normal file
1
scripts/straight_projectile.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://crsltf0vxq1xd
|
||||||
30
scripts/unit.gd
Normal file
30
scripts/unit.gd
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
extends CharacterBody3D
|
||||||
|
class_name Unit
|
||||||
|
|
||||||
|
# Базовый класс для всех юнитов (игрок и противники)
|
||||||
|
|
||||||
|
@export var speed: float = 5.0
|
||||||
|
@export var health: float = 100.0
|
||||||
|
@export var max_health: float = 100.0
|
||||||
|
|
||||||
|
signal health_changed(new_health: float)
|
||||||
|
signal died
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
health = max_health
|
||||||
|
|
||||||
|
func take_damage(amount: float):
|
||||||
|
health -= amount
|
||||||
|
health = max(0, health)
|
||||||
|
health_changed.emit(health)
|
||||||
|
|
||||||
|
if health <= 0:
|
||||||
|
die()
|
||||||
|
|
||||||
|
func die():
|
||||||
|
died.emit()
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func _physics_process(delta):
|
||||||
|
# Базовая физика движения
|
||||||
|
move_and_slide()
|
||||||
1
scripts/unit.gd.uid
Normal file
1
scripts/unit.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cok6ep4d2e6mf
|
||||||
Reference in New Issue
Block a user