init
This commit is contained in:
182
scripts/projectile.gd
Normal file
182
scripts/projectile.gd
Normal file
@@ -0,0 +1,182 @@
|
||||
extends Area3D
|
||||
class_name Projectile
|
||||
|
||||
# Базовый класс для снарядов
|
||||
|
||||
@export var speed: float = 120.0
|
||||
@export var damage: float = 20.0
|
||||
@export var lifetime: float = 5.0
|
||||
@export var is_explosive: bool = false
|
||||
@export var explosion_radius: float = 3.0
|
||||
|
||||
var direction: Vector3 = Vector3.ZERO
|
||||
var velocity: Vector3 = Vector3.ZERO
|
||||
var owner_unit: Node3D = null
|
||||
var lifetime_timer: float = 0.0
|
||||
var has_hit: bool = false
|
||||
var previous_position: Vector3 = Vector3.ZERO
|
||||
|
||||
signal hit(target: Node3D, position: Vector3)
|
||||
signal exploded(position: Vector3)
|
||||
|
||||
func _ready():
|
||||
lifetime_timer = lifetime
|
||||
previous_position = global_position
|
||||
# Настраиваем Area3D для обнаружения целей
|
||||
body_entered.connect(_on_body_entered)
|
||||
# Отключаем мониторинг по умолчанию для параболических
|
||||
monitoring = true
|
||||
monitorable = false
|
||||
|
||||
func _physics_process(delta):
|
||||
if has_hit:
|
||||
return
|
||||
|
||||
lifetime_timer -= delta
|
||||
if lifetime_timer <= 0:
|
||||
if is_explosive:
|
||||
explode(global_position)
|
||||
else:
|
||||
queue_free()
|
||||
return
|
||||
|
||||
# Сохраняем предыдущую позицию для raycast
|
||||
previous_position = global_position
|
||||
|
||||
# Движение снаряда
|
||||
global_position += velocity * delta
|
||||
|
||||
# Проверка столкновений через raycast
|
||||
check_collisions_raycast()
|
||||
|
||||
func check_collisions_raycast():
|
||||
# Используем raycast для проверки столкновений
|
||||
var space_state = get_world_3d().direct_space_state
|
||||
var query = PhysicsRayQueryParameters3D.create(previous_position, global_position)
|
||||
query.exclude = [self, owner_unit] if owner_unit else [self]
|
||||
query.collision_mask = 1 # Только слой земли и объектов
|
||||
|
||||
var result = space_state.intersect_ray(query)
|
||||
if result:
|
||||
var collider = result.collider
|
||||
var hit_position = result.position
|
||||
|
||||
# Если это враг, наносим урон
|
||||
if collider.has_method("take_damage"):
|
||||
collider.take_damage(damage)
|
||||
hit.emit(collider, hit_position)
|
||||
|
||||
on_hit(hit_position)
|
||||
|
||||
func _on_body_entered(body: Node3D):
|
||||
# Дополнительная проверка через Area3D
|
||||
if has_hit:
|
||||
return
|
||||
|
||||
if body == owner_unit:
|
||||
return
|
||||
|
||||
if body is Projectile:
|
||||
return
|
||||
|
||||
if body.has_method("take_damage"):
|
||||
body.take_damage(damage)
|
||||
hit.emit(body, global_position)
|
||||
|
||||
on_hit(global_position)
|
||||
|
||||
func on_hit(position: Vector3):
|
||||
if has_hit:
|
||||
return
|
||||
|
||||
has_hit = true
|
||||
velocity = Vector3.ZERO
|
||||
# Останавливаем частицы
|
||||
var fire_particles = get_node_or_null("FireParticles")
|
||||
var trail_particles = get_node_or_null("TrailParticles")
|
||||
if fire_particles:
|
||||
fire_particles.emitting = false
|
||||
if trail_particles:
|
||||
trail_particles.emitting = false
|
||||
|
||||
if is_explosive:
|
||||
explode(position)
|
||||
else:
|
||||
# Простое попадание
|
||||
hit.emit(null, position)
|
||||
# Воспроизводим анимацию попадания
|
||||
play_hit_animation()
|
||||
# Удаляем через небольшую задержку
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
queue_free()
|
||||
|
||||
func explode(position: Vector3):
|
||||
# Находим все цели в радиусе взрыва
|
||||
var space_state = get_world_3d().direct_space_state
|
||||
var query = PhysicsShapeQueryParameters3D.new()
|
||||
var sphere_shape = SphereShape3D.new()
|
||||
sphere_shape.radius = explosion_radius
|
||||
query.shape = sphere_shape
|
||||
query.transform.origin = position
|
||||
query.collision_mask = 1
|
||||
|
||||
var results = space_state.intersect_shape(query)
|
||||
|
||||
# Наносим урон всем в радиусе
|
||||
for result in results:
|
||||
var collider = result.collider
|
||||
if collider != owner_unit and collider.has_method("take_damage"):
|
||||
var distance = position.distance_to(collider.global_position)
|
||||
var damage_multiplier = 1.0 - (distance / explosion_radius)
|
||||
collider.take_damage(damage * damage_multiplier)
|
||||
|
||||
exploded.emit(position)
|
||||
play_explosion_animation()
|
||||
# Ждем, пока частицы взрыва отыграют (0.5 секунды)
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
queue_free()
|
||||
|
||||
func play_hit_animation():
|
||||
# Создаем простой визуальный эффект попадания
|
||||
var mesh = get_node_or_null("MeshInstance3D")
|
||||
if mesh:
|
||||
# Увеличиваем размер и скрываем
|
||||
var tween = create_tween()
|
||||
tween.tween_property(mesh, "scale", Vector3(2.0, 2.0, 2.0), 0.2)
|
||||
tween.tween_callback(func(): mesh.visible = false)
|
||||
|
||||
func play_explosion_animation():
|
||||
# Скрываем основной меш
|
||||
var mesh = get_node_or_null("MeshInstance3D")
|
||||
if mesh:
|
||||
mesh.visible = false
|
||||
|
||||
# Останавливаем частицы полета
|
||||
var fire_particles = get_node_or_null("FireParticles")
|
||||
var trail_particles = get_node_or_null("TrailParticles")
|
||||
if fire_particles:
|
||||
fire_particles.emitting = false
|
||||
if trail_particles:
|
||||
trail_particles.emitting = false
|
||||
|
||||
# Воспроизводим частицы взрыва
|
||||
var explosion_particles = get_node_or_null("ExplosionParticles")
|
||||
var explosion_core = get_node_or_null("ExplosionCore")
|
||||
var explosion_smoke = get_node_or_null("ExplosionSmoke")
|
||||
|
||||
# Масштабируем узлы частиц в зависимости от радиуса взрыва
|
||||
# Это создаст визуальный эффект взрыва нужного размера
|
||||
var scale_factor = explosion_radius / 3.0 # 3.0 - базовый радиус взрыва
|
||||
|
||||
if explosion_particles:
|
||||
explosion_particles.scale = Vector3.ONE * scale_factor
|
||||
explosion_particles.restart()
|
||||
explosion_particles.emitting = true
|
||||
if explosion_core:
|
||||
explosion_core.scale = Vector3.ONE * scale_factor * 0.6
|
||||
explosion_core.restart()
|
||||
explosion_core.emitting = true
|
||||
if explosion_smoke:
|
||||
explosion_smoke.scale = Vector3.ONE * scale_factor * 1.2
|
||||
explosion_smoke.restart()
|
||||
explosion_smoke.emitting = true
|
||||
Reference in New Issue
Block a user