diff --git a/gfx/hit_decal.png b/gfx/hit_decal.png new file mode 100644 index 0000000..74ef0dc Binary files /dev/null and b/gfx/hit_decal.png differ diff --git a/gfx/hit_decal.png.import b/gfx/hit_decal.png.import new file mode 100644 index 0000000..3c49781 --- /dev/null +++ b/gfx/hit_decal.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/hit_decal.png-774262fc5a2cc970463c1e1e2886a094.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://gfx/hit_decal.png" +dest_files=[ "res://.import/hit_decal.png-774262fc5a2cc970463c1e1e2886a094.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=false +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +stream=false +size_limit=0 +detect_3d=false +svg/scale=1.0 diff --git a/scene/HitDecal.tscn b/scene/HitDecal.tscn new file mode 100644 index 0000000..7dbe597 --- /dev/null +++ b/scene/HitDecal.tscn @@ -0,0 +1,182 @@ +[gd_scene load_steps=17 format=2] + +[ext_resource path="res://gfx/hit_decal.png" type="Texture" id=1] +[ext_resource path="res://src/Objects/HitDecal.cs" type="Script" id=2] + +[sub_resource type="VisualShaderNodeInput" id=15] +input_name = "modulate_color" + +[sub_resource type="VisualShaderNodeInput" id=16] +input_name = "modulate_alpha" + +[sub_resource type="VisualShaderNodeScalarOp" id=17] +operator = 2 + +[sub_resource type="VisualShaderNodeExpression" id=18] +size = Vector2( 512, 260 ) +expression = "vec2 tex_size = vec2(textureSize(mask, 0)); +vec2 pix_loc = uv.xy / TEXTURE_PIXEL_SIZE; +mask_uv = vec3((pix_loc + offset.xy) / tex_size, 0); +outside = mask_uv.x >= 0.0 && mask_uv.x <= 1.0 && + mask_uv.y >= 0.0 && mask_uv.y <= 1.0;" + +[sub_resource type="VisualShaderNodeInput" id=19] +input_name = "uv" + +[sub_resource type="VisualShaderNodeScalarSwitch" id=20] + +[sub_resource type="VisualShaderNodeVectorOp" id=21] +operator = 2 + +[sub_resource type="VisualShaderNodeTexture" id=22] +source = 5 + +[sub_resource type="VisualShaderNodeInput" id=23] +input_name = "texture" + +[sub_resource type="VisualShaderNodeScalarOp" id=24] +operator = 2 + +[sub_resource type="VisualShaderNodeVec3Uniform" id=25] +uniform_name = "offset" + +[sub_resource type="VisualShaderNodeTextureUniform" id=26] +uniform_name = "mask" + +[sub_resource type="VisualShader" id=27] +code = "shader_type canvas_item; +uniform vec3 offset; +uniform sampler2D mask; + + + +void vertex() { +// Output:0 + +} + +void fragment() { +// Input:10 + vec3 n_out10p0 = MODULATE.rgb; + +// Input:3 + +// Texture:2 + vec3 n_out2p0; + float n_out2p1; + { + vec4 TEXTURE_tex_read = texture(TEXTURE, UV.xy); + n_out2p0 = TEXTURE_tex_read.rgb; + n_out2p1 = TEXTURE_tex_read.a; + } + +// VectorOp:18 + vec3 n_out18p0 = n_out10p0 * n_out2p0; + +// Input:13 + float n_out13p0 = MODULATE.a; + +// VectorUniform:7 + vec3 n_out7p0 = offset; + +// Input:16 + vec3 n_out16p0 = vec3(UV, 0.0); + +// Expression:15 + vec3 n_out15p0; + bool n_out15p1; + n_out15p0 = vec3(0.0, 0.0, 0.0); + n_out15p1 = false; + { + vec2 tex_size = vec2(textureSize(mask, 0)); + vec2 pix_loc = n_out16p0.xy / TEXTURE_PIXEL_SIZE; + n_out15p0 = vec3((pix_loc + n_out7p0.xy) / tex_size, 0); + n_out15p1 = n_out15p0.x >= 0.0 && n_out15p0.x <= 1.0 && + n_out15p0.y >= 0.0 && n_out15p0.y <= 1.0; + } + +// TextureUniform:8 + vec3 n_out8p0; + float n_out8p1; + { + vec4 n_tex_read = texture(mask, n_out15p0.xy); + n_out8p0 = n_tex_read.rgb; + n_out8p1 = n_tex_read.a; + } + +// ScalarSwitch:17 + float n_in17p2 = 0.00000; + float n_out17p0; + if(n_out15p1) + { + n_out17p0 = n_out8p1; + } + else + { + n_out17p0 = n_in17p2; + } + +// ScalarOp:6 + float n_out6p0 = n_out2p1 * n_out17p0; + +// ScalarOp:14 + float n_out14p0 = n_out13p0 * n_out6p0; + +// Output:0 + COLOR.rgb = n_out18p0; + COLOR.a = n_out14p0; + +} + +void light() { +// Output:0 + +} +" +graph_offset = Vector2( 341, -275 ) +mode = 1 +flags/light_only = false +nodes/fragment/0/position = Vector2( 840, -100 ) +nodes/fragment/2/node = SubResource( 22 ) +nodes/fragment/2/position = Vector2( 400, -40 ) +nodes/fragment/3/node = SubResource( 23 ) +nodes/fragment/3/position = Vector2( 220, -40 ) +nodes/fragment/6/node = SubResource( 24 ) +nodes/fragment/6/position = Vector2( 640, 60 ) +nodes/fragment/7/node = SubResource( 25 ) +nodes/fragment/7/position = Vector2( -340, 60 ) +nodes/fragment/8/node = SubResource( 26 ) +nodes/fragment/8/position = Vector2( 400, 100 ) +nodes/fragment/10/node = SubResource( 15 ) +nodes/fragment/10/position = Vector2( 320, -200 ) +nodes/fragment/13/node = SubResource( 16 ) +nodes/fragment/13/position = Vector2( 320, -120 ) +nodes/fragment/14/node = SubResource( 17 ) +nodes/fragment/14/position = Vector2( 640, -60 ) +nodes/fragment/15/node = SubResource( 18 ) +nodes/fragment/15/position = Vector2( -140, 40 ) +nodes/fragment/15/size = Vector2( 512, 260 ) +nodes/fragment/15/input_ports = "0,1,offset;1,1,uv;" +nodes/fragment/15/output_ports = "0,1,mask_uv;1,2,outside;" +nodes/fragment/15/expression = "vec2 tex_size = vec2(textureSize(mask, 0)); +vec2 pix_loc = uv.xy / TEXTURE_PIXEL_SIZE; +mask_uv = vec3((pix_loc + offset.xy) / tex_size, 0); +outside = mask_uv.x >= 0.0 && mask_uv.x <= 1.0 && + mask_uv.y >= 0.0 && mask_uv.y <= 1.0;" +nodes/fragment/16/node = SubResource( 19 ) +nodes/fragment/16/position = Vector2( -340, 140 ) +nodes/fragment/17/node = SubResource( 20 ) +nodes/fragment/17/position = Vector2( 620, 180 ) +nodes/fragment/18/node = SubResource( 21 ) +nodes/fragment/18/position = Vector2( 640, -180 ) +nodes/fragment/connections = PoolIntArray( 3, 0, 2, 2, 2, 1, 6, 0, 6, 0, 14, 1, 13, 0, 14, 0, 14, 0, 0, 1, 7, 0, 15, 0, 16, 0, 15, 1, 15, 0, 8, 0, 15, 1, 17, 0, 8, 1, 17, 1, 17, 0, 6, 1, 10, 0, 18, 0, 2, 0, 18, 1, 18, 0, 0, 0 ) + +[sub_resource type="ShaderMaterial" id=14] +shader = SubResource( 27 ) +shader_param/offset = Vector3( 0, 0, 0 ) + +[node name="HitDecal" type="Sprite"] +material = SubResource( 14 ) +texture = ExtResource( 1 ) +centered = false +script = ExtResource( 2 ) diff --git a/scene/Player.tscn b/scene/Player.tscn index a2106cf..cd74a8a 100644 --- a/scene/Player.tscn +++ b/scene/Player.tscn @@ -157,6 +157,15 @@ texture = ExtResource( 10 ) offset = Vector2( 8, 0 ) script = ExtResource( 8 ) Automatic = true +RateOfFire = 120 +Capacity = 4 +ReloadTime = 2.0 +Knockback = 60.0 +Spread = 3.0 +SpreadIncrease = 10.0 +BulletVelocity = 640 +BulletsPerShot = 16 +BulletOpacity = 0.06 [node name="Tip" type="Node2D" parent="Items/Super Soaker"] position = Vector2( 17, 0.5 ) diff --git a/src/Items/Weapon.cs b/src/Items/Weapon.cs index 1b5b1f4..6ce31ac 100644 --- a/src/Items/Weapon.cs +++ b/src/Items/Weapon.cs @@ -66,8 +66,8 @@ public class Weapon : Sprite public override void _Process(float delta) { - var spreadDecrease = Mathf.Max(Mathf.Tau / 300, _currentSpreadInc * 2); - var recoilDecrease = Mathf.Max(Mathf.Tau / 800, _currentRecoil * 2); + var spreadDecrease = Mathf.Max(Mathf.Tau / 200, _currentSpreadInc * 1.5F); + var recoilDecrease = Mathf.Max(Mathf.Tau / 600, _currentRecoil * 1.5F); _currentSpreadInc = Mathf.Max(0, _currentSpreadInc - spreadDecrease * delta); _currentRecoil = Mathf.Max(0, _currentRecoil - recoilDecrease * delta); diff --git a/src/Objects/Bullet.cs b/src/Objects/Bullet.cs index a5c231c..c266f9a 100644 --- a/src/Objects/Bullet.cs +++ b/src/Objects/Bullet.cs @@ -3,7 +3,9 @@ using Godot; public class Bullet : Node2D { - private static readonly TimeSpan TRAIL_DURATION = TimeSpan.FromSeconds(0.6); + private static readonly TimeSpan LIFE_TIME = TimeSpan.FromSeconds(0.6); + private static readonly TimeSpan FADE_TIME = TimeSpan.FromSeconds(0.6); + private static readonly PackedScene HIT_DECAL = GD.Load("res://scene/HitDecal.tscn"); public Vector2 Direction { get; } public int EffectiveRange { get; } @@ -12,7 +14,7 @@ public class Bullet : Node2D public Color Color { get; } private readonly Vector2 _startPosition; - private TimeSpan _age; + private TimeSpan _age = TimeSpan.Zero; private float _distance; public Bullet(Vector2 position, Vector2 direction, @@ -26,6 +28,16 @@ public class Bullet : Node2D Color = color; } + protected void OnCollide(CollisionObject2D obj, Vector2 hitPosition) + { + var sprite = obj.GetNodeOrNull("Sprite"); + if (sprite == null) return; + + var hole = HIT_DECAL.Init(); + var color = new Color(Color, (1 + Color.a) / 2); + hole.Add(sprite, hitPosition, color); + } + public override void _Ready() { if (this.GetGame() is Server) Visible = false; } @@ -33,8 +45,8 @@ public class Bullet : Node2D { _age += TimeSpan.FromSeconds(delta); - if (_age > TRAIL_DURATION) { - Modulate = new Color(Modulate, Modulate.a - delta * 2); + if (_age > LIFE_TIME) { + Modulate = new Color(Modulate, Modulate.a - delta / (float)FADE_TIME.TotalSeconds); if (Modulate.a <= 0) this.RemoveFromParent(); } } @@ -50,6 +62,8 @@ public class Bullet : Node2D if (collision.Count != 0) { Position = (Vector2)collision["position"]; _distance = _startPosition.DistanceTo(Position); + var obj = (CollisionObject2D)collision["collider"]; + OnCollide(obj, Position - obj.Position); SetPhysicsProcess(false); } diff --git a/src/Objects/HitDecal.cs b/src/Objects/HitDecal.cs new file mode 100644 index 0000000..abce850 --- /dev/null +++ b/src/Objects/HitDecal.cs @@ -0,0 +1,38 @@ +using System; +using Godot; + +// TODO: When spawned, add to multiple nearby sprites. +public class HitDecal : Sprite +{ + private static readonly TimeSpan LIFE_TIME = TimeSpan.FromSeconds(5.0); + private static readonly TimeSpan FADE_TIME = TimeSpan.FromSeconds(5.0); + + private TimeSpan _age = TimeSpan.Zero; + private float _fadeFactor; + + public void Add(Sprite sprite, Vector2 hitVec, Color color) + { + Position = (hitVec - Texture.GetSize() / 2).Round(); + var offset = Position + sprite.Texture.GetSize() / 2; + + ShaderMaterial material; + Material = material = (ShaderMaterial)Material.Duplicate(); + material.SetShaderParam("offset", new Vector3(offset.x, offset.y, 0)); + material.SetShaderParam("mask", sprite.Texture); + + Modulate = color; + _fadeFactor = color.a; + + sprite.AddChild(this); + } + + public override void _Process(float delta) + { + _age += TimeSpan.FromSeconds(delta); + if (_age > LIFE_TIME) { + var dec = delta / (float)FADE_TIME.TotalSeconds * _fadeFactor; + Modulate = new Color(Modulate, Modulate.a - dec); + if (Modulate.a <= 0) this.RemoveFromParent(); + } + } +}