second one

This commit is contained in:
2026-04-22 14:27:36 +03:00
parent b47cd46703
commit 716d0e7d1f
15 changed files with 326 additions and 135 deletions
+12 -36
View File
@@ -19,30 +19,32 @@ var stun_timer: float = 0.0
var contact_timer: float = 0.0
var target: Node3D = null
var mesh_node: MeshInstance3D
@onready var mesh_node: MeshInstance3D = $BodyMesh
var mat: StandardMaterial3D
var COLOR_CHASE = Color(1.0, 0.28, 0.18)
var COLOR_FLY = Color(1.0, 0.85, 0.1)
var COLOR_STUN = Color(0.55, 0.55, 0.65)
var COLOR_CHASE = Color(1.0, 0.28, 0.18)
var COLOR_FLY = Color(1.0, 0.85, 0.1)
var COLOR_STUN = Color(0.55, 0.55, 0.65)
const CONTACT_CD = 0.7
const AIR_FRICTION = 0.86
func _ready() -> void:
add_to_group("enemies")
_build_mesh()
_build_collider()
mat = mesh_node.material_override.duplicate() as StandardMaterial3D
mesh_node.material_override = mat
COLOR_CHASE = mat.albedo_color
func setup(type: String, wave: int) -> void:
match type:
"slime":
move_speed = 2.8 + wave * 0.12
health = 28 + wave * 4
health = 28 + wave * 4
score_value = 10
damage_to_player = 8
"bat":
move_speed = 5.5 + wave * 0.15
health = 14 + wave * 2
health = 14 + wave * 2
score_value = 15
damage_to_player = 6
base_scale = 0.7
@@ -51,7 +53,7 @@ func setup(type: String, wave: int) -> void:
mat.albedo_color = COLOR_CHASE
"ogre":
move_speed = 1.8 + wave * 0.08
health = 80 + wave * 12
health = 80 + wave * 12
score_value = 25
damage_to_player = 18
base_scale = 1.5
@@ -59,26 +61,6 @@ func setup(type: String, wave: int) -> void:
COLOR_CHASE = Color(0.3, 0.7, 0.3)
mat.albedo_color = COLOR_CHASE
func _build_mesh() -> void:
mesh_node = MeshInstance3D.new()
var box := BoxMesh.new()
box.size = Vector3(0.85, 0.85, 0.85)
mesh_node.mesh = box
mesh_node.position.y = 0.425
mat = StandardMaterial3D.new()
mat.albedo_color = COLOR_CHASE
mat.roughness = 0.8
mesh_node.material_override = mat
add_child(mesh_node)
func _build_collider() -> void:
var col := CollisionShape3D.new()
var shape := BoxShape3D.new()
shape.size = Vector3(0.85, 0.85, 0.85)
col.shape = shape
col.position.y = 0.425
add_child(col)
func _physics_process(delta: float) -> void:
match state:
State.CHASING: _chase(delta)
@@ -90,16 +72,13 @@ func _chase(delta: float) -> void:
if not is_instance_valid(target):
return
contact_timer = max(0.0, contact_timer - delta)
var diff := target.global_position - global_position
diff.y = 0.0
var dist := diff.length()
if dist < 1.0 and contact_timer <= 0.0:
contact_timer = CONTACT_CD
if target.has_method("take_damage"):
target.take_damage(damage_to_player)
if dist > 0.05:
var dir := diff.normalized()
velocity.x = dir.x * move_speed
@@ -120,10 +99,8 @@ func _fly(delta: float) -> void:
var col3d := col.get_collider() as Node3D
if col3d == null:
continue
if col3d.has_meta("is_wall"):
var dmg := int(speed_now * wall_damage_mult)
_take_hit(dmg)
_take_hit(int(speed_now * wall_damage_mult))
_wall_impact_effect()
fly_vel = Vector3.ZERO
velocity = Vector3.ZERO
@@ -145,7 +122,6 @@ func _fly(delta: float) -> void:
if Vector2(fly_vel.x, fly_vel.z).length() < 0.4:
_enter_chase()
# Spin while airborne
mesh_node.rotation.y += delta * 10.0
func _stun_tick(delta: float) -> void:
+1 -1
View File
@@ -209,7 +209,7 @@ func _on_spawn_timer() -> void:
if not game_active or upgrading:
return
_spawn_enemy()
spawn_timer.wait_time = max(0.25, 1.4 - wave * 0.07)
spawn_timer.wait_time = 10 # max(0.25, 1.4 - wave * 0.07)
func _spawn_enemy() -> void:
var enemy := ENEMY_SCENE.instantiate() as CharacterBody3D
+24 -76
View File
@@ -5,9 +5,9 @@ signal health_changed(current: int, maximum: int)
@export var move_speed: float = 7.0
@export var kick_range: float = 3.5
@export var kick_force: float = 22.0
@export var kick_force: float = 60.0
@export var kick_cooldown: float = 0.6
@export var kick_angle: float = 120.0
@export var kick_angle: float = 60.0
@export var max_health: int = 100
var health: int = max_health
@@ -16,9 +16,10 @@ var invincible_timer: float = 0.0
var is_alive: bool = true
var last_move_dir: Vector3 = Vector3.FORWARD
var mesh_node: MeshInstance3D
@onready var mesh_node: MeshInstance3D = $BodyMesh
@onready var indicator_node: MeshInstance3D = $KickIndicator
var player_mat: StandardMaterial3D
var indicator_node: MeshInstance3D
var indicator_mat: StandardMaterial3D
const IFRAMES_DURATION := 0.6
@@ -26,27 +27,13 @@ const BASE_COLOR := Color(0.2, 0.55, 1.0)
func _ready() -> void:
add_to_group("player")
_build_visuals()
_build_collider()
func _build_visuals() -> void:
mesh_node = MeshInstance3D.new()
var capsule := CapsuleMesh.new()
capsule.radius = 0.4
capsule.height = 1.0
mesh_node.mesh = capsule
mesh_node.position.y = 0.5
player_mat = StandardMaterial3D.new()
player_mat.albedo_color = BASE_COLOR
player_mat.roughness = 0.6
player_mat.metallic = 0.2
player_mat = mesh_node.material_override.duplicate() as StandardMaterial3D
mesh_node.material_override = player_mat
add_child(mesh_node)
_setup_indicator()
# Kick arc indicator (sector/fan mesh on floor)
indicator_node = MeshInstance3D.new()
indicator_node.mesh = _make_kick_arc_mesh()
func _setup_indicator() -> void:
indicator_node.position.y = 0.02
indicator_node.mesh = _make_kick_arc_mesh()
indicator_mat = StandardMaterial3D.new()
indicator_mat.albedo_color = Color(1.0, 0.85, 0.1, 0.2)
indicator_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
@@ -54,7 +41,6 @@ func _build_visuals() -> void:
indicator_mat.no_depth_test = true
indicator_mat.cull_mode = BaseMaterial3D.CULL_DISABLED
indicator_node.material_override = indicator_mat
add_child(indicator_node)
func _make_kick_arc_mesh() -> ArrayMesh:
var verts := PackedVector3Array()
@@ -65,39 +51,25 @@ func _make_kick_arc_mesh() -> ArrayMesh:
var t: float = float(i) / float(SEGS)
var a: float = lerpf(-half_rad, half_rad, t)
verts.append(Vector3(sin(a) * kick_range, 0.0, -cos(a) * kick_range))
var indices := PackedInt32Array()
for i in range(SEGS):
indices.append(0)
indices.append(i + 1)
indices.append(i + 2)
var arrays: Array = []
arrays.resize(Mesh.ARRAY_MAX)
arrays[Mesh.ARRAY_VERTEX] = verts
arrays[Mesh.ARRAY_INDEX] = indices
var mesh := ArrayMesh.new()
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
return mesh
func _build_collider() -> void:
var col := CollisionShape3D.new()
var shape := CapsuleShape3D.new()
shape.radius = 0.4
shape.height = 1.0
col.shape = shape
col.position.y = 0.5
add_child(col)
func _physics_process(delta: float) -> void:
if not is_alive:
return
_handle_movement(delta)
_handle_kick(delta)
_handle_iframes(delta)
if Input.is_action_just_pressed("ui_accept") and kick_timer <= 0.0:
_do_kick()
@@ -110,24 +82,14 @@ func _handle_movement(delta: float) -> void:
float(Input.is_key_pressed(KEY_S) or Input.is_key_pressed(KEY_DOWN)) -
float(Input.is_key_pressed(KEY_W) or Input.is_key_pressed(KEY_UP))
)
# Camera-relative movement: camera is independent (mouse-controlled), no feedback loop
var cam := get_viewport().get_camera_3d()
if (abs(input_x) > 0.0 or abs(input_z) > 0.0) and cam != null:
var cam_fwd := -cam.global_transform.basis.z
cam_fwd.y = 0.0
if cam_fwd.length() > 0.01:
cam_fwd = cam_fwd.normalized()
else:
cam_fwd = Vector3(0.0, 0.0, -1.0)
cam_fwd = cam_fwd.normalized() if cam_fwd.length() > 0.01 else Vector3(0.0, 0.0, -1.0)
var cam_right := cam.global_transform.basis.x
cam_right.y = 0.0
if cam_right.length() > 0.01:
cam_right = cam_right.normalized()
else:
cam_right = Vector3(1.0, 0.0, 0.0)
cam_right = cam_right.normalized() if cam_right.length() > 0.01 else Vector3(1.0, 0.0, 0.0)
var move := cam_fwd * (-input_z) + cam_right * input_x
if move.length() > 0.01:
move = move.normalized()
@@ -139,7 +101,6 @@ func _handle_movement(delta: float) -> void:
else:
velocity.x = move_toward(velocity.x, 0.0, move_speed * 12.0 * delta)
velocity.z = move_toward(velocity.z, 0.0, move_speed * 12.0 * delta)
velocity.y = 0.0
move_and_slide()
@@ -158,16 +119,10 @@ func _handle_iframes(delta: float) -> void:
func _do_kick() -> void:
kick_timer = kick_cooldown
var forward := -global_transform.basis.z
forward.y = 0.0
if forward.length() > 0.01:
forward = forward.normalized()
else:
forward = Vector3(0, 0, -1)
forward = forward.normalized() if forward.length() > 0.01 else Vector3(0.0, 0.0, -1.0)
var half_cos: float = cos(deg_to_rad(kick_angle * 0.5))
var enemies := get_tree().get_nodes_in_group("enemies")
var kicked_any := false
for e in enemies:
@@ -181,11 +136,9 @@ func _do_kick() -> void:
var dist := diff.length()
if dist < 0.1 or dist > kick_range:
continue
var dir_to_enemy := diff / dist
if dir_to_enemy.dot(forward) >= half_cos:
en.call("receive_kick", dir_to_enemy, kick_force)
if (diff / dist).dot(forward) >= half_cos:
en.call("receive_kick", diff / dist, kick_force)
kicked_any = true
if kicked_any:
_squish_effect()
@@ -198,15 +151,13 @@ func take_damage(amount: int) -> void:
if not is_alive or invincible_timer > 0.0:
return
invincible_timer = IFRAMES_DURATION
health = max(0, health - amount)
emit_signal("health_changed", health, max_health)
var tw := create_tween()
tw.tween_property(player_mat, "albedo_color", Color.RED, 0.08)
tw.tween_property(player_mat, "albedo_color", BASE_COLOR, 0.25)
if health <= 0:
_die()
#health = max(0, health - amount)
#emit_signal("health_changed", health, max_health)
#var tw := create_tween()
#tw.tween_property(player_mat, "albedo_color", Color.RED, 0.08)
#tw.tween_property(player_mat, "albedo_color", BASE_COLOR, 0.25)
#if health <= 0:
#_die()
func _die() -> void:
is_alive = false
@@ -216,15 +167,12 @@ func _die() -> void:
func apply_upgrade(id: String) -> void:
match id:
"kick_force":
kick_force += 6.0
"kick_force": kick_force += 6.0
"kick_range":
kick_range += 0.7
indicator_node.mesh = _make_kick_arc_mesh()
"kick_cooldown":
kick_cooldown = max(0.12, kick_cooldown - 0.09)
"move_speed":
move_speed += 1.2
"kick_cooldown": kick_cooldown = max(0.12, kick_cooldown - 0.09)
"move_speed": move_speed += 1.2
"max_health":
max_health += 30
health = min(health + 30, max_health)