diff --git a/assets/textures/enemies/lashy/lashy_anchor.png b/assets/textures/enemies/lashy/lashy_anchor.png new file mode 100644 index 0000000..b5285c6 Binary files /dev/null and b/assets/textures/enemies/lashy/lashy_anchor.png differ diff --git a/assets/textures/enemies/lashy/lashy_anchor.png.import b/assets/textures/enemies/lashy/lashy_anchor.png.import new file mode 100644 index 0000000..9d7149f --- /dev/null +++ b/assets/textures/enemies/lashy/lashy_anchor.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cm4cantqbhkwx" +path="res://.godot/imported/lashy_anchor.png-9018700d9959e1ce2de25066b2ad5deb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/enemies/lashy/lashy_anchor.png" +dest_files=["res://.godot/imported/lashy_anchor.png-9018700d9959e1ce2de25066b2ad5deb.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 diff --git a/assets/textures/enemies/lashy/lashy_body.png b/assets/textures/enemies/lashy/lashy_body.png new file mode 100644 index 0000000..06fde00 Binary files /dev/null and b/assets/textures/enemies/lashy/lashy_body.png differ diff --git a/assets/textures/enemies/lashy/lashy_body.png.import b/assets/textures/enemies/lashy/lashy_body.png.import new file mode 100644 index 0000000..be4df18 --- /dev/null +++ b/assets/textures/enemies/lashy/lashy_body.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://gnkke4rr0wcr" +path="res://.godot/imported/lashy_body.png-5a8d8988a263a55d2f3ee182268a610d.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/enemies/lashy/lashy_body.png" +dest_files=["res://.godot/imported/lashy_body.png-5a8d8988a263a55d2f3ee182268a610d.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 diff --git a/assets/textures/enemies/lashy/lashy_head.png b/assets/textures/enemies/lashy/lashy_head.png new file mode 100644 index 0000000..c306c0b Binary files /dev/null and b/assets/textures/enemies/lashy/lashy_head.png differ diff --git a/assets/textures/enemies/lashy/lashy_head.png.import b/assets/textures/enemies/lashy/lashy_head.png.import new file mode 100644 index 0000000..4d6f196 --- /dev/null +++ b/assets/textures/enemies/lashy/lashy_head.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bf0i64q2dw0au" +path="res://.godot/imported/lashy_head.png-877548aaa0421024db625942f78e1401.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/textures/enemies/lashy/lashy_head.png" +dest_files=["res://.godot/imported/lashy_head.png-877548aaa0421024db625942f78e1401.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 diff --git a/maps/level_z.tscn b/maps/level_z.tscn index c674ebd..2848dd4 100644 --- a/maps/level_z.tscn +++ b/maps/level_z.tscn @@ -1,3 +1,24 @@ -[gd_scene format=3 uid="uid://cccb8wltupasj"] +[gd_scene load_steps=5 format=4 uid="uid://cccb8wltupasj"] + +[ext_resource type="Texture2D" uid="uid://b6a7l24y30iht" path="res://assets/textures/backgrounds/chocomint.png" id="1_h5jcm"] +[ext_resource type="TileSet" uid="uid://xwfn24if3pxk" path="res://assets/tilesets/chocomint.tres" id="2_dj7w1"] +[ext_resource type="PackedScene" uid="uid://mh2gfm7iqqsm" path="res://objects/player/player.tscn" id="3_kyrxg"] +[ext_resource type="PackedScene" uid="uid://c8r040r4glui4" path="res://objects/enemies/lashy/lashy.tscn" id="4_gykx6"] [node name="LevelZ" type="Node2D"] + +[node name="Background" type="Sprite2D" parent="."] +modulate = Color(0.996924, 0.421436, 0, 1) +position = Vector2(144, 108) +texture = ExtResource("1_h5jcm") + +[node name="TileMap" type="TileMapLayer" parent="."] +use_parent_material = true +tile_map_data = PackedByteArray("AAAAAAsAAAAAAAAAAAABAAsAAAAAAAAAAAACAAsAAAAAAAAAAAAHAAsAAAAAAAAAAAAIAAsAAAAAAAAAAAAJAAsAAAAAAAAAAAAKAAsAAAAAAAAAAAALAAsAAAAAAAAAAAANAAsAAAAAAAAAAAAOAAsAAAAAAAAAAAAPAAsAAAAAAAAAAAAQAAsAAAAAAAAAAAARAAsAAAAAAAAAAAADAAsAAAAAAAAAAAAEAAsAAAAAAAAAAAAFAAsAAAAAAAAAAAAGAAsAAAAAAAAAAAAMAAsAAAAAAAAAAAAFAAoAAAAAAAAAAAAGAAoAAAAAAAAAAAAGAAkAAAAAAAAAAAAHAAkAAAAAAAAAAAAIAAkAAAAAAAAAAAAJAAkAAAAAAAAAAAAKAAkAAAAAAAAAAAALAAkAAAAAAAAAAAAMAAkAAAAAAAAAAAALAAoAAAAAAAAAAAAKAAoAAAAAAAAAAAAJAAoAAAAAAAAAAAAIAAoAAAAAAAAAAAAHAAoAAAAAAAAAAAAMAAoAAAAAAAAAAAANAAoAAAAAAAAAAAAOAAoAAAAAAAAAAAAPAAoAAAAAAAAAAAAPAAkAAAAAAAAAAAAQAAkAAAAAAAAAAAAQAAgAAAAAAAAAAAAQAAcAAAAAAAAAAAAQAAYAAAAAAAAAAAARAAcAAAAAAAAAAAAQAAoAAAAAAAAAAAARAAkAAAAAAAAAAAARAAgAAAAAAAAAAAARAAoAAAAAAAAAAAARAAYAAAAAAAAAAAARAAUAAAAAAAAAAAARAAQAAAAAAAAAAAAQAAQAAAAAAAAAAAAQAAUAAAAAAAAAAAAFAAkAAAAAAAAAAAAEAAkAAAAAAAAAAAADAAkAAAAAAAAAAAACAAkAAAAAAAAAAAABAAkAAAAAAAAAAAABAAoAAAAAAAAAAAACAAoAAAAAAAAAAAADAAoAAAAAAAAAAAAEAAoAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAAkAAAAAAAAAAAA=") +tile_set = ExtResource("2_dj7w1") + +[node name="Player" parent="." instance=ExtResource("3_kyrxg")] +position = Vector2(40, 124) + +[node name="Lashy" parent="." instance=ExtResource("4_gykx6")] +position = Vector2(141, 99) diff --git a/objects/enemies/lashy/lashy.gd b/objects/enemies/lashy/lashy.gd new file mode 100644 index 0000000..4991781 --- /dev/null +++ b/objects/enemies/lashy/lashy.gd @@ -0,0 +1,83 @@ +@tool +extends Node2D + + +enum State { + IDLE, + WINDING_UP, + ATTACK, + RECOVER, +} + + +@export var idle_distance: float +@export_custom(PROPERTY_HINT_NONE, "radians_as_degrees") +var idle_rotate_speed: float + +@export var wind_up_time: float +@export var wind_up_distance: float + +@export var attack_time: float +@export var attack_distance: float + +@export var recover_time: float + +@export_range(0,1,1,"or_greater") var detection_radius: float: + set(value): + detection_radius = value + if not is_inside_tree(): + await tree_entered + var shape = detector_shape.shape as CircleShape2D + if shape: + shape.radius = detection_radius + +@export_group("Internal References") +@export var head: Node2D +@export var head_pivot: Node2D +@export var detector_shape: CollisionShape2D + + +var state: State = State.IDLE +var tween: Tween = null +var tracked_player: Player = null +var idle_angle: float = 0.0 +var target_pos: Vector2 = Vector2.ZERO +var progress: float = 0.0 + + +func _process(delta: float) -> void: + if Engine.is_editor_hint(): + return + + match state: + State.IDLE: + idle_angle = fposmod(idle_angle + idle_rotate_speed * delta, TAU) + head_pivot.rotation = idle_angle + State.WINDING_UP: + target_pos = tracked_player.global_position + var angle = (global_position - target_pos).angle() + progress += delta / wind_up_time + head_pivot.rotation = lerp_angle(head_pivot.rotation, angle, progress) + State.RECOVER: + progress += delta / recover_time + head_pivot.rotation = lerp_angle(head_pivot.rotation, idle_angle, progress) + + +func _start_attack() -> void: + state = State.WINDING_UP + if tween: + tween.kill() + tween = create_tween().set_process_mode(Tween.TWEEN_PROCESS_PHYSICS) + tween.tween_property(head, ^"position:x", wind_up_distance, wind_up_time) + tween.tween_property(self, ^"state", State.ATTACK, 0.0) + tween.tween_property(head, ^"position:x", -attack_distance, attack_time).set_trans(Tween.TRANS_BOUNCE) + tween.tween_property(self, ^"state", State.RECOVER, 0.0) + tween.tween_property(head, ^"position:x", idle_distance, recover_time) + tween.tween_property(self, ^"state", State.IDLE, 0.0) + + +func _on_player_detector_body_entered(body: Node2D) -> void: + if body is Player: + if state == State.IDLE: + tracked_player = body + _start_attack() diff --git a/objects/enemies/lashy/lashy.tscn b/objects/enemies/lashy/lashy.tscn new file mode 100644 index 0000000..0b29199 --- /dev/null +++ b/objects/enemies/lashy/lashy.tscn @@ -0,0 +1,71 @@ +[gd_scene load_steps=8 format=3 uid="uid://c8r040r4glui4"] + +[ext_resource type="Script" path="res://objects/enemies/lashy/lashy.gd" id="1_34o54"] +[ext_resource type="Texture2D" uid="uid://cm4cantqbhkwx" path="res://assets/textures/enemies/lashy/lashy_anchor.png" id="2_8ls3k"] +[ext_resource type="Script" path="res://scripts/ball_snake.gd" id="3_8edxw"] +[ext_resource type="Texture2D" uid="uid://gnkke4rr0wcr" path="res://assets/textures/enemies/lashy/lashy_body.png" id="4_xnkdk"] +[ext_resource type="Texture2D" uid="uid://bf0i64q2dw0au" path="res://assets/textures/enemies/lashy/lashy_head.png" id="5_b5g1y"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_woon5"] +resource_local_to_scene = true +radius = 64.0 + +[sub_resource type="CircleShape2D" id="CircleShape2D_g5iss"] +radius = 6.0 + +[node name="Lashy" type="Node2D" node_paths=PackedStringArray("head", "head_pivot", "detector_shape")] +script = ExtResource("1_34o54") +idle_distance = 16.0 +idle_rotate_speed = 1.5708 +wind_up_time = 2.0 +wind_up_distance = 32.0 +attack_time = 0.5 +attack_distance = 64.0 +recover_time = 2.0 +detection_radius = 64.0 +head = NodePath("HeadPivot/Head") +head_pivot = NodePath("HeadPivot") +detector_shape = NodePath("PlayerDetector/DetectorShape") + +[node name="PlayerDetector" type="Area2D" parent="."] +collision_layer = 0 +collision_mask = 16 +monitorable = false + +[node name="DetectorShape" type="CollisionShape2D" parent="PlayerDetector"] +shape = SubResource("CircleShape2D_woon5") +debug_color = Color(0.752941, 0.196078, 1, 0.25098) + +[node name="Anchor" type="Sprite2D" parent="."] +texture = ExtResource("2_8ls3k") + +[node name="BallSnake" type="Node2D" parent="." node_paths=PackedStringArray("target")] +script = ExtResource("3_8edxw") +texture = ExtResource("4_xnkdk") +target = NodePath("../HeadPivot/Head") +segments = 2 +head_segment = false +auto_density = true +pixels_per_segment = 5.0 + +[node name="HeadSprite" type="Sprite2D" parent="."] +position = Vector2(-5.79198e-05, -16) +texture = ExtResource("5_b5g1y") + +[node name="HeadPivot" type="Node2D" parent="."] +rotation = -1.5708 + +[node name="Head" type="Area2D" parent="HeadPivot"] +position = Vector2(16, 0) +metadata/_edit_group_ = true + +[node name="CollisionShape2D" type="CollisionShape2D" parent="HeadPivot/Head"] +shape = SubResource("CircleShape2D_g5iss") +debug_color = Color(1, 0, 0, 0.419608) + +[node name="RemoteTransform2D" type="RemoteTransform2D" parent="HeadPivot/Head"] +remote_path = NodePath("../../../HeadSprite") +update_rotation = false +update_scale = false + +[connection signal="body_entered" from="PlayerDetector" to="." method="_on_player_detector_body_entered"]