Added Boss

Added Giant Leech
This commit is contained in:
RealMelwei 2025-09-18 18:10:44 +02:00
parent 714ea48554
commit ebc9a77acb
28 changed files with 286 additions and 10 deletions

84
boss.gd Normal file
View file

@ -0,0 +1,84 @@
extends CharacterBody2D
@onready var earthaligner = $EarthAligner
@onready var player = get_tree().get_root().get_node("main/Player")
var moves = ["slam", "wave", "water_rise", "splash"]
@onready var next_move = choose_next_move()
var risen = 0
var attack_ready = true
var idle_dir : Vector2 = Vector2.ZERO
var idle_dir_remaining = 0
var idle_move = true
var target_pos = Vector2.ZERO
var damage = 1
signal grounded
func choose_next_move() -> String:
if $EnemyHurtbox.hp < 2 * $EnemyHurtbox.max_hp / 3 and risen == 0:
risen += 1
return "water_rise"
if $EnemyHurtbox.hp < $EnemyHurtbox.max_hp / 3 and risen == 1:
risen += 1
return "water_rise"
return ["slam", "wave", "splash"].pick_random()
func _physics_process(delta: float) -> void:
up_direction = earthaligner.global_from_local(Vector2.UP)
if attack_ready:
attack_ready = false
call(next_move)
next_move = choose_next_move()
if(is_on_floor()):
grounded.emit()
if idle_move: move_idle(delta)
if($Hitbox.overlaps_body(player)):
player.hurt(damage, self.position - player.position)
move_and_slide()
func move_idle(delta : float):
idle_dir_remaining -= delta
if(idle_dir_remaining <= 0):
target_pos = player.position + player.earth_aligner.global_from_local(Vector2.UP) * 400
target_pos += randf_range(0, max(200, (target_pos - global_position).length())*0.25) * Vector2.from_angle(randf_range(0,TAU))
idle_dir = (target_pos - global_position).normalized()* max(200, (target_pos - global_position).length()) * 0.4
idle_dir_remaining = 0.5
velocity = idle_dir
func slam():
idle_move = false
velocity = up_direction * 500
await get_tree().create_timer(0.6).timeout
damage = 2
velocity = up_direction * -1500
await grounded
destroy_below()
damage = 1
velocity = up_direction * 500
await get_tree().create_timer(0.3).timeout
damage = 2
velocity = up_direction * -1500
await grounded
destroy_below()
damage = 1
velocity = up_direction * 35
await get_tree().create_timer(3).timeout
idle_move = true
attack_ready = true
func destroy_below():
for body in $DestructionChecker.get_overlapping_bodies():
if(body.has_method("destroy")): body.destroy()
func wave():
await get_tree().create_timer(4).timeout
attack_ready = true
func water_rise():
await get_tree().create_timer(4).timeout
attack_ready = true
func splash():
await get_tree().create_timer(4).timeout
attack_ready = true

1
boss.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://uv672p8f4n6k

58
boss.tscn Normal file
View file

@ -0,0 +1,58 @@
[gd_scene load_steps=7 format=3 uid="uid://cpe4s6vsn0ujd"]
[ext_resource type="Texture2D" uid="uid://d3b5hmhjw2jyc" path="res://enemies/ghost animation/Ghost 1.png" id="1_6xxrv"]
[ext_resource type="Script" uid="uid://uv672p8f4n6k" path="res://boss.gd" id="1_skx2t"]
[ext_resource type="PackedScene" uid="uid://mtfsdd4cdf3a" path="res://utils/enemy_hurtbox.tscn" id="2_skx2t"]
[ext_resource type="PackedScene" uid="uid://chs0u61f45nau" path="res://utils/earth_aligner.tscn" id="4_lnbgr"]
[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_lnbgr"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_lnbgr"]
size = Vector2(300, 250)
[node name="Boss" type="CharacterBody2D"]
collision_mask = 32
script = ExtResource("1_skx2t")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
rotation = 1.5708
scale = Vector2(10, 10)
shape = SubResource("CapsuleShape2D_lnbgr")
[node name="Sprite2D" type="Sprite2D" parent="."]
scale = Vector2(3.85156, 1.9375)
texture = ExtResource("1_6xxrv")
[node name="EnemyHurtbox" parent="." node_paths=PackedStringArray("canvasItem") instance=ExtResource("2_skx2t")]
collision_layer = 16
collision_mask = 32
max_hp = 600
canvasItem = NodePath("..")
[node name="CollisionShape2D" type="CollisionShape2D" parent="EnemyHurtbox"]
rotation = 1.5708
scale = Vector2(11, 11)
shape = SubResource("CapsuleShape2D_lnbgr")
[node name="CollisionShape2D2" type="CollisionShape2D" parent="EnemyHurtbox"]
position = Vector2(0, 6)
rotation = 1.5708
scale = Vector2(5, 14)
shape = SubResource("CapsuleShape2D_lnbgr")
[node name="EarthAligner" parent="." instance=ExtResource("4_lnbgr")]
[node name="Hitbox" type="Area2D" parent="."]
scale = Vector2(1.05, 1.05)
[node name="CollisionShape2D" type="CollisionShape2D" parent="Hitbox"]
rotation = 1.5708
scale = Vector2(10, 10)
shape = SubResource("CapsuleShape2D_lnbgr")
[node name="DestructionChecker" type="Area2D" parent="."]
collision_mask = 10
[node name="CollisionShape2D" type="CollisionShape2D" parent="DestructionChecker"]
position = Vector2(0, 200)
shape = SubResource("RectangleShape2D_lnbgr")

View file

@ -4,6 +4,9 @@ class_name Building extends Node2D
@export var dimension : Vector2i = Vector2(2, 1) # same as above
@onready var grid : Grid = get_parent()
var objects = []
var destroyed = false
# make sure location is set before adding a building to the scene tree
# also make sure that the buildings are instantiated as children of the grid
func _ready() -> void:
@ -14,7 +17,7 @@ func _ready() -> void:
grid.buildings.append(self)
await get_tree().create_timer(0).timeout
await get_tree().create_timer(0.2).timeout
if get_node_or_null("EnemyList") != null:
var enemies = $EnemyList.get_children()
@ -23,6 +26,9 @@ func _ready() -> void:
for enemy in enemies:
var oldpos = enemy.position;
enemy.position = get_world_position(oldpos)
if enemy is Platform or enemy is Trap or enemy is Item:
objects.append(enemy)
if "building" in enemy: enemy.building = self
if(enemy.has_method("init_at_horizontal_distortion")):
enemy.init_at_horizontal_distortion(enemy.position.length() / grid.ground_radius)
@ -43,4 +49,12 @@ func overlaps(other : Building):
# If we get here, angles do not overlap
return false
func destroy():
if not destroyed:
grid.buildings.remove_at(grid.buildings.find(self))
for object in objects:
if object != null and not ("collected" in object and object.collected):
object.queue_free()
destroyed = true
queue_free()

View file

@ -39,18 +39,22 @@ position = Vector2(238, -149)
[node name="Platform" parent="EnemyList" instance=ExtResource("8_evf2t")]
visible = false
position = Vector2(75, -285)
collision_layer = 41
[node name="Platform2" parent="EnemyList" instance=ExtResource("8_evf2t")]
visible = false
position = Vector2(225, -285)
collision_layer = 41
[node name="Platform3" parent="EnemyList" instance=ExtResource("8_evf2t")]
visible = false
position = Vector2(375, -285)
collision_layer = 41
[node name="Platform4" parent="EnemyList" instance=ExtResource("8_evf2t")]
visible = false
position = Vector2(525, -285)
collision_layer = 41
[node name="Platform5" parent="EnemyList" instance=ExtResource("8_evf2t")]
position = Vector2(431, -150)

View file

@ -33,10 +33,12 @@ position = Vector2(150, -300)
[node name="Platform" parent="EnemyList" instance=ExtResource("6_e6j05")]
visible = false
position = Vector2(75, -585)
collision_layer = 41
[node name="Platform2" parent="EnemyList" instance=ExtResource("6_e6j05")]
visible = false
position = Vector2(225, -585)
collision_layer = 41
[node name="Platform3" parent="EnemyList" instance=ExtResource("6_e6j05")]
position = Vector2(290, -431)

View file

@ -35,10 +35,12 @@ position = Vector2(-38, -481)
[node name="Platform" parent="EnemyList" instance=ExtResource("6_caaff")]
visible = false
position = Vector2(75, -585)
collision_layer = 41
[node name="Platform2" parent="EnemyList" instance=ExtResource("6_caaff")]
visible = false
position = Vector2(225, -585)
collision_layer = 41
[node name="Platform3" parent="EnemyList" instance=ExtResource("6_caaff")]
position = Vector2(5, -251)

View file

@ -32,10 +32,12 @@ script = ExtResource("4_ri5b7")
[node name="Platform" parent="EnemyList" instance=ExtResource("6_kom4b")]
visible = false
position = Vector2(75, -585)
collision_layer = 41
[node name="Platform2" parent="EnemyList" instance=ExtResource("6_kom4b")]
visible = false
position = Vector2(225, -585)
collision_layer = 41
[node name="Platform5" parent="EnemyList" instance=ExtResource("6_kom4b")]
position = Vector2(85, -287)

View file

@ -44,18 +44,22 @@ position = Vector2(118, -125)
[node name="Platform" parent="EnemyList" instance=ExtResource("8_sifiv")]
visible = false
position = Vector2(75, -285)
collision_layer = 41
[node name="Platform2" parent="EnemyList" instance=ExtResource("8_sifiv")]
visible = false
position = Vector2(225, -285)
collision_layer = 41
[node name="Platform3" parent="EnemyList" instance=ExtResource("8_sifiv")]
visible = false
position = Vector2(375, -285)
collision_layer = 41
[node name="Platform4" parent="EnemyList" instance=ExtResource("8_sifiv")]
visible = false
position = Vector2(525, -285)
collision_layer = 41
[node name="Platform5" parent="EnemyList" instance=ExtResource("8_sifiv")]
position = Vector2(300, -150)

View file

@ -38,18 +38,22 @@ grid_offset = Vector2i(0, -1)
[node name="Platform" parent="EnemyList" instance=ExtResource("6_me65q")]
visible = false
position = Vector2(75, -285)
collision_layer = 41
[node name="Platform2" parent="EnemyList" instance=ExtResource("6_me65q")]
visible = false
position = Vector2(225, -285)
collision_layer = 41
[node name="Platform3" parent="EnemyList" instance=ExtResource("6_me65q")]
visible = false
position = Vector2(375, -285)
collision_layer = 41
[node name="Platform4" parent="EnemyList" instance=ExtResource("6_me65q")]
visible = false
position = Vector2(525, -285)
collision_layer = 41
[node name="ItemSpawn" parent="EnemyList" instance=ExtResource("7_crruu")]
position = Vector2(137, -329)

4
destroy_area.gd Normal file
View file

@ -0,0 +1,4 @@
extends Area2D
func destroy():
get_parent().queue_free()

1
destroy_area.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://dwvb52u1hnx5m

62
enemies/giant_leech.tscn Normal file
View file

@ -0,0 +1,62 @@
[gd_scene load_steps=5 format=3 uid="uid://5nb7pf8g1ck"]
[ext_resource type="Script" uid="uid://b70f2ylbb3btt" path="res://enemies/leech.gd" id="1_wfsrb"]
[ext_resource type="PackedScene" uid="uid://cvoicwo2xnf7e" path="res://segment.tscn" id="2_7ngsb"]
[ext_resource type="PackedScene" uid="uid://chs0u61f45nau" path="res://utils/earth_aligner.tscn" id="3_vk62e"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_cq6dk"]
size = Vector2(2, 24)
[node name="Giant_Leech" type="Node2D"]
scale = Vector2(1, 1.2)
script = ExtResource("1_wfsrb")
broadth = 400
hp = 500
[node name="Segments" type="Node2D" parent="."]
[node name="Segment0" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="Segment2" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="Segment3" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="Segment4" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="Segment5" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="Segment6" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="Segment7" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="Segment8" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="Segment9" parent="Segments" instance=ExtResource("2_7ngsb")]
scale = Vector2(2, 2)
[node name="EarthAligner" parent="." instance=ExtResource("3_vk62e")]
[node name="RayCast2D" type="Area2D" parent="."]
position = Vector2(248, 31.2)
collision_layer = 0
collision_mask = 8
[node name="CollisionShape2D" type="CollisionShape2D" parent="RayCast2D"]
position = Vector2(0, 14.8)
shape = SubResource("RectangleShape2D_cq6dk")
[node name="RayCast2D2" type="Area2D" parent="."]
collision_layer = 0
collision_mask = 8
[node name="CollisionShape2D" type="CollisionShape2D" parent="RayCast2D2"]
position = Vector2(0, 14.8)
shape = SubResource("RectangleShape2D_cq6dk")

View file

@ -12,6 +12,8 @@ var pause_time = 0.1
var iframes = 0.2
var iframe_time = 0
var check_grounded_delay = 8
func _ready() -> void:
for segment in segments:
segment.segment_damaged.connect(hurt)
@ -47,6 +49,10 @@ func _physics_process(delta: float) -> void:
var segment_pos_data = calculate_segment_location_and_rotation(i)
segments[i].position = segment_pos_data.position
segments[i].rotation = segment_pos_data.rotation
if check_grounded_delay > 0:
check_grounded_delay -= delta
elif not $RayCast2D2.has_overlapping_bodies():
queue_free()
func calculate_segment_location_and_rotation (i) -> Dictionary:
var aerial_end_location = Vector2.from_angle(-angle) * broadth

View file

@ -8,7 +8,10 @@
size = Vector2(2, 24)
[node name="Leech" type="Node2D"]
scale = Vector2(1, 1.2)
script = ExtResource("1_6u582")
broadth = 200
hp = 250
[node name="Segments" type="Node2D" parent="."]
@ -40,3 +43,11 @@ collision_mask = 8
[node name="CollisionShape2D" type="CollisionShape2D" parent="RayCast2D"]
position = Vector2(0, 14.8)
shape = SubResource("RectangleShape2D_cq6dk")
[node name="RayCast2D2" type="Area2D" parent="."]
collision_layer = 0
collision_mask = 8
[node name="CollisionShape2D" type="CollisionShape2D" parent="RayCast2D2"]
position = Vector2(0, 14.8)
shape = SubResource("RectangleShape2D_cq6dk")

View file

@ -8,7 +8,7 @@ size = Vector2(20, 5)
[node name="Arrow" type="Area2D"]
collision_layer = 0
collision_mask = 2
collision_mask = 18
script = ExtResource("1_lxthq")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]

View file

@ -1,5 +1,6 @@
class_name Item extends Area2D
@onready var player = get_tree().get_root().get_node_or_null("main/Player")
var collected = false
func _physics_process(_delta: float) -> void:
if(is_instance_valid(player) and overlaps_body(player)):
@ -8,6 +9,7 @@ func _physics_process(_delta: float) -> void:
set_deferred("monitorable", false)
call_deferred("reparent", player)
collect_animation()
collected = true
func collect_animation():
self.visible = false

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=10 format=3 uid="uid://cxo6bq26huau7"]
[gd_scene load_steps=11 format=3 uid="uid://cxo6bq26huau7"]
[ext_resource type="PackedScene" uid="uid://cmaovvr15b3qk" path="res://player/player.tscn" id="2_1bvp3"]
[ext_resource type="Texture2D" uid="uid://d3fpq76anm4t7" path="res://world/Background prototype.png" id="3_kek77"]
@ -9,6 +9,7 @@
[ext_resource type="PackedScene" uid="uid://dpdn2php3ydsv" path="res://death_screen/death_screen.tscn" id="7_5vw27"]
[ext_resource type="Script" uid="uid://3k6r3jnko4hg" path="res://show_fps.gd" id="8_5vw27"]
[ext_resource type="PackedScene" uid="uid://b62xcg0dd3vct" path="res://enemies/leech.tscn" id="9_kek77"]
[ext_resource type="PackedScene" uid="uid://cpe4s6vsn0ujd" path="res://boss.tscn" id="10_4c57u"]
[node name="main" type="Node2D"]
@ -67,6 +68,9 @@ script = ExtResource("8_5vw27")
[node name="Leech" parent="." instance=ExtResource("9_kek77")]
position = Vector2(0, -3015)
[node name="Boss" parent="." instance=ExtResource("10_4c57u")]
position = Vector2(0, -3500)
[connection signal="active_item_changed" from="Player" to="CanvasLayer/ItemUI" method="_on_player_active_item_changed"]
[connection signal="health_changed" from="Player" to="CanvasLayer/Healthbar" method="_on_player_health_changed"]
[connection signal="max_hp_changed" from="Player" to="CanvasLayer/Healthbar" method="_on_player_max_hp_changed"]

View file

@ -18,7 +18,7 @@ animations = [{
[node name="Sword" type="Area2D"]
scale = Vector2(1.8, 1.8)
collision_mask = 2
collision_mask = 18
script = ExtResource("1_hv1tj")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]

View file

@ -69,3 +69,5 @@ drop_item={
2d_physics/layer_2="EnemyHurtBox"
2d_physics/layer_3="PlayerHurtBox"
2d_physics/layer_4="SolidGround"
2d_physics/layer_5="EnemyHurtBoxNonTrap"
2d_physics/layer_6="TrulySolidGround"

View file

@ -1,4 +1,4 @@
extends Node2D
extends Trap
@export var player_damage : int;
@export var enemy_damage : int;

View file

@ -1,4 +1,4 @@
extends Node2D
extends Trap
@onready var ball : Area2D = $Area2D
var anglespeed = 0.3
var player_damage = 1

1
traps/trap.gd Normal file
View file

@ -0,0 +1 @@
class_name Trap extends Node2D

1
traps/trap.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://umx7q0tml2ul

View file

@ -26,3 +26,6 @@ func hurt(damage : int, dir : Vector2 = Vector2.ZERO):
func die():
died.emit()
func destroy():
hurt(9999)

View file

@ -3,5 +3,5 @@
[ext_resource type="Script" uid="uid://ct8am2xeyymuj" path="res://utils/enemy_hurtbox.gd" id="1_wa58b"]
[node name="EnemyHurtbox" type="Area2D"]
collision_layer = 2
collision_layer = 18
script = ExtResource("1_wa58b")

View file

@ -1,4 +1,8 @@
extends StaticBody2D
class_name Platform extends StaticBody2D
var building
func init_at_horizontal_distortion(distortion : float):
scale.x *= distortion
func destroy():
building.destroy()

View file

@ -17,7 +17,7 @@ radius = 3000.0
script = ExtResource("1_wxnww")
[node name="Ground" type="StaticBody2D" parent="."]
collision_layer = 9
collision_layer = 41
[node name="CollisionShape2D" type="CollisionShape2D" parent="Ground"]
shape = SubResource("CircleShape2D_5i67w")