我正在研究和尝试从一周后建立一个血腥解体系统,但我差不多已经放弃了。
我希望在动态载入预设体时,不仅仅是正常位置和方向,还有原部位的变形或动画姿势的系统。
在性能消耗较高的旧骨骼上转移重量时,我有了一个想法,在击中时我将捕捉到原始角色姿势的快照,在runtime时将位置和方向数据传递到每个个体骨骼。像一个臂位位的预设体将包含原始相同的骨骼,而不是集体传递数据。相反,我将数据传递到每个单独的骨骼,如前臂、拇指等,所以它看起来像是变形。
我编写了这个脚本,然而即使重新试了好几次,也没有成功,而且预设体只会在身体关节处重置成原始姿势。
using System;
using System.Collections.Generic;
using UnityEngine;
【DisallowMultipleComponent】
public class DismembermentManager : MonoBehaviour
{
【Serializable】
public class BodyPiecePrefab
{
public string pieceName;
public GameObject prefab;
}
【Serializable】
private 结构 BonePose
{
public Vector3 worldPosition;
public Quaternion worldRotation;
}
[Serialize Field] private Transform characterRoot;
[Serialize Field] private Animator characterAnimator;
[Serialize Field] private List
[Serialize Field] private float explosionForce = 12f;
[Serialize Field] private float explosionRadius = 4f;
[Serialize Field] private float upwardModifier = 0.3f;
private readonly Dictionary
private readonly List
private bool hasExploded;
private void Awake()
{
if (characterRoot == null)
characterRoot = transform;
if (characterAnimator == null)
characterAnimator = GetComponentInChildren
缓存source骨骼();
}
[ContextMenu("重建源骨骼缓存") ]
public void CacheSourceBones()
{
sourceBones.Clear();
sourceBones.AddRange(GetComponentsInChildren
}
public void Explode(Vector3 hitPoint, Vector3 hitNormal)
{
if (hasExploded) return;
hasExploded = true;
捕捉姿势快照();
if (characterAnimator != null)
characterAnimator.enabled = false;
foreach (var piece in bodyPieces)
{
if (piece == null || piece.prefab == null)
continue;
GameObject instance = Instantiate(piece.prefab, characterRoot.position, characterRoot.rotation);
应用快照到实例(instance.transform);
启用物理(instance, hitPoint, hitNormal);
}
gameObject.SetActive(false);
}
private void CapturePoseSnapshot()
{
poseSnapshot.Clear();
foreach (var bone in sourceBones)
{
if (bone == null) continue;
poseSnapshot[bone.name] = new BonePose
{
worldPosition = bone.position,
worldRotation = bone.rotation
};
}
}
private void ApplySnapshotToInstance(Transform root)
{
Transform[] all = root.GetComponentsInChildren
Array.Sort(all, (a, b) => GetDepth(a).CompareTo(GetDepth(b)));
foreach (var t in all)
{
if (t == null) continue;
if (poseSnapshot.TryGetValue(t.name, out BonePose pose))
{
t.SetPositionAndRotation(pose.worldPosition, pose.worldRotation);
}
}
}
private int GetDepth(Transform t)
{
int depth = 0;
while (t.parent != null)
{
depth++;
t = t.parent;
}
return depth;
}
private void EnablePhysics(GameObject instance, Vector3 hitPoint, Vector3 hitNormal)
{
Animator anim = instance.GetComponentInChildren
if (anim != null)
anim.enabled = false;
Rigidbody[] rigidbodies = instance.GetComponentsInChildren
Collider[] colliders = instance.GetComponentsInChildren
foreach (var col in colliders)
col.enabled = true;
foreach (var rb in rigidbodies)
{
rb.isKinematic = false;
rb.useGravity = true;
rb.detectCollisions = true;
rb.WakeUp();
Vector3 direction = (rb.worldCenterOfMass - hitPoint).normalized;
if (direction.sqrMagnitude < 0.0001f)
direction = hitNormal.normalized;
rb.AddExplosionForce(explosionForce, hitPoint, explosionRadius, upwardModifier, ForceMode.Impulse);
rb.AddForce(direction * explosionForce, ForceMode.Impulse);
}
}
评论 (0)