bow and arrow weapon

godot-4.2
John Montagu, the 4th Earl of Sandvich 2023-09-10 17:08:14 -07:00
parent db62cd2495
commit 6a42816bdb
Signed by: sandvich
GPG Key ID: 9A39BE37E602B22D
23 changed files with 516 additions and 13 deletions

Binary file not shown.

View File

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://bkekgj4gu7fw4"
path="res://.godot/imported/bow-draw.wav-ee71f46d06974ee4e5189d4b26502070.sample"
[deps]
source_file="res://Assets/Sounds/bow-draw.wav"
dest_files=["res://.godot/imported/bow-draw.wav-ee71f46d06974ee4e5189d4b26502070.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=0

Binary file not shown.

View File

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://cwy4giq8eod5g"
path="res://.godot/imported/bow-release.wav-d35b52831a4c6f71b205857c7b22db33.sample"
[deps]
source_file="res://Assets/Sounds/bow-release.wav"
dest_files=["res://.godot/imported/bow-release.wav-d35b52831a4c6f71b205857c7b22db33.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=0

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dam6aigkw8xs"
path="res://.godot/imported/bow-and-arrow.png-60392c320abf41d03c424138c789f873.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Assets/Sprites/Items/bow-and-arrow.png"
dest_files=["res://.godot/imported/bow-and-arrow.png-60392c320abf41d03c424138c789f873.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://blr4xbgysdyto"
path="res://.godot/imported/arrow.png-6bb20391966d951f9ad648e44b1019b9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Assets/Sprites/Misc/arrow.png"
dest_files=["res://.godot/imported/arrow.png-6bb20391966d951f9ad648e44b1019b9.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=64 format=3 uid="uid://b2254pup8k161"]
[gd_scene load_steps=65 format=3 uid="uid://b2254pup8k161"]
[ext_resource type="Script" path="res://Characters/Player.cs" id="1_flygr"]
[ext_resource type="Shader" path="res://Shaders/Flash.gdshader" id="2_ngsgt"]
@ -35,6 +35,7 @@
[ext_resource type="PackedScene" uid="uid://ce0ph4wk0ylra" path="res://UI/TargetTracer.tscn" id="22_hxi53"]
[ext_resource type="PackedScene" uid="uid://5y1acxl4j4n7" path="res://Items/Weapons/Pugio.tscn" id="22_mqpn7"]
[ext_resource type="PackedScene" uid="uid://d1d4vg7we5rjr" path="res://Items/Weapons/Shotgun.tscn" id="22_rmciq"]
[ext_resource type="PackedScene" uid="uid://cgg0sfm2qeiwn" path="res://Items/Weapons/Bow.tscn" id="29_7j1fs"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_h78y7"]
shader = ExtResource("2_ngsgt")
@ -645,16 +646,22 @@ InventoryMap = {
}
[node name="Sword" parent="Inventory" instance=ExtResource("22_mqpn7")]
visible = false
[node name="Node2D" parent="Inventory" instance=ExtResource("7_4rxuv")]
visible = false
[node name="Bow" parent="Inventory" instance=ExtResource("29_7j1fs")]
[node name="Shotgun" parent="Inventory" instance=ExtResource("22_rmciq")]
visible = false
[node name="Railgun" parent="Inventory" instance=ExtResource("21_n8w32")]
visible = false
UseTime = 0.2
[node name="DocLance" parent="Inventory" instance=ExtResource("14_bj0lo")]
visible = false
[node name="RemoteTransform2D2" type="RemoteTransform2D" parent="Inventory"]
position = Vector2(0, 4)

View File

@ -0,0 +1,57 @@
[gd_scene load_steps=9 format=3 uid="uid://cjiftn2suskla"]
[ext_resource type="Texture2D" uid="uid://blr4xbgysdyto" path="res://Assets/Sprites/Misc/arrow.png" id="1_0im1r"]
[ext_resource type="Script" path="res://Entities/Projectile.cs" id="1_8ijcc"]
[ext_resource type="PackedScene" uid="uid://du5vhccg75nrq" path="res://BoundingBoxes/Hitbox.tscn" id="3_f4lib"]
[sub_resource type="CircleShape2D" id="CircleShape2D_m22ef"]
radius = 3.0
[sub_resource type="Gradient" id="Gradient_uqfn8"]
offsets = PackedFloat32Array(0, 0.1, 0.9)
colors = PackedColorArray(1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_te0n4"]
gradient = SubResource("Gradient_uqfn8")
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_yg5po"]
particle_flag_disable_z = true
direction = Vector3(-1, 0, 0)
gravity = Vector3(0, 0, 0)
initial_velocity_min = 4.0
initial_velocity_max = 8.0
orbit_velocity_min = 0.0
orbit_velocity_max = 0.0
scale_min = 2.0
scale_max = 2.0
color_ramp = SubResource("GradientTexture1D_te0n4")
[sub_resource type="CanvasTexture" id="CanvasTexture_ggksk"]
[node name="Arrow" type="RigidBody2D" node_paths=PackedStringArray("Hitbox")]
script = ExtResource("1_8ijcc")
ProjectileName = "Arrow"
Speed = 256.0
Hitbox = NodePath("Hitbox")
Lifetime = 3.0
[node name="Sprite2D" type="Sprite2D" parent="."]
position = Vector2(-11, -2)
texture = ExtResource("1_0im1r")
centered = false
[node name="Hitbox" parent="." instance=ExtResource("3_f4lib")]
[node name="CollisionShape2D" parent="Hitbox" index="0"]
position = Vector2(0, -0.5)
shape = SubResource("CircleShape2D_m22ef")
[node name="GPUParticles2D" type="GPUParticles2D" parent="."]
position = Vector2(-9, 0)
amount = 16
process_material = SubResource("ParticleProcessMaterial_yg5po")
texture = SubResource("CanvasTexture_ggksk")
lifetime = 0.8
fixed_fps = 12
[editable path="Hitbox"]

View File

@ -0,0 +1,170 @@
[gd_scene load_steps=15 format=3 uid="uid://cgg0sfm2qeiwn"]
[ext_resource type="Texture2D" uid="uid://dam6aigkw8xs" path="res://Assets/Sprites/Items/bow-and-arrow.png" id="1_1ghvv"]
[ext_resource type="Script" path="res://Items/Weapons/ProjectileSpawner.cs" id="1_76bur"]
[ext_resource type="PackedScene" uid="uid://cjiftn2suskla" path="res://Entities/Arrow.tscn" id="2_mvw0j"]
[ext_resource type="Script" path="res://State/Weapon/WeaponStateMachine.cs" id="3_pg4gy"]
[ext_resource type="Script" path="res://State/Weapon/RangedIdleState.cs" id="3_uxif8"]
[ext_resource type="Script" path="res://State/Weapon/RangedFireState.cs" id="4_moo4d"]
[ext_resource type="Script" path="res://State/Weapon/RangedChargeState.cs" id="5_k8y6f"]
[ext_resource type="AudioStream" uid="uid://bkekgj4gu7fw4" path="res://Assets/Sounds/bow-draw.wav" id="7_t07v0"]
[ext_resource type="AudioStream" uid="uid://cwy4giq8eod5g" path="res://Assets/Sounds/bow-release.wav" id="9_v051g"]
[sub_resource type="Animation" id="Animation_h0fti"]
resource_name = "RESET"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Anchor/Sprite2D:frame")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [0]
}
[sub_resource type="Animation" id="Animation_8qr8x"]
resource_name = "charge"
length = 0.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Anchor/Sprite2D:frame")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.9),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1),
"update": 1,
"values": [0, 1, 2, 3, 4, 6, 5]
}
tracks/1/type = "audio"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("AudioStreamPlayer2D")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"clips": [{
"end_offset": 0.0,
"start_offset": 0.0,
"stream": ExtResource("7_t07v0")
}],
"times": PackedFloat32Array(0)
}
tracks/1/use_blend = true
[sub_resource type="Animation" id="Animation_bejvb"]
resource_name = "fire"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Anchor/Sprite2D:frame")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [7]
}
tracks/1/type = "audio"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("AudioStreamPlayer2D")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"clips": [{
"end_offset": 0.0,
"start_offset": 0.03,
"stream": ExtResource("9_v051g")
}],
"times": PackedFloat32Array(0)
}
tracks/1/use_blend = true
[sub_resource type="Animation" id="Animation_riv7t"]
resource_name = "idle"
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Anchor/Sprite2D:frame")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_5vx8d"]
_data = {
"RESET": SubResource("Animation_h0fti"),
"charge": SubResource("Animation_8qr8x"),
"fire": SubResource("Animation_bejvb"),
"idle": SubResource("Animation_riv7t")
}
[node name="Bow" type="Node2D" node_paths=PackedStringArray("StateMachine")]
y_sort_enabled = true
script = ExtResource("1_76bur")
Projectile = ExtResource("2_mvw0j")
ChargeTime = 0.5
StateMachine = NodePath("StateMachine")
Damage = 20.0
UseTime = 0.5
Knockback = 64.0
InitialVelocity = 200.0
ShouldFreezeAngleOnUse = false
PlayerLevelGain = 1.0
[node name="StateMachine" type="Node" parent="." node_paths=PackedStringArray("InitialState")]
script = ExtResource("3_pg4gy")
InitialState = NodePath("Idle")
UsedItemStates = Array[NodePath]([NodePath("Charge"), NodePath("Fire")])
DeusedItemStates = Array[NodePath]([NodePath("Idle")])
[node name="Idle" type="Node" parent="StateMachine" node_paths=PackedStringArray("FireState", "Weapon", "AnimationPlayer")]
script = ExtResource("3_uxif8")
FireState = NodePath("../Charge")
Weapon = NodePath("../..")
AnimationPlayer = NodePath("../../AnimationPlayer")
AnimationKey = "idle"
[node name="Charge" type="Node" parent="StateMachine" node_paths=PackedStringArray("Weapon", "FireState", "IdleState", "AnimationPlayer")]
script = ExtResource("5_k8y6f")
Weapon = NodePath("../..")
FireState = NodePath("../Fire")
IdleState = NodePath("../Idle")
AnimationPlayer = NodePath("../../AnimationPlayer")
AnimationKey = "charge"
[node name="Fire" type="Node" parent="StateMachine" node_paths=PackedStringArray("Weapon", "IdleState", "AnimationPlayer")]
script = ExtResource("4_moo4d")
Weapon = NodePath("../..")
IdleState = NodePath("../Idle")
AnimationPlayer = NodePath("../../AnimationPlayer")
AnimationKey = "fire"
[node name="Anchor" type="Node2D" parent="."]
y_sort_enabled = true
position = Vector2(0, 4)
[node name="Sprite2D" type="Sprite2D" parent="Anchor"]
y_sort_enabled = true
position = Vector2(4, 2)
texture = ExtResource("1_1ghvv")
centered = false
offset = Vector2(-8, -16)
hframes = 8
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_5vx8d")
}
[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="."]

View File

@ -24,7 +24,7 @@ public partial class ProjectileSpawner : Ranged
[Export]
public float ProjectileAngleDeviation { get; set; }
private void SpawnProjectile(Scenes.Map map, Vector2 direction)
private void SpawnProjectile(Scenes.Map map, Vector2 direction, float v = 1)
{
var projectile = map.SpawnEntity<Entities.Projectile>(Projectile);
projectile.Hitbox.Faction = Character.Faction;
@ -33,7 +33,7 @@ public partial class ProjectileSpawner : Ranged
if (ShouldOverrideVelocity)
{
projectile.Speed = InitialVelocity;
projectile.Speed = InitialVelocity * v;
}
if (ShouldRotate)
@ -63,6 +63,11 @@ public partial class ProjectileSpawner : Ranged
}
public override void Attack()
{
Attack(1);
}
public override void Attack(float velocityModifier)
{
Character.Inventory.EmitSignal("UsedItem", this);
@ -78,7 +83,7 @@ public partial class ProjectileSpawner : Ranged
// avoid unnecessary math if only spawning 1 projectile
if (ProjectileCount == 1)
{
SpawnProjectile(map, target);
SpawnProjectile(map, target, velocityModifier);
return;
}
@ -95,7 +100,9 @@ public partial class ProjectileSpawner : Ranged
for (int i = 0; i < ProjectileCount; i++)
{
float curDeviation = -i + maxAngleDeviations;
SpawnProjectile(map, target.Rotated(curDeviation * theta));
SpawnProjectile(map,
target.Rotated(curDeviation * theta),
velocityModifier);
}
}
}

View File

@ -17,7 +17,7 @@ public abstract partial class Ranged : Weapon
public State.Weapon.WeaponStateMachine StateMachine { get; set; }
public override bool IsUsingPrimary => StateMachine.CurrentState
is State.Weapon.RangedFireState;
is State.Weapon.RangedFireState or State.Weapon.RangedChargeState;
public bool IsChargeable => ChargeTime > 0;
@ -42,4 +42,6 @@ public abstract partial class Ranged : Weapon
}
public abstract void Attack();
public virtual void Attack(float velocityModifier) => Attack();
}

View File

@ -0,0 +1,57 @@
/*
* This shader is based on the Godrays shader by pend00
* (https://godotshaders.com/shader/god-rays/), but heavily modified to be
* compatible with both the Forward+ (Vulkan) and Compatibility (OpenGL)
* renderers.
*/
shader_type canvas_item;
uniform vec4 tint_color : source_color;
uniform float alpha : hint_range(0.0, 1.0) = 0.75;
uniform sampler2D noise_texture : repeat_enable;
uniform float speed : hint_range(0.0, 1.0) = 0.25;
uniform float spread = 1;
uniform float opposite_ray_mult = 1.0;
uniform float negative_intensity = 1.0;
uniform float negative_ray_speed : hint_range(0.0, 1.0) = 0;
uniform float cutoff : hint_range(0.0, 1.0) = 0;
uniform float smooth_cutoff : hint_range(0.0, 1.0) = 0;
uniform float y_cutoff : hint_range(0.0, 1.0) = 0;
uniform float y_smooth_cutoff : hint_range(0.0, 1.0) = 0;
uniform float angle : hint_range(-3.14, 3.14);
float noise(vec2 uv) {
return texture(noise_texture, uv).r;
}
mat2 rotate(float _angle){
return mat2(vec2(cos(_angle), -sin(_angle)),
vec2(sin(_angle), cos(_angle)));
}
void fragment() {
vec2 t_uv = UV * rotate(angle) / ((UV.y + spread) - (UV.y * spread));
vec2 ray1 = vec2(t_uv.x + sin(TIME * speed / 10.0));
vec2 ray2 = vec2(-t_uv.x + sin(TIME * speed / 15.0));
vec2 ray3 = vec2(t_uv.x + cos(TIME * negative_ray_speed / 10.0));
float a;
// if t_uv.x exceeds cut value then do not show ray (multiply by 0)
float cut = step(cutoff, t_uv.x) * step(cutoff, 1.0 - UV.x);
cut *= smoothstep(cutoff, cutoff + smooth_cutoff, t_uv.x) *
smoothstep(cutoff, cutoff + smooth_cutoff, 1.0 - t_uv.x);
float y_cut = step(y_cutoff, 1.0 - t_uv.y) * smoothstep(y_cutoff, y_cutoff + y_smooth_cutoff, 1.0 - UV.y);
ray1 *= cut;
ray2 *= cut;
ray3 *= cut;
a = cut * y_cut;
float rays;
rays = clamp(noise(ray1) + opposite_ray_mult * noise(ray2) - negative_intensity * noise(ray3), 0.0, 1.0);
//shine = screen(texture(SCREEN_TEXTURE, SCREEN_UV), vec4(color)).rgb;
COLOR = vec4(vec3(1.0), rays * a) * tint_color;
}

View File

@ -23,15 +23,16 @@ public abstract partial class CharacterState : Node, IState<CharacterState>
var item = Character.Inventory.SelectedItem;
// angle towards item use angle or offhand use angle if not used
bool targetTowards(Items.Item item)
{
if (item is Items.Weapon weapon)
{
if (weapon.IsUsing)
{
Character.Target = weapon.UseDirection;
if (weapon.ShouldFreezeAngleOnUse)
{
Character.Target = weapon.UseDirection;
}
return true;
}
}

View File

@ -22,6 +22,7 @@ public partial class PlayerHealState : PlayerState
}
_timeLeftToHeal = TimeToHeal;
GD.Print("Heal anim");
_player.MovementAnimation.Stop();
_player.AttackAnimation.Play("heal_start");
_player.AttackAnimation.Queue("heal");
_hasHealed = false;

View File

@ -36,6 +36,14 @@ public partial class PlayerIdleState : PlayerState
// NOTE: more conditions may be added soon
}
if (Godot.Input.IsActionPressed("ability"))
{
if (CanHeal())
{
return HealState;
}
}
if (shouldPlayStopAnim)
{
_player.MovementAnimation.Play("stop");
@ -69,7 +77,7 @@ public partial class PlayerIdleState : PlayerState
if (Godot.Input.IsActionPressed("ability"))
{
if (!_player.Inventory.IsUsingItem)
if (CanHeal())
{
return HealState;
}
@ -77,4 +85,9 @@ public partial class PlayerIdleState : PlayerState
return null;
}
private bool CanHeal()
{
return !_player.Inventory.IsUsingItem && _player.Stats.Level.Value > 0;
}
}

View File

@ -68,7 +68,7 @@ public abstract partial class PlayerState : CharacterState
var isAttack1On = Godot.Input.IsActionPressed("attack1");
var isAttack2On = Godot.Input.IsActionPressed("attack2");
if (!weapon.ShouldHideIdle || isAttack1On)
if (!weapon.ShouldHideIdle || !weapon.ShouldFreezeAngleOnUse || isAttack1On)
{
player.Target = player.DesiredTarget;
}
@ -81,6 +81,11 @@ public abstract partial class PlayerState : CharacterState
{
Character.UseCurrentItemAlt();
}
if (Godot.Input.IsActionJustReleased("attack1"))
{
Character.DeuseCurrentItem();
}
}
return base.Process(delta);

View File

@ -0,0 +1,65 @@
using Godot;
using SupaLidlGame.Extensions;
namespace SupaLidlGame.State.Weapon;
public partial class RangedChargeState : WeaponState
{
[Export]
public Items.Weapons.Ranged Weapon { get; set; }
[Export]
public RangedFireState FireState { get; set; }
[Export]
public RangedIdleState IdleState { get; set; }
[Export]
public AnimationPlayer AnimationPlayer { get; set; }
[Export]
public string AnimationKey { get; set; }
private double _timeLeftToCharge = 0;
//private double _timeLeftToOvercharge = 0;
public override IState<WeaponState> Enter(IState<WeaponState> prev)
{
_timeLeftToCharge = Weapon.ChargeTime;
AnimationPlayer?.TryPlay(AnimationKey);
return null;
}
public override WeaponState Process(double delta)
{
if (_timeLeftToCharge > 0)
{
if ((_timeLeftToCharge -= delta) < 0)
{
_timeLeftToCharge = 0;
}
}
Weapon.UseDirection = Weapon.Character.Target;
GD.Print(Weapon.UseDirection);
return null;
}
public override WeaponState Deuse()
{
// fire
double progress = _timeLeftToCharge / Weapon.ChargeTime;
if (progress > 0.5)
{
GD.Print("not enough");
return IdleState;
}
GD.Print("firing");
FireState.VelocityModifier = (float)(1 - progress);
return FireState;
}
}

View File

@ -17,13 +17,15 @@ public partial class RangedFireState : WeaponState
[Export]
public string AnimationKey { get; set; }
public float VelocityModifier { get; set; }
private double _timeLeft = 0;
public override IState<WeaponState> Enter(IState<WeaponState> prev)
{
//_timeLeft
_timeLeft = Weapon.UseTime;
Weapon.Attack();
Weapon.Attack(VelocityModifier);
Weapon.UseDirection = Weapon.Character.Target;
AnimationPlayer?.TryPlay(AnimationKey);
return null;

View File

@ -6,7 +6,7 @@ namespace SupaLidlGame.State.Weapon;
public partial class RangedIdleState : WeaponState
{
[Export]
public RangedFireState FireState { get; set; }
public WeaponState FireState { get; set; }
[Export]
public Items.Weapons.Ranged Weapon { get; set; }