Sky Delivery — Разрушение самолета 2.0

Закончил работу над механикой разрушения самолёта в моём авиасимуляторе. Более того, авиакатастрофу теперь можно ещё и послушать.

Вы только посмотрите на эти взрывы. Я прирождённый гуру VFX

Основные изменения претерпел коллайдер аэроплана. Ранее это был MeshCollider с поднятым флагом Convex. Теперь используется один BoxCollider для корпуса и по одному на каждое крыло.

Логика устроена достаточно просто.

Есть класс AircraftDestructiblePart — он хранит информацию о текущем уровне прочности детали. Его я повесил на кузов и крылья.

public class AircraftDestructiblePart : MonoBehaviour { public float maxHealth; public float currentHealh; public float currentState; public float mainDamageCoef; public bool isDestroyed = false; void Start(){ currentHealh = maxHealth; currentState = 1; } public void Separate() { transform.parent = null; var rb = GetComponent<Rigidbody>(); if (rb == null) rb = this.AddComponent<Rigidbody>(); rb.mass = 20f; } public void TurnOff() { GetComponent<BoxCollider>().enabled = false; } public void SendDamage(float damage) { currentHealh -= damage; if (currentHealh < 0) { currentHealh = 0; isDestroyed = true; currentState = 0; } else currentState = currentHealh / maxHealth; } }

Есть общий менеджер разрушаемости AircraftDestructionManager. Он хранит информацию о деталях, обладающих запасом прочности (левое крыло, правое крыло, кузов).

Он же отслеживает физические коллизии и, в зависимости от силы импульса, сообщает урон соответствующему элементу.

Если HP элемента закончилось и это не кузов, он отсоединяется и к нему добавляется Rigidbody. Если HP закончилось у кузова, значит, весь пепелац разрушен.

private void OnCollisionEnter(Collision collision) { if (!isDamageOn) return; foreach (var contact in collision.contacts) { AircraftDestructiblePart contactPart = contact.thisCollider.GetComponent<AircraftDestructiblePart>(); if (contactPart != null) { float currentDamage = collision.impulse.magnitude; var rb = model.structure.rigidBody; if (currentDamage == 0) currentDamage = rb.mass * rb.linearVelocity.magnitude; contactPart.SendDamage(currentDamage); if (contactPart != gear) gear.SendDamage(currentDamage * contactPart.mainDamageCoef); if (contactPart.currentState < 0.01) if (contactPart != gear) { contactPart.Separate(); model.sound.playCrack(contactPart.transform); } if (gear.currentState < 0.01) { var explosionObject = GameObject.Instantiate(explosionPrefab, transform.position, Quaternion.identity); model.sound.playExplosion(transform); Root.gameState.setCameraDistanceMultiply(2, 20f); rb.linearDamping = 4; rb.angularDamping = 10; StartCoroutine(SendCrashEvent(1f)); isDamageOn = false; } } break; } }

В контроллере самолёта тягу я умножаю на текущий процент состояния кузова. Касательно аэродинамики, я привязываюсь к состоянию крыльев при расчёте подъёмной силы и силы руля крена. Их величина зависит от состояния крыла к которому они должны быть приложены. Именно поэтому самолёт эффектно уходит в пике при потере крыла.

В данный момент повреждения возможны только механические. В планах — добавить факторы среды: например, грозовой фронт или токсичный туман. Также хочу аналогичным образом реализовать механику потери шасси с сохранением возможности посадить воздушное судно на брюхо.

В итоге аэроплан теперь достоверно разваливается на куски и не отскакивает от препятствий как деревянная болванка. А это плюс к погружению и ощущению от игры. И, конечно, ещё один шаг в сторону законченной игры.

Спасибо за внимание! Подписывайтесь тут или в телеге, если проект заинтересовал :)

23
5
3
19 комментариев