Death animation

This commit is contained in:
2025-11-30 21:37:31 -08:00
parent c491ea5050
commit 8f8cc217dc
11 changed files with 338 additions and 146 deletions

View File

@@ -36,12 +36,18 @@ public class HealthComponent : IHealthComponent
public void Heal(int healAmount)
{
if (CurrentHP.Value <= 0)
return;
var cappedAmount = Math.Min(healAmount + _currentHP.Value, _maximumHP.Value);
_currentHP.OnNext(cappedAmount);
}
public void Damage(int damageAmount)
{
if (CurrentHP.Value <= 0)
return;
var cappedAmount = Math.Max(_currentHP.Value - damageAmount, 0);
_currentHP.OnNext(cappedAmount);

View File

@@ -1,140 +1,42 @@
// Attach to a ColorRect in front of texture/background
shader_type canvas_item;
// Handles the resolution changes, color depth, and dithering
group_uniforms resolution_and_colors;
uniform bool change_color_depth = false;
uniform int target_color_depth : hint_range(1, 8) = 5;
uniform bool dithering = false;
uniform bool scale_resolution = false;
uniform int target_resolution_scale = 3;
// Handles the concentric ripples
uniform float frequency: hint_range(0, 15, 0.01) = 4.0;
uniform float amplitude: hint_range(0, 3, 0.1) = 2.0;
uniform float ripple_rate : hint_range(0, 20.0, 1) = 5;
// Handles the LUTish recoloring
group_uniforms gradient_recoloring;
uniform bool enable_recolor = false;
uniform sampler2D to_gradient: hint_default_black;
// Handles the waves themselves
uniform float wave_amplitude: hint_range(0.001, 0.1, 0.001) = 0.05;
uniform float wave_frequency: hint_range(0, 15, 0.01) = 4.0;
int dithering_pattern(ivec2 fragcoord) {
const int pattern[] = {
-4, +0, -3, +1,
+2, -2, +3, -1,
-3, +1, -4, +0,
+3, -1, +2, -2
};
uniform sampler2D noise;
int x = fragcoord.x % 4;
int y = fragcoord.y % 4;
uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, filter_linear_mipmap;
return pattern[y * 4 + x];
}
vec3 rgb2hsv(vec3 rgb) { //Converts RGB values to HSV
float r = rgb.r;
float g = rgb.g;
float b = rgb.b;
float cmax = max(r,max(g,b));
float cmin = min(r,min(g,b));
float delta = cmax - cmin;
float h = 0.f; //hue
if (delta > 0.f){
if (cmax == r){
h = (g-b)/delta;
h = mod(h,6.f);
} else if (cmax == g){
h = ((b - r) / delta) + 2.f;
} else {
h = ((r-g)/delta) + 4.f;
}
h = h * 60.f;
}
float s = 0.f; //saturation
if (cmax > 0.f){
s = delta / cmax;
}
return vec3(h,s,cmax); // Keep original alpha value
}
vec3 hsv2rgb(vec3 hsv) { //Converts HSV values to RGB
float h = hsv.r;
float s = hsv.g;
float v = hsv.b;
float c = v * s;
//X = C × (1 - |(H / 60°) mod 2 - 1|)
float x = h / 60.f;
x = mod(x,2.f);
x = abs(x - 1.f);
x = c * (1.f - x);
float m = v - c;
vec3 rgb = vec3(0.f,0.f,0.f);
if (h < 60.f) {
rgb = vec3(c,x,0.f);
} else if (h < 120.f){
rgb = vec3(x,c,0.f);
} else if (h < 180.f){
rgb = vec3(0.f,c,x);
} else if (h < 240.f){
rgb = vec3(0.f,x,c);
} else if (h < 300.f){
rgb = vec3(x,0.f,c);
} else if (h < 360.f){
rgb = vec3(c,0.f,x);
}
rgb[0] = rgb[0] + m;
rgb[1] = rgb[1] + m;
rgb[2] = rgb[2] + m;
return rgb;
vec2 wave(vec2 uv, float time) {
return vec2(
uv.x + sin(uv.y * wave_frequency + time) * wave_amplitude,
uv.y + sin(uv.x * wave_frequency + time) * wave_amplitude
);
}
void fragment() {
ivec2 uv;
vec3 color;
vec2 center_position = -1.0 + 2.0 * UV / (1.0 / TEXTURE_PIXEL_SIZE);
float center_distance = length(center_position);
if(scale_resolution){
uv = ivec2(FRAGCOORD.xy / float(target_resolution_scale));
color = texelFetch(TEXTURE, uv * target_resolution_scale, 0).rgb;
} else {
uv = ivec2(FRAGCOORD.xy);
color = texelFetch(TEXTURE, uv, 0).rgb;
}
float ripple = sin(center_distance * -frequency * PI + ripple_rate * TIME) * amplitude / (center_distance + 1.0);
if(enable_recolor){
vec3 hsv = rgb2hsv(color);
float color_pos = (hsv.x / 360.0);
vec3 new_color = texture(to_gradient, vec2((color_pos), 0.5)).rgb;
vec3 new_hsv = rgb2hsv(new_color);
hsv.x = new_hsv.x;
vec3 final_rgb = hsv2rgb(hsv);
vec2 uv = FRAGCOORD.xy / (1.0 / SCREEN_PIXEL_SIZE).xy + (center_position/center_distance) * ripple * wave_amplitude;
vec2 background_wave = wave(uv, TIME);
vec4 background_texture = texture(SCREEN_TEXTURE,background_wave) * sqrt(amplitude);
color.rgb = final_rgb;
}
float alpha_scalar = (1.0 - min(center_distance, 1.0)) * background_texture.x * 2.5;
background_texture.a *= 1.0 * alpha_scalar * (ripple + background_texture.x * background_texture.y);
background_texture.a = max(background_texture.a - (background_texture.y * 0.45), 0.0);
// Convert from [0.0, 1.0] range to [0, 255] range
ivec3 c = ivec3(round(color * 255.0));
COLOR = vec4(background_texture.xyz, background_texture.a);
// Apply the dithering pattern
if (dithering) {
c += ivec3(dithering_pattern(uv));
}
vec3 final_color;
if(change_color_depth){
// Truncate from 8 bits to color_depth bits
c >>= (8 - target_color_depth);
final_color = vec3(c) / float(1 << target_color_depth);
} else {
final_color = vec3(c) / float(1 << 8);
}
// Convert back to [0.0, 1.0] range
COLOR.rgb = final_color;
}

View File

@@ -124,8 +124,8 @@ max_polyphony = 3
[node name="EngagePlayerBehavior" parent="Components" instance=ExtResource("14_xdeci")]
unique_name_in_owner = true
_minimumAttackTime = 10.0
_maximumAttackTime = 15.0
_minimumAttackTime = 5.0
_maximumAttackTime = 10.0
[node name="PlayerDetector" type="Area3D" parent="."]
unique_name_in_owner = true

View File

@@ -333,8 +333,8 @@ public partial class Game : Node3D, IGame
})
.Handle((in GameState.Output.GameOver _) =>
{
GameRepo.Pause();
DeathMenu.FadeIn();
//GameRepo.Pause();
//DeathMenu.FadeIn();
});
}

View File

@@ -1,28 +1,17 @@
[gd_scene load_steps=9 format=3 uid="uid://33ek675mfb5n"]
[gd_scene load_steps=7 format=3 uid="uid://33ek675mfb5n"]
[ext_resource type="Script" uid="uid://chftlu4proh3d" path="res://src/game/Game.cs" id="1_ytcii"]
[ext_resource type="Shader" uid="uid://dmjxo4k2rx1an" path="res://src/app/App.gdshader" id="2_6ifxs"]
[ext_resource type="PackedScene" uid="uid://b1muxus5qdbeu" path="res://src/ui/in_game_ui/InGameUI.tscn" id="5_lxtnp"]
[ext_resource type="Script" uid="uid://cbal5oeaha4nx" path="res://src/ui/pause_menu/PauseMenu.cs" id="11_5ng8c"]
[ext_resource type="PackedScene" uid="uid://pu6gp8de3ck4" path="res://src/ui/floor_clear/FloorClearMenu.tscn" id="11_rya1n"]
[ext_resource type="PackedScene" uid="uid://dbtfgrtgpr4qg" path="res://src/ui/death_menu/DeathMenu.tscn" id="11_wypid"]
[ext_resource type="PackedScene" uid="uid://blbqgw3wosc1w" path="res://src/ui/pause_menu/PauseMenu.tscn" id="12_yev8k"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_e75a2"]
shader = ExtResource("2_6ifxs")
shader_parameter/change_color_depth = false
shader_parameter/target_color_depth = 7
shader_parameter/dithering = false
shader_parameter/scale_resolution = false
shader_parameter/target_resolution_scale = 4
shader_parameter/enable_recolor = false
[node name="Game" type="Node3D"]
process_mode = 3
script = ExtResource("1_ytcii")
[node name="SubViewportContainer" type="SubViewportContainer" parent="."]
material = SubResource("ShaderMaterial_e75a2")
custom_minimum_size = Vector2(1440, 1080)
anchors_preset = 15
anchor_right = 1.0

View File

@@ -0,0 +1,54 @@
shader_type spatial;
render_mode unshaded, fog_disabled;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
uniform vec3 colorCount = vec3(32); //Max HSV Count
uniform vec3 colorShift = vec3(1.0); //Shift HSV colors
uniform bool doShiftFirst = false; // do shifting colors first or flooring colors
uniform bool includeAlpha = true; // Include alpha objects. if certain objects that have alpha aren`t rendering disabling might help
vec3 hsv_to_rgb(vec3 color) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(color.xxx + K.xyz) * 6.0 - K.www);
return color.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), color.y);
}
vec3 rgb_to_hsv(vec3 color) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(color.bg, K.wz), vec4(color.gb, K.xy), step(color.b, color.g));
vec4 q = mix(vec4(p.xyw, color.r), vec4(color.r, p.yzx), step(p.x, color.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
void vertex()
{
POSITION = vec4(VERTEX.xy, 1.0, 1.0);
}
void fragment() {
vec4 tex = texture(SCREEN_TEXTURE, vec2(UV.x, -UV.y));
vec3 hvs = rgb_to_hsv(tex.xyz);
if (doShiftFirst){
hvs.xyz = (hvs * colorShift);
}
hvs.x = floor(hvs.x * colorCount.x) / colorCount.x;
hvs.y = floor(hvs.y * colorCount.y) / colorCount.y;
hvs.z = floor(hvs.z * colorCount.z) / colorCount.z;
if (!doShiftFirst){
hvs.xyz = (hvs * colorShift);
}
ALBEDO = hsv_to_rgb(hvs.xyz);
if (!includeAlpha){
ALPHA = tex.w;
}
}

View File

@@ -0,0 +1 @@
uid://dfk3eps71yyyl

View File

@@ -74,6 +74,8 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
#region Node Dependencies
[Node] private IAnimationPlayer AnimationPlayer { get; set; } = default!;
[Node] private IAnimationPlayer PlayerFXAnimations { get; set; } = default!;
[Node] private Area3D Hitbox { get; set; } = default!;
[Node] private Area3D CollisionDetector { get; set; } = default!;
@@ -83,6 +85,8 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
[Node] private RigidBody3D WallCheck { get; set; } = default!;
[Node] private AudioStreamPlayer3D WalkSFX { get; set; } = default!;
[Node] private CollisionShape3D MainCollision { get; set; } = default!;
#endregion
@@ -164,6 +168,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
public void Activate()
{
MainCollision.Disabled = false;
SetProcessInput(true);
SetPhysicsProcess(true);
SetHealthTimerStatus(HealthTimerIsActive);
@@ -171,6 +176,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
public void Deactivate()
{
MainCollision.Disabled = true;
SetProcessInput(false);
SetPhysicsProcess(false);
SetHealthTimerStatus(false);
@@ -213,6 +219,7 @@ public partial class Player : CharacterBody3D, IPlayer, IProvide<IPlayer>
public void Die()
{
PlayerFXAnimations.Play("death");
HealthTimer.WaitTime = _healthTimerWaitTime;
HealthTimer.Timeout -= OnHealthTimerTimeout;
SetProcessInput(false);

View File

@@ -1,8 +1,9 @@
[gd_scene load_steps=55 format=3 uid="uid://cfecvvav8kkp6"]
[gd_scene load_steps=59 format=3 uid="uid://cfecvvav8kkp6"]
[ext_resource type="Script" uid="uid://yxmiqy7i0t7r" path="res://src/player/Player.cs" id="1_xcol5"]
[ext_resource type="AudioStream" uid="uid://cth2xgoqhdf0m" path="res://src/audio/sfx/player_hit_wall.ogg" id="3_565yv"]
[ext_resource type="Texture2D" uid="uid://c4ps26w7h3vpq" path="res://src/minimap/textures/player_map_icon.png" id="4_3ojaj"]
[ext_resource type="Shader" uid="uid://dfk3eps71yyyl" path="res://src/player/InvertColors.gdshader" id="4_v5qoq"]
[ext_resource type="Texture2D" uid="uid://2ig1arptr1e8" path="res://src/vfx/Items Etc/slash_2.png" id="4_v7rlw"]
[ext_resource type="Texture2D" uid="uid://qhxl3nejqlk1" path="res://src/vfx/World/DUST_1.png" id="5_v5qoq"]
[ext_resource type="AudioStream" uid="uid://bsprdc3ka6am0" path="res://src/audio/sfx/player_steps_concrete.ogg" id="6_v7rlw"]
@@ -11,6 +12,13 @@
radius = 1.0
height = 3.07596
[sub_resource type="ShaderMaterial" id="ShaderMaterial_jtmj1"]
[sub_resource type="QuadMesh" id="QuadMesh_v7rlw"]
material = SubResource("ShaderMaterial_jtmj1")
flip_faces = true
size = Vector2(2, 2)
[sub_resource type="Animation" id="Animation_3ojaj"]
resource_name = "IconAnimation"
length = 2.5
@@ -154,6 +162,66 @@ tracks/1/keys = {
"update": 1,
"values": [0]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../Camera/Camera3D:position")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(0.003, 1.2, -0.01)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("../Camera/Camera3D/MeshInstance3D:mesh:material:shader")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [null]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("../Camera/Camera3D/MeshInstance3D:mesh:material:shader_parameter/colorCount")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(32, 32, 32)]
}
tracks/5/type = "value"
tracks/5/imported = false
tracks/5/enabled = true
tracks/5/path = NodePath("../Camera/Camera3D/MeshInstance3D:mesh:material:shader_parameter/includeAlpha")
tracks/5/interp = 1
tracks/5/loop_wrap = true
tracks/5/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [true]
}
tracks/6/type = "value"
tracks/6/imported = false
tracks/6/enabled = true
tracks/6/path = NodePath("../Camera/Camera3D/MeshInstance3D:mesh:material:shader_parameter/colorShift")
tracks/6/interp = 1
tracks/6/loop_wrap = true
tracks/6/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(1, 1, 1)]
}
[sub_resource type="Animation" id="Animation_ebyyx"]
resource_name = "hit_wall"
@@ -213,9 +281,74 @@ tracks/1/keys = {
"values": [0, 30]
}
[sub_resource type="Animation" id="Animation_es4xk"]
resource_name = "death"
length = 2.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("../Camera/Camera3D:position")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 2),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(0.003, 1.2, -0.01), Vector3(0.003, 0, -1)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("../Camera/Camera3D/MeshInstance3D:mesh:material:shader")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(3.35872e-05),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [ExtResource("4_v5qoq")]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("../Camera/Camera3D/MeshInstance3D:mesh:material:shader_parameter/colorCount")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(-0.266666, 0, 0.0333338),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector3(640.06, 1, 640), Vector3(640, 640, 640), Vector3(640.06, 1, 640)]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("../Camera/Camera3D/MeshInstance3D:mesh:material:shader_parameter/includeAlpha")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [true]
}
tracks/4/type = "value"
tracks/4/imported = false
tracks/4/enabled = true
tracks/4/path = NodePath("../Camera/Camera3D/MeshInstance3D:mesh:material:shader_parameter/colorShift")
tracks/4/interp = 1
tracks/4/loop_wrap = true
tracks/4/keys = {
"times": PackedFloat32Array(0, 2.5),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [Vector3(1, 1, 1), Vector3(1, 1, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_ebyyx"]
_data = {
&"RESET": SubResource("Animation_jtmj1"),
&"death": SubResource("Animation_es4xk"),
&"hit_wall": SubResource("Animation_ebyyx"),
&"normal_attack": SubResource("Animation_v5qoq")
}
@@ -492,7 +625,8 @@ collision_layer = 802
collision_mask = 775
script = ExtResource("1_xcol5")
[node name="PlayerGeometryCollision" type="CollisionShape3D" parent="."]
[node name="MainCollision" type="CollisionShape3D" parent="."]
unique_name_in_owner = true
transform = Transform3D(-0.0242399, 0.00507889, 0.999693, 0.000123113, 0.999987, -0.00507739, -0.999706, 0, -0.0242402, 0, 1.06447, 0.00162865)
shape = SubResource("CapsuleShape3D_dw45s")
@@ -511,6 +645,10 @@ fov = 52.0
near = 0.01
far = 9000.0
[node name="MeshInstance3D" type="MeshInstance3D" parent="Camera/Camera3D"]
extra_cull_margin = 16384.0
mesh = SubResource("QuadMesh_v7rlw")
[node name="player_model" type="Node3D" parent="Camera"]
transform = Transform3D(-0.015, 0, -2.26494e-09, 0, 0.015, 0, 2.26494e-09, 0, -0.015, 0, -0.268445, -0.00941753)

View File

@@ -0,0 +1,48 @@
[gd_resource type="VisualShader" load_steps=4 format=3 uid="uid://dj8qw2316m8ju"]
[sub_resource type="VisualShaderNodeVec3Constant" id="VisualShaderNodeVec3Constant_jppg4"]
[sub_resource type="VisualShaderNodeTexture" id="VisualShaderNodeTexture_32eaw"]
source = 1
[sub_resource type="VisualShaderNodeVectorFunc" id="VisualShaderNodeVectorFunc_0twpm"]
function = 32
[resource]
code = "shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx, wireframe;
uniform sampler2D screen_tex_frg_4 : hint_screen_texture;
void fragment() {
// Vector3Constant:2
vec3 n_out2p0 = vec3(0.000000, 0.000000, 0.000000);
vec4 n_out4p0;
// Texture2D:4
n_out4p0 = texture(screen_tex_frg_4, SCREEN_UV);
// VectorFunc:5
vec3 n_out5p0 = vec3(1.0) - vec3(n_out4p0.xyz);
// Output:0
SPECULAR = n_out2p0.x;
EMISSION = n_out5p0;
}
"
graph_offset = Vector2(-584.421, 209.987)
flags/wireframe = true
nodes/fragment/2/node = SubResource("VisualShaderNodeVec3Constant_jppg4")
nodes/fragment/2/position = Vector2(-340, 280)
nodes/fragment/4/node = SubResource("VisualShaderNodeTexture_32eaw")
nodes/fragment/4/position = Vector2(-640, 640)
nodes/fragment/5/node = SubResource("VisualShaderNodeVectorFunc_0twpm")
nodes/fragment/5/position = Vector2(-140, 620)
nodes/fragment/connections = PackedInt32Array(2, 0, 0, 4, 4, 0, 5, 0, 5, 0, 0, 5)

View File

@@ -0,0 +1,47 @@
[gd_resource type="VisualShader" load_steps=4 format=3 uid="uid://bqarkh52u6xvg"]
[sub_resource type="VisualShaderNodeVec3Constant" id="VisualShaderNodeVec3Constant_jppg4"]
[sub_resource type="VisualShaderNodeTexture" id="VisualShaderNodeTexture_32eaw"]
source = 1
[sub_resource type="VisualShaderNodeVectorFunc" id="VisualShaderNodeVectorFunc_0twpm"]
function = 32
[resource]
code = "shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_lambert, specular_schlick_ggx;
uniform sampler2D screen_tex_frg_4 : hint_screen_texture;
void fragment() {
// Vector3Constant:2
vec3 n_out2p0 = vec3(0.000000, 0.000000, 0.000000);
vec4 n_out4p0;
// Texture2D:4
n_out4p0 = texture(screen_tex_frg_4, SCREEN_UV);
// VectorFunc:5
vec3 n_out5p0 = vec3(1.0) - vec3(n_out4p0.xyz);
// Output:0
SPECULAR = n_out2p0.x;
EMISSION = n_out5p0;
}
"
graph_offset = Vector2(-297.91, -31.8365)
nodes/fragment/2/node = SubResource("VisualShaderNodeVec3Constant_jppg4")
nodes/fragment/2/position = Vector2(-340, 280)
nodes/fragment/4/node = SubResource("VisualShaderNodeTexture_32eaw")
nodes/fragment/4/position = Vector2(-640, 640)
nodes/fragment/5/node = SubResource("VisualShaderNodeVectorFunc_0twpm")
nodes/fragment/5/position = Vector2(-140, 620)
nodes/fragment/connections = PackedInt32Array(2, 0, 0, 4, 4, 0, 5, 0, 5, 0, 0, 5)