Compare commits

...

83 Commits

Author SHA1 Message Date
Vladislav Khorev
fb7b42ddf9 Some clean up 2026-05-02 20:40:29 +03:00
Vladislav Khorev
6149182f02 Fixing bugs, added girl 2026-05-02 20:34:43 +03:00
Vladislav Khorev
d24748df1e Model optimization 2026-05-01 21:47:54 +03:00
Vladislav Khorev
be6a8cca9e working on texture manager 2026-05-01 21:00:51 +03:00
Vladislav Khorev
e04fcbb9bd Clean up 2026-05-01 20:26:50 +03:00
Vladislav Khorev
519d780b3c Clean up 2026-05-01 20:01:06 +03:00
Vladislav Khorev
16d250a51d merge 2026-05-01 19:03:13 +03:00
Vladislav Khorev
5231b50aab Merge branch 'witcher001-path' into witcher001 2026-05-01 16:53:25 +03:00
8b0a18a6cf corrected collision of tree 2026-05-01 16:01:32 +06:00
Vlad
4de8f78eca merge 2026-04-30 15:15:11 +06:00
Vlad
5dd964c740 speed 2026-04-30 14:20:10 +06:00
Vladislav Khorev
b98631a8c0 Fixing stuff 2026-04-30 11:08:06 +03:00
d78286a9c2 add quest journal (QuestJournal + split UI view) 2026-04-30 03:20:52 +06:00
Vlad
635960007c added slow-mo 2026-04-29 20:02:35 +06:00
dbf0af2cb2 implement dynamic text wrapping based on pixel width 2026-04-29 13:30:02 +06:00
cebbb8bb5d Added collision 2026-04-26 22:18:42 +06:00
Vladislav Khorev
2ee288cbe0 Added full screen mode 2026-04-25 21:17:40 +03:00
Vladislav Khorev
348aa632dd Code works more or less good 2026-04-25 21:11:07 +03:00
Vladislav Khorev
3495d28edf Fixing minor bugs 2026-04-25 20:30:27 +03:00
Vladislav Khorev
c7b3f04cd4 Working on fog, 2nd level, locations, dialogs 2026-04-25 19:56:00 +03:00
Vladislav Khorev
eac914e073 minor fixing, adapting for mobile web 2026-04-25 14:39:27 +03:00
Vladislav Khorev
44cc0fba67 Added hp and attack actions, and labels 2026-04-25 12:07:52 +03:00
0a073243ad safe LMB hold-to-skip cutscenes and multiple images with crossfade 2026-04-25 01:32:16 +06:00
Vladislav Khorev
393ebcd831 Added sparks 2026-04-24 19:53:18 +03:00
Vladislav Khorev
2bb7da2e37 Added hp 2026-04-24 18:40:51 +03:00
Vladislav Khorev
b4b41e8620 Added more animations 2026-04-24 17:39:32 +03:00
Vladislav Khorev
3241ab3735 Working on more animations 2026-04-23 22:24:33 +03:00
Vladislav Khorev
c655678486 Some strange shit happens 2026-04-22 22:38:20 +03:00
Vladislav Khorev
4d9a5b0a6e Set new type of animation 2026-04-22 20:45:40 +03:00
Vladislav Khorev
52c4ad8ee0 Working on new animations 2026-04-22 18:53:27 +03:00
Vladislav Khorev
fe01a5d1b2 Working on audio in web part 2 2026-04-17 17:14:44 +03:00
Vladislav Khorev
b6e0422d71 Working on audio in web part 1 2026-04-17 17:13:55 +03:00
Vladislav Khorev
3778a603f2 merge 2026-04-17 16:30:09 +03:00
Vladislav Khorev
e310822462 Working on web version 2026-04-17 16:13:56 +03:00
Vladislav Khorev
3d3c3b2a36 merge 2026-04-17 13:42:45 +03:00
Vlad
b5bcd3a812 added music 2026-04-17 14:23:56 +06:00
16e7580418 Merge branch 'witcher001-cutscene' of gitea.fishrungames.com:salmon-engine-projects/space-game001 into witcher001-cutscene 2026-04-17 02:33:56 +06:00
be4dcd4cf9 fix: make choice options the only clickable area in dialogue choices 2026-04-17 02:04:36 +06:00
Vladislav Khorev
a1dda3fd50 Major refactoring 2026-04-16 20:24:27 +03:00
Vladislav Khorev
92ba3f2b60 Some refactoring 2026-04-16 20:06:03 +03:00
Vladislav Khorev
f2f56125f0 Refactoring 2026-04-16 18:07:22 +03:00
Vladislav Khorev
2ef2e456f7 GPU skinning refactoring 2026-04-16 17:48:23 +03:00
Vladislav Khorev
83cceecccd Refactoring 2026-04-16 15:37:48 +03:00
Vladislav Khorev
24851a89e8 Merge 2026-04-16 15:16:45 +03:00
Vladislav Khorev
d47cfd1b6b Minor refactoring 2026-04-16 15:07:59 +03:00
Vladislav Khorev
71346b4227 Remove unused files 2026-04-16 14:03:52 +03:00
Vladislav Khorev
08e1174eaf Fixing minor bugs 2026-04-16 13:44:40 +03:00
Vladislav Khorev
cc2eba1352 merge 2026-04-16 13:24:04 +03:00
Vladislav Khorev
cfee60d71a merge 2026-04-16 13:11:01 +03:00
Vladislav Khorev
dc76986cd3 Added path showing 2026-04-16 11:39:14 +03:00
Vladislav Khorev
61665434ab Fixing minor bugs 2026-04-16 09:37:36 +03:00
2494a44e4a refactor: switch cutscene camera to viewport/UV-based system 2026-04-16 01:29:01 +06:00
Vladislav Khorev
d8795ec076 Added shadow maps 2026-04-15 19:54:21 +03:00
ceebb13719 improve dialogue advance and add flexible cutscene camera system 2026-04-15 20:42:41 +06:00
Vladislav Khorev
a47306533e Working on stuff 2026-04-15 16:51:55 +03:00
Vladislav Khorev
f708843747 Working on optimization: GPU skinning and binary animations 2026-04-15 16:39:33 +03:00
Vladislav Khorev
a589765b7e prepare to add anims 2026-04-15 16:38:30 +03:00
4eaefd25d4 added finding path with A* and json file to know where character can walk 2026-04-15 18:36:27 +06:00
Vladislav Khorev
eff7322140 Working on dialog portraits 2026-04-15 11:56:38 +03:00
Vlad
44dd09fcb5 fix inventory 2026-04-15 14:50:46 +06:00
Vladislav Khorev
de2e18e38f Fixing rotation issues in battle mode 2026-04-15 10:34:55 +03:00
Vladislav Khorev
984d7489d5 Working on enemies and attack 2026-04-15 10:00:16 +03:00
Vlad
f7e6f063d1 added dialog start radius and background by time in cutscenes 2026-04-14 18:07:46 +06:00
Vlad
db8b9b7a18 fix timetyper and dialog start by click on npc 2026-04-14 17:41:28 +06:00
Vladislav Khorev
493eb5a5d7 Working on battle animation 2026-04-13 23:19:03 +03:00
Vlad
422ff1fbe3 merge 2026-04-13 15:08:38 +06:00
6465549c3b fix: dialogue text now displays correctly 2026-04-13 02:16:25 +06:00
Vlad
34759326b9 added npc's gift 2026-04-12 14:52:37 +06:00
7125674308 add dialogue and cutscene system 2026-04-12 01:46:33 +06:00
Vlad
bc2997d86f added activeFunc for active obj 2026-04-11 16:18:59 +06:00
Vlad
943b6b4d21 added load npcs from json 2026-04-11 15:30:29 +06:00
Vlad
b3fda88784 added inventory & active object 2026-04-09 15:33:55 +06:00
Vlad
e1b491be73 added load from json game objects 2026-04-07 20:17:04 +06:00
Vladislav Khorev
178f69967b Working on web, change python to lua 2026-04-04 14:29:20 +03:00
Vladislav Khorev
90e2a369f4 Added attack animation for ghots 2026-04-03 21:54:40 +03:00
Vladislav Khorev
403b93e7f5 Added more scripts 2026-04-03 20:06:33 +03:00
Vladislav Khorev
63c9d7b35b Adding scripts 2026-04-03 19:46:43 +03:00
Vladislav Khorev
995e2c8e5b NPC code 2026-04-02 21:03:55 +03:00
Vladislav Khorev
2e4a7ab467 Some cleanup 2026-04-02 19:24:15 +03:00
Vladislav Khorev
a96d0b207a Added ai generated animation 2026-04-01 19:07:21 +03:00
Vladislav Khorev
7840bfdb4e Added viola 2026-04-01 13:02:39 +03:00
Vladislav Khorev
56ce826205 Remove unused references 2026-04-01 12:03:35 +03:00
Vladislav Khorev
5364b97235 Working on new scene 2026-04-01 12:03:16 +03:00
322 changed files with 324913 additions and 40885 deletions

4
.gitattributes vendored
View File

@ -1,3 +1,7 @@
*.bmp filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.anim filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text

View File

@ -0,0 +1,65 @@
import bpy
def append_layered_action_5_0(source_obj_name, target_obj_name):
source_obj = bpy.data.objects.get(source_obj_name)
target_obj = bpy.data.objects.get(target_obj_name)
if not (source_obj and target_obj):
print("Ошибка: Объекты не найдены")
return
src_action = source_obj.animation_data.action
tgt_action = target_obj.animation_data.action
# 1. Получаем слои (обычно первый)
src_layer = src_action.layers[0]
tgt_layer = tgt_action.layers[0]
# 2. Получаем стрипы
src_strip = src_layer.strips[0]
tgt_strip = tgt_layer.strips[0]
# Смещение (опираемся на конец диапазона целевого экшена)
offset = tgt_action.frame_range[1]
# 3. Итерируемся по channelbags в исходном стрипе
for src_bag in src_strip.channelbags:
# Ищем или создаем соответствующий bag в целевом стрипе
# Обычно они сопоставляются по имени или типу (например, 'Keyframe Channel Bag')
# В простейшем случае берем первый или сопоставляем по индексу
dst_bag = None
if len(tgt_strip.channelbags) > 0:
# Пытаемся найти по названию (если оно есть) или берем тот же индекс
dst_bag = tgt_strip.channelbags[0]
if not dst_bag:
# Если в целевом стрипе нет сумок, это странно, но можно создать
# (Метод создания может зависеть от конкретного подтипа стрипа в 5.0)
continue
#print(f"Обработка channelbag: {src_bag.name}, кривых: {len(src_bag.fcurves)}")
# 4. Итерируемся по fcurves внутри сумки
for src_fcurve in src_bag.fcurves:
dst_fcurve = dst_bag.fcurves.find(src_fcurve.data_path, index=src_fcurve.array_index)
if not dst_fcurve:
dst_fcurve = dst_bag.fcurves.new(data_path=src_fcurve.data_path, index=src_fcurve.array_index)
# 5. Копируем ключи с офсетом
for keyframe in src_fcurve.keyframe_points:
new_frame = keyframe.co[0] + offset
new_value = keyframe.co[1]
new_kp = dst_fcurve.keyframe_points.insert(new_frame, new_value, options={'FAST'})
new_kp.interpolation = keyframe.interpolation
# Обновляем интерполяцию
for fc in dst_bag.fcurves:
fc.update()
print(f"Анимация успешно дозаписана. Новый конец: {tgt_action.frame_range[1]}")
append_layered_action_5_0('Armature.001', 'Armature')

View File

@ -0,0 +1,192 @@
import bpy
import bmesh
# Имена mesh и арматуры
mesh_name = "arm"
armature_name = "Reference"
# Находим объект mesh по имени
mesh_obj = bpy.data.objects.get(mesh_name)
# Находим объект арматуры по имени
armature_obj = bpy.data.objects.get(armature_name)
# Устанавливаем текущий кадр на 0
bpy.context.scene.frame_set(0)
# Принудительно обновляем сцену, чтобы применить анимацию
bpy.context.view_layer.update()
# Открываем файл для записи
with open("C:\\Work\\Projects\\witcher001\\resources\\w\\zombie002.txt", "w") as file:
# Обработка арматуры и анимации
if armature_obj and armature_obj.type == 'ARMATURE':
file.write("=== Armature Matrix ===\n")
for row in armature_obj.matrix_world:
file.write(f"{row}\n")
file.write(f"=== Armature Bones: {len(armature_obj.data.bones)}\n")
for bone in armature_obj.data.bones:
# Записываем имя кости, длину и связи
file.write(f"Bone: {bone.name}\n")
file.write(f" HEAD_LOCAL: {bone.head_local}\n")
file.write(f" TAIL_LOCAL: {bone.tail_local}\n")
file.write(f" Length: {(bone.tail_local - bone.head_local).length}\n")
for row in bone.matrix:
file.write(f" {row}\n")
file.write(f" Parent: {bone.parent.name if bone.parent else 'None'}\n")
file.write(f" Children: {[child.name for child in bone.children]}\n")
# Обработка mesh
if mesh_obj and mesh_obj.type == 'MESH':
# Создаем копию mesh, чтобы не изменять оригинал
mesh_copy = mesh_obj.copy()
mesh_copy.data = mesh_obj.data.copy()
bpy.context.collection.objects.link(mesh_copy)
# Убедимся, что объект активен
bpy.context.view_layer.objects.active = mesh_copy
mesh_copy.select_set(True)
# Применяем модификатор Armature (если он есть)
for modifier in mesh_copy.modifiers:
if modifier.type == 'ARMATURE':
# Включаем модификатор, если он отключен
if not modifier.show_viewport:
modifier.show_viewport = True
if not modifier.show_render:
modifier.show_render = True
# Проверяем, что модификатор связан с арматурой
if modifier.object is None:
print(f"Модификатор Armature на объекте {mesh_copy.name} не связан с арматурой. Пропускаем.")
continue
# Временно применяем модификатор, чтобы получить правильные координаты вершин
try:
bpy.ops.object.modifier_apply(modifier=modifier.name)
except RuntimeError as e:
print(f"Ошибка при применении модификатора Armature: {e}")
continue
# Переходим в режим редактирования
bpy.ops.object.mode_set(mode='EDIT')
# Получаем BMesh представление mesh
bm = bmesh.from_edit_mesh(mesh_copy.data)
# Записываем список вершин
file.write(f"===Vertices: {len(bm.verts)}\n")
for vertex in bm.verts:
file.write(f"Vertex {vertex.index}: {vertex.co}\n")
# Убедимся, что у меша есть UV слой
uv_layer = bm.loops.layers.uv.active
if not uv_layer:
file.write("UV слой не найден.\n")
if uv_layer:
file.write(f"===UV Coordinates:\n")
file.write(f"Face count: {len(bm.faces)}\n")
for face in bm.faces:
file.write(f"Face {face.index}\n")
file.write(f"UV Count: {len(face.loops)}\n")
for loop in face.loops:
uv_coords = loop[uv_layer].uv
file.write(f" UV {uv_coords}\n")
# Записываем нормали
file.write(f"===Normals:\n")
for vertex in bm.verts:
file.write(f"Vertex {vertex.index}: Normal {vertex.normal}\n")
# Записываем треугольники (индексы вершин)
file.write(f"===Triangles: {len(bm.faces)}\n")
for face in bm.faces:
if len(face.verts) == 3: # Проверяем, что это треугольник
verts_indices = [vert.index for vert in face.verts]
file.write(f"Triangle: {verts_indices}\n")
# Возвращаемся в объектный режим
bpy.ops.object.mode_set(mode='OBJECT')
# Записываем веса вершин
file.write("=== Vertex Weights ===\n")
for vertex in mesh_copy.data.vertices:
file.write(f"Vertex {vertex.index}:\n")
file.write(f"Vertex groups: {len(vertex.groups)}\n")
for group in vertex.groups:
group_name = mesh_copy.vertex_groups[group.group].name
file.write(f" Group: '{group_name}', Weight: {group.weight}\n")
# Удаляем временную копию mesh
bpy.data.objects.remove(mesh_copy)
else:
file.write(f"Объект с именем '{mesh_name}' не найден или не является mesh.\n")
# Обработка арматуры и анимации
if armature_obj and armature_obj.type == 'ARMATURE':
# Получаем все ключевые кадры для арматуры
file.write("=== Animation Keyframes ===\n")
if armature_obj.animation_data and armature_obj.animation_data.action:
action = armature_obj.animation_data.action
# Собираем все уникальные ключевые кадры
keyframes = set()
# Логика для Blender 5.0 (Strip-based / ChannelBag structure)
if hasattr(action, "layers"):
for layer in action.layers:
if hasattr(layer, "strips"):
for strip in layer.strips:
# Проверяем наличие channelbags (согласно вашему dir(strip))
if hasattr(strip, "channelbags"):
for bag in strip.channelbags:
for fcurve in bag.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
# На случай, если в этой версии используется единственное число
elif hasattr(strip, "channelbag") and strip.channelbag:
for fcurve in strip.channelbag.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
# Фоллбек для Legacy экшенов
if not keyframes and hasattr(action, "fcurves"):
for fcurve in action.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
keyframes = sorted(keyframes)
# Сортируем ключевые кадры
keyframes = sorted(keyframes)
# Сохраняем координаты и матрицы поворота для каждой кости на каждом ключевом кадре
file.write("=== Bone Transforms per Keyframe ===\n")
file.write(f"Keyframes: {len(keyframes)}\n")
for frame in keyframes:
# Устанавливаем текущий кадр
bpy.context.scene.frame_set(frame)
bpy.context.view_layer.update() # Обновляем сцену
file.write(f"Frame: {frame}\n")
for bone in armature_obj.pose.bones:
# Получаем координаты и матрицу поворота кости в мировом пространстве
matrix = bone.matrix
location = matrix.translation
rotation = matrix.to_euler()
# Записываем данные
file.write(f" Bone: {bone.name}\n")
file.write(f" Location: {location}\n")
file.write(f" Rotation: {rotation}\n")
file.write(f" Matrix:\n")
for row in matrix:
file.write(f" {row}\n")
else:
file.write(f"Объект с именем '{armature_name}' не найден или не является арматурой.\n")
print("Данные сохранены в файл 'mesh_armature_and_animation_data.txt'")

View File

@ -0,0 +1,228 @@
import bpy
import bmesh
#!
# Имена mesh и арматуры
mesh_name = "Joined"
armature_name = "Armature"
# Находим объект mesh по имени
mesh_obj = bpy.data.objects.get(mesh_name)
# Находим объект арматуры по имени
armature_obj = bpy.data.objects.get(armature_name)
# Устанавливаем текущий кадр на 0
bpy.context.scene.frame_set(0)
# Принудительно обновляем сцену, чтобы применить анимацию
bpy.context.view_layer.update()
# Открываем файл для записи
with open("C:\\Work\\Media\\witcher\\2026-04-13\\output\\gg_stand_idle001.txt", "w") as file:
# Обработка арматуры и анимации
if armature_obj and armature_obj.type == 'ARMATURE':
file.write("=== Armature Matrix ===\n")
for row in armature_obj.matrix_world:
file.write(f"{row}\n")
file.write(f"=== Armature Bones: {len(armature_obj.data.bones)}\n")
for bone in armature_obj.data.bones:
# Записываем имя кости, длину и связи
file.write(f"Bone: {bone.name}\n")
file.write(f" HEAD_LOCAL: {bone.head_local}\n")
file.write(f" TAIL_LOCAL: {bone.tail_local}\n")
file.write(f" Length: {(bone.tail_local - bone.head_local).length}\n")
for row in bone.matrix:
file.write(f" {row}\n")
file.write(f" Parent: {bone.parent.name if bone.parent else 'None'}\n")
file.write(f" Children: {[child.name for child in bone.children]}\n")
# Обработка mesh
if mesh_obj and mesh_obj.type == 'MESH':
# Создаем копию mesh, чтобы не изменять оригинал
mesh_copy = mesh_obj.copy()
mesh_copy.data = mesh_obj.data.copy()
bpy.context.collection.objects.link(mesh_copy)
# Убедимся, что объект активен
bpy.context.view_layer.objects.active = mesh_copy
mesh_copy.select_set(True)
# Применяем модификатор Armature (если он есть)
for modifier in mesh_copy.modifiers:
if modifier.type == 'ARMATURE':
# Включаем модификатор, если он отключен
if not modifier.show_viewport:
modifier.show_viewport = True
if not modifier.show_render:
modifier.show_render = True
# Проверяем, что модификатор связан с арматурой
if modifier.object is None:
print(f"Модификатор Armature на объекте {mesh_copy.name} не связан с арматурой. Пропускаем.")
continue
# Временно применяем модификатор, чтобы получить правильные координаты вершин
try:
bpy.ops.object.modifier_apply(modifier=modifier.name)
except RuntimeError as e:
print(f"Ошибка при применении модификатора Armature: {e}")
continue
# Переходим в режим редактирования
bpy.ops.object.mode_set(mode='EDIT')
# Получаем BMesh представление mesh
bm = bmesh.from_edit_mesh(mesh_copy.data)
# Записываем список вершин
file.write(f"===Vertices: {len(bm.verts)}\n")
for vertex in bm.verts:
file.write(f"Vertex {vertex.index}: {vertex.co}\n")
# Убедимся, что у меша есть UV слой
uv_layer = bm.loops.layers.uv.active
if not uv_layer:
file.write("UV слой не найден.\n")
if uv_layer:
file.write(f"===UV Coordinates:\n")
file.write(f"Face count: {len(bm.faces)}\n")
for face in bm.faces:
file.write(f"Face {face.index}\n")
file.write(f"UV Count: {len(face.loops)}\n")
for loop in face.loops:
uv_coords = loop[uv_layer].uv
file.write(f" UV {uv_coords}\n")
# Записываем нормали
file.write(f"===Normals:\n")
for vertex in bm.verts:
file.write(f"Vertex {vertex.index}: Normal {vertex.normal}\n")
# Записываем треугольники (индексы вершин)
file.write(f"===Triangles: {len(bm.faces)}\n")
for face in bm.faces:
if len(face.verts) == 3: # Проверяем, что это треугольник
verts_indices = [vert.index for vert in face.verts]
file.write(f"Triangle: {verts_indices}\n")
# Возвращаемся в объектный режим
bpy.ops.object.mode_set(mode='OBJECT')
# Записываем веса вершин
file.write("=== Vertex Weights (Max 5 bones per vertex) ===\n")
MAX_BONES = 5
for vertex in mesh_copy.data.vertices:
# Извлекаем все группы и веса для текущей вершины
all_weights = []
for group_element in vertex.groups:
all_weights.append({
'index': group_element.group,
'weight': group_element.weight
})
# Если костей больше лимита, фильтруем и перераспределяем
if len(all_weights) > MAX_BONES:
# Сортируем по весу (от большего к меньшему)
all_weights.sort(key=lambda x: x['weight'], reverse=True)
# Берем только топ-5
kept_weights = all_weights[:MAX_BONES]
# Считаем сумму весов оставшихся костей для нормализации
total_weight = sum(gw['weight'] for gw in kept_weights)
if total_weight > 0:
for gw in kept_weights:
gw['weight'] /= total_weight
else:
# На случай, если у всех веса были по 0.0 (редкий баг меша)
kept_weights[0]['weight'] = 1.0
final_weights = kept_weights
else:
final_weights = all_weights
file.write(f"Vertex {vertex.index}:\n")
file.write(f"Vertex groups: {len(final_weights)}\n")
for gw in final_weights:
group_name = mesh_copy.vertex_groups[gw['index']].name
file.write(f" Group: '{group_name}', Weight: {gw['weight']:.6f}\n")
# Удаляем временную копию mesh
bpy.data.objects.remove(mesh_copy)
else:
file.write(f"Объект с именем '{mesh_name}' не найден или не является mesh.\n")
# Обработка арматуры и анимации
if armature_obj and armature_obj.type == 'ARMATURE':
# Получаем все ключевые кадры для арматуры
file.write("=== Animation Keyframes ===\n")
if armature_obj.animation_data and armature_obj.animation_data.action:
action = armature_obj.animation_data.action
# Собираем все уникальные ключевые кадры
keyframes = set()
# Логика для Blender 5.0 (Strip-based / ChannelBag structure)
if hasattr(action, "layers"):
for layer in action.layers:
if hasattr(layer, "strips"):
for strip in layer.strips:
# Проверяем наличие channelbags (согласно вашему dir(strip))
if hasattr(strip, "channelbags"):
for bag in strip.channelbags:
for fcurve in bag.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
# На случай, если в этой версии используется единственное число
elif hasattr(strip, "channelbag") and strip.channelbag:
for fcurve in strip.channelbag.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
# Фоллбек для Legacy экшенов
if not keyframes and hasattr(action, "fcurves"):
for fcurve in action.fcurves:
for keyframe in fcurve.keyframe_points:
keyframes.add(int(keyframe.co[0]))
keyframes = sorted(keyframes)
# Сортируем ключевые кадры
keyframes = sorted(keyframes)
# Сохраняем координаты и матрицы поворота для каждой кости на каждом ключевом кадре
file.write("=== Bone Transforms per Keyframe ===\n")
file.write(f"Keyframes: {len(keyframes)}\n")
for frame in keyframes:
# Устанавливаем текущий кадр
bpy.context.scene.frame_set(frame)
bpy.context.view_layer.update() # Обновляем сцену
file.write(f"Frame: {frame}\n")
for bone in armature_obj.pose.bones:
# Получаем координаты и матрицу поворота кости в мировом пространстве
matrix = bone.matrix
location = matrix.translation
rotation = matrix.to_euler()
# Записываем данные
file.write(f" Bone: {bone.name}\n")
file.write(f" Location: {location}\n")
file.write(f" Rotation: {rotation}\n")
file.write(f" Matrix:\n")
for row in matrix:
file.write(f" {row}\n")
else:
file.write(f"Объект с именем '{armature_name}' не найден или не является арматурой.\n")
print("Данные сохранены в файл 'mesh_armature_and_animation_data.txt'")

View File

@ -0,0 +1,111 @@
import bpy
import bmesh
import mathutils
import random
import math
class SolidTreeGenerator:
def __init__(self, levels=5, length=3.0, radius=0.3):
self.levels = levels
self.base_length = length
self.base_radius = radius
# Хранилище для данных: (start_pos, end_pos, radius_start, radius_end)
self.branches_data = []
def calculate_tree(self, start_pos, direction, length, radius, level):
if level <= 0 or length < 0.1:
return
end_pos = start_pos + direction * length
# Сохраняем данные сегмента
self.branches_data.append({
'start': start_pos.copy(),
'end': end_pos.copy(),
'r_start': radius,
'r_end': radius * 0.7
})
# 1. Основной ствол (продолжение)
trunk_dir = (direction + self.get_random_vector(0.1)).normalized()
self.calculate_tree(end_pos, trunk_dir, length * 0.8, radius * 0.7, level - 1)
# 2. Боковые ветки (ветвление)
if level > 1:
num_sides = random.randint(2, 3) # Минимум 2 ветки для видимости
for _ in range(num_sides):
# Создаем вектор, сильно отклоненный от ствола (30-60 градусов)
axis = self.get_random_vector(1.0).normalized()
angle = math.radians(random.uniform(30, 60))
side_dir = direction.copy()
side_dir.rotate(mathutils.Quaternion(axis, angle))
# Боковые ветки короче
self.calculate_tree(end_pos, side_dir, length * 0.6, radius * 0.5, level - 1)
def get_random_vector(self, intensity):
return mathutils.Vector((
random.uniform(-intensity, intensity),
random.uniform(-intensity, intensity),
random.uniform(-intensity, intensity)
))
def build_mesh(self):
mesh = bpy.data.meshes.new("TreeMesh")
obj = bpy.data.objects.new("Tree", mesh)
bpy.context.collection.objects.link(obj)
bm = bmesh.new()
skin_layer = bm.verts.layers.skin.verify()
# Словарь для предотвращения дублирования вершин в одной точке
# Ключ - кортеж координат, Значение - объект вершины BMesh
vert_map = {}
for b in self.branches_data:
# Превращаем координаты в кортежи для словаря
s_key = tuple(round(v, 4) for v in b['start'])
e_key = tuple(round(v, 4) for v in b['end'])
# Получаем или создаем начальную вершину
if s_key not in vert_map:
v_start = bm.verts.new(b['start'])
v_start[skin_layer].radius = (b['r_start'], b['r_start'])
vert_map[s_key] = v_start
else:
v_start = vert_map[s_key]
# Получаем или создаем конечную вершину
if e_key not in vert_map:
v_end = bm.verts.new(b['end'])
v_end[skin_layer].radius = (b['r_end'], b['r_end'])
vert_map[e_key] = v_end
else:
v_end = vert_map[e_key]
# Создаем ребро, если его еще нет
if not bm.edges.get((v_start, v_end)):
bm.edges.new((v_start, v_end))
# Находим корень (самую нижнюю точку) и помечаем его
root_v = min(bm.verts, key=lambda v: v.co.z)
root_v[skin_layer].use_root = True
bm.to_mesh(mesh)
bm.free()
# Модификаторы
obj.modifiers.new(name="Skin", type='SKIN')
sub = obj.modifiers.new(name="Subdiv", type='SUBSURF')
sub.levels = 1 # Для начала 1, чтобы не тормозило
# Очистка сцены
bpy.ops.object.select_all(action='SELECT')
bpy.ops.object.delete()
# Запуск
generator = SolidTreeGenerator(levels=5, length=3.0, radius=0.4)
generator.calculate_tree(mathutils.Vector((0,0,0)), mathutils.Vector((0,0,1)), 3.0, 0.4, 5)
generator.build_mesh()

View File

@ -25,7 +25,7 @@ macro(check_and_download URL ARCHIVE_NAME EXTRACTED_DIR_NAME CHECK_FILE)
endmacro()
# 1) ZLIB (Нужна только для инклудов, если не используете emscripten порты)
check_and_download("https://www.zlib.net/zlib131.zip" "zlib131.zip" "zlib-1.3.1" "CMakeLists.txt")
check_and_download("https://www.zlib.net/zlib132.zip" "zlib132.zip" "zlib-1.3.2" "CMakeLists.txt")
# 2) SDL2
check_and_download("https://github.com/libsdl-org/SDL/archive/refs/tags/release-2.32.10.zip" "release-2.32.10.zip" "SDL-release-2.32.10" "CMakeLists.txt")
@ -47,3 +47,12 @@ check_and_download("https://download.savannah.gnu.org/releases/freetype/freetype
# 8) SDL_ttf
check_and_download("https://github.com/libsdl-org/SDL_ttf/archive/refs/tags/release-2.24.0.zip" "release-2.24.0.zip" "SDL_ttf-release-2.24.0" "CMakeLists.txt")
# 9) Lua
check_and_download("https://github.com/lua/lua/archive/refs/tags/v5.4.8.zip" "lua-v5.4.8.zip" "lua-5.4.8" "lapi.c")
# 10) sol2 (header-only C++ bindings for Lua)
check_and_download("https://github.com/ThePhD/sol2/archive/refs/tags/v3.3.0.zip" "sol2-v3.3.0.zip" "sol2-3.3.0" "include/sol/sol.hpp")
# 11) SDL2_mixer
check_and_download("https://github.com/libsdl-org/SDL_mixer/archive/refs/tags/release-2.8.0.zip" "SDL_mixer-release-2.8.0.zip" "SDL_mixer-release-2.8.0" "CMakeLists.txt")

View File

@ -8,11 +8,16 @@ endmacro()
set(BUILD_CONFIGS Debug Release)
# Map MinSizeRel and RelWithDebInfo to Release libs for all imported targets.
# Without this CMake warns that IMPORTED_LOCATION is missing for those configs.
set(CMAKE_MAP_IMPORTED_CONFIG_MINSIZEREL Release)
set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release)
# ===========================================
# 1) ZLIB (zlib131.zip zlib-1.3.1) - без изменений
# 1) ZLIB (zlib131.zip zlib-1.3.2) - без изменений
# ===========================================
set(ZLIB_SRC_DIR "${THIRDPARTY_DIR}/zlib-1.3.1")
set(ZLIB_SRC_DIR "${THIRDPARTY_DIR}/zlib-1.3.2")
set(ZLIB_BUILD_DIR "${ZLIB_SRC_DIR}/build")
set(ZLIB_INSTALL_DIR "${ZLIB_SRC_DIR}/install")
@ -76,8 +81,8 @@ set_target_properties(zlib_external_lib PROPERTIES
#IMPORTED_LOCATION_RELEASE "${ZLIB_INSTALL_DIR}/lib/zlib.lib"
# Можно также указать статические библиотеки, если вы хотите их использовать
IMPORTED_LOCATION_DEBUG "${ZLIB_INSTALL_DIR}/lib/zlibstaticd.lib"
IMPORTED_LOCATION_RELEASE "${ZLIB_INSTALL_DIR}/lib/zlibstatic.lib"
IMPORTED_LOCATION_DEBUG "${ZLIB_INSTALL_DIR}/lib/zsd.lib"
IMPORTED_LOCATION_RELEASE "${ZLIB_INSTALL_DIR}/lib/zs.lib"
INTERFACE_INCLUDE_DIRECTORIES "${ZLIB_INSTALL_DIR}/include"
)
@ -547,3 +552,177 @@ if(NOT TARGET boost_external_lib)
# Boost заголовки находятся непосредственно в корне распакованной папки
target_include_directories(boost_external_lib INTERFACE "${BOOST_SRC_DIR}")
endif()
# ===========================================
# 9) Lua (5.5.0) - embedded scripting language
# ===========================================
set(LUA_SRC_DIR "${THIRDPARTY_DIR}/lua-5.4.8")
if(NOT TARGET lua_static)
file(GLOB LUA_SOURCES "${LUA_SRC_DIR}/*.c")
# Exclude the standalone interpreter, compiler, and unity-build wrapper.
# onelua.c #includes all other .c files compiling it alongside them
# causes every symbol to be defined twice.
list(REMOVE_ITEM LUA_SOURCES
"${LUA_SRC_DIR}/lua.c"
"${LUA_SRC_DIR}/luac.c"
"${LUA_SRC_DIR}/onelua.c"
)
add_library(lua_static STATIC ${LUA_SOURCES})
target_include_directories(lua_static PUBLIC "${LUA_SRC_DIR}")
target_compile_definitions(lua_static PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()
# ===========================================
# 10) sol2 (3.3.0) - header-only C++ bindings for Lua
# ===========================================
set(SOL2_SRC_DIR "${THIRDPARTY_DIR}/sol2-3.3.0")
# Apply patch for Clang/Emscripten compatibility in optional<T&>::emplace().
# The sentinel file prevents re-applying on subsequent cmake runs.
set(_sol2_sentinel "${SOL2_SRC_DIR}/.patched")
if(NOT EXISTS "${_sol2_sentinel}")
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} apply --ignore-whitespace
"${CMAKE_CURRENT_LIST_DIR}/patches/sol2-3.3.0-clang-optional.patch"
WORKING_DIRECTORY "${SOL2_SRC_DIR}"
RESULT_VARIABLE _sol2_patch_res
)
if(_sol2_patch_res EQUAL 0)
file(WRITE "${_sol2_sentinel}" "patched\n")
message(STATUS "Applied sol2 Clang optional patch")
else()
message(WARNING "sol2 patch failed (exit ${_sol2_patch_res}) — Clang/Emscripten builds may not compile")
endif()
else()
message(WARNING "Git not found — cannot apply sol2 patch automatically. "
"Apply cmake/patches/sol2-3.3.0-clang-optional.patch manually.")
endif()
endif()
if(NOT TARGET sol2_external_lib)
add_library(sol2_external_lib INTERFACE)
target_include_directories(sol2_external_lib INTERFACE "${SOL2_SRC_DIR}/include")
target_link_libraries(sol2_external_lib INTERFACE lua_static)
endif()
# ===========================================
# 11) SDL2_mixer (2.8.0) сборка из исходников
# ===========================================
set(SDL2MIXER_SRC_DIR "${THIRDPARTY_DIR}/SDL_mixer-release-2.8.0")
set(SDL2MIXER_BASE_DIR "${SDL2MIXER_SRC_DIR}/install")
set(SDL2MIXER_BASE_DIR "${SDL2MIXER_BASE_DIR}" CACHE PATH "SDL2_mixer install base directory" FORCE)
set(_have_sdl2mixer TRUE)
foreach(cfg IN LISTS BUILD_CONFIGS)
if(NOT EXISTS "${SDL2MIXER_BASE_DIR}-${cfg}/lib/SDL2_mixer.lib" AND
NOT EXISTS "${SDL2MIXER_BASE_DIR}-${cfg}/lib/SDL2_mixerd.lib")
set(_have_sdl2mixer FALSE)
endif()
endforeach()
if(NOT _have_sdl2mixer)
foreach(cfg IN LISTS BUILD_CONFIGS)
if(cfg STREQUAL "Debug")
set(_SDL2_LIB "${SDL2_INSTALL_DIR}/lib/SDL2d.lib")
else()
set(_SDL2_LIB "${SDL2_INSTALL_DIR}/lib/SDL2.lib")
endif()
log("Configuring SDL2_mixer (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
-G "${CMAKE_GENERATOR}"
-S "${SDL2MIXER_SRC_DIR}"
-B "${SDL2MIXER_SRC_DIR}/build-${cfg}"
-DCMAKE_INSTALL_PREFIX=${SDL2MIXER_BASE_DIR}-${cfg}
-DCMAKE_PREFIX_PATH=${SDL2_INSTALL_DIR}
-DSDL2_LIBRARY=${_SDL2_LIB}
-DSDL2_INCLUDE_DIR=${SDL2_INSTALL_DIR}/include/SDL2
-DSDL2MIXER_DEPS_SHARED=OFF
-DSDL2MIXER_VENDORED=ON
-DSDL2MIXER_SAMPLES=OFF
-DSDL2MIXER_MUSIC_CMD=OFF
-DSDL2MIXER_MOD=OFF
-DSDL2MIXER_MIDI=OFF
-DSDL2MIXER_OPUS=OFF
-DSDL2MIXER_WAVPACK=OFF
-DSDL2MIXER_MP3_MPG123=OFF
-DSDL2MIXER_MP3_DRMP3=ON
-DSDL2MIXER_FLAC_DRFLAC=ON
-DSDL2MIXER_OGG_STB=ON
-DCMAKE_DISABLE_FIND_PACKAGE_OGG=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_Vorbis=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_FLAC=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_MPG123=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_LibModPlug=TRUE
-DCMAKE_DISABLE_FIND_PACKAGE_FluidLite=TRUE
RESULT_VARIABLE _mixer_cfg_res
OUTPUT_VARIABLE _mixer_cfg_out
ERROR_VARIABLE _mixer_cfg_err
)
if(NOT _mixer_cfg_res EQUAL 0)
message(STATUS "SDL2_mixer configure stdout: ${_mixer_cfg_out}")
message(STATUS "SDL2_mixer configure stderr: ${_mixer_cfg_err}")
message(FATAL_ERROR "SDL2_mixer configure failed for ${cfg}")
endif()
log("Building SDL2_mixer (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--build "${SDL2MIXER_SRC_DIR}/build-${cfg}" --config ${cfg}
RESULT_VARIABLE _mixer_build_res
)
if(NOT _mixer_build_res EQUAL 0)
message(FATAL_ERROR "SDL2_mixer build failed for ${cfg}")
endif()
log("Installing SDL2_mixer (${cfg}) ...")
execute_process(
COMMAND ${CMAKE_COMMAND}
--install "${SDL2MIXER_SRC_DIR}/build-${cfg}" --config ${cfg}
RESULT_VARIABLE _mixer_inst_res
)
if(NOT _mixer_inst_res EQUAL 0)
message(FATAL_ERROR "SDL2_mixer install failed for ${cfg}")
endif()
endforeach()
endif()
set(_mixer_debug_lib "")
foreach(cand
"${SDL2MIXER_BASE_DIR}-Debug/lib/SDL2_mixerd.lib"
"${SDL2MIXER_BASE_DIR}-Debug/lib/SDL2_mixer.lib"
)
if(EXISTS "${cand}")
set(_mixer_debug_lib "${cand}")
break()
endif()
endforeach()
set(_mixer_release_lib "")
foreach(cand
"${SDL2MIXER_BASE_DIR}-Release/lib/SDL2_mixer.lib"
)
if(EXISTS "${cand}")
set(_mixer_release_lib "${cand}")
break()
endif()
endforeach()
if(_mixer_debug_lib STREQUAL "" OR _mixer_release_lib STREQUAL "")
message(FATAL_ERROR "SDL2_mixer libs not found in ${SDL2MIXER_BASE_DIR}-Debug/Release")
endif()
add_library(SDL2_mixer_external_lib UNKNOWN IMPORTED GLOBAL)
set_target_properties(SDL2_mixer_external_lib PROPERTIES
IMPORTED_LOCATION_DEBUG "${_mixer_debug_lib}"
IMPORTED_LOCATION_RELEASE "${_mixer_release_lib}"
INTERFACE_INCLUDE_DIRECTORIES
"$<IF:$<CONFIG:Debug>,${SDL2MIXER_BASE_DIR}-Debug/include,${SDL2MIXER_BASE_DIR}-Release/include>"
INTERFACE_LINK_LIBRARIES
"SDL2_external_lib"
)

View File

@ -0,0 +1,14 @@
--- a/include/sol/optional_implementation.hpp
+++ b/include/sol/optional_implementation.hpp
@@ -2189,7 +2189,10 @@
template <class... Args>
T& emplace(Args&&... args) noexcept {
static_assert(std::is_constructible<T, Args&&...>::value, "T must be constructible with Args");
*this = nullopt;
- this->construct(std::forward<Args>(args)...);
+ // Reference specialization stores a pointer; set it directly.
+ // construct() only exists in the non-reference specialization.
+ m_value = std::addressof(std::forward<Args>(args)...);
+ return *m_value;
}

View File

@ -1,156 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": 1280,
"height": 720,
"children": [
{
"type": "FrameLayout",
"name": "leftPanel",
"x": 100,
"y": 100,
"width": 320,
"height": 400,
"children": [
{
"type": "LinearLayout",
"name": "mainButtons",
"orientation": "vertical",
"spacing": 10,
"x": 0,
"y": 0,
"width": 300,
"height": 300,
"children": [
{
"type": "Button",
"name": "playButton",
"x": 100,
"y": 300,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
}
},
"textures": {
"normal": "./resources/button.png",
"hover": "./resources/sand.png",
"pressed": "./resources/button.png"
}
},
{
"type": "Button",
"name": "settingsButton",
"x": 100,
"y": 200,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "wait",
"duration": 0.5
},
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
}
},
"textures": {
"normal": "./resources/sand.png",
"hover": "./resources/button.png",
"pressed": "./resources/sand.png"
}
},
{
"type": "Button",
"name": "exitButton",
"x": 100,
"y": 100,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "wait",
"duration": 1.0
},
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
},
"bgScroll": {
"repeat": true,
"steps": [
{
"type": "move",
"to": [
1280,
0
],
"duration": 5.0,
"easing": "linear"
}
]
}
},
"textures": {
"normal": "./resources/rock.png",
"hover": "./resources/button.png",
"pressed": "./resources/rock.png"
}
}
]
}
]
},
{
"type": "Slider",
"name": "musicVolumeSlider",
"x": 1140,
"y": 100,
"width": 10,
"height": 500,
"value": 0.5,
"orientation": "vertical",
"textures": {
"track": "./resources/musicVolumeBarTexture.png",
"knob": "./resources/musicVolumeBarButton.png"
}
}
]
}
}

323
convert_anim_to_binary.py Normal file
View File

@ -0,0 +1,323 @@
#!/usr/bin/env python3
"""
Convert a text-based bone animation file to the BSAF binary format.
Usage:
python convert_anim_to_binary.py <input.txt> <output.bin>
Binary format (BSAF v2) -- all values little-endian:
HEADER
4 bytes magic "BSAF"
uint32 version (2)
BONES
uint32 numBones
per bone:
3 x float boneStartWorld (from HEAD_LOCAL)
float boneLength
9 x float 3x3 rotation matrix (row-major)
int32 parentIndex (-1 if none)
uint32 numChildren
numChildren x int32 childIndices
BONE NAMES (v2+)
per bone:
uint32 nameLen
nameLen bytes UTF-8 name (no terminator)
VERTICES
uint32 numVertices
numVertices x 3 x float positions
UV COORDINATES
uint32 numFaces
numFaces x 6 x float 3 UV pairs per face (u0,v0,u1,v1,u2,v2)
NORMALS
numVertices x 3 x float normals
TRIANGLES
uint32 numTriangles
numTriangles x 3 x int32 vertex indices
VERTEX WEIGHTS
per vertex (numVertices):
uint32 numGroups
numGroups x (int32 boneIndex, float weight)
ANIMATION KEYFRAMES
uint32 numKeyframes
per keyframe:
int32 frameNumber
per bone (numBones, in index order 0..N-1):
3 x float location
16 x float 4x4 matrix (row-major)
"""
import struct
import re
import sys
def parse_floats(line):
return [float(x) for x in re.findall(r'[-]?\d+\.\d+', line)]
def parse_first_int(line):
m = re.search(r'\d+', line)
if m:
return int(m.group())
raise ValueError(f"No integer found in: {line}")
def parse_children(line):
return re.findall(r"'([^']+)'", line)
def convert(input_path, output_path):
with open(input_path, 'r', encoding='utf-8', errors='replace') as f:
lines = f.readlines()
idx = 0
def next_line():
nonlocal idx
line = lines[idx].rstrip()
idx += 1
return line
# --- Skip armature matrix (5 lines) ---
for _ in range(5):
next_line()
# --- Bone count ---
line = next_line() # "=== Armature Bones: 65"
num_bones = parse_first_int(line)
bone_names = []
bones = []
bone_parent_names = []
bone_children_names = []
for _ in range(num_bones):
bone = {}
# "Bone: mixamorig:Hips"
line = next_line()
bone_name = line[6:]
bone_names.append(bone_name)
# " HEAD_LOCAL: <Vector (x, y, z)>"
line = next_line()
bone['head'] = parse_floats(line)[:3]
# " TAIL_LOCAL: ..." -- skip
next_line()
# " Length: 0.123"
line = next_line()
bone['length'] = parse_floats(line)[0]
# 3x3 matrix (3 rows)
mat = []
for _ in range(3):
mat.extend(parse_floats(next_line()))
bone['matrix_3x3'] = mat
# " Parent: None" or " Parent: boneName"
line = next_line()
if line == " Parent: None":
bone_parent_names.append(None)
else:
bone_parent_names.append(line[10:])
# " Children: ['a', 'b'] or []"
line = next_line()
bone_children_names.append(parse_children(line))
bones.append(bone)
# Build name -> index map
name_to_idx = {name: i for i, name in enumerate(bone_names)}
# Resolve parent / child indices
for i in range(num_bones):
if bone_parent_names[i] is None:
bones[i]['parent'] = -1
else:
bones[i]['parent'] = name_to_idx[bone_parent_names[i]]
bones[i]['children'] = [name_to_idx[c] for c in bone_children_names[i]]
# --- Vertices ---
line = next_line() # "===Vertices: 5140"
num_vertices = parse_first_int(line)
vertices = []
for _ in range(num_vertices):
vertices.append(parse_floats(next_line())[:3])
# --- UV Coordinates ---
next_line() # "===UV Coordinates:"
line = next_line() # "Face count: 8602"
num_faces = parse_first_int(line)
uvs = []
for _ in range(num_faces):
next_line() # "Face N"
next_line() # "UV Count: 3"
face_uvs = []
for _ in range(3):
face_uvs.extend(parse_floats(next_line())[:2])
uvs.append(face_uvs) # 6 floats
# --- Normals ---
next_line() # "===Normals:"
normals = []
for _ in range(num_vertices):
normals.append(parse_floats(next_line())[:3])
# --- Triangles ---
line = next_line() # "===Triangles: 8602"
num_triangles = parse_first_int(line)
triangles = []
for _ in range(num_triangles):
line = next_line()
ints = [int(x) for x in re.findall(r'[-]?\d+', line)]
triangles.append(ints[:3])
# --- Vertex Weights ---
next_line() # "=== Vertex Weights ..."
vertex_weights = []
for _ in range(num_vertices):
next_line() # "Vertex N:"
line = next_line() # "Vertex groups: 2"
num_groups = parse_first_int(line)
groups = []
for _ in range(num_groups):
line = next_line()
m = re.search(r"'([^']+)'.*?([-]?\d+\.\d+)", line)
bone_name = m.group(1)
weight = float(m.group(2))
groups.append((name_to_idx[bone_name], weight))
vertex_weights.append(groups)
# --- Animation Keyframes ---
next_line() # "=== Animation Keyframes ==="
next_line() # "=== Bone Transforms per Keyframe ==="
line = next_line() # "Keyframes: 32"
num_keyframes = parse_first_int(line)
keyframes = []
for _ in range(num_keyframes):
line = next_line() # "Frame: 0"
frame_number = parse_first_int(line)
bone_data = {}
for _ in range(num_bones):
line = next_line() # " Bone: mixamorig:Hips"
bone_name = line.strip()
if bone_name.startswith("Bone: "):
bone_name = bone_name[6:]
bone_idx = name_to_idx[bone_name]
# Location
location = parse_floats(next_line())[:3]
# Rotation (skip)
next_line()
# " Matrix:" (skip header)
next_line()
# 4 rows of 4 floats
matrix = []
for _ in range(4):
matrix.extend(parse_floats(next_line()))
bone_data[bone_idx] = {
'location': location,
'matrix': matrix,
}
keyframes.append((frame_number, bone_data))
# ================================================================
# Write binary file
# ================================================================
with open(output_path, 'wb') as out:
# Header
out.write(b'BSAF')
out.write(struct.pack('<I', 2))
# Bones
out.write(struct.pack('<I', num_bones))
for i in range(num_bones):
b = bones[i]
out.write(struct.pack('<3f', *b['head']))
out.write(struct.pack('<f', b['length']))
out.write(struct.pack('<9f', *b['matrix_3x3']))
out.write(struct.pack('<i', b['parent']))
out.write(struct.pack('<I', len(b['children'])))
for c in b['children']:
out.write(struct.pack('<i', c))
# Bone names (v2+)
for name in bone_names:
name_bytes = name.encode('utf-8')
out.write(struct.pack('<I', len(name_bytes)))
out.write(name_bytes)
# Vertices
out.write(struct.pack('<I', num_vertices))
for v in vertices:
out.write(struct.pack('<3f', *v))
# UV Coordinates
out.write(struct.pack('<I', num_faces))
for uv in uvs:
out.write(struct.pack('<6f', *uv))
# Normals
for n in normals:
out.write(struct.pack('<3f', *n))
# Triangles
out.write(struct.pack('<I', num_triangles))
for t in triangles:
out.write(struct.pack('<3i', *t))
# Vertex Weights
for vw in vertex_weights:
out.write(struct.pack('<I', len(vw)))
for bone_idx, weight in vw:
out.write(struct.pack('<if', bone_idx, weight))
# Animation Keyframes
out.write(struct.pack('<I', num_keyframes))
for frame_num, bone_data in keyframes:
out.write(struct.pack('<i', frame_num))
for i in range(num_bones):
bd = bone_data[i]
out.write(struct.pack('<3f', *bd['location']))
out.write(struct.pack('<16f', *bd['matrix']))
input_size = sum(len(l) for l in lines)
import os
output_size = os.path.getsize(output_path)
print(f"Converted: {input_path} ({input_size:,} bytes text) -> {output_path} ({output_size:,} bytes binary)")
print(f" Bones: {num_bones}, Vertices: {num_vertices}, Faces: {num_faces}, "
f"Triangles: {num_triangles}, Keyframes: {num_keyframes}")
if __name__ == '__main__':
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <input.txt> <output.bin>")
sys.exit(1)
convert(sys.argv[1], sys.argv[2])

View File

@ -0,0 +1,370 @@
#!/usr/bin/env python3
"""
Convert a text-based multi-mesh bone animation file to the BSMF binary format.
Usage:
python convert_anim_to_binary_new.py <input.txt> <output.bin>
Binary format (BSMF v2) -- all values little-endian:
HEADER
4 bytes magic "BSMF"
uint32 version (2)
ARMATURE MATRIX
16 x float 4x4 matrix (row-major)
BONES
uint32 numBones
per bone:
3 x float boneStartWorld (from HEAD_LOCAL)
float boneLength
9 x float 3x3 rotation matrix (row-major)
int32 parentIndex (-1 if none)
uint32 numChildren
numChildren x int32 childIndices
BONE NAMES
per bone:
uint32 nameLen
nameLen bytes UTF-8 name (no terminator)
MESHES
uint32 numMeshes
per mesh:
uint32 nameLength
nameLength x char meshName (UTF-8, no null terminator)
VERTICES
uint32 numVertices
numVertices x 3 x float positions
UV COORDINATES
uint32 numFaces
numFaces x 6 x float 3 UV pairs per face (u0,v0,u1,v1,u2,v2)
NORMALS
numVertices x 3 x float normals
TRIANGLES
uint32 numTriangles
numTriangles x 3 x int32 vertex indices
VERTEX WEIGHTS
per vertex (numVertices):
uint32 numGroups
numGroups x (int32 boneIndex, float weight)
ANIMATION KEYFRAMES
uint32 numKeyframes
per keyframe:
int32 frameNumber
per bone (numBones, in index order 0..N-1):
3 x float location
16 x float 4x4 matrix (row-major)
"""
import struct
import re
import sys
def parse_floats(line):
return [float(x) for x in re.findall(r'[-]?\d+\.\d+', line)]
def parse_first_int(line):
m = re.search(r'\d+', line)
if m:
return int(m.group())
raise ValueError(f"No integer found in: {line}")
def parse_children(line):
return re.findall(r"'([^']+)'", line)
def convert(input_path, output_path):
with open(input_path, 'r', encoding='utf-8', errors='replace') as f:
lines = f.readlines()
idx = 0
def next_line():
nonlocal idx
line = lines[idx].rstrip()
idx += 1
return line
# --- Armature matrix header + 4 rows ---
next_line() # "=== Armature Matrix ==="
armature_matrix = []
for _ in range(4):
armature_matrix.extend(parse_floats(next_line())[:4])
# --- Bone count ---
line = next_line() # "=== Armature Bones: 65"
num_bones = parse_first_int(line)
bone_names = []
bones = []
bone_parent_names = []
bone_children_names = []
for _ in range(num_bones):
bone = {}
# "Bone: mixamorig:Hips"
line = next_line()
bone_name = line[6:]
bone_names.append(bone_name)
# " HEAD_LOCAL: <Vector (x, y, z)>"
line = next_line()
bone['head'] = parse_floats(line)[:3]
# " TAIL_LOCAL: ..." -- skip
next_line()
# " Length: 0.123"
line = next_line()
bone['length'] = parse_floats(line)[0]
# 3x3 matrix (3 rows)
mat = []
for _ in range(3):
mat.extend(parse_floats(next_line()))
bone['matrix_3x3'] = mat
# " Parent: None" or " Parent: boneName"
line = next_line()
if line == " Parent: None":
bone_parent_names.append(None)
else:
bone_parent_names.append(line[10:])
# " Children: ['a', 'b'] or []"
line = next_line()
bone_children_names.append(parse_children(line))
bones.append(bone)
# Build name -> index map
name_to_idx = {name: i for i, name in enumerate(bone_names)}
# Resolve parent / child indices
for i in range(num_bones):
if bone_parent_names[i] is None:
bones[i]['parent'] = -1
else:
bones[i]['parent'] = name_to_idx[bone_parent_names[i]]
bones[i]['children'] = [name_to_idx[c] for c in bone_children_names[i]]
# --- Multi-mesh header ---
line = next_line() # "=== TOTAL MESHES TO EXPORT: 7 ==="
num_meshes = parse_first_int(line)
meshes = []
for _ in range(num_meshes):
# "=== Mesh Object: Name ==="
line = next_line()
m = re.match(r"===\s*Mesh Object:\s*(.+?)\s*===$", line)
if not m:
raise ValueError(f"Invalid mesh header: {line}")
mesh_name = m.group(1)
# --- Vertices ---
line = next_line() # "===Vertices: N"
num_vertices = parse_first_int(line)
vertices = []
for _ in range(num_vertices):
vertices.append(parse_floats(next_line())[:3])
# --- UV Coordinates ---
next_line() # "===UV Coordinates:"
line = next_line() # "Face count: M"
num_faces = parse_first_int(line)
uvs = []
for _ in range(num_faces):
next_line() # "Face N"
next_line() # "UV Count: 3"
face_uvs = []
for _ in range(3):
face_uvs.extend(parse_floats(next_line())[:2])
uvs.append(face_uvs)
# --- Normals ---
next_line() # "===Normals:"
normals = []
for _ in range(num_vertices):
normals.append(parse_floats(next_line())[:3])
# --- Triangles ---
line = next_line() # "===Triangles: M"
num_triangles = parse_first_int(line)
triangles = []
for _ in range(num_triangles):
line = next_line()
ints = [int(x) for x in re.findall(r'[-]?\d+', line)]
triangles.append(ints[:3])
# --- Vertex Weights ---
next_line() # "=== Vertex Weights (Max 5 bones per vertex) ==="
vertex_weights = []
for _ in range(num_vertices):
next_line() # "Vertex N:"
line = next_line() # "Vertex groups: K"
num_groups = parse_first_int(line)
groups = []
for _ in range(num_groups):
line = next_line()
m = re.search(r"'([^']+)'.*?([-]?\d+\.\d+)", line)
bone_name = m.group(1)
weight = float(m.group(2))
groups.append((name_to_idx[bone_name], weight))
vertex_weights.append(groups)
meshes.append({
'name': mesh_name,
'num_vertices': num_vertices,
'vertices': vertices,
'num_faces': num_faces,
'uvs': uvs,
'normals': normals,
'num_triangles': num_triangles,
'triangles': triangles,
'vertex_weights': vertex_weights,
})
# --- Animation Keyframes ---
next_line() # "=== Animation Keyframes ==="
next_line() # "=== Bone Transforms per Keyframe ==="
line = next_line() # "Keyframes: N"
num_keyframes = parse_first_int(line)
keyframes = []
for _ in range(num_keyframes):
line = next_line() # "Frame: N"
frame_number = parse_first_int(line)
bone_data = {}
for _ in range(num_bones):
line = next_line() # " Bone: mixamorig:Hips"
bone_name = line.strip()
if bone_name.startswith("Bone: "):
bone_name = bone_name[6:]
bone_idx = name_to_idx[bone_name]
# Location
location = parse_floats(next_line())[:3]
# Rotation (skip)
next_line()
# " Matrix:" (skip header)
next_line()
# 4 rows of 4 floats
matrix = []
for _ in range(4):
matrix.extend(parse_floats(next_line()))
bone_data[bone_idx] = {
'location': location,
'matrix': matrix,
}
keyframes.append((frame_number, bone_data))
# ================================================================
# Write binary file
# ================================================================
with open(output_path, 'wb') as out:
# Header
out.write(b'BSMF')
out.write(struct.pack('<I', 2))
# Armature matrix (16 floats, row-major)
out.write(struct.pack('<16f', *armature_matrix))
# Bones
out.write(struct.pack('<I', num_bones))
for i in range(num_bones):
b = bones[i]
out.write(struct.pack('<3f', *b['head']))
out.write(struct.pack('<f', b['length']))
out.write(struct.pack('<9f', *b['matrix_3x3']))
out.write(struct.pack('<i', b['parent']))
out.write(struct.pack('<I', len(b['children'])))
for c in b['children']:
out.write(struct.pack('<i', c))
# Bone names
for name in bone_names:
name_bytes = name.encode('utf-8')
out.write(struct.pack('<I', len(name_bytes)))
out.write(name_bytes)
# Meshes
out.write(struct.pack('<I', num_meshes))
for md in meshes:
name_bytes = md['name'].encode('utf-8')
out.write(struct.pack('<I', len(name_bytes)))
out.write(name_bytes)
# Vertices
out.write(struct.pack('<I', md['num_vertices']))
for v in md['vertices']:
out.write(struct.pack('<3f', *v))
# UV Coordinates
out.write(struct.pack('<I', md['num_faces']))
for uv in md['uvs']:
out.write(struct.pack('<6f', *uv))
# Normals
for n in md['normals']:
out.write(struct.pack('<3f', *n))
# Triangles
out.write(struct.pack('<I', md['num_triangles']))
for t in md['triangles']:
out.write(struct.pack('<3i', *t))
# Vertex weights
for vw in md['vertex_weights']:
out.write(struct.pack('<I', len(vw)))
for bone_idx, weight in vw:
out.write(struct.pack('<if', bone_idx, weight))
# Animation Keyframes
out.write(struct.pack('<I', num_keyframes))
for frame_num, bone_data in keyframes:
out.write(struct.pack('<i', frame_num))
for i in range(num_bones):
bd = bone_data[i]
out.write(struct.pack('<3f', *bd['location']))
out.write(struct.pack('<16f', *bd['matrix']))
input_size = sum(len(l) for l in lines)
import os
output_size = os.path.getsize(output_path)
print(f"Converted: {input_path} ({input_size:,} bytes text) -> {output_path} ({output_size:,} bytes binary)")
print(f" Bones: {num_bones}, Meshes: {num_meshes}, Keyframes: {num_keyframes}")
for md in meshes:
print(f" - {md['name']}: {md['num_vertices']} verts, "
f"{md['num_faces']} faces, {md['num_triangles']} tris")
if __name__ == '__main__':
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <input.txt> <output.bin>")
sys.exit(1)
convert(sys.argv[1], sys.argv[2])

142
convert_model_to_binary.py Normal file
View File

@ -0,0 +1,142 @@
#!/usr/bin/env python3
"""
Convert a text-based static mesh file (.txt) to binary format (.txt.bin).
Usage:
python convert_model_to_binary.py <input.txt> [<output.bin>]
If the output path is not given it is derived by appending ".bin" to the input path,
e.g. resources/w/firebox.txt -> resources/w/firebox.txt.bin
Binary format (BSMF v1) -- all values little-endian:
HEADER
4 bytes magic "BSMF"
uint32 version (1)
uint32 numVertices
uint32 numTriangles
VERTICES (numVertices entries):
3 x float position x, y, z -- engine coordinate space
3 x float normal x, y, z -- engine coordinate space
2 x float UV u, v
TRIANGLES (numTriangles entries):
3 x uint32 vertex indices i0, i1, i2
The same Blender->engine axis swap applied by LoadFromTextFile02 is baked in here,
so the C++ binary loader can read coordinates directly without any post-processing:
engine_x = blender_y
engine_y = blender_z
engine_z = blender_x
"""
import struct
import re
import sys
import os
def _parse_floats(text):
return [float(x) for x in re.findall(r'[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?', text)]
def _parse_ints(text):
return [int(x) for x in re.findall(r'[-]?\d+', text)]
def _swap_axes(x, y, z):
"""Blender Y-up -> engine coordinate system (mirrors LoadFromTextFile02)."""
return y, z, x
def convert(input_path, output_path):
with open(input_path, 'r', encoding='utf-8') as f:
lines = [line.rstrip('\n') for line in f]
idx = 0
def next_line():
nonlocal idx
while idx < len(lines):
line = lines[idx]
idx += 1
return line
raise EOFError("Unexpected end of file while parsing: " + input_path)
# --- Vertices ---
while True:
line = next_line()
if '===Vertices' in line:
break
m = re.search(r'\d+', line)
if not m:
raise ValueError("Could not parse vertex count from: " + line)
num_vertices = int(m.group())
positions = []
normals = []
uvs = []
for i in range(num_vertices):
line = next_line()
# V N: Pos(x, y, z) Norm(nx, ny, nz) UV(u, v)
nums = _parse_floats(line)
# nums[0] = vertex index (float-parsed), then 3 pos, 3 norm, 2 uv
if len(nums) < 9:
raise ValueError(f"Malformed vertex line {i}: {line}")
px, py, pz = _swap_axes(nums[1], nums[2], nums[3])
nx, ny, nz = _swap_axes(nums[4], nums[5], nums[6])
positions.append((px, py, pz))
normals.append((nx, ny, nz))
uvs.append((nums[7], nums[8]))
# --- Triangles ---
while True:
line = next_line()
if '===Triangles' in line:
break
m = re.search(r'\d+', line)
if not m:
raise ValueError("Could not parse triangle count from: " + line)
num_triangles = int(m.group())
triangles = []
for i in range(num_triangles):
line = next_line()
ints = _parse_ints(line)
if len(ints) != 3:
raise ValueError(f"Malformed triangle line {i}: {line}")
triangles.append(tuple(ints))
# --- Write binary ---
with open(output_path, 'wb') as out:
out.write(b'BSMF')
out.write(struct.pack('<I', 1))
out.write(struct.pack('<I', num_vertices))
out.write(struct.pack('<I', num_triangles))
for i in range(num_vertices):
out.write(struct.pack('<3f', *positions[i]))
out.write(struct.pack('<3f', *normals[i]))
out.write(struct.pack('<2f', *uvs[i]))
for tri in triangles:
out.write(struct.pack('<3I', *tri))
in_size = os.path.getsize(input_path)
out_size = os.path.getsize(output_path)
print(f"Converted: {input_path} ({in_size:,} bytes text) -> {output_path} ({out_size:,} bytes binary)")
print(f" Vertices: {num_vertices}, Triangles: {num_triangles}")
if __name__ == '__main__':
if len(sys.argv) < 2 or len(sys.argv) > 3:
print(f"Usage: {sys.argv[0]} <input.txt> [<output.bin>]")
sys.exit(1)
input_path = sys.argv[1]
output_path = sys.argv[2] if len(sys.argv) == 3 else input_path + '.bin'
convert(input_path, output_path)

View File

@ -0,0 +1,54 @@
#!/usr/bin/env python3
"""
Convert an old single-mesh text animation file to the new multi-mesh text format.
The only structural difference is that the new format wraps the mesh block
between these two extra headers before the "===Vertices:" line:
=== TOTAL MESHES TO EXPORT: 1 ===
=== Mesh Object: Body ===
Usage:
python convert_old_anim_to_new.py <input.txt> <output.txt> [mesh_name]
If mesh_name is omitted, "Body" is used.
"""
import sys
def convert(input_path, output_path, mesh_name="Body"):
with open(input_path, 'r', encoding='utf-8', errors='replace') as f:
lines = f.readlines()
# Find the first "===Vertices:" line -- that's where the bone block ends
# and the mesh block begins in the old format.
insert_at = None
for i, line in enumerate(lines):
if line.lstrip().startswith("===Vertices:"):
insert_at = i
break
if insert_at is None:
raise RuntimeError("Could not find '===Vertices:' line in input file")
header_lines = [
"=== TOTAL MESHES TO EXPORT: 1 ===\n",
f"=== Mesh Object: {mesh_name} ===\n",
]
out_lines = lines[:insert_at] + header_lines + lines[insert_at:]
with open(output_path, 'w', encoding='utf-8') as out:
out.writelines(out_lines)
print(f"Converted: {input_path} -> {output_path} (mesh name: {mesh_name})")
if __name__ == '__main__':
if len(sys.argv) not in (3, 4):
print(f"Usage: {sys.argv[0]} <input.txt> <output.txt> [mesh_name]")
sys.exit(1)
mesh_name = sys.argv[3] if len(sys.argv) == 4 else "Body"
convert(sys.argv[1], sys.argv[2], mesh_name)

View File

@ -47,10 +47,12 @@ add_library(main SHARED
../../../../src/utils/Perlin.cpp
../../../../src/utils/TaskManager.cpp
../../../../src/utils/Utils.cpp
../../../../src/navigation/PathFinder.cpp
../../../../src/planet/PlanetData.cpp
../../../../src/planet/PlanetObject.cpp
../../../../src/planet/StoneObject.cpp
../../../../src/render/FrameBuffer.cpp
../../../../src/render/ShadowMap.cpp
../../../../src/render/Renderer.cpp
../../../../src/render/ShaderManager.cpp
../../../../src/render/TextureManager.cpp

View File

@ -8,7 +8,7 @@ if(NOT CMAKE_MAKE_PROGRAM AND WIN32)
endif()
endif()
project(space-game001 CXX)
project(bishkek-witcher LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
@ -17,11 +17,52 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FetchDependencies.cmake")
# Теперь гарантированно есть папка ../thirdparty со всеми исходниками
# Список исходных файлов (без изменений)
# ===========================================
# Lua (5.5.0) - embedded scripting, pure C, compiles with Emscripten
# ===========================================
set(LUA_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/lua-5.4.8")
file(GLOB LUA_SOURCES "${LUA_SRC_DIR}/*.c")
list(REMOVE_ITEM LUA_SOURCES
"${LUA_SRC_DIR}/lua.c"
"${LUA_SRC_DIR}/luac.c"
"${LUA_SRC_DIR}/onelua.c"
)
add_library(lua_static STATIC ${LUA_SOURCES})
target_include_directories(lua_static PUBLIC "${LUA_SRC_DIR}")
# sol2 (header-only)
set(SOL2_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/sol2-3.3.0")
# Apply patch for Clang/Emscripten compatibility in optional<T&>::emplace().
set(_sol2_sentinel "${SOL2_SRC_DIR}/.patched")
if(NOT EXISTS "${_sol2_sentinel}")
find_package(Git QUIET)
if(GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} apply --ignore-whitespace
"${CMAKE_CURRENT_SOURCE_DIR}/../cmake/patches/sol2-3.3.0-clang-optional.patch"
WORKING_DIRECTORY "${SOL2_SRC_DIR}"
RESULT_VARIABLE _sol2_patch_res
)
if(_sol2_patch_res EQUAL 0)
file(WRITE "${_sol2_sentinel}" "patched\n")
message(STATUS "Applied sol2 Clang optional patch")
else()
message(WARNING "sol2 patch failed (exit ${_sol2_patch_res}) — Clang/Emscripten builds may not compile")
endif()
else()
message(WARNING "Git not found — cannot apply sol2 patch automatically. "
"Apply cmake/patches/sol2-3.3.0-clang-optional.patch manually.")
endif()
endif()
# Список исходных файлов (синхронизирован с proj-windows/CMakeLists.txt)
set(SOURCES
../src/main.cpp
../src/Game.cpp
../src/Game.h
../src/Character.cpp
../src/Character.h
../src/Environment.cpp
../src/Environment.h
../src/render/Renderer.cpp
@ -36,58 +77,67 @@ set(SOURCES
../src/AudioPlayerAsync.h
../src/BoneAnimatedModel.cpp
../src/BoneAnimatedModel.h
../src/BoneAnimatedModelNew.cpp
../src/BoneAnimatedModelNew.h
../src/render/OpenGlExtensions.cpp
../src/render/OpenGlExtensions.h
../src/utils/Utils.cpp
../src/utils/Utils.h
../src/SparkEmitter.cpp
../src/SparkEmitter.h
../src/planet/PlanetObject.cpp
../src/planet/PlanetObject.h
../src/planet/PlanetData.cpp
../src/planet/PlanetData.h
../src/utils/Perlin.cpp
../src/utils/Perlin.h
../src/utils/TaskManager.cpp
../src/utils/TaskManager.h
../src/planet/StoneObject.cpp
../src/planet/StoneObject.h
../src/render/FrameBuffer.cpp
../src/render/FrameBuffer.h
../src/utils/Perlin.cpp
../src/utils/Perlin.h
../src/utils/TaskManager.cpp
../src/utils/TaskManager.h
../src/render/FrameBuffer.cpp
../src/render/FrameBuffer.h
../src/render/ShadowMap.cpp
../src/render/ShadowMap.h
../src/UiManager.cpp
../src/UiManager.h
../src/Projectile.h
../src/Projectile.cpp
../src/network/NetworkInterface.h
../src/network/LocalClient.h
../src/network/LocalClient.cpp
../src/network/ClientState.h
../src/network/ClientState.cpp
../src/network/WebSocketClientBase.h
../src/network/WebSocketClientBase.cpp
../src/network/WebSocketClientEmscripten.h
../src/network/WebSocketClientEmscripten.cpp
../src/render/TextRenderer.h
../src/render/TextRenderer.cpp
../src/MenuManager.h
../src/MenuManager.cpp
../src/Space.h
../src/Space.cpp
../src/GameConstants.h
../src/GameConstants.cpp
../src/render/TextRenderer.h
../src/render/TextRenderer.cpp
../src/MenuManager.h
../src/MenuManager.cpp
../src/Location.h
../src/Location.cpp
../src/GameConstants.h
../src/GameConstants.cpp
../src/ScriptEngine.h
../src/ScriptEngine.cpp
../src/navigation/PathFinder.h
../src/navigation/PathFinder.cpp
../src/items/GameObjectLoader.h
../src/items/GameObjectLoader.cpp
../src/items/Item.h
../src/items/Item.cpp
../src/items/InteractiveObject.h
../src/items/InteractiveObject.cpp
../src/dialogue/DialogueTypes.h
../src/dialogue/DialogueDatabase.h
../src/dialogue/DialogueDatabase.cpp
../src/dialogue/DialogueRuntime.h
../src/dialogue/DialogueRuntime.cpp
../src/dialogue/DialogueOverlay.h
../src/dialogue/DialogueOverlay.cpp
../src/dialogue/DialogueSystem.h
../src/dialogue/DialogueSystem.cpp
../src/quest/QuestTypes.h
../src/quest/QuestJournal.h
../src/quest/QuestJournal.cpp
)
add_executable(space-game001 ${SOURCES})
add_executable(bishkek-witcher ${SOURCES})
# Настройка путей к инклудам (используем скачанные исходники)
target_include_directories(space-game001 PRIVATE
target_include_directories(bishkek-witcher PRIVATE
../src
../thirdparty/eigen-5.0.0
../thirdparty/boost_1_90_0
"${SOL2_SRC_DIR}/include"
)
# Сборка libzip через add_subdirectory (Emscripten соберет её из исходников)
# Опции для либзипа, чтобы он не искал лишнего в системе
set(ENABLE_GNUTLS OFF CACHE BOOL "" FORCE)
set(ENABLE_OPENSSL OFF CACHE BOOL "" FORCE)
set(ENABLE_WINDOWS_CRYPTO OFF CACHE BOOL "" FORCE)
@ -95,7 +145,7 @@ set(ENABLE_COMMONCRYPTO OFF CACHE BOOL "" FORCE)
add_subdirectory("../thirdparty/libzip-1.11.4" libzip-build)
target_link_libraries(space-game001 PRIVATE zip z websocket.js)
target_link_libraries(bishkek-witcher PRIVATE zip z lua_static websocket.js)
# Эмскриптен-флаги
set(EMSCRIPTEN_FLAGS
@ -104,13 +154,15 @@ set(EMSCRIPTEN_FLAGS
"-sUSE_LIBPNG=1"
"-sUSE_ZLIB=1"
"-sUSE_SDL_TTF=2"
"-sUSE_SDL_MIXER=2"
"-sSDL2_MIXER_FORMATS=[ogg,mp3]"
#"-pthread"
#"-sUSE_PTHREADS=1"
"-fexceptions"
"-DNETWORK"
"-DNETWORK"
)
target_compile_options(space-game001 PRIVATE ${EMSCRIPTEN_FLAGS} "-O2")
target_compile_options(bishkek-witcher PRIVATE ${EMSCRIPTEN_FLAGS} "-O2")
# Only loading.png and the shaders used before resources.zip is ready are preloaded.
# resources.zip is downloaded asynchronously at runtime and served as a separate file.
@ -119,17 +171,20 @@ set(EMSCRIPTEN_LINK_FLAGS
"-O2"
#"-sPTHREAD_POOL_SIZE=4"
"-sALLOW_MEMORY_GROWTH=1"
"-sFULL_ES3=1"
"-sFULL_ES3=1"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/loading.png@resources/loading.png"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/shaders@resources/shaders"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start.lua@resources/start.lua"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../resources/start2.lua@resources/start2.lua"
"--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/../audio@audio"
)
# Применяем настройки линковки
target_link_options(space-game001 PRIVATE ${EMSCRIPTEN_LINK_FLAGS})
target_link_options(bishkek-witcher PRIVATE ${EMSCRIPTEN_LINK_FLAGS})
# Для совместимости со старыми версиями CMake, если target_link_options недостаточно
string(REPLACE ";" " " EMSCRIPTEN_LINK_FLAGS_STR "${EMSCRIPTEN_LINK_FLAGS}")
set_target_properties(space-game001 PROPERTIES
set_target_properties(bishkek-witcher PROPERTIES
LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS_STR}"
SUFFIX ".html"
)
@ -147,34 +202,33 @@ add_custom_command(
)
add_custom_target(pack_resources DEPENDS "${RESOURCES_ZIP}")
add_dependencies(space-game001 pack_resources)
add_dependencies(bishkek-witcher pack_resources)
# Определяем путь к директории установки (относительно папки билда)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/public")
# 1. Устанавливаем основной HTML файл
install(TARGETS space-game001
install(TARGETS bishkek-witcher
RUNTIME DESTINATION .
)
# 2. Устанавливаем сопутствующие файлы (JS, WASM и сгенерированный архив данных)
# Emscripten создает их в той же папке, что и таргет
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/space-game001.js"
"${CMAKE_CURRENT_BINARY_DIR}/space-game001.wasm"
"${CMAKE_CURRENT_BINARY_DIR}/space-game001.data"
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.js"
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.wasm"
"${CMAKE_CURRENT_BINARY_DIR}/bishkek-witcher.data"
DESTINATION .
)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/space-game001plain.html"
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/index.html"
DESTINATION .
)
# resources.zip is served separately and downloaded asynchronously at runtime
install(FILES "${RESOURCES_ZIP}" DESTINATION .)
add_custom_command(TARGET space-game001 POST_BUILD
add_custom_command(TARGET bishkek-witcher POST_BUILD
COMMAND ${CMAKE_COMMAND} --install .
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
COMMENT "Automatically deploying to public directory..."

82
proj-web/index.html Normal file
View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
<title>Bishkek Witcher</title>
<style>
body, html {
margin: 0; padding: 0; width: 100%; height: 100%;
overflow: hidden; background-color: #000;
position: fixed;
}
#canvas {
display: block;
position: absolute;
top: 0; left: 0;
width: 100vw; height: 100vh;
border: none;
}
#fs-button {
position: absolute;
top: 10px; right: 10px;
padding: 10px;
z-index: 10;
background: rgba(255,255,255,0.3);
color: white; border: 1px solid white;
cursor: pointer;
font-family: sans-serif;
border-radius: 5px;
}
#status { color: white; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
</style>
</head>
<body>
<button id="fs-button">Fullscreen</button>
<div id="status">Downloading...</div>
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex="-1"></canvas>
<script>
function prepareModuleEnvironment() {
window.Module = window.Module || {};
var canvasEl = document.getElementById('canvas');
window.Module.canvas = canvasEl;
window.Module.setStatus = window.Module.setStatus || function (text) {
var statusElement = document.getElementById("status");
statusElement.innerHTML = text;
statusElement.style.display = text ? 'block' : 'none';
};
}
function loadGameScript() {
var s = document.createElement('script');
s.src = 'bishkek-witcher.js';
s.async = true;
document.body.appendChild(s);
}
document.getElementById('fs-button').addEventListener('click', function() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().catch(function(e) {
console.error('Fullscreen error: ' + e.message);
});
} else {
document.exitFullscreen();
}
});
document.addEventListener('DOMContentLoaded', function() {
prepareModuleEnvironment();
loadGameScript();
});
window.addEventListener("orientationchange", function() {
setTimeout(() => {
window.dispatchEvent(new Event('resize'));
}, 200);
});
</script>
</body>
</html>

View File

@ -1,19 +1,25 @@
cmake_minimum_required(VERSION 3.16)
project(space-game001 LANGUAGES CXX)
project(witcher001 LANGUAGES C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Build option (Windows-only): when ON, the game launches in fullscreen.
# When OFF (default), it launches in a 1280x720 window like before.
option(FULLSCREEN "Launch the game in fullscreen mode" OFF)
include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/ThirdParty.cmake)
# ===========================================
# Основной проект space-game001
# Основной проект witcher001
# ===========================================
add_executable(space-game001
add_executable(witcher001
../src/main.cpp
../src/Game.cpp
../src/Game.h
../src/Character.cpp
../src/Character.h
../src/Environment.cpp
../src/Environment.h
../src/render/Renderer.cpp
@ -26,79 +32,86 @@ add_executable(space-game001
../src/TextModel.h
../src/AudioPlayerAsync.cpp
../src/AudioPlayerAsync.h
../src/BoneAnimatedModel.cpp
../src/BoneAnimatedModel.h
../src/BoneAnimatedModelNew.cpp
../src/BoneAnimatedModelNew.h
../src/render/OpenGlExtensions.cpp
../src/render/OpenGlExtensions.h
../src/utils/Utils.cpp
../src/utils/Utils.h
../src/SparkEmitter.cpp
../src/SparkEmitter.h
../src/planet/PlanetObject.cpp
../src/planet/PlanetObject.h
../src/planet/PlanetData.cpp
../src/planet/PlanetData.h
../src/utils/Perlin.cpp
../src/utils/Perlin.h
../src/utils/TaskManager.cpp
../src/utils/TaskManager.h
../src/planet/StoneObject.cpp
../src/planet/StoneObject.h
../src/render/FrameBuffer.cpp
../src/render/FrameBuffer.h
../src/render/ShadowMap.cpp
../src/render/ShadowMap.h
../src/UiManager.cpp
../src/UiManager.h
../src/Projectile.h
../src/Projectile.cpp
../src/network/NetworkInterface.h
../src/network/LocalClient.h
../src/network/LocalClient.cpp
../src/network/ClientState.h
../src/network/ClientState.cpp
../src/network/WebSocketClient.h
../src/network/WebSocketClient.cpp
../src/network/WebSocketClientBase.h
../src/network/WebSocketClientBase.cpp
../src/network/WebSocketClientEmscripten.h
../src/network/WebSocketClientEmscripten.cpp
../src/render/TextRenderer.h
../src/render/TextRenderer.cpp
../src/MenuManager.h
../src/MenuManager.cpp
../src/Space.h
../src/Space.cpp
../src/GameConstants.h
../src/GameConstants.cpp
../src/Location.h
../src/Location.cpp
../src/GameConstants.h
../src/GameConstants.cpp
../src/ScriptEngine.h
../src/ScriptEngine.cpp
../src/navigation/PathFinder.h
../src/navigation/PathFinder.cpp
../src/items/GameObjectLoader.h
../src/items/GameObjectLoader.cpp
../src/items/Item.h
../src/items/Item.cpp
../src/items/InteractiveObject.h
../src/items/InteractiveObject.cpp
../src/dialogue/DialogueTypes.h
../src/dialogue/DialogueDatabase.h
../src/dialogue/DialogueDatabase.cpp
../src/dialogue/DialogueRuntime.h
../src/dialogue/DialogueRuntime.cpp
../src/dialogue/DialogueOverlay.h
../src/dialogue/DialogueOverlay.cpp
../src/dialogue/DialogueSystem.h
../src/dialogue/DialogueSystem.cpp
../src/quest/QuestTypes.h
../src/quest/QuestJournal.h
../src/quest/QuestJournal.cpp
)
# Установка проекта по умолчанию для Visual Studio
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT space-game001)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT witcher001)
# include-пути проекта
target_include_directories(space-game001 PRIVATE
target_include_directories(witcher001 PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/../src"
)
set_target_properties(space-game001 PROPERTIES
OUTPUT_NAME "space-game001"
set_target_properties(witcher001 PROPERTIES
OUTPUT_NAME "witcher001"
)
# Определения препроцессора:
# PNG_ENABLED включает код PNG в TextureManager
# SDL_MAIN_HANDLED отключает переопределение main -> SDL_main
target_compile_definitions(space-game001 PRIVATE
target_compile_definitions(witcher001 PRIVATE
WIN32_LEAN_AND_MEAN
PNG_ENABLED
SDL_MAIN_HANDLED
NETWORK
# SIMPLIFIED
# DEBUG_LIGHT
# SHOW_PATH
)
if(FULLSCREEN)
target_compile_definitions(witcher001 PRIVATE FULLSCREEN)
endif()
# Линкуем с SDL2main, если он вообще установлен
target_link_libraries(space-game001 PRIVATE SDL2main_external_lib)
target_link_libraries(witcher001 PRIVATE SDL2main_external_lib)
# Линкуем сторонние библиотеки
target_link_libraries(space-game001 PRIVATE
target_link_libraries(witcher001 PRIVATE
SDL2_external_lib
libpng_external_lib
zlib_external_lib
@ -107,11 +120,13 @@ target_link_libraries(space-game001 PRIVATE
SDL2_ttf_external_lib
eigen_external_lib
boost_external_lib
sol2_external_lib
SDL2_mixer_external_lib
)
# Линкуем OpenGL (Windows)
if(WIN32)
target_link_libraries(space-game001 PRIVATE opengl32)
target_link_libraries(witcher001 PRIVATE opengl32)
endif()
# ===========================================
@ -121,18 +136,19 @@ if (WIN32)
# SDL2: в Debug - SDL2d.dll, в Release - SDL2.dll
set(SDL2_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2_INSTALL_DIR}/bin/SDL2d.dll,${SDL2_INSTALL_DIR}/bin/SDL2.dll>")
set(SDL2_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:space-game001>/SDL2d.dll,$<TARGET_FILE_DIR:space-game001>/SDL2.dll>")
set(SDL2_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:witcher001>/SDL2d.dll,$<TARGET_FILE_DIR:witcher001>/SDL2.dll>")
set(LIBZIP_DLL_SRC "$<IF:$<CONFIG:Debug>,${LIBZIP_BASE_DIR}-Debug/bin/zip.dll,${LIBZIP_BASE_DIR}-Release/bin/zip.dll>")
set(ZLIB_DLL_SRC "$<IF:$<CONFIG:Debug>,${ZLIB_INSTALL_DIR}/bin/zlibd.dll,${ZLIB_INSTALL_DIR}/bin/zlib.dll>")
set(ZLIB_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:space-game001>/zlibd.dll,$<TARGET_FILE_DIR:space-game001>/zlib.dll>")
set(ZLIB_DLL_SRC "$<IF:$<CONFIG:Debug>,${ZLIB_INSTALL_DIR}/bin/zd.dll,${ZLIB_INSTALL_DIR}/bin/z.dll>")
set(ZLIB_DLL_DST "$<IF:$<CONFIG:Debug>,$<TARGET_FILE_DIR:witcher001>/zd.dll,$<TARGET_FILE_DIR:witcher001>/z.dll>")
set(SDL2TTF_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2TTF_BASE_DIR}-Debug/bin/SDL2_ttfd.dll,${SDL2TTF_BASE_DIR}-Release/bin/SDL2_ttf.dll>")
set(SDL2MIXER_DLL_SRC "$<IF:$<CONFIG:Debug>,${SDL2MIXER_BASE_DIR}-Debug/bin/SDL2_mixerd.dll,${SDL2MIXER_BASE_DIR}-Release/bin/SDL2_mixer.dll>")
add_custom_command(TARGET space-game001 POST_BUILD
add_custom_command(TARGET witcher001 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying DLLs to output folder..."
# Копируем SDL2 (целевое имя всегда SDL2.dll)
@ -143,7 +159,7 @@ if (WIN32)
# Копируем LIBZIP (целевое имя всегда zip.dll)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${LIBZIP_DLL_SRC}"
"$<TARGET_FILE_DIR:space-game001>/zip.dll"
"$<TARGET_FILE_DIR:witcher001>/zip.dll"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${ZLIB_DLL_SRC}"
@ -151,7 +167,11 @@ if (WIN32)
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${SDL2TTF_DLL_SRC}"
"$<TARGET_FILE_DIR:space-game001>"
"$<TARGET_FILE_DIR:witcher001>"
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${CMAKE_CURRENT_SOURCE_DIR}/../thirdparty/SDL_mixer-release-2.8.0/install-$<CONFIG>/bin/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
"$<TARGET_FILE_DIR:witcher001>/SDL2_mixer$<$<CONFIG:Debug>:d>.dll"
)
endif()
@ -162,16 +182,17 @@ endif()
# Какие папки с ресурсами нужно копировать
set(RUNTIME_RESOURCE_DIRS
"resources"
"audio"
)
# Копируем ресурсы и шейдеры в папку exe и в корень build/
foreach(resdir IN LISTS RUNTIME_RESOURCE_DIRS)
add_custom_command(TARGET space-game001 POST_BUILD
add_custom_command(TARGET witcher001 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo "Copying ${resdir} to runtime folders..."
# 1) туда, где лежит exe (build/Debug, build/Release и т.п.)
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/../${resdir}"
"$<TARGET_FILE_DIR:space-game001>/${resdir}"
"$<TARGET_FILE_DIR:witcher001>/${resdir}"
# 2) в корень build, если захочешь запускать из этой папки
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${CMAKE_SOURCE_DIR}/../${resdir}"

BIN
resources/Cargo_Base_color_sRGB.png (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
resources/blue_transparent.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/box/box.png (Stored with Git LFS)

Binary file not shown.

View File

@ -1,29 +0,0 @@
===Vertices (Split by UV/Normal): 14
V 0: Pos(1.0, 1.0, 1.0) Norm(0.57735, 0.57735, 0.57735) UV(0.5, 0.5)
V 1: Pos(-1.0, 1.0, 1.0) Norm(-0.57735, 0.57735, 0.57735) UV(0.75, 0.5)
V 2: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.75, 0.75)
V 3: Pos(1.0, -1.0, 1.0) Norm(0.57735, -0.57735, 0.57735) UV(0.5, 0.75)
V 4: Pos(1.0, -1.0, -1.0) Norm(0.57735, -0.57735, -0.57735) UV(0.25, 0.75)
V 5: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.5, 1.0)
V 6: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.25, 1.0)
V 7: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.25, 0.0)
V 8: Pos(-1.0, -1.0, 1.0) Norm(-0.57735, -0.57735, 0.57735) UV(0.5, 0.0)
V 9: Pos(-1.0, 1.0, 1.0) Norm(-0.57735, 0.57735, 0.57735) UV(0.5, 0.25)
V 10: Pos(-1.0, 1.0, -1.0) Norm(-0.57735, 0.57735, -0.57735) UV(0.25, 0.25)
V 11: Pos(-1.0, 1.0, -1.0) Norm(-0.57735, 0.57735, -0.57735) UV(0.0, 0.5)
V 12: Pos(1.0, 1.0, -1.0) Norm(0.57735, 0.57735, -0.57735) UV(0.25, 0.5)
V 13: Pos(-1.0, -1.0, -1.0) Norm(-0.57735, -0.57735, -0.57735) UV(0.0, 0.75)
===Triangles (Indices): 12
Tri: 0 1 2
Tri: 0 2 3
Tri: 4 3 5
Tri: 4 5 6
Tri: 7 8 9
Tri: 7 9 10
Tri: 11 12 4
Tri: 11 4 13
Tri: 12 0 3
Tri: 12 3 4
Tri: 10 9 0
Tri: 10 0 12

BIN
resources/button_info.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_info_pressed.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_invmouse.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_invmouse_pressed.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_minus.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_minus_disabled.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_minus_pressed.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_players.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_players_disabled.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_plus.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_plus_disabled.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_plus_pressed.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_take.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_take_disabled.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/button_take_pressed.png (Stored with Git LFS)

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,256 +0,0 @@
{
"root": {
"type": "LinearLayout",
"orientation": "vertical",
"vertical_align": "center",
"horizontal_align": "center",
"spacing": 10,
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "titleBtn",
"width": 434,
"height": 35,
"texture": "resources/main_menu/title.png"
},
{
"type": "StaticImage",
"name": "aboutSpace1",
"width": 434,
"height": 10
},
{
"type": "FrameLayout",
"spacing": 10,
"width": 434,
"height": 460,
"children": [
{
"type": "TextView",
"name": "aboutText1",
"width": 434,
"height": 30,
"x": -300,
"y": 0,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Producer: Vladislav Khorev",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 30,
"x": -300,
"y": 40,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Lead Developer: Vladislav Khorev",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 2,
"x": -300,
"y": 80,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Game Designer: Leila Bobrova",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 30,
"x": -300,
"y": 120,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Developers: ",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 40,
"x": -300,
"y": 150,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Vladislav Kan",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 40,
"x": -300,
"y": 180,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Beksultan Almazbekov",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 40,
"x": -300,
"y": 210,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Sergei Zotov",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 40,
"x": -300,
"y": 250,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "3D Artist: David \"nokken\" Im",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 40,
"x": -300,
"y": 290,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "UI/UX Design: Kenje Kazmatova",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 40,
"x": -300,
"y": 330,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Sky Trek Tales v. 0.1",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
},
{
"type": "TextView",
"name": "aboutText2",
"width": 434,
"height": 40,
"x": -300,
"y": 370,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "https://fishrungames.com",
"fontSize": 24,
"color": [
255,
255,
255,
1
],
"centered": false
}
]
},
{
"type": "Button",
"name": "aboutBackButton",
"width": 382,
"height": 56,
"textures": {
"normal": "resources/game_over/Secondarybutton.png",
"hover": "resources/game_over/Secondarybutton.png",
"pressed": "resources/game_over/Secondarybutton.png"
}
}
]
}
}

View File

@ -1,22 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "connecting",
"x" : 0,
"y" : 0,
"width": 488,
"height": 154,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"texture": "resources/connecting.png"
}
]
}
}

View File

@ -1,52 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "connectionFailed",
"x" : 0,
"y" : 0,
"width": 488,
"height": 308,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"texture": "resources/connection_failed.png"
},
{
"type": "Button",
"name": "connectionFailedReconnectButton",
"width": 382,
"height": 56,
"x" : 0,
"y" : -20,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"textures": {
"normal": "resources/game_over/reconnect1.png",
"hover": "resources/game_over/reconnect2.png",
"pressed": "resources/game_over/reconnect3.png"
}
},
{
"type": "Button",
"name": "connectionFailedGoBack",
"width": 382,
"height": 56,
"x" : 0,
"y" : -86,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"textures": {
"normal": "resources/game_over/Secondarybutton.png",
"hover": "resources/game_over/Secondarybutton.png",
"pressed": "resources/game_over/Secondarybutton.png"
}
}
]
}
}

View File

@ -1,52 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "connectionLost",
"x" : 0,
"y" : 0,
"width": 488,
"height": 308,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"texture": "resources/connection_lost.png"
},
{
"type": "Button",
"name": "reconnectButton",
"width": 382,
"height": 56,
"x" : 0,
"y" : -20,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"textures": {
"normal": "resources/game_over/reconnect1.png",
"hover": "resources/game_over/reconnect2.png",
"pressed": "resources/game_over/reconnect3.png"
}
},
{
"type": "Button",
"name": "exitServerButton",
"width": 382,
"height": 56,
"x" : 0,
"y" : -86,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"textures": {
"normal": "resources/game_over/Secondarybutton.png",
"hover": "resources/game_over/Secondarybutton.png",
"pressed": "resources/game_over/Secondarybutton.png"
}
}
]
}
}

View File

@ -1,21 +0,0 @@
{
"enabled": true,
"referenceResolution": [1280, 720],
"color": [1.0, 1.0, 1.0],
"cl_crosshairalpha": 1.0,
"cl_crosshairthickness": 2.0,
"centerGapPx": 10.0,
"top": {
"lengthPx": 14.0,
"angleDeg": 90.0
},
"arms": [
{ "lengthPx": 20.0, "angleDeg": 210.0 },
{ "lengthPx": 20.0, "angleDeg": 330.0 }
]
}

View File

@ -1,15 +0,0 @@
{
"emissionPoints": [
{ "position": [0.0, 0.0, 0.0] }
],
"texture": "resources/spark_white.png",
"speedRange": [10.0, 30.0],
"zSpeedRange": [-1.0, 1.0],
"scaleRange": [5.0, 10.0],
"lifeTimeRange": [200.0, 800.0],
"emissionRate": 50.0,
"maxParticles": 5,
"particleSize": 2,
"biasX": 0.1,
"shaderProgramName": "default"
}

View File

@ -1,85 +0,0 @@
{
"root": {
"type": "LinearLayout",
"orientation": "vertical",
"vertical_align": "center",
"horizontal_align": "center",
"spacing": 10,
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "Button",
"name": "gameOverText",
"width": 327,
"height": 26,
"textures": {
"normal": "resources/game_over/MissionFailed.png",
"hover": "resources/game_over/MissionFailed.png",
"pressed": "resources/game_over/MissionFailed.png"
}
},
{
"type": "Button",
"name": "underlineBtn",
"width": 168,
"height": 44,
"textures": {
"normal": "resources/game_over/Container.png",
"hover": "resources/game_over/Container.png",
"pressed": "resources/game_over/Container.png"
}
},
{
"type": "Button",
"name": "finalscore",
"width": 87,
"height": 9,
"textures": {
"normal": "resources/game_over/FinalScore.png",
"hover": "resources/game_over/FinalScore.png",
"pressed": "resources/game_over/FinalScore.png"
}
},
{
"type": "TextView",
"name": "scoreText",
"width": 600,
"height": 80,
"text": "0",
"fontSize": 36,
"color": [
0,
217,
255,
1
],
"align": "center"
},
{
"type": "Button",
"name": "restartButton",
"width": 382,
"height": 56,
"textures": {
"normal": "resources/game_over/Filledbuttons.png",
"hover": "resources/game_over/Variant5.png",
"pressed": "resources/game_over/Variant6.png"
}
},
{
"type": "Button",
"name": "gameOverExitButton",
"width": 382,
"height": 56,
"textures": {
"normal": "resources/game_over/Secondarybutton.png",
"hover": "resources/game_over/Secondarybutton.png",
"pressed": "resources/game_over/Secondarybutton.png"
}
}
]
}
}

View File

@ -1,93 +0,0 @@
{
"root": {
"type": "LinearLayout",
"orientation": "vertical",
"align": "center",
"x": 0,
"y": 0,
"width": 1920,
"height": 1080,
"background": {
"color": [0, 0, 0, 0.7]
},
"children": [
{
"type": "Button",
"name": "gameOverText",
"x": 476.5,
"y": 500,
"width": 327,
"height": 26,
"textures": {
"normal": "resources/game_over/MissionFailed.png",
"hover": "resources/game_over/MissionFailed.png",
"pressed": "resources/game_over/MissionFailed.png"
}
},
{
"type": "Button",
"name": "underlineBtn",
"x": 556,
"y": 465,
"width": 168,
"height": 44,
"textures": {
"normal": "resources/game_over/Container.png",
"hover": "resources/game_over/Container.png",
"pressed": "resources/game_over/Container.png"
}
},
{
"type": "Button",
"name": "finalscore",
"x": 596.5,
"y": 436,
"width": 87,
"height": 9,
"textures": {
"normal": "resources/game_over/FinalScore.png",
"hover": "resources/game_over/FinalScore.png",
"pressed": "resources/game_over/FinalScore.png"
}
},
{
"type": "TextView",
"name": "scoreText",
"x": 350,
"y": 356,
"width": 600,
"height": 80,
"text": "0",
"fontSize": 36,
"color": [0, 217, 255, 1],
"align": "center"
},
{
"type": "Button",
"name": "restartButton",
"x": 449,
"y": 308,
"width": 382,
"height": 56,
"textures": {
"normal": "resources/game_over/Filledbuttons.png",
"hover": "resources/game_over/Filledbuttons.png",
"pressed": "resources/game_over/Filledbuttons.png"
}
},
{
"type": "Button",
"name": "gameOverExitButton",
"x": 449,
"y": 240,
"width": 382,
"height": 56,
"textures": {
"normal": "resources/game_over/Secondarybutton.png",
"hover": "resources/game_over/Secondarybutton.png",
"pressed": "resources/game_over/Secondarybutton.png"
}
}
]
}
}

View File

@ -1,76 +0,0 @@
{
"root": {
"type": "LinearLayout",
"orientation": "vertical",
"vertical_align": "center",
"horizontal_align": "center",
"spacing": 10,
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "titleBtn",
"width": 434,
"height": 35,
"texture": "resources/main_menu/title.png"
},
{
"type": "StaticImage",
"name": "underlineBtn",
"width": 168,
"height": 44,
"texture": "resources/main_menu/line.png"
},
{
"type": "StaticImage",
"name": "subtitleBtn",
"width": 144,
"height": 11,
"texture": "resources/main_menu/subtitle.png"
},
{
"type": "Button",
"name": "singleButton",
"width": 382,
"height": 56,
"textures": {
"normal": "resources/main_menu/single.png",
"hover": "resources/main_menu/Variant5.png",
"pressed": "resources/main_menu/Variant6.png"
}
},
{
"type": "Button",
"name": "multiplayerButton",
"width": 382,
"height": 56,
"textures": {
"normal": "resources/main_menu/multi.png",
"hover": "resources/main_menu/Variant7.png",
"pressed": "resources/main_menu/Variant8.png"
}
},
{
"type": "Button",
"name": "aboutButton",
"width": 382,
"height": 56,
"textures": {
"normal": "resources/main_menu/about.png",
"hover": "resources/main_menu/about_hover.png",
"pressed": "resources/main_menu/about_pressed.png"
}
},
{
"type": "StaticImage",
"name": "versionLabel",
"width": 81,
"height": 9,
"texture": "resources/main_menu/version.png"
}
]
}
}

View File

@ -1,158 +0,0 @@
{
"root": {
"type": "LinearLayout",
"x": 0,
"y": 0,
"width": 1280,
"height": 720,
"children": [
{
"type": "Button",
"name": "langButton",
"x": 1100,
"y": 580,
"width": 142,
"height": 96,
"textures": {
"normal": "resources/main_menu/lang.png",
"hover": "resources/main_menu/lang.png",
"pressed": "resources/main_menu/lang.png"
}
},
{
"type": "Button",
"name": "titleBtn",
"x": 512,
"y": 500,
"width": 254,
"height": 35,
"textures": {
"normal": "resources/multiplayer_menu/title.png",
"hover": "resources/multiplayer_menu/title.png",
"pressed": "resources/multiplayer_menu/title.png"
}
},
{
"type": "Button",
"name": "subtitle",
"x": 596.5,
"y": 470,
"width": 87,
"height": 11,
"textures": {
"normal": "resources/multiplayer_menu/JoinServer.png",
"hover": "resources/multiplayer_menu/JoinServer.png",
"pressed": "resources/multiplayer_menu/JoinServer.png"
}
},
{
"type": "Button",
"name": "subtitleBtn",
"x": 450,
"y": 445,
"width": 94,
"height": 9,
"textures": {
"normal": "resources/multiplayer_menu/ServerName.png",
"hover": "resources/multiplayer_menu/ServerName.png",
"pressed": "resources/multiplayer_menu/ServerName.png"
}
},
{
"type": "TextField",
"name": "serverInputField",
"x": 449,
"y": 390,
"width": 382,
"height": 56,
"placeholder": "Enter server name or IP",
"fontPath": "resources/fonts/DroidSans.ttf",
"fontSize": 16,
"maxLength": 256,
"color": [122, 156, 198, 1],
"placeholderColor": [122, 156, 198, 1],
"backgroundColor": [15, 29, 51, 1],
"borderColor": [15, 29, 51, 1]
},
{
"type": "Button",
"name": "connectButton",
"x": 449,
"y": 350,
"width": 382,
"height": 56,
"textures": {
"normal": "resources/multiplayer_menu/Filledbuttons.png",
"hover": "resources/multiplayer_menu/Filledbuttons.png",
"pressed": "resources/multiplayer_menu/Filledbuttons.png"
}
},
{
"type": "Button",
"name": "backButton",
"x": 449,
"y": 280,
"width": 382,
"height": 56,
"textures": {
"normal": "resources/multiplayer_menu/Backbutton.png",
"hover": "resources/multiplayer_menu/Backbutton.png",
"pressed": "resources/multiplayer_menu/Backbutton.png"
}
},
{
"type": "Button",
"name": "AvailableServers",
"x": 450,
"y": 240,
"width": 139,
"height": 9,
"textures": {
"normal": "resources/multiplayer_menu/AvailableServers.png",
"hover": "resources/multiplayer_menu/AvailableServers.png",
"pressed": "resources/multiplayer_menu/AvailableServers.png"
}
},
{
"type": "Button",
"name": "SerButton",
"x": 436.5,
"y": 170,
"width": 407,
"height": 62,
"textures": {
"normal": "resources/multiplayer_menu/Button.png",
"hover": "resources/multiplayer_menu/Button.png",
"pressed": "resources/multiplayer_menu/Button.png"
}
},
{
"type": "Button",
"name": "SerButton2",
"x": 436.5,
"y": 88,
"width": 407,
"height": 62,
"textures": {
"normal": "resources/multiplayer_menu/Button2.png",
"hover": "resources/multiplayer_menu/Button2.png",
"pressed": "resources/multiplayer_menu/Button2.png"
}
},
{
"type": "Button",
"name": "SerButton3",
"x": 436.5,
"y": 6,
"width": 407,
"height": 62,
"textures": {
"normal": "resources/multiplayer_menu/Button3.png",
"hover": "resources/multiplayer_menu/Button3.png",
"pressed": "resources/multiplayer_menu/Button3.png"
}
}
]
}
}

View File

@ -1,72 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": 1280,
"height": 720,
"children": [
{
"type": "FrameLayout",
"name": "centerPanel",
"x": 480,
"y": 160,
"width": 320,
"height": 400,
"children": [
{
"type": "LinearLayout",
"name": "settingsButtons",
"orientation": "vertical",
"spacing": 10,
"x": 0,
"y": 0,
"width": 300,
"height": 300,
"children": [
{
"type": "Button",
"name": "Opt1",
"x": 100,
"y": 300,
"width": 200,
"height": 50,
"textures": {
"normal": "resources/sand2.png",
"hover": "resources/sand2.png",
"pressed": "resources/sand2.png"
}
},
{
"type": "Button",
"name": "Opt2",
"x": 100,
"y": 200,
"width": 200,
"height": 50,
"textures": {
"normal": "resources/sand2.png",
"hover": "resources/sand2.png",
"pressed": "resources/sand2.png"
}
},
{
"type": "Button",
"name": "backButton",
"x": 100,
"y": 100,
"width": 200,
"height": 50,
"textures": {
"normal": "resources/sand2.png",
"hover": "resources/sand2.png",
"pressed": "resources/sand2.png"
}
}
]
}
]
}
]
}
}

View File

@ -1,66 +0,0 @@
{
"root": {
"type": "LinearLayout",
"orientation": "vertical",
"vertical_align": "center",
"horizontal_align": "center",
"spacing": 10,
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "titleBtn",
"width": 266,
"height": 66,
"texture": "resources/select_your_ship.png"
},
{
"type": "LinearLayout",
"orientation": "horizontal",
"vertical_align": "center",
"horizontal_align": "center",
"spacing": 10,
"width": "match_parent",
"height": 260,
"children": [
{
"type": "Button",
"name": "spaceshipButton",
"width": 256,
"height": 256,
"textures": {
"normal": "resources/multiplayer_menu/ship_fighter.png",
"hover": "resources/multiplayer_menu/ship_fighter_pressed.png",
"pressed": "resources/multiplayer_menu/ship_fighter_pressed.png"
}
},
{
"type": "Button",
"name": "cargoshipButton",
"width": 256,
"height": 256,
"textures": {
"normal": "resources/multiplayer_menu/ship_cargo.png",
"hover": "resources/multiplayer_menu/ship_cargo_pressed.png",
"pressed": "resources/multiplayer_menu/ship_cargo_pressed.png"
}
}
]
},
{
"type": "Button",
"name": "backButton",
"width": 382,
"height": 56,
"textures": {
"normal": "resources/multiplayer_menu/Backbutton.png",
"hover": "resources/multiplayer_menu/Backbutton.png",
"pressed": "resources/multiplayer_menu/Backbutton.png"
}
}
]
}
}

View File

@ -1,14 +0,0 @@
{
"emissionRate": 1.2,
"maxParticles": 400,
"particleSize": 0.3,
"biasX": 0.3,
"emissionPoints": [
],
"speedRange": [0.5, 2.0],
"zSpeedRange": [1.0, 3.0],
"scaleRange": [0.8, 1.2],
"lifeTimeRange": [300.0, 500.0],
"texture": "resources/spark.png",
"shaderProgramName": "spark"
}

View File

@ -1,20 +0,0 @@
{
"emissionRate": 1.2,
"maxParticles": 400,
"particleSize": 0.3,
"biasX": 0.3,
"emissionPoints": [
{
"position": [0.0, 2.8, -3.5]
},
{
"position": [0.0, 1.5, -3.5]
}
],
"speedRange": [0.5, 2.0],
"zSpeedRange": [1.0, 3.0],
"scaleRange": [0.8, 1.2],
"lifeTimeRange": [600.0, 1400.0],
"texture": "resources/spark.png",
"shaderProgramName": "spark"
}

View File

@ -1,15 +0,0 @@
{
"emissionPoints": [
{ "position": [0.0, 0.0, 0.0] }
],
"texture": "resources/spark2.png",
"speedRange": [5.0, 10.0],
"zSpeedRange": [-1.0, 1.0],
"scaleRange": [0.5, 2.0],
"lifeTimeRange": [200.0, 800.0],
"emissionRate": 30.0,
"maxParticles": 150,
"particleSize": 1.0,
"biasX": 0.1,
"shaderProgramName": "default"
}

View File

@ -1,163 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "TextView",
"name": "gameScoreText",
"x": 0,
"y": 30,
"width": 200,
"height": 60,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"text": "Score: 0",
"fontSize": 36,
"color": [
0,
217,
255,
1
],
"centered": false
},
{
"type": "Button",
"name": "showPlayersButton",
"x": 0,
"y": 100,
"width": 150,
"height": 150,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"textures": {
"normal": "resources/button_players.png",
"hover": "resources/button_players.png",
"pressed": "resources/button_players.png",
"disabled": "resources/button_players_disabled.png"
}
},
{
"type": "Button",
"name": "inverseMouseButton",
"x": 0,
"y": 100,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "right",
"vertical_gravity": "top",
"textures": {
"normal": "resources/button_invmouse.png",
"hover": "resources/button_invmouse.png",
"pressed": "resources/button_invmouse_pressed.png",
"disabled": "resources/button_invmouse.png"
}
},
{
"type": "Button",
"name": "infoButton",
"x": 0,
"y": 250,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"textures": {
"normal": "resources/button_info.png",
"hover": "resources/button_info.png",
"pressed": "resources/button_info_pressed.png",
"disabled": "resources/button_info.png"
}
},
{
"type": "Button",
"name": "shootButton",
"x": 0,
"y": 0,
"width": 150,
"height": 150,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"textures": {
"normal": "resources/fire.png",
"hover": "resources/fire.png",
"pressed": "resources/fire2.png",
"disabled": "resources/fire_disabled.png"
}
},
{
"type": "Button",
"name": "shootButton2",
"x": 0,
"y": 0,
"width": 150,
"height": 150,
"horizontal_gravity": "left",
"vertical_gravity": "bottom",
"textures": {
"normal": "resources/fire.png",
"hover": "resources/fire.png",
"pressed": "resources/fire2.png",
"disabled": "resources/fire_disabled.png"
}
},
{
"type": "Button",
"name": "minusButton",
"x": -20,
"y": 110,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"textures": {
"normal": "resources/button_minus.png",
"hover": "resources/button_minus.png",
"pressed": "resources/button_minus_pressed.png",
"disabled" : "resources/button_minus_disabled.png"
}
},
{
"type": "Button",
"name": "plusButton",
"x": -20,
"y": 220,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"textures": {
"normal": "resources/button_plus.png",
"hover": "resources/button_plus.png",
"pressed": "resources/button_plus_pressed.png",
"disabled" : "resources/button_plus_disabled.png"
}
},
{
"type": "Button",
"name": "takeButton",
"x": -20,
"y": 320,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"textures": {
"normal": "resources/button_take.png",
"hover": "resources/button_take.png",
"pressed": "resources/button_take_pressed.png",
"disabled" : "resources/button_take_disabled.png"
}
}
]
}
}

View File

@ -1,194 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": 1280,
"height": 720,
"children": [
{
"type": "FrameLayout",
"name": "leftPanel",
"x": 100,
"y": 100,
"width": 320,
"height": 400,
"children": [
{
"type": "LinearLayout",
"name": "mainButtons",
"orientation": "vertical",
"spacing": 10,
"x": 0,
"y": 0,
"width": 300,
"height": 300,
"children": [
{
"type": "Button",
"name": "playButton",
"x": -1000,
"y": 500,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
}
},
"textures": {
"normal": "./resources/sand2.png",
"hover": "./resources/sand2.png",
"pressed": "./resources/sand2.png"
}
},
{
"type": "Button",
"name": "settingsButton",
"x": -1000,
"y": 400,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "wait",
"duration": 0.5
},
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
}
},
"textures": {
"normal": "./resources/sand2.png",
"hover": "./resources/sand2.png",
"pressed": "./resources/sand2.png"
}
},
{
"type": "Button",
"name": "exitButton",
"x": -1000,
"y": 300,
"width": 200,
"height": 50,
"animations": {
"buttonsExit": {
"repeat": false,
"steps": [
{
"type": "wait",
"duration": 1.0
},
{
"type": "move",
"to": [
-400,
0
],
"duration": 1.0,
"easing": "easein"
}
]
},
"bgScroll": {
"repeat": true,
"steps": [
{
"type": "move",
"to": [
1280,
0
],
"duration": 5.0,
"easing": "linear"
}
]
}
},
"textures": {
"normal": "./resources/sand2.png",
"hover": "./resources/sand2.png",
"pressed": "./resources/sand2.png"
}
}
]
}
]
},
{
"type": "Slider",
"name": "velocitySlider",
"x": 1140,
"y": 300,
"width": 50,
"height": 300,
"value": 0.0,
"orientation": "vertical",
"textures": {
"track": "resources/velocitySliderTexture.png",
"knob": "resources/velocitySliderButton.png"
}
},
{
"type": "Button",
"name": "shootButton",
"x": 100,
"y": 100,
"width": 100,
"height": 100,
"textures": {
"normal": "resources/shoot_normal.png",
"hover": "resources/shoot_hover.png",
"pressed": "resources/shoot_pressed.png"
}
},
{
"type": "Button",
"name": "shootButton2",
"x": 1000,
"y": 100,
"width": 100,
"height": 100,
"textures": {
"normal": "resources/shoot_normal.png",
"hover": "resources/shoot_hover.png",
"pressed": "resources/shoot_pressed.png"
}
},
{
"type": "TextView",
"name": "velocityText",
"x": 10,
"y": 10,
"width": 200,
"height": 40,
"text": "Velocity: 0",
"fontSize": 24,
"color": [1.0, 1.0, 1.0, 1.0],
"centered": false
}
]
}
}

View File

@ -1,163 +0,0 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "showPlayersButton_help",
"x": 0,
"y": 100,
"width": 150,
"height": 150,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"texture": "resources/button_players.png"
},
{
"type": "StaticImage",
"name": "infoButton_help",
"x": 0,
"y": 250,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"texture":"resources/button_info.png"
},
{
"type": "StaticImage",
"name": "infoButtonTopLeft_help",
"x": 0,
"y": 0,
"width": 300,
"height": 400,
"border" : 0,
"horizontal_gravity": "left",
"vertical_gravity": "top",
"texture": "resources/help_top_left.png"
},
{
"type": "StaticImage",
"name": "inverseMouseButton_help",
"x": 0,
"y": 100,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "right",
"vertical_gravity": "top",
"texture": "resources/button_invmouse.png"
},
{
"type": "StaticImage",
"name": "infoButtonTopRight_help",
"x": 0,
"y": 0,
"width": 300,
"height": 230,
"border" : 0,
"horizontal_gravity": "right",
"vertical_gravity": "top",
"texture": "resources/help_top_right.png"
},
{
"type": "StaticImage",
"name": "infoButtonBottomLeft_help",
"x": 0,
"y": 0,
"width": 300,
"height": 200,
"border" : 0,
"horizontal_gravity": "left",
"vertical_gravity": "bottom",
"texture": "resources/help_bottom_left.png"
},
{
"type": "StaticImage",
"name": "shootButton_help",
"x": 0,
"y": 0,
"width": 150,
"height": 150,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"texture": "resources/fire.png"
},
{
"type": "StaticImage",
"name": "shootButton2_help",
"x": 0,
"y": 0,
"width": 150,
"height": 150,
"horizontal_gravity": "left",
"vertical_gravity": "bottom",
"texture": "resources/fire.png"
},
{
"type": "StaticImage",
"name": "minusButton_help",
"x": -20,
"y": 110,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"texture": "resources/button_minus.png"
},
{
"type": "StaticImage",
"name": "plusButton_help",
"x": -20,
"y": 220,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"texture": "resources/button_plus.png"
},
{
"type": "StaticImage",
"name": "takeButton_help",
"x": -20,
"y": 320,
"width": 150,
"height": 150,
"border" : 20,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"texture": "resources/button_take.png"
},
{
"type": "StaticImage",
"name": "infoButtonBottomRight_help",
"x": 0,
"y": 0,
"width": 300,
"height": 450,
"border" : 0,
"horizontal_gravity": "right",
"vertical_gravity": "bottom",
"texture": "resources/help_bottom_right.png"
},
{
"type": "Button",
"name": "infoButtonUnderlying_help",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"border" : 0,
"textures": {
}
}
]
}
}

View File

@ -0,0 +1,43 @@
{
"objects": [
{
"name": "firebox",
"texturePath": "resources/w/Cube001.png",
"meshPath": "resources/w/firebox.txt",
"rotationX": 0.0,
"rotationY": -1.5707963267948966,
"rotationZ": 0.0,
"positionX": 0.0,
"positionY": 0.0,
"positionZ": 0.0,
"scale": 1.0,
"interactive": false
},
{
"name": "inai",
"texturePath": "resources/w/inai001.png",
"meshPath": "resources/w/inai001.txt",
"rotationX": 0.0,
"rotationY": -1.5707963267948966,
"rotationZ": 0.0,
"positionX": 2.5,
"positionY": 1.4,
"positionZ": -9.9,
"scale": 1.0,
"interactive": false
},
{
"name": "bench",
"texturePath": "resources/w/bench001opt.png",
"meshPath": "resources/w/bench002opt.txt",
"rotationX": 0.0,
"rotationY": 3.141592653589793,
"rotationZ": 0.0,
"positionX": -2.1,
"positionY": 0.5,
"positionZ": -7.9,
"scale": 3.0,
"interactive": false
}
]
}

View File

@ -0,0 +1,160 @@
{
"objects": [
{
"name": "door",
"texturePath": "resources/w/exterior/door002.png",
"meshPath": "resources/w/exterior/door002.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 0.0,
"positionY": 0.0,
"positionZ": 0.0,
"scale": 1.0,
"interactive": false
},
{
"name": "inai",
"texturePath": "resources/w/exterior/Main_Building.png",
"meshPath": "resources/w/exterior/Main_Building.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 0.0,
"positionY": 0.0,
"positionZ": 0.0,
"scale": 1.0,
"interactive": false
},
{
"name": "tree001",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": -1.5707963267948966,
"rotationZ": 0.0,
"positionX": 10.0,
"positionY": 0.0,
"positionZ": 12.0,
"scale": 1.0,
"interactive": false
},
{
"name": "tree002",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": 1.5707963267948966,
"rotationZ": 0.0,
"positionX": -12,
"positionY": 0.0,
"positionZ": 19.0,
"scale": 1.0,
"interactive": false
},
{
"name": "tree003",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": -12.0,
"positionY": 0.0,
"positionZ": 8.0,
"scale": 1.0,
"interactive": false
},
{
"name": "tree004",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": -1.5707963267948966,
"rotationZ": 0.0,
"positionX": -12.0,
"positionY": 0.0,
"positionZ": 0.0,
"scale": 1.0,
"interactive": false
},
{
"name": "tree005",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": 1.5707963267948966,
"rotationZ": 0.0,
"positionX": -12.0,
"positionY": 0.0,
"positionZ": -8.0,
"scale": 1.0,
"interactive": false
},
{
"name": "tree006",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 8.49915,
"positionY": 0.0,
"positionZ": -2.59884,
"scale": 1.0,
"interactive": false
},
{
"name": "tree007",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": -1.5707963267948966,
"rotationZ": 0.0,
"positionX": 14.5936,
"positionY": 0.0,
"positionZ": 5.3401,
"scale": 1.0,
"interactive": false
},
{
"name": "tree008",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": 1.5707963267948966,
"rotationZ": 0.0,
"positionX": 23.9295,
"positionY": 0.0,
"positionZ": 9.00583,
"scale": 1.0,
"interactive": false
},
{
"name": "tree009",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": 0.0,
"rotationZ": 0.0,
"positionX": 29.8128,
"positionY": 0.0,
"positionZ": -1.45278,
"scale": 1.0,
"interactive": false
},
{
"name": "tree010",
"texturePath": "resources/w/exterior/tree001.png",
"meshPath": "resources/w/exterior/tree003.txt",
"rotationX": 0.0,
"rotationY": -1.5707963267948966,
"rotationZ": 0.0,
"positionX": 33.1771,
"positionY": 0.0,
"positionZ": 14.609,
"scale": 1.0,
"interactive": false
}
]
}

View File

@ -0,0 +1,46 @@
{
"root": {
"type": "FrameLayout",
"name": "hud_root",
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "TextButton",
"name": "inventory_button",
"x": 50.0,
"y": 50.0,
"width": 150.0,
"height": 60.0,
"text": "Inventory",
"fontSize": 24,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": true,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": {
"normal": "resources/w/red.png",
"hover": "resources/w/red.png",
"pressed": "resources/w/red.png"
}
},
{
"type": "TextButton",
"name": "quest_journal_button",
"x": 220.0,
"y": 50.0,
"width": 170.0,
"height": 60.0,
"text": "Quests",
"fontSize": 24,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": true,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": {
"normal": "resources/w/red.png",
"hover": "resources/w/red.png",
"pressed": "resources/w/red.png"
}
}
]
}
}

View File

@ -0,0 +1,475 @@
{
"cellSize": 0.4,
"agentRadius": 0.45,
"floorY": 0.0,
"objectPadding": 0.25,
"boundaryPadding": 0.35,
"areas": [
{
"name": "main_corridor",
"available": true,
"polygon": [
[
-2.2,
0.8
],
[
2.2,
0.8
],
[
2.2,
-40.8
],
[
-2.2,
-40.8
]
]
},
{
"name": "left_door_05",
"available": true,
"polygon": [
[
-3.4,
-4.2
],
[
-2.0,
-4.2
],
[
-2.0,
-5.8
],
[
-3.4,
-5.8
]
]
},
{
"name": "right_door_05",
"available": true,
"polygon": [
[
2.0,
-4.2
],
[
3.4,
-4.2
],
[
3.4,
-5.8
],
[
2.0,
-5.8
]
]
},
{
"name": "left_room_05",
"available": true,
"polygon": [
[
-8.8,
-1.0
],
[
-3.0,
-1.0
],
[
-3.0,
-9.0
],
[
-8.8,
-9.0
]
]
},
{
"name": "right_room_05",
"available": true,
"polygon": [
[
3.0,
-1.0
],
[
8.8,
-1.0
],
[
8.8,
-9.0
],
[
3.0,
-9.0
]
]
},
{
"name": "left_door_15",
"available": true,
"polygon": [
[
-3.4,
-14.2
],
[
-2.0,
-14.2
],
[
-2.0,
-15.8
],
[
-3.4,
-15.8
]
]
},
{
"name": "right_door_15",
"available": true,
"polygon": [
[
2.0,
-14.2
],
[
3.4,
-14.2
],
[
3.4,
-15.8
],
[
2.0,
-15.8
]
]
},
{
"name": "left_room_15",
"available": true,
"polygon": [
[
-8.8,
-11.0
],
[
-3.0,
-11.0
],
[
-3.0,
-19.0
],
[
-8.8,
-19.0
]
]
},
{
"name": "right_room_15",
"available": true,
"polygon": [
[
3.0,
-11.0
],
[
8.8,
-11.0
],
[
8.8,
-19.0
],
[
3.0,
-19.0
]
]
},
{
"name": "left_door_25",
"available": true,
"polygon": [
[
-3.4,
-24.2
],
[
-2.0,
-24.2
],
[
-2.0,
-25.8
],
[
-3.4,
-25.8
]
]
},
{
"name": "right_door_25",
"available": true,
"polygon": [
[
2.0,
-24.2
],
[
3.4,
-24.2
],
[
3.4,
-25.8
],
[
2.0,
-25.8
]
]
},
{
"name": "left_room_25",
"available": true,
"polygon": [
[
-8.8,
-21.0
],
[
-3.0,
-21.0
],
[
-3.0,
-29.0
],
[
-8.8,
-29.0
]
]
},
{
"name": "right_room_25",
"available": true,
"polygon": [
[
3.0,
-21.0
],
[
8.8,
-21.0
],
[
8.8,
-29.0
],
[
3.0,
-29.0
]
]
},
{
"name": "left_door_35",
"available": true,
"polygon": [
[
-3.4,
-34.2
],
[
-2.0,
-34.2
],
[
-2.0,
-35.8
],
[
-3.4,
-35.8
]
]
},
{
"name": "right_door_35",
"available": true,
"polygon": [
[
2.0,
-34.2
],
[
3.4,
-34.2
],
[
3.4,
-35.8
],
[
2.0,
-35.8
]
]
},
{
"name": "left_room_35",
"available": true,
"polygon": [
[
-8.8,
-31.0
],
[
-3.0,
-31.0
],
[
-3.0,
-39.0
],
[
-8.8,
-39.0
]
]
},
{
"name": "right_room_35",
"available": true,
"polygon": [
[
3.0,
-31.0
],
[
8.8,
-31.0
],
[
8.8,
-39.0
],
[
3.0,
-39.0
]
]
}
],
"obstacles": [
{
"name": "firebox",
"polygon": [
[
-2.49468,
-32.87888
],
[
-2.05776,
-32.87888
],
[
-2.05776,
-31.51618
],
[
-2.49468,
-31.51618
]
]
},
{
"name": "bench",
"polygon": [
[
-2.54485,
-9.31999
],
[
-2.51786,
-9.3557
],
[
-2.48369,
-9.37177
],
[
-2.45574,
-9.38357
],
[
-2.17907,
-9.39566
],
[
-1.80829,
-9.40749
],
[
-1.7521,
-9.36413
],
[
-1.66462,
-9.28728
],
[
-1.65801,
-9.14512
],
[
-1.65114,
-7.22169
],
[
-1.65535,
-6.51944
],
[
-1.72626,
-6.42306
],
[
-1.76837,
-6.39498
],
[
-2.47166,
-6.39746
],
[
-2.5309,
-6.44135
],
[
-2.53691,
-7.18464
]
]
}
]
}

View File

@ -0,0 +1,676 @@
{
"cellSize": 0.4,
"agentRadius": 0.45,
"floorY": 0.0,
"objectPadding": 0.25,
"areas": [
{
"name": "main_corridor",
"available": true,
"polygon": [
[
-100,
100
],
[
100,
100
],
[
100,
-100
],
[
-100,
-100
]
]
}
],
"obstacles": [
{
"name": "door",
"polygon": [
[
-5.2,
7.08001
],
[
-5.19904,
7.07025
],
[
-5.19619,
7.06087
],
[
-5.19157,
7.05223
],
[
-5.18536,
7.04465
],
[
-5.17778,
7.03843
],
[
-5.16913,
7.03381
],
[
-5.15975,
7.03097
],
[
-5.15,
7.03001
],
[
-3.75,
7.13001
],
[
-3.625,
7.43001
],
[
-3.625,
8.83001
],
[
-3.75,
9.13001
],
[
-5.15,
9.23001
],
[
-5.15975,
9.22905
],
[
-5.16913,
9.2262
],
[
-5.17778,
9.22158
],
[
-5.18536,
9.21536
],
[
-5.19157,
9.20778
],
[
-5.19619,
9.19914
],
[
-5.19904,
9.18976
],
[
-5.2,
9.18001
]
]
},
{
"name": "inai",
"polygon": [
[
-3.75,
-15.0
],
[
3.75,
-15.0
],
[
3.75,
15.0
],
[
-3.75,
15.0
]
]
},
{
"name": "tree001",
"polygon": [
[
10.45,
12.0
],
[
10.38971,
12.225
],
[
10.225,
12.38971
],
[
10.0,
12.45
],
[
9.775,
12.38971
],
[
9.61029,
12.225
],
[
9.55,
12.0
],
[
9.61029,
11.775
],
[
9.775,
11.61029
],
[
10.0,
11.55
],
[
10.225,
11.61029
],
[
10.38971,
11.775
]
]
},
{
"name": "tree002",
"polygon": [
[
-11.55,
19.0
],
[
-11.61029,
19.225
],
[
-11.775,
19.38971
],
[
-12.0,
19.45
],
[
-12.225,
19.38971
],
[
-12.38971,
19.225
],
[
-12.45,
19.0
],
[
-12.38971,
18.775
],
[
-12.225,
18.61029
],
[
-12.0,
18.55
],
[
-11.775,
18.61029
],
[
-11.61029,
18.775
]
]
},
{
"name": "tree003",
"polygon": [
[
-11.55,
8.0
],
[
-11.61029,
8.225
],
[
-11.775,
8.38971
],
[
-12.0,
8.45
],
[
-12.225,
8.38971
],
[
-12.38971,
8.225
],
[
-12.45,
8.0
],
[
-12.38971,
7.775
],
[
-12.225,
7.61029
],
[
-12.0,
7.55
],
[
-11.775,
7.61029
],
[
-11.61029,
7.775
]
]
},
{
"name": "tree004",
"polygon": [
[
-11.55,
0.0
],
[
-11.61029,
0.225
],
[
-11.775,
0.38971
],
[
-12.0,
0.45
],
[
-12.225,
0.38971
],
[
-12.38971,
0.225
],
[
-12.45,
0.0
],
[
-12.38971,
-0.225
],
[
-12.225,
-0.38971
],
[
-12.0,
-0.45
],
[
-11.775,
-0.38971
],
[
-11.61029,
-0.225
]
]
},
{
"name": "tree005",
"polygon": [
[
-11.55,
-8.0
],
[
-11.61029,
-7.775
],
[
-11.775,
-7.61029
],
[
-12.0,
-7.55
],
[
-12.225,
-7.61029
],
[
-12.38971,
-7.775
],
[
-12.45,
-8.0
],
[
-12.38971,
-8.225
],
[
-12.225,
-8.38971
],
[
-12.0,
-8.45
],
[
-11.775,
-8.38971
],
[
-11.61029,
-8.225
]
]
},
{
"name": "tree006",
"polygon": [
[
8.94915,
-2.59884
],
[
8.88886,
-2.37384
],
[
8.72415,
-2.20913
],
[
8.49915,
-2.14884
],
[
8.27415,
-2.20913
],
[
8.10944,
-2.37384
],
[
8.04915,
-2.59884
],
[
8.10944,
-2.82384
],
[
8.27415,
-2.98855
],
[
8.49915,
-3.04884
],
[
8.72415,
-2.98855
],
[
8.88886,
-2.82384
]
]
},
{
"name": "tree007",
"polygon": [
[
15.0436,
5.3401
],
[
14.98331,
5.5651
],
[
14.8186,
5.72981
],
[
14.5936,
5.7901
],
[
14.3686,
5.72981
],
[
14.20389,
5.5651
],
[
14.1436,
5.3401
],
[
14.20389,
5.1151
],
[
14.3686,
4.95039
],
[
14.5936,
4.8901
],
[
14.8186,
4.95039
],
[
14.98331,
5.1151
]
]
},
{
"name": "tree008",
"polygon": [
[
24.3795,
9.00583
],
[
24.31921,
9.23083
],
[
24.1545,
9.39554
],
[
23.9295,
9.45583
],
[
23.7045,
9.39554
],
[
23.53979,
9.23083
],
[
23.4795,
9.00583
],
[
23.53979,
8.78083
],
[
23.7045,
8.61612
],
[
23.9295,
8.55583
],
[
24.1545,
8.61612
],
[
24.31921,
8.78083
]
]
},
{
"name": "tree009",
"polygon": [
[
30.2628,
-1.45278
],
[
30.20251,
-1.22778
],
[
30.0378,
-1.06307
],
[
29.8128,
-1.00278
],
[
29.5878,
-1.06307
],
[
29.42309,
-1.22778
],
[
29.3628,
-1.45278
],
[
29.42309,
-1.67778
],
[
29.5878,
-1.84249
],
[
29.8128,
-1.90278
],
[
30.0378,
-1.84249
],
[
30.20251,
-1.67778
]
]
},
{
"name": "tree010",
"polygon": [
[
33.6271,
14.609
],
[
33.56681,
14.834
],
[
33.4021,
14.99871
],
[
33.1771,
15.059
],
[
32.9521,
14.99871
],
[
32.78739,
14.834
],
[
32.7271,
14.609
],
[
32.78739,
14.384
],
[
32.9521,
14.21929
],
[
33.1771,
14.159
],
[
33.4021,
14.21929
],
[
33.56681,
14.384
]
]
}
]
}

View File

@ -0,0 +1,99 @@
{
"npcs": [
{
"id": "npc_04_ghost",
"name": "Беспокойный Призрак",
"texturePath": "resources/w/ghost_skin001.png",
"animationIdlePath": "resources/w/default_float001.anim",
"animationWalkPath": "resources/w/default_float001.anim",
"positionX": 0.0,
"positionY": 0.0,
"positionZ": -35.0,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.01,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0,
"interactionRadius": 1.0,
"gift": {
"id": "ghost_essence",
"name": "Ghost's Essence",
"description": "A mysterious essence from the Ghost realm",
"icon": "resources/w/red.png"
}
},
{
"id": "ghost_01x",
"name": "Опасный Призрак",
"texturePath": "resources/w/ghost_skin002.png",
"animationIdlePath": "resources/w/default_float001.anim",
"animationWalkPath": "resources/w/default_float001.anim",
"animationActionIdlePath": "resources/w/float_attack003_cut.anim",
"animationActionAttackPath": "resources/w/float_attack003.anim",
"animationStandToActionPath": "resources/w/default_float001_cut.anim",
"animationActionToStandPath": "resources/w/default_float001_cut.anim",
"animationActionToDeathPath": "resources/w/default_float001_cut.anim",
"animationDeathIdlePath": "resources/w/default_float001_cut.anim",
"positionX": 0.0,
"positionY": 0.0,
"positionZ": -20.0,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.01,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0,
"hp": 35,
"canAttack": true
},
{
"id": "ghost_02x",
"name": "Злой призрак",
"texturePath": "resources/w/ghost_skin002.png",
"animationIdlePath": "resources/w/default_float001.anim",
"animationWalkPath": "resources/w/default_float001.anim",
"animationActionIdlePath": "resources/w/float_attack003_cut.anim",
"animationActionAttackPath": "resources/w/float_attack003.anim",
"animationStandToActionPath": "resources/w/default_float001_cut.anim",
"animationActionToStandPath": "resources/w/default_float001_cut.anim",
"animationActionToDeathPath": "resources/w/default_float001_cut.anim",
"animationDeathIdlePath": "resources/w/default_float001_cut.anim",
"positionX": -5.91548,
"positionY": 0.0,
"positionZ": -25.1861,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.01,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0,
"hp": 25,
"canAttack": true
},
{
"id": "ghost_02x",
"name": "Злой дух",
"texturePath": "resources/w/ghost_skin002.png",
"animationIdlePath": "resources/w/default_float001.anim",
"animationWalkPath": "resources/w/default_float001.anim",
"animationActionIdlePath": "resources/w/float_attack003_cut.anim",
"animationActionAttackPath": "resources/w/float_attack003.anim",
"animationStandToActionPath": "resources/w/default_float001_cut.anim",
"animationActionToStandPath": "resources/w/default_float001_cut.anim",
"animationActionToDeathPath": "resources/w/default_float001_cut.anim",
"animationDeathIdlePath": "resources/w/default_float001_cut.anim",
"positionX": 6.64604,
"positionY": 0.0,
"positionZ": -16.0176,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.01,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0,
"hp": 15,
"canAttack": true
}
]
}

View File

@ -0,0 +1,85 @@
{
"npcs": [
{
"id": "npc_01_default",
"name": "Студент",
"animationIdlePath": "resources/w/jam/man_stand_idle002.anim",
"animationWalkPath": "resources/w/jam/man_walk002.anim",
"meshTextures": {
"Body": "resources/w/jam/male_packed0_diffuse.png",
"Bottoms": "resources/w/jam/male_packed1_diffuse.png",
"Eyelashes": "resources/w/jam/male_packed0_diffuse.png",
"Eyes": "resources/w/jam/male_packed0_diffuse.png",
"Eyewear": "resources/w/jam/male_packed0_diffuse.png",
"Gloves": "resources/w/jam/male_packed1_diffuse.png",
"Hair": "resources/w/jam/male_packed0_diffuse.png",
"Shoes": "resources/w/jam/male_packed1_diffuse.png",
"Tops": "resources/w/jam/male_packed2_diffuse.png"
},
"positionX": 2.95,
"positionY": 0.0,
"positionZ": 16.65,
"facingAngle" : 3.141592,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.0001,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0,
"interactionRadius": 2.0,
"gift": {
"id": "guard_token",
"name": "Guard's Token",
"description": "A token from the Guard - sign of respect",
"icon": "resources/w/red.png"
}
},
{
"id": "npc_02_woman",
"name": "Студентка",
"animationIdlePath": "resources/w/new_anims/girl_stand_idle005.txt",
"animationWalkPath": "resources/w/new_anims/girl_walk005.txt",
"meshTextures": {
"polySurface1": "resources/w/new_anims/Chat_02_diff.png"
},
"positionX": 19.5,
"positionY": 0.0,
"positionZ": 32.0,
"facingAngle" : 3.141592,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.00016,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0,
"interactionRadius": 2.0
},
{
"id": "npc_03_salesman",
"name": "Мухтар Байке",
"animationIdlePath": "resources/w/jam/salesperson_stand_idle003.anim",
"animationWalkPath": "resources/w/jam/salesperson_walk001.anim",
"meshTextures": {
"Body": "resources/w/jam/Salesperson_packed0_diffuse.png",
"Bottoms": "resources/w/jam/Salesperson_packed2_diffuse.png",
"Eyelashes": "resources/w/jam/Salesperson_packed0_diffuse.png",
"Eyes": "resources/w/jam/Salesperson_packed0_diffuse.png",
"Hats": "resources/w/jam/Salesperson_packed1_diffuse.png",
"Mustashes": "resources/w/jam/Salesperson_packed1_diffuse.png",
"Shoes": "resources/w/jam/Salesperson_packed1_diffuse.png",
"Tops": "resources/w/jam/Salesperson_packed1_diffuse.png"
},
"positionX": -1.94774,
"positionY": 0.0,
"positionZ": 16.2712,
"facingAngle" : 3.141592,
"walkSpeed": 1.5,
"rotationSpeed": 8.0,
"modelScale": 0.001,
"modelCorrectionRotX": 0.0,
"modelCorrectionRotY": 180.0,
"modelCorrectionRotZ": 0.0,
"interactionRadius": 2.0
}
]
}

View File

@ -0,0 +1,81 @@
{
"root": {
"type": "FrameLayout",
"name": "inventory_root",
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "FrameLayout",
"name": "inventory_items_panel",
"x": 50.0,
"y": 150.0,
"width": 320.0,
"height": 420.0,
"children": [
{
"type": "StaticImage",
"name": "panel_background",
"x": 0.0,
"y": 0.0,
"width": 320.0,
"height": 420.0,
"texture": "resources/w/red.png"
},
{
"type": "TextView",
"name": "inventory_title_text",
"x": 20.0,
"y": 18.0,
"width": 230.0,
"height": 34.0,
"text": "Inventory",
"fontSize": 24,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"paddingX": 0.0,
"paddingY": 0.0,
"color": [1.0, 1.0, 1.0, 1.0]
},
{
"type": "TextView",
"name": "inventory_items_text",
"x": 20.0,
"y": 70.0,
"width": 280.0,
"height": 320.0,
"text": "Inventory (Empty)",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"wrap": true,
"paddingX": 0.0,
"paddingY": 0.0,
"maxLines": 14,
"color": [1.0, 1.0, 1.0, 1.0]
},
{
"type": "TextButton",
"name": "close_inventory_button",
"x": 266.0,
"y": 16.0,
"width": 40.0,
"height": 40.0,
"text": "X",
"fontSize": 20,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": true,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": {
"normal": "resources/w/blue.png",
"hover": "resources/w/blue.png",
"pressed": "resources/w/blue.png"
}
}
]
}
]
}
}

View File

@ -0,0 +1,335 @@
{
"root": {
"type": "FrameLayout",
"name": "quest_journal_root",
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "FrameLayout",
"name": "quest_journal_panel",
"x": 55.0,
"y": 85.0,
"width": 1170.0,
"height": 590.0,
"children": [
{
"type": "StaticImage",
"name": "quest_panel_background",
"x": 0.0,
"y": 0.0,
"width": 1170.0,
"height": 590.0,
"texture": "resources/black.png"
},
{
"type": "TextView",
"name": "quest_journal_title_text",
"x": 0.0,
"y": 18.0,
"width": 1170.0,
"height": 44.0,
"text": "QUESTS",
"fontSize": 32,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": true,
"topAligned": true,
"paddingY": 2.0,
"color": [1.0, 1.0, 1.0, 1.0]
},
{
"type": "TextButton",
"name": "quest_close_button",
"x": 1110.0,
"y": 20.0,
"width": 38.0,
"height": 38.0,
"text": "X",
"fontSize": 20,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": true,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": {
"normal": "resources/w/blue.png",
"hover": "resources/w/blue.png",
"pressed": "resources/w/blue.png"
}
},
{
"type": "StaticImage",
"name": "quest_separator_left",
"x": 390.0,
"y": 88.0,
"width": 2.0,
"height": 470.0,
"texture": "resources/w/red.png"
},
{
"type": "StaticImage",
"name": "quest_separator_right",
"x": 770.0,
"y": 88.0,
"width": 2.0,
"height": 470.0,
"texture": "resources/w/red.png"
},
{
"type": "TextView",
"name": "quest_list_header_text",
"x": 35.0,
"y": 90.0,
"width": 330.0,
"height": 32.0,
"text": "ЗАДАНИЯ",
"fontSize": 22,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"paddingX": 4.0,
"paddingY": 0.0,
"color": [1.0, 0.88, 0.45, 1.0]
},
{
"type": "TextButton",
"name": "quest_slot_0",
"x": 35.0,
"y": 130.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextButton",
"name": "quest_slot_1",
"x": 35.0,
"y": 178.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextButton",
"name": "quest_slot_2",
"x": 35.0,
"y": 226.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextButton",
"name": "quest_slot_3",
"x": 35.0,
"y": 274.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextButton",
"name": "quest_slot_4",
"x": 35.0,
"y": 322.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextButton",
"name": "quest_slot_5",
"x": 35.0,
"y": 370.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextButton",
"name": "quest_slot_6",
"x": 35.0,
"y": 418.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextButton",
"name": "quest_slot_7",
"x": 35.0,
"y": 466.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextButton",
"name": "quest_slot_8",
"x": 35.0,
"y": 514.0,
"width": 330.0,
"height": 42.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": false,
"textPaddingX": 12.0,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": { "normal": "resources/transparent.png", "hover": "resources/w/blue.png", "pressed": "resources/w/blue.png" }
},
{
"type": "TextView",
"name": "quest_middle_title_text",
"x": 415.0,
"y": 94.0,
"width": 330.0,
"height": 72.0,
"text": "Выберите задание",
"fontSize": 22,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"wrap": true,
"paddingX": 8.0,
"paddingY": 4.0,
"maxLines": 2,
"color": [1.0, 0.88, 0.45, 1.0]
},
{
"type": "TextView",
"name": "quest_meta_text",
"x": 415.0,
"y": 168.0,
"width": 330.0,
"height": 48.0,
"text": "",
"fontSize": 16,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"wrap": true,
"paddingX": 8.0,
"paddingY": 2.0,
"maxLines": 2,
"color": [0.72, 0.72, 0.72, 1.0]
},
{
"type": "TextView",
"name": "quest_objectives_header_text",
"x": 415.0,
"y": 232.0,
"width": 330.0,
"height": 32.0,
"text": "ЦЕЛИ",
"fontSize": 20,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"paddingX": 8.0,
"paddingY": 0.0,
"color": [1.0, 0.88, 0.45, 1.0]
},
{
"type": "TextView",
"name": "quest_objectives_text",
"x": 415.0,
"y": 272.0,
"width": 330.0,
"height": 285.0,
"text": "",
"fontSize": 17,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"wrap": true,
"paddingX": 8.0,
"paddingY": 4.0,
"maxLines": 10,
"color": [0.88, 0.88, 0.88, 1.0]
},
{
"type": "TextView",
"name": "quest_lore_title_text",
"x": 795.0,
"y": 94.0,
"width": 330.0,
"height": 38.0,
"text": "Описание задания",
"fontSize": 22,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"paddingX": 8.0,
"paddingY": 0.0,
"color": [1.0, 0.88, 0.45, 1.0]
},
{
"type": "TextView",
"name": "quest_description_text",
"x": 795.0,
"y": 145.0,
"width": 330.0,
"height": 410.0,
"text": "",
"fontSize": 18,
"fontPath": "resources/fonts/DroidSans.ttf",
"centered": false,
"topAligned": true,
"wrap": true,
"paddingX": 8.0,
"paddingY": 6.0,
"maxLines": 15,
"color": [0.92, 0.92, 0.92, 1.0]
}
]
}
]
}
}

BIN
resources/connecting.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/connection_failed.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/connection_lost.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/dialogue/choice_main.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/dialogue/choice_optional.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/dialogue/choice_selected.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,290 @@
{
"dialogues": [
{
"id": "test_cutscene_skip_hold_dialogue",
"start": "cutscene_start",
"nodes": [
{
"id": "cutscene_start",
"type": "CutsceneStart",
"cutsceneId": "test_cutscene_skip_hold_01",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_cutscene_images_hardcut_dialogue",
"start": "cutscene_start",
"nodes": [
{
"id": "cutscene_start",
"type": "CutsceneStart",
"cutsceneId": "test_cutscene_images_hardcut_01",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_cutscene_images_crossfade_dialogue",
"start": "cutscene_start",
"nodes": [
{
"id": "cutscene_start",
"type": "CutsceneStart",
"cutsceneId": "test_cutscene_images_crossfade_01",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_cutscene_images_silent_dialogue",
"start": "cutscene_start",
"nodes": [
{
"id": "cutscene_start",
"type": "CutsceneStart",
"cutsceneId": "test_cutscene_images_silent_01",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
}
],
"cutscenes": [
{
"id": "test_cutscene_skip_hold_01",
"background": "resources/first_cutscene.png",
"skippable": true,
"durationMs": 12000,
"cameraTrack": [
{
"durationMs": 3000,
"from": { "anchor": "Center", "zoom": 1.0, "rotationDeg": 0.0 },
"to": { "anchor": "TopLeft", "zoom": 1.45, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 3000,
"from": { "anchor": "TopLeft", "zoom": 1.45, "rotationDeg": 0.0 },
"to": { "anchor": "TopRight", "zoom": 1.45, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 3000,
"from": { "anchor": "TopRight", "zoom": 1.45, "rotationDeg": 0.0 },
"to": { "anchor": "BottomRight", "zoom": 1.65, "rotationDeg": 0.0 },
"easing": "EaseInCubic"
},
{
"durationMs": 3000,
"from": { "anchor": "BottomRight", "zoom": 1.65, "rotationDeg": 0.0 },
"to": { "anchor": "BottomLeft", "zoom": 1.45, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
}
],
"lines": [
{
"speaker": "Narrator",
"portrait": "",
"text": "This cutscene is long enough to test hold-to-skip.",
"durationMs": 2600
},
{
"speaker": "Narrator",
"portrait": "",
"text": "A normal click must not skip it.",
"durationMs": 2600
},
{
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"text": "Only the skip button with hold should work.",
"durationMs": 2600
}
]
},
{
"id": "test_cutscene_images_hardcut_01",
"background": "resources/first_cutscene.png",
"skippable": true,
"durationMs": 9000,
"cameraTrack": [
{
"durationMs": 4500,
"from": { "anchor": "Center", "zoom": 1.0, "rotationDeg": 0.0 },
"to": { "anchor": "TopLeft", "zoom": 1.35, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 4500,
"from": { "anchor": "TopLeft", "zoom": 1.35, "rotationDeg": 0.0 },
"to": { "anchor": "BottomRight", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
}
],
"images": [
{
"path": "resources/first_cutscene.png",
"startMs": 0,
"endMs": 4500,
"fadeInMs": 0,
"fadeOutMs": 0
},
{
"path": "resources/second_cutscene.png",
"startMs": 4500,
"endMs": 9000,
"fadeInMs": 0,
"fadeOutMs": 0
}
],
"lines": [
{
"speaker": "Narrator",
"portrait": "",
"text": "First image should switch sharply to the second one.",
"durationMs": 2800
},
{
"speaker": "Narrator",
"portrait": "",
"text": "No fade should be visible here.",
"durationMs": 2800
}
]
},
{
"id": "test_cutscene_images_crossfade_01",
"background": "resources/first_cutscene.png",
"skippable": true,
"durationMs": 10000,
"cameraTrack": [
{
"durationMs": 2500,
"from": { "anchor": "Center", "zoom": 1.0, "rotationDeg": 0.0 },
"to": { "anchor": "Custom", "centerX": 0.35, "centerY": 0.30, "zoom": 1.45, "rotationDeg": 0.0 },
"easing": "EaseInOutQuad"
},
{
"durationMs": 2500,
"from": { "anchor": "Custom", "centerX": 0.35, "centerY": 0.30, "zoom": 1.45, "rotationDeg": 0.0 },
"to": { "anchor": "Custom", "centerX": 0.70, "centerY": 0.32, "zoom": 1.45, "rotationDeg": 0.0 },
"easing": "EaseOutCubic"
},
{
"durationMs": 2500,
"from": { "anchor": "Custom", "centerX": 0.70, "centerY": 0.32, "zoom": 1.45, "rotationDeg": 0.0 },
"to": { "anchor": "BottomRight", "zoom": 1.70, "rotationDeg": 0.0 },
"easing": "EaseInCubic"
},
{
"durationMs": 2500,
"from": { "anchor": "BottomRight", "zoom": 1.70, "rotationDeg": 0.0 },
"to": { "anchor": "BottomLeft", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
}
],
"images": [
{
"path": "resources/first_cutscene.png",
"startMs": 0,
"endMs": 6000,
"fadeInMs": 0,
"fadeOutMs": 0
},
{
"path": "resources/second_cutscene.png",
"startMs": 4500,
"endMs": 10000,
"fadeInMs": 1500,
"fadeOutMs": 0
}
],
"lines": [
{
"speaker": "Narrator",
"portrait": "",
"text": "The second image should fade over the first one.",
"durationMs": 2600
},
{
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"text": "This test checks overlap and alpha blending.",
"durationMs": 2600
}
]
},
{
"id": "test_cutscene_images_silent_01",
"background": "resources/first_cutscene.png",
"skippable": true,
"durationMs": 11000,
"cameraTrack": [
{
"durationMs": 2500,
"from": { "anchor": "Center", "zoom": 1.0, "rotationDeg": 0.0 },
"to": { "anchor": "TopLeft", "zoom": 1.35, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 3000,
"from": { "anchor": "TopLeft", "zoom": 1.35, "rotationDeg": 0.0 },
"to": { "anchor": "TopRight", "zoom": 1.35, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 3000,
"from": { "anchor": "TopRight", "zoom": 1.35, "rotationDeg": 0.0 },
"to": { "anchor": "BottomRight", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseOutCubic"
},
{
"durationMs": 2500,
"from": { "anchor": "BottomRight", "zoom": 1.55, "rotationDeg": 0.0 },
"to": { "anchor": "BottomLeft", "zoom": 1.45, "rotationDeg": 0.0 },
"easing": "EaseInOutQuad"
}
],
"images": [
{
"path": "resources/first_cutscene.png",
"startMs": 0,
"endMs": 3500,
"fadeInMs": 0,
"fadeOutMs": 800
},
{
"path": "resources/second_cutscene.png",
"startMs": 3000,
"endMs": 7500,
"fadeInMs": 800,
"fadeOutMs": 1000
},
{
"path": "resources/loading.png",
"startMs": 7000,
"endMs": 11000,
"fadeInMs": 1000,
"fadeOutMs": 0
}
],
"lines": []
}
]
}

BIN
resources/dialogue/cutscene_subtitle_bg.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/dialogue/portrait_frame.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,475 @@
{
"dialogues": [
{
"id": "dialog_student",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Студент",
"portrait": "resources/w/avatar_unknown.png",
"text": "В университете завелись призраки, мне страшно ходить на занятия.",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Можешь рассказать подробнее?",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Студент",
"portrait": "resources/w/avatar_unknown.png",
"text": "Спроси у Мухтара байке, он все знает.",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Хорошо.",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "dialog_mukhtar",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Мухтар байке",
"portrait": "resources/w/avatar_unknown.png",
"text": "Здравствуй, мы давно тебя ждем! Ты поможешь нам избавиться от призраков?",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Где их найти?",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Мухтар байке",
"portrait": "resources/w/avatar_unknown.png",
"text": "Заходи в здание универа и поднимайся на второй этаж.",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Мухтар байке",
"portrait": "resources/w/avatar_unknown.png",
"text": "Ты их встретишь прямо там.",
"next": "line_5"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Хорошо, я скоро вернусь!",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "dialog_female_student",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Студентка",
"portrait": "resources/w/avatar_unknown.png",
"text": "С этими призраками совсем невозможно ходить на лекции!",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_line_dialogue",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"text": "Наконец-то ты пришел.",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Ты сделан из дыма?",
"next": "line_3"
},
{
"id": "line_3",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"text": "Ты думаешь, это смешно?",
"next": "line_4"
},
{
"id": "line_4",
"type": "Line",
"speaker": "Hero",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Я думаю что ты пахнешь как выхлоп от Камаза.",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "ghost_choice_dialogue",
"start": "line_1",
"nodes": [
{
"id": "line_1",
"type": "Line",
"speaker": "Беспокойный Призрак",
"portrait": "resources/ghost_avatar.png",
"text": "Нечасто я вижу смертных, готовых разговаривать со мной.",
"next": "choice_1"
},
{
"id": "choice_1",
"type": "Choice",
"speaker": "Hero",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "",
"choices": [
{
"id": "main_1",
"kind": "Main",
"text": "Не мешай студентам учиться!",
"next": "line_goods"
},
{
"id": "optional_1",
"kind": "Optional",
"text": "Почему ты появился здесь?",
"next": "line_who"
}
]
},
{
"id": "line_goods",
"type": "Line",
"speaker": "Беспокойный Призрак",
"portrait": "resources/ghost_avatar.png",
"text": "Это моя месть студентам за то что они призвали меня.",
"next": "end_1"
},
{
"id": "line_who",
"type": "Line",
"speaker": "Беспокойный Призрак",
"portrait": "resources/ghost_avatar.png",
"text": "Группа студентов совершила ритуал и призвала меня сюда. Пока проклятие не спадет, я всегда буду здесь обитать.",
"next": "choice_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_condition_dialogue",
"start": "set_flag_1",
"nodes": [
{
"id": "set_flag_1",
"type": "SetFlag",
"effects": [
{ "flag": "met_ghost", "value": 1 }
],
"next": "condition_1"
},
{
"id": "condition_1",
"type": "Condition",
"conditions": [
{ "flag": "met_ghost", "op": "Equals", "value": 1 }
],
"trueNext": "line_true",
"falseNext": "line_false"
},
{
"id": "line_true",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"text": "Now you know who I am.",
"next": "end_1"
},
{
"id": "line_false",
"type": "Line",
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"text": "You should not hear this line.",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_cutscene_dialogue",
"start": "cutscene_start",
"nodes": [
{
"id": "cutscene_start",
"type": "CutsceneStart",
"cutsceneId": "test_cutscene_01",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_silent_cutscene_dialogue",
"start": "cutscene_start",
"nodes": [
{
"id": "cutscene_start",
"type": "CutsceneStart",
"cutsceneId": "test_cutscene_silent_01",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_cutscene_pan_dialogue",
"start": "cutscene_start",
"nodes": [
{
"id": "cutscene_start",
"type": "CutsceneStart",
"cutsceneId": "test_cutscene_pan_01",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
},
{
"id": "test_cutscene_pan_dialogue_silent",
"start": "cutscene_start",
"nodes": [
{
"id": "cutscene_start",
"type": "CutsceneStart",
"cutsceneId": "test_cutscene_pan_02",
"next": "end_1"
},
{
"id": "end_1",
"type": "End"
}
]
}
],
"cutscenes": [
{
"id": "test_cutscene_01",
"background": "resources/first_cutscene.png",
"durationMs": 6800,
"cameraTrack": [
{
"durationMs": 2400,
"from": { "focusX": 0.50, "focusY": 0.55, "zoom": 1.00, "rotationDeg": 0.0 },
"to": { "focusX": 0.63, "focusY": 0.58, "zoom": 1.16, "rotationDeg": -1.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 2200,
"from": { "focusX": 0.63, "focusY": 0.58, "zoom": 1.16, "rotationDeg": -1.0 },
"to": { "focusX": 0.74, "focusY": 0.52, "zoom": 1.30, "rotationDeg": -2.4 },
"easing": "EaseInOutCubic"
},
{
"durationMs": 2200,
"from": { "focusX": 0.74, "focusY": 0.52, "zoom": 1.30, "rotationDeg": -2.4 },
"to": { "focusX": 0.58, "focusY": 0.46, "zoom": 1.10, "rotationDeg": -0.6 },
"easing": "EaseOutSine"
}
],
"lines": [
{
"speaker": "Narrator",
"portrait": "resources/hero.png",
"text": "The air in the room turned cold.",
"durationMs": 2200
},
{
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"text": "Some memories never fade.",
"durationMs": 2600,
"background": "resources/loading.png"
}
]
},
{
"id": "test_cutscene_silent_01",
"background": "resources/first_cutscene.png",
"durationMs": 5200,
"cameraTrack": [
{
"durationMs": 2600,
"from": { "focusX": 0.40, "focusY": 0.54, "zoom": 1.00, "rotationDeg": 0.0 },
"to": { "focusX": 0.58, "focusY": 0.54, "zoom": 1.22, "rotationDeg": 0.8 },
"easing": "EaseInOutSine"
},
{
"durationMs": 2600,
"from": { "focusX": 0.58, "focusY": 0.54, "zoom": 1.22, "rotationDeg": 0.8 },
"to": { "focusX": 0.72, "focusY": 0.48, "zoom": 1.34, "rotationDeg": -0.5 },
"easing": "EaseOutCubic"
}
],
"lines": []
},
{
"id": "test_cutscene_pan_01",
"background": "resources/first_cutscene.png",
"durationMs": 12000,
"cameraTrack": [
{
"durationMs": 1200,
"from": { "anchor": "Center", "zoom": 1.00, "rotationDeg": 0.0 },
"to": { "anchor": "Center", "zoom": 1.00, "rotationDeg": 0.0 },
"easing": "Linear"
},
{
"durationMs": 2500,
"from": { "anchor": "Center", "zoom": 1.00, "rotationDeg": 0.0 },
"to": { "anchor": "TopLeft", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 2600,
"from": { "anchor": "TopLeft", "zoom": 1.55, "rotationDeg": 0.0 },
"to": { "anchor": "TopRight", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 1800,
"from": { "anchor": "TopRight", "zoom": 1.55, "rotationDeg": 0.0 },
"to": { "anchor": "BottomRight", "zoom": 1.72, "rotationDeg": 0.0 },
"easing": "EaseInCubic"
},
{
"durationMs": 3900,
"from": { "anchor": "BottomRight", "zoom": 1.72, "rotationDeg": 0.0 },
"to": { "anchor": "BottomLeft", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
}
],
"lines": [
{
"speaker": "Narrator",
"portrait": "resources/hero.png",
"text": "The memory begins in silence.",
"durationMs": 2200
},
{
"speaker": "Narrator",
"portrait": "resources/hero.png",
"text": "Something is drawing your eyes across the whole scene.",
"durationMs": 2800
},
{
"speaker": "Ghost",
"portrait": "resources/ghost_avatar.png",
"text": "Do not look away.",
"durationMs": 2400
}
]
},
{
"id": "test_cutscene_pan_02",
"background": "resources/first_cutscene.png",
"durationMs": 12000,
"cameraTrack": [
{
"durationMs": 1200,
"from": { "anchor": "Center", "zoom": 1.00, "rotationDeg": 0.0 },
"to": { "anchor": "Center", "zoom": 1.00, "rotationDeg": 0.0 },
"easing": "Linear"
},
{
"durationMs": 2500,
"from": { "anchor": "Center", "zoom": 1.00, "rotationDeg": 0.0 },
"to": { "anchor": "TopLeft", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 2600,
"from": { "anchor": "TopLeft", "zoom": 1.55, "rotationDeg": 0.0 },
"to": { "anchor": "TopRight", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
},
{
"durationMs": 1800,
"from": { "anchor": "TopRight", "zoom": 1.55, "rotationDeg": 0.0 },
"to": { "anchor": "BottomRight", "zoom": 1.72, "rotationDeg": 0.0 },
"easing": "EaseInCubic"
},
{
"durationMs": 3900,
"from": { "anchor": "BottomRight", "zoom": 1.72, "rotationDeg": 0.0 },
"to": { "anchor": "BottomLeft", "zoom": 1.55, "rotationDeg": 0.0 },
"easing": "EaseInOutSine"
}
],
"lines": []
}
]
}

BIN
resources/dialogue/textbox_bg.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/fire.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/fire2.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/fire_disabled.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/first_cutscene.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/game_over/Container.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/Filledbuttons.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/FinalScore.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/MissionFailed.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/Secondarybutton.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/Variant5.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/Variant6.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/reconnect1.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/reconnect2.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/game_over/reconnect3.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/ghost_avatar.png (Stored with Git LFS) Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
resources/help_bottom_left.png (Stored with Git LFS)

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
resources/help_bottom_right.png (Stored with Git LFS)

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
resources/help_top_left.png (Stored with Git LFS)

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
resources/help_top_right.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/hero.png (Stored with Git LFS) Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More