From cfc28168bcba9c46ac4bac2ccc36e842c977a93c Mon Sep 17 00:00:00 2001 From: Nikolai Fedorov Date: Wed, 22 Apr 2026 15:49:02 +0300 Subject: [PATCH] initial merge --- scripts/Enemy.gd | 60 ++++++++++++++++++++++++++++++++++++++++++++---- scripts/Main.gd | 27 ++++++++++++++++++++++ 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/scripts/Enemy.gd b/scripts/Enemy.gd index 1129fa5..37104ad 100644 --- a/scripts/Enemy.gd +++ b/scripts/Enemy.gd @@ -1,23 +1,29 @@ extends CharacterBody3D signal died(points: int) +signal merged(upgrade: bool) -enum State { CHASING, FLYING, STUNNED, DEAD } +enum State { CHASING, FLYING, STUNNED, DEAD, MERGING } var move_speed: float = 3.0 var health: int = 30 var damage_to_player: int = 8 var score_value: int = 10 +var enemy_level: int = 1 +var enemy_type: String = "slime" var wall_damage_mult: float = 1.8 var chain_factor: float = 0.65 var stun_time: float = 0.5 var base_scale: float = 1.0 +var wave_num: int = 1 var state: State = State.CHASING var fly_vel: Vector3 = Vector3.ZERO var stun_timer: float = 0.0 var contact_timer: float = 0.0 var target: Node3D = null +var merge_partner: Node = null +var is_upgrading: bool = false @onready var mesh_node: MeshInstance3D = $BodyMesh var mat: StandardMaterial3D @@ -36,6 +42,8 @@ func _ready() -> void: COLOR_CHASE = mat.albedo_color func setup(type: String, wave: int) -> void: + enemy_type = type + wave_num = wave match type: "slime": move_speed = 2.8 + wave * 0.12 @@ -89,6 +97,7 @@ func _chase(delta: float) -> void: func _fly(delta: float) -> void: var speed_now := Vector2(fly_vel.x, fly_vel.z).length() + print_debug("speed is ", speed_now) velocity = fly_vel velocity.y = 0.0 move_and_slide() @@ -108,10 +117,14 @@ func _fly(delta: float) -> void: hit_wall = true break elif col3d.is_in_group("enemies") and col3d != self: - var chain_dir := col3d.global_position - global_position - chain_dir.y = 0.0 - if chain_dir.length() > 0.01: - col3d.call("receive_kick", chain_dir.normalized(), speed_now * chain_factor) + var other: Node = col3d + if speed_now >= 3.0 and other.get("enemy_level") == enemy_level and other.get("is_upgrading") == false and is_upgrading == false: + _start_merge(other) + else: + var chain_dir := col3d.global_position - global_position + chain_dir.y = 0.0 + if chain_dir.length() > 0.01: + col3d.call("receive_kick", chain_dir.normalized(), speed_now * chain_factor) elif col3d.is_in_group("player"): col3d.call("take_damage", int(speed_now * 0.6)) @@ -141,6 +154,43 @@ func receive_kick(direction: Vector3, force: float) -> void: tw.tween_property(mesh_node, "scale:y", base_scale * 0.35, 0.06) tw.tween_property(mesh_node, "scale:y", base_scale, 0.18) +func _start_merge(other: Node) -> void: + is_upgrading = true + other.is_upgrading = true + other.merge_partner = self + merge_partner = other + state = State.MERGING + other.state = State.MERGING + fly_vel = Vector3.ZERO + velocity = Vector3.ZERO + other.fly_vel = Vector3.ZERO + other.velocity = Vector3.ZERO + mat.albedo_color = Color(1.0, 1.0, 0.5) + other.mat.albedo_color = Color(1.0, 1.0, 0.5) + var tw := create_tween().set_parallel(true) + tw.tween_property(self, "global_position", other.global_position, 0.2) + tw.tween_property(other, "global_position", global_position, 0.2) + tw.tween_callback(_on_merge_complete) + +func _on_merge_complete() -> void: + var merge_pos := global_position + var merge_type := enemy_type + var new_level: int = enemy_level + 1 + var new_wave: int = wave_num + if is_instance_valid(merge_partner): + merge_pos = (global_position + merge_partner.global_position) / 2.0 + merge_partner.queue_free() + queue_free() + emit_signal("merged", true) + var tree := get_tree() + if tree != null and tree.has_group("main"): + var main := tree.get_nodes_in_group("main")[0] as Node + if main != null and main.has_method("_spawn_upgraded_enemy"): + var new_enemy := main.call("_spawn_upgraded_enemy", merge_pos, merge_type, new_level, new_wave) as CharacterBody3D + if new_enemy != null: + new_enemy.state = State.FLYING + new_enemy.fly_vel = Vector3.ZERO + func _enter_stun() -> void: state = State.STUNNED stun_timer = stun_time diff --git a/scripts/Main.gd b/scripts/Main.gd index ee71cc4..68bd41b 100644 --- a/scripts/Main.gd +++ b/scripts/Main.gd @@ -43,6 +43,7 @@ func _ready() -> void: _create_ui() _spawn_player() _start_game() + add_to_group("main") Input.mouse_mode = Input.MOUSE_MODE_CAPTURED func _input(event: InputEvent) -> void: @@ -224,6 +225,7 @@ func _spawn_enemy() -> void: enemy.setup(type, wave) enemy.target = player enemy.connect("died", _on_enemy_died) + enemy.connect("merged", _on_enemy_merged) # Spawn at random edge var side := randi() % 4 @@ -246,6 +248,31 @@ func _on_enemy_died(points: int) -> void: wave += 1 _show_upgrade() +func _spawn_upgraded_enemy(pos: Vector3, type: String, level: int, w: int) -> CharacterBody3D: + var enemy := ENEMY_SCENE.instantiate() as CharacterBody3D + add_child(enemy) + enemy.setup(type, w) + enemy.target = player + enemy.enemy_level = level + 1 + enemy.global_position = pos + enemy.connect("died", _on_enemy_died) + enemy.connect("merged", _on_enemy_merged) + var tw := enemy.create_tween() + var s: float = 1.0 + level * 0.3 + tw.tween_property(enemy.mesh_node, "scale", Vector3(s, s, s), 0.2) + var col_shape := enemy.get_node_or_null("CollisionShape3D") as CollisionShape3D + if col_shape != null and col_shape.shape != null: + var s3d: BoxShape3D = col_shape.shape as BoxShape3D + var old_size: Vector3 = s3d.size + col_shape.shape = BoxShape3D.new() + (col_shape.shape as BoxShape3D).size = old_size * s + var color := Color(1.0, 1.0, 0.5) if level > 2 else Color(1.0, 0.9, 0.3) + tw.tween_property(enemy.mat, "albedo_color", color, 0.25) + return enemy + +func _on_enemy_merged(_upgrade: bool) -> void: + pass + func _on_player_died() -> void: game_active = false spawn_timer.stop()