From e39066e978d2ace20955a5c495debe0dbf52c258 Mon Sep 17 00:00:00 2001 From: Rob Kelly Date: Wed, 12 Mar 2025 00:18:27 -0600 Subject: [PATCH] Popping grunk nodules! --- asset_dev/level/airlock/floor_mask.xcf | Bin 0 -> 8734 bytes assets/black.png | 3 + assets/black.png.import | 35 ++++++ assets/materials/grunk_jittery.material | Bin 0 -> 1052 bytes assets/materials/gunk.material | Bin 825 -> 879 bytes assets/materials/gunk_lowrez.material | Bin 830 -> 783 bytes assets/particles/splatter_1.png | 3 + assets/particles/splatter_1.png.import | 35 ++++++ assets/particles/splatter_2.png | 3 + assets/particles/splatter_2.png.import | 34 ++++++ levels/ghost_ship/airlock/floor_mask.png | 3 + .../ghost_ship/airlock/floor_mask.png.import | 35 ++++++ levels/ghost_ship/ghost_ship_level.tscn | 62 +++++++++- levels/sandbox/sandbox.tscn | 37 +++++- src/effects/grunk_splatter.tscn | 112 ++++++++++++++++++ src/equipment/point_spray/point_spray.gd | 2 + src/equipment/wide_spray/wide_spray.gd | 7 +- src/shaders/gunk.gdshader | 21 +++- src/shaders/nodule.gdshader | 17 +++ src/shaders/nodule.gdshader.uid | 1 + src/world/gunk_node/grunk_nodule.gd | 22 ++++ src/world/gunk_node/grunk_nodule.gd.uid | 1 + src/world/gunk_node/grunk_nodule.tscn | 55 +++++++++ src/world/gunk_node/gunk_node.gd | 54 +++++++++ src/world/gunk_node/gunk_node.gd.uid | 1 + 25 files changed, 537 insertions(+), 6 deletions(-) create mode 100644 asset_dev/level/airlock/floor_mask.xcf create mode 100644 assets/black.png create mode 100644 assets/black.png.import create mode 100644 assets/materials/grunk_jittery.material create mode 100644 assets/particles/splatter_1.png create mode 100644 assets/particles/splatter_1.png.import create mode 100644 assets/particles/splatter_2.png create mode 100644 assets/particles/splatter_2.png.import create mode 100644 levels/ghost_ship/airlock/floor_mask.png create mode 100644 levels/ghost_ship/airlock/floor_mask.png.import create mode 100644 src/effects/grunk_splatter.tscn create mode 100644 src/shaders/nodule.gdshader create mode 100644 src/shaders/nodule.gdshader.uid create mode 100644 src/world/gunk_node/grunk_nodule.gd create mode 100644 src/world/gunk_node/grunk_nodule.gd.uid create mode 100644 src/world/gunk_node/grunk_nodule.tscn create mode 100644 src/world/gunk_node/gunk_node.gd create mode 100644 src/world/gunk_node/gunk_node.gd.uid diff --git a/asset_dev/level/airlock/floor_mask.xcf b/asset_dev/level/airlock/floor_mask.xcf new file mode 100644 index 0000000000000000000000000000000000000000..d7fce2250a62c3b1c7749ef5010d2c7459573689 GIT binary patch literal 8734 zcmeHMeQaCR6~B&S=flo-g5DMyslF-tY(6~wL_}#N}?t9O9 z$qM7IO=W%7xxaJoJ@>wM-#zzt&wUPcZQUV1vbj@!*w@&|7&B>tz}WLBMJOgJEkVh? z9g9ftnun5!VncCgI@y(?jHBd*uDET|M{7Yu2@W zhiVFiY1h_Gp4GW|r&lEb(5nR$H|e)UF-02`Dku9K zO-EoJgI;dXa}By|&}qu3AG+))x}Imy3s9%~=~osiWJmp1YdQj}A|3ETtTgDldr&*W zm7%>CDoT%EyMM+$)iB?u;R+QgP1~YwZdS`J^o)2}TpBj0X#G^h?AKJxeMUvwuT{)@ zL&M`5{zb!c8jh)$uL8?2)bg@czi>1(+B=oLEi} z8WA83EQbun_l)04&~}bMk&Y#nftm5>MFD}KWspe?mlA}|3#cCz@aPo+h>?Yw^8OSR zDeZ%N30RmC`9Ns~E93WkD8O}4K=nxhwZjD9CrfT^6<`m3Igp8Jk3Fi5xz?4|aY?V} z*xK3*S!B{g;5sP49&CbaEWEgw!1vs!2Ny#Qj*C+MHV+W=jS(o` z823XiWeF(T2sRw;C)@{ifenx+upaVRDiRyxwNSvOy?v-Hf+Cji_Pre&9GY4Hr7YzQ zyql_qGV#``U_MJm22%iB27OXB{K`DedeHv$k`5c%`I$)2H{w2q>B;Ju^h6cuyPcHo zETc4Nr?kUHsh_dskiu33Xi9)q1ZYNpcI;N*abE_(i7Ej*%LH`TGT1VzGZUPs60oyO zK!?rDmQr0N!4Z#u4qGN$LWLHBBOU=AHVbP8e!jsttXqEy>w>5$_Q)7E zXtg>RpZ`o1zVP`BR$y<#wex9Z;uGz5qUPM~#s^w$#V5vxkf{`h;(XC1N^y|Zka9D= z=NC)L8GNe(l+>XBYJL|@0lt~?11_AHa;BJD&QzdwGn>k6IRJ3w{Y!S3PK>_Of6jt4 zyuO0P&EN!2=(OoOh6z5zdN?B>0zaxX?^gE$vDY@(lyx29X2-L=r3NFY{%+b2DSo-X9qIa1BdTMu2#!4FgVb28&x=I5 zXS@zl$&-Cvq|Lzb#4R|TFBhQ4?H~7o!as==vFSkg=|5bm5;-KvlGVG1bHJ3yL1xTR zdn{wqRwou)AUV9Z=a(lwx4`t+djlg^5%G?FUWt8Vb=LY@gTYpRtc- zp`pRp+kIY{rL1eiPpmN$tt)S}WD?mcgDqyU6C5bd#61K2dWw6*`3Bk? zl=x$gOlooIRkwwDn0(G5b^^6S{*ol_vLj!>7L%ZR?Y$D@(tk@OA^c3Bi zim*3ffxbPyA6uYfU)UKAWYdNaBYNkF!vaP^>W*+sBIF|>J8cY!W0IZKBfi^~$KZ=v zq2)99+bu#XU>GrZA(a@|)mA71fNEr|fn6JWIxZ5GR(cSwx+=3qWvIV0!jYK4{9WHB{@L62z_iMYN`<#^bA~B!ZYIe zfGQH3d*4TK8}O@vu}NFo(Mtfhx|gz~*Xk8riY!m3RchP>A`D9 znSvjwb*_+x;cM7pQ6V+NtN1+)|Eb{>6-%E`vFw71(k>Nm`dGz^Q4J?mbZN&e7em`ABR?i*}@pJS2>Kq=y3Jh9V3TOW8sU{A(~^Tab?KZyez; zmiY!9;nEX}3`zRzd`55D*^Q3>@A}L_&=-V?GmAo99O}Z*7l?V*0x>$haZ%{bO^&VW zbCK%ExdXzP$)RV&FPz&h%2bC}9bexQzTUZ1oL_GoPXE`3Qzxs&qo+G9<;;VJ&PpK? ztHPtEDr85zMf~MpUgWa5vQY3Fahy>c8sAY{RjRchBS zuE$NfRycMUI;(`vDGLWQqpcZcoe^(*1o(!21js#z5$G~>&Su=?8ljlo0`rj3oXCjf ztODGu9IBWTysQ)!u@YpcBB*Bt(7^Jck!8aYVk_e*`v3Psf-y26-54qxL+ZJa2dzws zT)r&Sr#iBk+m7fZpy^-ZX6HfY4G3hhs;~Sq%ZhSVmzCN4Kf!y}(O`9JGb#H%Y+ZM`ZP=ePt>HlDT zOzOy({Bun~NPk4pKD5Y3)H)B1A1_a_ij<~pQFq^=mb<^J;XNAOui?WQKCYqmf3SOx yme>Awb|2L8Z)x~v4d2&L`#9sitmTs`ivNOVpD}0tAHFWiaU4-iXh^FxVgCYaqmAqU literal 0 HcmV?d00001 diff --git a/assets/black.png b/assets/black.png new file mode 100644 index 0000000..6bf4ab2 --- /dev/null +++ b/assets/black.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2038a28b1ccfa88a80de25e407e5725edecb108cf20cf9d6ad152c916be516b1 +size 546 diff --git a/assets/black.png.import b/assets/black.png.import new file mode 100644 index 0000000..b54184a --- /dev/null +++ b/assets/black.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cm1jrvx7ftx4c" +path.s3tc="res://.godot/imported/black.png-0c928088330c4cddf9e28b960b6ccae3.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://assets/black.png" +dest_files=["res://.godot/imported/black.png-0c928088330c4cddf9e28b960b6ccae3.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/assets/materials/grunk_jittery.material b/assets/materials/grunk_jittery.material new file mode 100644 index 0000000000000000000000000000000000000000..76b86db319c21d1289cb393b0c00c3a8d0db5ed3 GIT binary patch literal 1052 zcmV+%1mpWsQ$s@n000005C8x*3IG5E1ONaiwJ-f(H3`)p0LE*PM)0yG9f%unD+@F5 zshu6ELvd)AktNUngldPgty!{{ne0us+(xXV-FD>u*VxrxeG#5LaO&B$5YPEv`~PcK z?WW9sJpL4L0CfO>04Hazb>HP=N6S`L%5AV;*IDEL0cR9)!mTU)FW|Rj%D#;9G(82k zmgff9{tximtfG?R?4mTusQ)NO-At}{gH+{AIoen6n=sb-ICfVp_kWiEJiqBtq9TI} z9|-=Jd_viLp@-%SqD1^J@E?H5AH2ba+-teD7IN>hxXR{Ub4Ixzz_euDm6O}xf&c_Zykk0XWG%Ir0q-JBdXTDhlD$-NwPHOhVM%XsB- zDxuc8vLWpvoC$7O1#hed&Rpw8NZ^<4=~P>ha(9CJlyRetuOuqE7IyfrQZxg`&We># ziEES_r6QarlD%v#WN@JpcXwGlf+)rWQo}~beWr~pDYhk%dMr0e&56p#;@hm6aX>Y= zJq~V9<|zxem!h4PF>4u580}MaE;OA<_N6sO=4=f`X<{LpFM1%l}+4(VCz-;JXKVGjFjK7p)f%M}VVLEU){J+6kpa?QVVa8}gR>27tz> zVYO0dMuwyy1qI1)Py!*O$c!5jppz-gk;D>3C=ij8krEXuJG%khgZ9(CiluU9hyIj5 z`#5iK;8P|b0OzOUeR`NCoiOy!n2^8|6F$5&xAKXPW7=cH0ealVPcd!LngQFWZ9*4vY$D^w?W zP88Jr0fb~@I?<@E zpRQKq?m@`%t`QztpKwFn7gr=d1Plnf{5ClOCq!M~a@(OQ8p(7Egz!}QBC|=WAY^ev W=^39ndCgUdM#IUpsa`u$Q$s_*()=s{ literal 0 HcmV?d00001 diff --git a/assets/materials/gunk.material b/assets/materials/gunk.material index 12f838b25d65dfea8d7a121ed702570430e58e52..abd4b9f835f1701be07af816eb32809c125bb9f6 100644 GIT binary patch literal 879 zcmV-#1CabuQ$s@n000005C8zZ2LJ$90{{RhwJ-f(y#{R>02ZcyL=dqg9ViYlbhTN2z0$$vr{;T)|z(9Pz4{l4jr}szk$m8 zpGoA~?6CvvSZr zOE-%B0kXO@(u}hCPx8O!)Px(?M6rfIOb=lhO7h8A|BhD^p=zH@h;4UGOd@hO+se_H zs)G4HMsVnCKqfEbo9(5zsxNm#zLKWqHVpA!goedd!$k!g_c5co!faO+Ot0Yl9x0_M zSvYoA&J1$T^1T5uH#j#dDt`*fJw~UKONPmZ(|@hlu`%OAlH$U_)6?LJVg0uNA_qy# zf(y?0j7|zhJUl%KuG8<~=VwL-9WYdk{0AHuxc&@Qq%M(gveD( zC&MHU-SJuB-I=p1R?`I>zFaSz)$Bx^=ofsn{tDQ5zsMP)9x>8MGs~?Ew^{j}15Fm85TxY2dFrBrHcQ2a4Mkt%rlwxy#rEH FLqqj-nnM5p literal 825 zcmV-91IGMPQ$s@n000005C8!D1^@sd0{{RhwJ-f(`~|%j0G1?sL=dqg9iSitK@p0m zqh}}z+U5J8Gev+aI?@`+cI&-2A+Z~2a_@Tqfv$IJb_xg4TGMVBs^CL+VC{^ze#XVD zMHhB_<90Vt&0J%-L8pEMDAu=H40NzFF!~L4_nO# zN(}jCdnv8z%iWK!oT0h>M*JU{X_4J{apC7aVpLbqc2&Lf%FXZb`ZOm2r=R9yk8Ym%7|HVQFhfI%&iU!xu4iAHChV>tV2puLcCD)Vb5uFr>c6N9YT&Ev| zk57#cJ7laN`45yBxc&D*LzZQQI=~Sq zk~CnmQrI@)SVg`zfP|<)HA7}ZXhyUoNzxclf+198wF43Wr7_Jp;*5xdf?=5{ls0w) zt=I>2@Mxl{X91@tGLrQJh)Moj0%lk(WnMD26JkvJm9kx@lw{)`WDd32-GaqJqP}~R z_6<5<5f(IA6J+ZQiEf diff --git a/assets/materials/gunk_lowrez.material b/assets/materials/gunk_lowrez.material index 6ab2e8ab3382ba6eb161ff1c21de1d78fba15390..21aa1d5ce1c88aa37f64bcba8606f947e0d80157 100644 GIT binary patch literal 783 zcmV+q1MvJ(Q$s@n000005C8zw1^@u}0ssIgwJ-f()CFx90G6R~Lh#Zg9W--kaRcY{ zy1bc4RdX-Tlsf-`=M$erh)5+Qdy`wgEKw$X!5AyinYQGSx*28T6Bls^M7z zw=Zs$YD__5*EZLI(+swR%L)6%s3oYa+{p=wM?t6+1sbNlr!_wT$fZu!<}$7 zw`xg}w+6RjWjLjly>&a|to|3c>cIH24JkkHtlObX8_v))zYqUMXlB63&?0AK;+NDy zr0T_+iCdW;gO5bITbGo?OpK_5Munihb%l7UmZ#~3bwwUrt*xQFUglQ2AqwqfE&_>P z=16k8EY-_Wm1}$zJDjb-u?{gcHZ>n#QGwY>p>Uvd_)opi*&*X&vSI-h#M49FaQSb+ z0}ll;CDfDgf!Rp_!^6`s7i-&Y{b7s5{ zpyXAlg>)iB#ziUSirmO$nqK~|h|sW&011GEs4+1^%!tg)gegq298iKGWOUsUKt(mq zNy3bXNSJ|{sqC>E!Ki%+|7xsYkYEQ-6Q@cjY`(E&3Nigc&D{Q6W^GlQG69*I?kcWe z{GF*Q@RC;HyR&}(!@6yF>YVnM;E=f@rGELU7Qs8Qm22jv&&q;q*q3C9pqBabD+HDR z)npai6?7(+BI@xA3`-*18YoI_#x9X%JE2^&}}02O2>2KZfIPz1V@ N&)}0xze-Y5Lqiazi1Ppd literal 830 zcmV-E1Ht@KQ$s@n000005C8xJ2LJ#j0{{RhwJ-f(0|w<70On+TL=dqg9iT*6#Ss9- z%tHiu5J3PnqyiwtN4D6=R%)_0SsS~NCO5e^fh#Lsxu1Gg@_+Z(jth7gZ)*m`+8GzK z9+7B$3SR(W0BZnIzKrRt98c}wTuE{Z-n}w=JK&WUHKVrBgvB+%cvH2=SN{)iQ+=9) zkIMf9zS)~2-?>*iTAh3sm2NNIXfOYF@IS&+STizWMri2y|8e;uZ+#?q;WOF%C;2Y| z@&~86VQ?3N3*jr@)eg0x+*Gl-T${p1id-kX96z~Tt96BG!Zyke+-9*(_@uEuDK{0h zl)Fh|cg$AhpcRX^Zuak89xpj4qZ%h5{*PYZ;E>@lY0+TxqqDis87~&>T1#ZDjEm*d9bTIX z19AaQsBC7n*~cG1@vZo)K+LS&O|qe-QdgqerI(q$Hqo#bbkP|H void: (collider as GunkBody).paint_continuous( point, laser.get_collision_normal(), point_scale ) + if collider is GunkNode: + (collider as GunkNode).hit() spray_effect.visible = true beam_particles_1.emitting = true diff --git a/src/equipment/wide_spray/wide_spray.gd b/src/equipment/wide_spray/wide_spray.gd index b8733a1..c571124 100644 --- a/src/equipment/wide_spray/wide_spray.gd +++ b/src/equipment/wide_spray/wide_spray.gd @@ -19,8 +19,9 @@ func _fire() -> void: for laser: LaserCast in spray_casts.get_children(): if laser.is_colliding(): - var target := laser.get_collider() as GunkBody - if target: + var collider := laser.get_collider() + if collider is GunkBody: + var target := collider as GunkBody var point := laser.get_collision_point() var normal := laser.get_collision_normal() @@ -34,6 +35,8 @@ func _fire() -> void: prev_target = target prev_point = point prev_normal = normal + elif collider is GunkNode: + (collider as GunkNode).hit() spray_effect.visible = true beam_particles_1.emitting = true diff --git a/src/shaders/gunk.gdshader b/src/shaders/gunk.gdshader index 980aa3f..0e18d0d 100644 --- a/src/shaders/gunk.gdshader +++ b/src/shaders/gunk.gdshader @@ -1,6 +1,7 @@ shader_type spatial; -render_mode blend_mix, depth_draw_opaque, cull_disabled, diffuse_burley, specular_schlick_ggx, sss_mode_skin; +render_mode diffuse_burley, specular_schlick_ggx, sss_mode_skin; +group_uniforms gunk_material; uniform vec3 color_1: source_color = vec3(0.0, 0.03, 0.1); uniform vec3 color_2: source_color = vec3(0.0, 0.1, 0.3); uniform vec3 emission_color: source_color = vec3(0.25, 0.88, 1.0); @@ -24,6 +25,24 @@ uniform sampler2D gunk_mask; uniform highp sampler3D gunk_noise; uniform highp sampler3D gunk_normal_map; +group_uniforms jitter; +uniform mediump float jitter_magnitude = 0.0; +uniform lowp float jitter_time_scale = 0.1; + +uniform highp sampler3D jitter_noise; + +group_uniforms inflation; +uniform highp float vertex_inflation = 0.0; +uniform highp float inflation_pixellation = 10.0; + +void vertex() { + float mixer = VERTEX.x + 0.553 * VERTEX.z + 1.618 * VERTEX.y; + float local_time = floor(TIME * jitter_time_scale * time_pixellation) / time_pixellation; + float sample = texture(jitter_noise, vec3(cos(mixer), sin(mixer), local_time)).r; + float inflation = floor(vertex_inflation * inflation_pixellation) / inflation_pixellation; + float jitter = jitter_magnitude * (sample - 0.5 + inflation); + VERTEX *= 1.0 + jitter; +} float hardstep(float value) { float x = clamp(value, 0.0, 1.0); diff --git a/src/shaders/nodule.gdshader b/src/shaders/nodule.gdshader new file mode 100644 index 0000000..36f5299 --- /dev/null +++ b/src/shaders/nodule.gdshader @@ -0,0 +1,17 @@ +/* The shuddererrrrrrrr +*/ +shader_type spatial; + +uniform mediump float jitter_magnitude = 0.1; +uniform mediump float time_scale = 0.1; +uniform lowp float time_pixellation = 100.0; + +uniform highp sampler3D jitter_noise; + +void vertex() { + float mixer = VERTEX.x + 0.553 * VERTEX.z + 1.618 * VERTEX.y; + float local_time = floor(TIME * time_scale * time_pixellation) / time_pixellation; + float sample = texture(jitter_noise, vec3(cos(mixer), sin(mixer), local_time)).r; + float jitter = jitter_magnitude * (sample - 0.5); + VERTEX *= 1.0 + jitter; +} \ No newline at end of file diff --git a/src/shaders/nodule.gdshader.uid b/src/shaders/nodule.gdshader.uid new file mode 100644 index 0000000..ee1ebe6 --- /dev/null +++ b/src/shaders/nodule.gdshader.uid @@ -0,0 +1 @@ +uid://by1atykyt6fkx diff --git a/src/world/gunk_node/grunk_nodule.gd b/src/world/gunk_node/grunk_nodule.gd new file mode 100644 index 0000000..e594d9f --- /dev/null +++ b/src/world/gunk_node/grunk_nodule.gd @@ -0,0 +1,22 @@ +extends GunkNode + +@export var jitter_scale_factor := 0.02 +@export var jitter_inflation_factor := 1.0 + +@export var splatter_scene: PackedScene + +@onready var mesh_instance: MeshInstance3D = %MeshInstance3D + + +func _process(_delta: float) -> void: + var shader: ShaderMaterial = mesh_instance.mesh.surface_get_material(0) + var value := _sustained_damage / durability + shader.set_shader_parameter("jitter_time_scale", value * jitter_scale_factor) + shader.set_shader_parameter("vertex_inflation", value * jitter_inflation_factor) + + +func _destroy() -> void: + var splatter: GPUParticles3D = splatter_scene.instantiate() + add_sibling(splatter) + splatter.global_position = global_position + splatter.emitting = true diff --git a/src/world/gunk_node/grunk_nodule.gd.uid b/src/world/gunk_node/grunk_nodule.gd.uid new file mode 100644 index 0000000..61e093b --- /dev/null +++ b/src/world/gunk_node/grunk_nodule.gd.uid @@ -0,0 +1 @@ +uid://07t7yhijru8f diff --git a/src/world/gunk_node/grunk_nodule.tscn b/src/world/gunk_node/grunk_nodule.tscn new file mode 100644 index 0000000..f1d9d94 --- /dev/null +++ b/src/world/gunk_node/grunk_nodule.tscn @@ -0,0 +1,55 @@ +[gd_scene load_steps=7 format=4 uid="uid://2yqi5u5eo025"] + +[ext_resource type="Script" uid="uid://07t7yhijru8f" path="res://src/world/gunk_node/grunk_nodule.gd" id="1_m8r0a"] +[ext_resource type="Material" uid="uid://bmab6i16v748m" path="res://assets/materials/grunk_jittery.material" id="2_530fq"] +[ext_resource type="PackedScene" uid="uid://xlt78xc1tmkl" path="res://src/effects/grunk_splatter.tscn" id="2_iyr82"] + +[sub_resource type="ArrayMesh" id="ArrayMesh_24j8i"] +_surfaces = [{ +"aabb": AABB(-0.894425, -1, -0.85064, 1.78885, 2, 1.70128), +"format": 34896613377, +"index_count": 60, +"index_data": PackedByteArray("AAABAAIAAgABAAMAAQAAAAQAAwABAAUABQABAAQABAAAAAYABQAEAAcABwAEAAYAAwAFAAgACAAFAAcAAgADAAkACQADAAgAAAACAAoACgACAAkABgAAAAoACAAHAAsABwAGAAsACQAIAAsABgAKAAsACgAJAAsA"), +"name": "Icosphere", +"primitive": 3, +"uv_scale": Vector4(0, 0, 0, 0), +"vertex_count": 12, +"vertex_data": PackedByteArray("jOfBRhrPAAD/fwAA/38AAHJYwUb//wAAAADBRv9/AACM58FG5DAAAHJYwUYAAAAA//89uf9/AACMpz25AAAAAHIYPbnkMAAAchg9uRrPAACMpz25//8AAP9/////fwAA") +}] +blend_shape_mode = 0 + +[sub_resource type="ArrayMesh" id="ArrayMesh_iyr82"] +resource_local_to_scene = true +_surfaces = [{ +"aabb": AABB(-0.894425, -1, -0.85064, 1.78885, 2, 1.70128), +"attribute_data": PackedByteArray("0UWv14su//9FF6/XFl3//9FFr9dcdK/X//+v17no//9z0a/Xc9Gv1y26///ooq/X6KKv16KL//9cdK/XXHSv19FFr9cWXWCv0UWv10UXr9eLLmCv//+v13PRr9e56GCvc9Gv1+iir9ctumCv6KKv11x0r9eii2CvFl1gr9FFr9eLLmCviy5gr0UXr9cAAGCvuehgr3PRr9ctumCvLbpgr+iir9eii2Cvootgr1x0r9cWXWCvFl1gr4suYK/RRRGHiy5grwAAYK9FFxGHuehgry26YK9z0RGHLbpgr6KLYK/oohGHootgrxZdYK9cdBGH"), +"format": 34896613399, +"index_count": 60, +"index_data": PackedByteArray("AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAJAAlACYAJwAoACkAKgArACwALQAuAC8AMAAxADIAMwA0ADUANgA3ADgAOQA6ADsA"), +"material": ExtResource("2_530fq"), +"name": "Icosphere", +"primitive": 3, +"uv_scale": Vector4(0, 0, 0, 0), +"vertex_count": 60, +"vertex_data": PackedByteArray("jOfBRhrPZaf/fwAA/39lp3JYwUb//2Wn/38AAP9/DciM58FGGs8NyIznwUbkMA3IcljBRv//nLT/fwAA/3+ctAAAwUb/f5y0AADBRv9/2N3/fwAA/3/Y3XJYwUYAANjdcljBRgAAiPT/fwAA/3+I9IznwUbkMIj0jOfBRuQwW8CM58FGGs9bwP//Pbn/f1vAjOfBRhrP6Y5yWMFG///pjoynPbn//+mOcljBRv//GacAAMFG/38Zp3IYPbkazxmnAADBRv9/yNlyWMFGAADI2XIYPbnkMMjZcljBRgAAQfOM58FG5DBB84ynPbkAAEHz//89uf9/GaeM58FGGs8Zp4ynPbn//xmnjKc9uf//6Y5yWMFG///pjnIYPbkaz+mOchg9uRrPW8AAAMFG/39bwHIYPbnkMFvAchg9ueQwQfNyWMFGAABB84ynPbkAAEHzjKc9uQAAyNmM58FG5DDI2f//Pbn/f8jZ//89uf9/nLSMpz25//+ctP9/////f5y0jKc9uf//ZadyGD25Gs9lp/9/////f2Wnchg9uRrPDchyGD255DANyP9/////fw3Ichg9ueQwiPSMpz25AACI9P9/////f4j0jKc9uQAA2N3//z25/3/Y3f9/////f9jdbylFZG8pRWRvKUVkLWCkPy1gpD8tYKQ/7DOZzewzmc3sM5nNSkmH7UpJh+1KSYftn3mdLp95nS6feZ0uz3VfFM91XxTPdV8UzFJcNMxSXDTMUlw092Nt7fdjbe33Y23t/2+Y+v9vmPr/b5j6RH6lDER+pQxEfqUMB5yREgeckRIHnJESMq2iyzKtossyraLLL4qf6y+Kn+svip/ruoFZ87qBWfO6gVnz/49mBf+PZgX/j2YFEsxlMhLMZTISzGUyj9a5m4/WuZuP1rmb0Z9awNGfWsDRn1rAX4Zh0V+GYdFfhmHRtLZ3ErS2dxK0tncS") +}] +blend_shape_mode = 0 +shadow_mesh = SubResource("ArrayMesh_24j8i") + +[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_530fq"] +data = PackedVector3Array(0.7236, -0.4472, 0.5257, 0, -1, 0, -0.2764, -0.4472, 0.8506, 0, -1, 0, 0.7236, -0.4472, 0.5257, 0.7236, -0.4472, -0.5257, -0.2764, -0.4472, 0.8506, 0, -1, 0, -0.8944, -0.4472, 0, -0.8944, -0.4472, 0, 0, -1, 0, -0.2764, -0.4472, -0.8506, -0.2764, -0.4472, -0.8506, 0, -1, 0, 0.7236, -0.4472, -0.5257, 0.7236, -0.4472, -0.5257, 0.7236, -0.4472, 0.5257, 0.8944, 0.4472, 0, 0.7236, -0.4472, 0.5257, -0.2764, -0.4472, 0.8506, 0.2764, 0.4472, 0.8506, -0.2764, -0.4472, 0.8506, -0.8944, -0.4472, 0, -0.7236, 0.4472, 0.5257, -0.8944, -0.4472, 0, -0.2764, -0.4472, -0.8506, -0.7236, 0.4472, -0.5257, -0.2764, -0.4472, -0.8506, 0.7236, -0.4472, -0.5257, 0.2764, 0.4472, -0.8506, 0.8944, 0.4472, 0, 0.7236, -0.4472, 0.5257, 0.2764, 0.4472, 0.8506, 0.2764, 0.4472, 0.8506, -0.2764, -0.4472, 0.8506, -0.7236, 0.4472, 0.5257, -0.7236, 0.4472, 0.5257, -0.8944, -0.4472, 0, -0.7236, 0.4472, -0.5257, -0.7236, 0.4472, -0.5257, -0.2764, -0.4472, -0.8506, 0.2764, 0.4472, -0.8506, 0.2764, 0.4472, -0.8506, 0.7236, -0.4472, -0.5257, 0.8944, 0.4472, 0, 0.8944, 0.4472, 0, 0.2764, 0.4472, 0.8506, 0, 1, 0, 0.2764, 0.4472, 0.8506, -0.7236, 0.4472, 0.5257, 0, 1, 0, -0.7236, 0.4472, 0.5257, -0.7236, 0.4472, -0.5257, 0, 1, 0, -0.7236, 0.4472, -0.5257, 0.2764, 0.4472, -0.8506, 0, 1, 0, 0.2764, 0.4472, -0.8506, 0.8944, 0.4472, 0, 0, 1, 0) + +[node name="GrunkNodule" type="StaticBody3D"] +collision_layer = 5 +script = ExtResource("1_m8r0a") +splatter_scene = ExtResource("2_iyr82") +durability = 3.0 +metadata/_custom_type_script = "uid://bypgxi0gy56yk" + +[node name="MeshInstance3D" type="MeshInstance3D" parent="."] +unique_name_in_owner = true +sorting_offset = 1.0 +mesh = SubResource("ArrayMesh_iyr82") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="."] +shape = SubResource("ConcavePolygonShape3D_530fq") diff --git a/src/world/gunk_node/gunk_node.gd b/src/world/gunk_node/gunk_node.gd new file mode 100644 index 0000000..5aad6d9 --- /dev/null +++ b/src/world/gunk_node/gunk_node.gd @@ -0,0 +1,54 @@ +class_name GunkNode extends StaticBody3D +## A static body which can be destroyed and collected by the player. + +## Emitted immediately after this node has been destroyed by the player, +## but before it's removed from the scene tree +signal destroyed + +const JITTER_FADE_RATE := 0.6 + +## Time in seconds the player must hit this node with a sustained beam before it's destroyed. +@export var durability := 1.0 + +## Value added to the player's grunk total on destruction. +@export var value := 1000.0 + +var _sustained_damage := 0.0 +var _hit_this_frame := false + + +## Called each frame this node takes a hit. +## +## Derived types should override `_hit()` as a lifecycle method. +func hit() -> void: + _hit_this_frame = true + _hit() + + +func _hit() -> void: + pass # Implemented in derived type + + +func _physics_process(delta: float) -> void: + if _hit_this_frame: + _sustained_damage += delta + else: + _sustained_damage *= JITTER_FADE_RATE + _hit_this_frame = false + + if _sustained_damage >= durability: + destroy() + + +## Destroy this node. Called automatically when this node sustains damage beyond its durability. +## +## Derived types should override `_destroy` as a lifecycle method. +func destroy() -> void: + Game.manager.collect_grunk(value) + _destroy() + destroyed.emit() + queue_free() + + +func _destroy() -> void: + pass # Implemented in derived type diff --git a/src/world/gunk_node/gunk_node.gd.uid b/src/world/gunk_node/gunk_node.gd.uid new file mode 100644 index 0000000..8ff01ef --- /dev/null +++ b/src/world/gunk_node/gunk_node.gd.uid @@ -0,0 +1 @@ +uid://bypgxi0gy56yk