From fdece3a3dc1c81e534a15857f5a30245f37b49a6 Mon Sep 17 00:00:00 2001 From: Ruslan Ignatov Date: Tue, 30 Jun 2026 22:16:44 +0300 Subject: [PATCH] Added turret projectile --- game/entities/danger/danger.gd | 1 + game/entities/turret/turret.gd | 19 +- game/entities/turret/turret_projectile.gd | 47 +++++ game/entities/turret/turret_projectile.gd.uid | 1 + game/entities/turret/turret_projectile.tscn | 174 ++++++++++++++++++ game/levels/abstract_level.gd | 1 + game/levels/test_level.tscn | 6 +- game/managers/hitstop_manager.gd | 20 +- game/managers/sound_manager.gd | 1 + game/managers/sound_manager.tscn | 2 + images/entities/turret_projectile.png | 3 + images/entities/turret_projectile.png.import | 40 ++++ project.godot | 1 + sound/sfx/turret_hit.wav | 3 + sound/sfx/turret_hit.wav.import | 24 +++ 15 files changed, 335 insertions(+), 8 deletions(-) create mode 100644 game/entities/turret/turret_projectile.gd create mode 100644 game/entities/turret/turret_projectile.gd.uid create mode 100644 game/entities/turret/turret_projectile.tscn create mode 100644 images/entities/turret_projectile.png create mode 100644 images/entities/turret_projectile.png.import create mode 100644 sound/sfx/turret_hit.wav create mode 100644 sound/sfx/turret_hit.wav.import diff --git a/game/entities/danger/danger.gd b/game/entities/danger/danger.gd index c11b1c6..c4ec5c5 100644 --- a/game/entities/danger/danger.gd +++ b/game/entities/danger/danger.gd @@ -32,6 +32,7 @@ func _hit_player() -> bool: if not _player: return false SoundManager.play_sfx_stream(SoundManager.sfx_stream_danger, global_position) _player.deal_damage(DAMAGE_VALUE) + HitstopManager.medium_hitstop() return true diff --git a/game/entities/turret/turret.gd b/game/entities/turret/turret.gd index 2efb821..d30217f 100644 --- a/game/entities/turret/turret.gd +++ b/game/entities/turret/turret.gd @@ -9,13 +9,15 @@ enum Direction { } +const PROJECTILE = preload("res://game/entities/turret/turret_projectile.tscn") + const ANIMATION_IDLE = "idle" const ANIMATION_SHOOT = "shoot" const SHOT_FRAME = 3 -@export_range(0.0, 60.0) var shoot_delay := 3.0 +@export_range(1.0, 10.0) var shoot_delay := 1.0 @export var direction := Direction.Left: set(value): @@ -46,7 +48,10 @@ func _ready() -> void: func _shoot() -> void: - print("Shot") + var projectile : TurretProjectile = PROJECTILE.instantiate() + projectile.global_position = _current_muzzle.global_position + projectile.direction = _get_projectile_direction() + get_tree().current_scene.add_child(projectile) func _update_direction() -> void: @@ -62,6 +67,16 @@ func _update_direction() -> void: _current_sprite.show() +func _get_projectile_direction() -> Vector2: + match direction: + Direction.Left: + return Vector2.LEFT + Direction.Right: + return Vector2.RIGHT + _: + return Vector2.ZERO + + func _on_left_sprite_animation_finished() -> void: left_sprite.play(ANIMATION_IDLE) diff --git a/game/entities/turret/turret_projectile.gd b/game/entities/turret/turret_projectile.gd new file mode 100644 index 0000000..323a932 --- /dev/null +++ b/game/entities/turret/turret_projectile.gd @@ -0,0 +1,47 @@ +class_name TurretProjectile +extends Node2D + + +const SPEED = 300 +const DAMAGE = 20.0 + +const ANIMATION_WOBBLE = "wobble" + + +@export var direction := Vector2.ZERO + + +var is_on_screen := false + + +@onready var sprite : AnimatedSprite2D = $AnimatedSprite2D +@onready var fly_particles : GPUParticles2D = $FlyParticles + + +func _ready() -> void: + sprite.play(ANIMATION_WOBBLE) + + +func _physics_process(delta: float) -> void: + position += direction * SPEED * delta + + +func _on_body_entered(body: Node2D) -> void: + if body is Player: + SoundManager.play_sfx_stream(SoundManager.sfx_stream_turret_hit, global_position) + HitstopManager.short_hitstop() + body.deal_damage(DAMAGE) + queue_free() + + +func _on_screen_entered() -> void: + is_on_screen = true + + +func _on_screen_exited() -> void: + if is_on_screen: + queue_free() + + +func _on_destroy_particles_finished() -> void: + queue_free() diff --git a/game/entities/turret/turret_projectile.gd.uid b/game/entities/turret/turret_projectile.gd.uid new file mode 100644 index 0000000..7b8122e --- /dev/null +++ b/game/entities/turret/turret_projectile.gd.uid @@ -0,0 +1 @@ +uid://boedoah7a3ew3 diff --git a/game/entities/turret/turret_projectile.tscn b/game/entities/turret/turret_projectile.tscn new file mode 100644 index 0000000..ff32faf --- /dev/null +++ b/game/entities/turret/turret_projectile.tscn @@ -0,0 +1,174 @@ +[gd_scene format=3 uid="uid://cfpukqa2am62o"] + +[ext_resource type="Script" uid="uid://boedoah7a3ew3" path="res://game/entities/turret/turret_projectile.gd" id="1_6obn6"] +[ext_resource type="Texture2D" uid="uid://domd2gwquuiec" path="res://images/entities/turret_projectile.png" id="2_kmlbp"] + +[sub_resource type="AtlasTexture" id="AtlasTexture_4stq6"] +atlas = ExtResource("2_kmlbp") +region = Rect2(0, 0, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_3v20y"] +atlas = ExtResource("2_kmlbp") +region = Rect2(16, 0, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_8xnl0"] +atlas = ExtResource("2_kmlbp") +region = Rect2(32, 0, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_vk0n8"] +atlas = ExtResource("2_kmlbp") +region = Rect2(48, 0, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_koth7"] +atlas = ExtResource("2_kmlbp") +region = Rect2(0, 16, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_kq137"] +atlas = ExtResource("2_kmlbp") +region = Rect2(16, 16, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_vwuh1"] +atlas = ExtResource("2_kmlbp") +region = Rect2(32, 16, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_6fv0s"] +atlas = ExtResource("2_kmlbp") +region = Rect2(48, 16, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_00ug4"] +atlas = ExtResource("2_kmlbp") +region = Rect2(0, 32, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_6ssmj"] +atlas = ExtResource("2_kmlbp") +region = Rect2(16, 32, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_b3avt"] +atlas = ExtResource("2_kmlbp") +region = Rect2(32, 32, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_sob1q"] +atlas = ExtResource("2_kmlbp") +region = Rect2(48, 32, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_g80b6"] +atlas = ExtResource("2_kmlbp") +region = Rect2(0, 48, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_7npid"] +atlas = ExtResource("2_kmlbp") +region = Rect2(16, 48, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_1uqp5"] +atlas = ExtResource("2_kmlbp") +region = Rect2(32, 48, 16, 16) + +[sub_resource type="AtlasTexture" id="AtlasTexture_71cqq"] +atlas = ExtResource("2_kmlbp") +region = Rect2(48, 48, 16, 16) + +[sub_resource type="SpriteFrames" id="SpriteFrames_bhunq"] +animations = [{ +"frames": [{ +"duration": 1.0, +"texture": SubResource("AtlasTexture_4stq6") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_3v20y") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_8xnl0") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_vk0n8") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_koth7") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_kq137") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_vwuh1") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_6fv0s") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_00ug4") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_6ssmj") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_b3avt") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_sob1q") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_g80b6") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_7npid") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_1uqp5") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_71cqq") +}], +"loop": 1, +"name": &"wobble", +"speed": 10.0 +}] + +[sub_resource type="CircleShape2D" id="CircleShape2D_bhunq"] +radius = 4.0 + +[sub_resource type="Gradient" id="Gradient_kmlbp"] +interpolation_mode = 1 +offsets = PackedFloat32Array(0, 0.2, 0.4, 0.6, 0.8) +colors = PackedColorArray(0.36862746, 0.99215686, 0.5529412, 1, 0.3529412, 0.81960785, 0.4862745, 1, 0.32941177, 0.6509804, 0.41568628, 1, 0.3019608, 0.49019608, 0.35686275, 1, 0.25882354, 0.3372549, 0.29803923, 1) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_sn0t7"] +gradient = SubResource("Gradient_kmlbp") +width = 5 + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_riqys"] +lifetime_randomness = 0.5 +particle_flag_disable_z = true +emission_shape = 1 +emission_sphere_radius = 4.0 +inherit_velocity_ratio = 0.1 +gravity = Vector3(0, 0, 0) +scale_min = 2.0 +scale_max = 2.0 +color_ramp = SubResource("GradientTexture1D_sn0t7") + +[node name="TurretProjectile" type="Node2D" unique_id=740761191] +z_index = -5 +script = ExtResource("1_6obn6") + +[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="." unique_id=1667166835] +sprite_frames = SubResource("SpriteFrames_bhunq") +animation = &"wobble" + +[node name="Area2D" type="Area2D" parent="." unique_id=658518046] +collision_layer = 8 +collision_mask = 3 + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D" unique_id=1265333400] +shape = SubResource("CircleShape2D_bhunq") + +[node name="VisibleOnScreenNotifier2D" type="VisibleOnScreenNotifier2D" parent="." unique_id=1219726055] +rect = Rect2(-100, -100, 200, 200) + +[node name="FlyParticles" type="GPUParticles2D" parent="." unique_id=1236465902] +amount = 16 +lifetime = 0.2 +process_material = SubResource("ParticleProcessMaterial_riqys") + +[connection signal="body_entered" from="Area2D" to="." method="_on_body_entered"] +[connection signal="screen_entered" from="VisibleOnScreenNotifier2D" to="." method="_on_screen_entered"] +[connection signal="screen_exited" from="VisibleOnScreenNotifier2D" to="." method="_on_screen_exited"] diff --git a/game/levels/abstract_level.gd b/game/levels/abstract_level.gd index c5d1db0..0e75a8d 100644 --- a/game/levels/abstract_level.gd +++ b/game/levels/abstract_level.gd @@ -99,6 +99,7 @@ func _on_corruption_timer_timeout() -> void: corruption_timer.stop() return player.deal_damage(CORRUPTION_DAMAGE) + HitstopManager.medium_hitstop() SoundManager.play_sfx_stream(SoundManager.sfx_stream_corruption, player.global_position) diff --git a/game/levels/test_level.tscn b/game/levels/test_level.tscn index 328ea76..ad58d4c 100644 --- a/game/levels/test_level.tscn +++ b/game/levels/test_level.tscn @@ -4,7 +4,7 @@ [ext_resource type="PackedScene" uid="uid://dn3x1qj88r8pn" path="res://game/entities/turret/turret.tscn" id="2_giiqr"] [ext_resource type="PackedScene" uid="uid://dxqq07mde0b4a" path="res://game/entities/danger/danger.tscn" id="2_yeikn"] -[sub_resource type="ViewportTexture" id="ViewportTexture_80l8l"] +[sub_resource type="ViewportTexture" id="ViewportTexture_giiqr"] viewport_path = NodePath("CanvasLayer/CodeViewport") [node name="TestLevel" unique_id=1001045799 instance=ExtResource("1_46m3m")] @@ -19,7 +19,7 @@ tile_map_data = PackedByteArray("AAAMAP//AAAFAAoAAAAMAP7/AAALAAYAAAAMAP3/AAAIAAY [node name="Turret" parent="Turrets" parent_id_path=PackedInt32Array(491073452) index="0" unique_id=328367237 instance=ExtResource("2_giiqr")] position = Vector2(606, -432) -shoot_delay = 3.0 +shoot_delay = 1.0 [node name="Danger" parent="Dangers" parent_id_path=PackedInt32Array(608961351) index="0" unique_id=554396375 instance=ExtResource("2_yeikn")] offset_left = 89.0 @@ -28,4 +28,4 @@ offset_right = 189.0 offset_bottom = -55.0 [node name="CodeSprite" parent="CanvasLayer" parent_id_path=PackedInt32Array(1125559156) index="1" unique_id=1152584149] -texture = SubResource("ViewportTexture_80l8l") +texture = SubResource("ViewportTexture_giiqr") diff --git a/game/managers/hitstop_manager.gd b/game/managers/hitstop_manager.gd index 95ba745..92b94cc 100644 --- a/game/managers/hitstop_manager.gd +++ b/game/managers/hitstop_manager.gd @@ -5,11 +5,25 @@ extends Node const NORMAL_TIME_SCALE = 1.0 -@export var hitstop_duration := 0.1 +@export var short_hitstop_duration := 0.05 +@export var medium_hitstop_duration := 0.1 +@export var long_hitstop_duration := 0.15 @export var hitstop_time_scale := 0.0 -func hitstop() -> void: +func short_hitstop() -> void: + _hitstop(short_hitstop_duration) + + +func medium_hitstop() -> void: + _hitstop(medium_hitstop_duration) + + +func long_hitstop() -> void: + _hitstop(long_hitstop_duration) + + +func _hitstop(duration: float) -> void: Engine.time_scale = hitstop_time_scale - await get_tree().create_timer(hitstop_duration, true, true, true).timeout + await get_tree().create_timer(duration, true, true, true).timeout Engine.time_scale = NORMAL_TIME_SCALE diff --git a/game/managers/sound_manager.gd b/game/managers/sound_manager.gd index b1eadbe..56c5341 100644 --- a/game/managers/sound_manager.gd +++ b/game/managers/sound_manager.gd @@ -32,6 +32,7 @@ const MUSIC_BUS = "Music" @export var sfx_stream_jump : AudioStream @export var sfx_stream_land : AudioStream @export var sfx_stream_swing : AudioStream +@export var sfx_stream_turret_hit : AudioStream @export var sfx_stream_turret_shot : AudioStream @export var sfx_stream_wall_jump : AudioStream diff --git a/game/managers/sound_manager.tscn b/game/managers/sound_manager.tscn index 2a8ddc2..6c5d297 100644 --- a/game/managers/sound_manager.tscn +++ b/game/managers/sound_manager.tscn @@ -14,6 +14,7 @@ [ext_resource type="AudioStream" uid="uid://bj6ausg5hyuyg" path="res://sound/sfx/swing.wav" id="7_ab171"] [ext_resource type="AudioStream" uid="uid://33unutlwsika" path="res://sound/sfx/wall_jump.wav" id="8_22ptj"] [ext_resource type="AudioStream" uid="uid://bnrvkm5wy8wda" path="res://sound/sfx/turret_shot.wav" id="13_814q3"] +[ext_resource type="AudioStream" uid="uid://8nag1oaly0by" path="res://sound/sfx/turret_hit.wav" id="13_ounmg"] [node name="SoundManager" type="Node" unique_id=1576371552] process_mode = 3 @@ -35,5 +36,6 @@ sfx_stream_game_over = ExtResource("6_6ll5c") sfx_stream_jump = ExtResource("5_fpnh3") sfx_stream_land = ExtResource("6_22ptj") sfx_stream_swing = ExtResource("7_ab171") +sfx_stream_turret_hit = ExtResource("13_ounmg") sfx_stream_turret_shot = ExtResource("13_814q3") sfx_stream_wall_jump = ExtResource("8_22ptj") diff --git a/images/entities/turret_projectile.png b/images/entities/turret_projectile.png new file mode 100644 index 0000000..0146368 --- /dev/null +++ b/images/entities/turret_projectile.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c2dc10caf7f9a7896f313a242e92534f90d06430d9e8e1ec77b713935507e5a1 +size 537 diff --git a/images/entities/turret_projectile.png.import b/images/entities/turret_projectile.png.import new file mode 100644 index 0000000..b8bb55d --- /dev/null +++ b/images/entities/turret_projectile.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://domd2gwquuiec" +path="res://.godot/imported/turret_projectile.png-1d9e1b8965b7897c658554585cc3756e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://images/entities/turret_projectile.png" +dest_files=["res://.godot/imported/turret_projectile.png-1d9e1b8965b7897c658554585cc3756e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +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/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +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 diff --git a/project.godot b/project.godot index f6e48e8..e244079 100644 --- a/project.godot +++ b/project.godot @@ -135,6 +135,7 @@ pause={ 2d_physics/layer_1="World" 2d_physics/layer_2="Player" 2d_physics/layer_3="Danger" +2d_physics/layer_4="Turret Projectile" [physics] diff --git a/sound/sfx/turret_hit.wav b/sound/sfx/turret_hit.wav new file mode 100644 index 0000000..51ce651 --- /dev/null +++ b/sound/sfx/turret_hit.wav @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e52c54742739965b25863f821fb7b498bd835a391c023256937b0ae73a7e4ae +size 13318 diff --git a/sound/sfx/turret_hit.wav.import b/sound/sfx/turret_hit.wav.import new file mode 100644 index 0000000..98fdb1d --- /dev/null +++ b/sound/sfx/turret_hit.wav.import @@ -0,0 +1,24 @@ +[remap] + +importer="wav" +type="AudioStreamWAV" +uid="uid://8nag1oaly0by" +path="res://.godot/imported/turret_hit.wav-1ade48b1adf836497da6beb5f416a8f9.sample" + +[deps] + +source_file="res://sound/sfx/turret_hit.wav" +dest_files=["res://.godot/imported/turret_hit.wav-1ade48b1adf836497da6beb5f416a8f9.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=2