Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(Rigidbody))] [RequireComponent(typeof(Collider))] public class SteeringEnemyAI : MonoBehaviour { [Header("Target")] [Tooltip("Трансформ игрока")] public Transform player; [Header("Steering Settings")] public float maxSpeed = 3f; public float maxForce = 15f; public float arrivalRadius = 1f; [Header("Boids Settings")] [Tooltip("Минимальное расстояние до соседей")] public float separationRadius = 1.5f; public float separationStrength = 7f; [Range(0f, 1f)] public float cohesionWeight = 0.5f; [Range(0f, 1f)] public float alignmentWeight = 0.5f; [Header("Obstacle Avoidance")] public float avoidDistance = 2f; public float avoidStrength = 10f; public LayerMask obstacleMask; [Header("Rotation")] public float angularSpeed = 10f; // Все враги в сцене private static List
allEnemies = new List
(); private Rigidbody rb; // Текущий и целевой множители скорости (Frost-эффект) [HideInInspector] public float frostMultiplier = 1f; private float targetMultiplier = 1f; private float smoothVelocity; // Слой до заморозки и слой во время Frost private int originalLayer; private int frostedLayer; private void Awake() { rb = GetComponent
(); allEnemies.Add(this); // Запомним, на каком слое был враг изначально, // и найдём индекс слоя "EnemyFrosted" originalLayer = gameObject.layer; frostedLayer = LayerMask.NameToLayer("EnemyFrosted"); if (frostedLayer < 0) Debug.LogWarning("Слой EnemyFrosted не найден! Создайте его в настройках Unity."); } private void OnDestroy() { allEnemies.Remove(this); } private void FixedUpdate() { if (player == null) return; // Плавно приближаем frostMultiplier к targetMultiplier frostMultiplier = Mathf.SmoothDamp( frostMultiplier, targetMultiplier, ref smoothVelocity, 0.3f ); // Если полностью заморожены — не добавляем никаких сил if (frostMultiplier <= 1e-4f) return; // ----- Steering AI как раньше, за вычетом ручного сброса скорости ----- // 1) Движение к игроку Vector3 toTarget = player.position - transform.position; float dist = toTarget.magnitude; Vector3 desired = toTarget.normalized * maxSpeed * frostMultiplier; if (dist < arrivalRadius) desired *= dist / arrivalRadius; // 2) Boids-силы: Separation, Cohesion, Alignment Vector3 sepForce = Vector3.zero, cohForce = Vector3.zero, aliForce = Vector3.zero; int count = 0; float sepRad2 = separationRadius * separationRadius; foreach (var other in allEnemies) { if (other == this) continue; Vector3 diff = transform.position - other.transform.position; float d2 = diff.sqrMagnitude; if (d2 < sepRad2 && d2 > 0.001f) { sepForce += diff.normalized / d2; count++; } } if (count > 0) { sepForce = sepForce.normalized * separationStrength * frostMultiplier; Vector3 center = Vector3.zero; foreach (var other in allEnemies) { if (other == this) continue; if ((other.transform.position - transform.position).sqrMagnitude < sepRad2) center += other.transform.position; } center /= count; cohForce = (center - transform.position).normalized * separationStrength * cohesionWeight * frostMultiplier; Vector3 avgVel = Vector3.zero; foreach (var other in allEnemies) { if (other == this) continue; if ((other.transform.position - transform.position).sqrMagnitude < sepRad2) avgVel += other.rb.velocity; } avgVel /= count; aliForce = (avgVel.normalized * maxSpeed * frostMultiplier - rb.velocity) * alignmentWeight * frostMultiplier; } // 3) Obstacle Avoidance Vector3 avoidForce = Vector3.zero; Vector3 forward = rb.velocity.sqrMagnitude > 0.01f ? rb.velocity.normalized : transform.forward; if (Physics.Raycast(transform.position, forward, out RaycastHit hit, avoidDistance, obstacleMask)) { avoidForce = Vector3.Cross(hit.normal, Vector3.up).normalized * avoidStrength * frostMultiplier; } // 4) Собираем итоговую силу и применяем Vector3 steer = desired + sepForce + cohForce + aliForce + avoidForce - rb.velocity; steer = Vector3.ClampMagnitude(steer, maxForce * frostMultiplier); rb.AddForce(steer, ForceMode.Acceleration); // 5) Ограничиваем максимальную скорость Vector3 horiz = new Vector3(rb.velocity.x, 0f, rb.velocity.z); if (horiz.magnitude > maxSpeed * frostMultiplier) { horiz = horiz.normalized * maxSpeed * frostMultiplier; rb.velocity = new Vector3(horiz.x, rb.velocity.y, horiz.z); } // 6) Лёгкий перенос – при заморозке силой Frost враг медленнее гасят внешние толчки rb.drag = Mathf.Lerp(0f, 5f, 1f - frostMultiplier); } ///
/// Устанавливает целевой множитель скорости (0…1) и переключает слой, /// чтобы замороженный враг больше не сталкивался с другими врагами, /// но мог сталкиваться с игроком. ///
public void SetMultiplier(float m) { targetMultiplier = Mathf.Clamp01(m); smoothVelocity = 0f; frostMultiplier = targetMultiplier; // Один раз обнуляем скорость при полной заморозке: if (frostMultiplier <= 1e-4f) { Vector3 v = rb.velocity; rb.velocity = new Vector3(0f, v.y, 0f); } // Переключаем игровой слой объекта и всех его потомков int layerTo = frostMultiplier < 1f - 1e-4f ? frostedLayer : originalLayer; SetLayerRecursively(transform, layerTo); } // Рекурсивно задаём слой объекту и всем потомкам private void SetLayerRecursively(Transform t, int layer) { t.gameObject.layer = layer; foreach (Transform child in t) SetLayerRecursively(child, layer); } }
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)