最近在做《搜打撤》类的第三人称射击类游戏,遇到一个问题,就是当角色死亡的时候,尸体要留在战场上,同时又希望死亡时,尸体会有一些不同的摆放姿势,如下:


如图所示,同一个模型的两个角色,在死亡后变成两个尸体,但他们的死亡姿势每次都不一样。
对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀
角色的制作思路如下:
Step1:角色我们都基于人形动画来进行制作,角色的模型就有标准的人形的骨骼。当角色没有死亡的时候,直接基于动画组件来播放动画即可。

Step2: 要模拟角色"死亡"后不同的骨骼摆放的位置,姿势各有不同,那么我们要给人形动画的每个关节带上一些物理刚体RigidBody+物理形状。做成"刚体骨骼"。

刚体骨骼与刚体骨骼之间用物理关节连接起来。

单独的针对"人形骨骼"的节点做一个独立的物理分组,不与其它的物理分组产生任何碰撞。
Step3: 编写一个"物理人形骨骼"控制代码: RagdollBehavior,用来控制这个物理人形骨骼。在角色创建的时候,正常情况下,先禁用"物理人形骨骼"。
public void Init(Transform ragdollParentTransform){List<Rigidbody> rigidbodies = new List<Rigidbody>();ragdollParentTransform.GetComponentsInChildren(rigidbodies);rbCases = new List<RigidbodyCase>();for (int i = 0; i < rigidbodies.Count; i++){var rigidbody = rigidbodies[i];if (rigidbody.gameObject.layer != 14)continue;var rbCase = new RigidbodyCase(rigidbodies[i]);rbCase.Disable();rbCases.Add(rbCase);}}
public void Disable(){rigidbody.isKinematic = true;rigidbody.useGravity = false;rigidbody.Sleep();if (collider != null)collider.enabled = false;}
运行的时候,正常情况下,"物理人形骨骼"都被禁用,不会对角色正常控制产生任何的影响。
Step4: 当角色死亡以后,用代码来控制"尸体"的摆放效果。
(1)角色死亡后,我们第一时间先把它的动画状态机给关停掉,让动画不再会控制到我们的人形骨骼,把NavMeshAgent, 角色物理碰撞器都关闭。
if (e.uStatus.status == (int)CharactorStatus.Died) {e.uNav.NavMeshAgent.isStopped = true;e.uNav.NavMeshAgent.enabled = false;e.uAnim.animator.enabled = false;EntityWrapper.ShowDeathFallAnimation(e);e.uAnim.unityObject.GetComponent<Collider>().enabled = false;EntityWrapper.ActivateRagdollOnDeath(e);}
(2) 把"物理人形骨骼"的每个骨骼的物理刚体,物理碰撞器都开启来。
public void Activate(){rigidbody.isKinematic = false;rigidbody.useGravity = true;rigidbody.WakeUp();if (collider != null)collider.enabled = true;}
(3)全部把"物理人形骨骼"开启以后,在脚下给"物理人形骨骼"一个"物理爆炸"的力。力的方向,位置,爆炸半径。使用的物理引擎 API:
publicvoidAddExplosionForce(float explosionForce,Vector3 explosionPosition,float explosionRadius);
| 参数 | 类型 | 说明 |
|---|---|---|
explosionForce | float | 爆炸的基准力量。 这是在爆炸中心或对特定物体施加力的强度参考值。单位是牛顿(N)。 |
explosionPosition | Vector3 | 爆炸中心在世界坐标系中的位置。 所有力的计算都以此点为原点。 |
explosionRadius | float | 爆炸的影响半径。 只有处于此球体范围内的 |
public void ActivateWithForce(Vector3 point, float force, float radius){for (int i = 0; i < rbCases.Count; i++){rbCases[i].Activate();rbCases[i].AddForce(point, force, radius);}}public void AddForce(Vector3 point, float force, float radius){rigidbody.AddExplosionForce(force, point, radius);}
Step5: "物理爆炸"结束2秒后,再禁用"物理人形骨骼",这样角色就会躺在地面上,骨骼摆放为不同的姿势。
protected static void ActivateRagdollOnDeath(CharactorEntity e){EnableRagdoll(e.uAnim.ragdoll, deathExplosionForce, e.uAnim.unityObject.transform.position + e.uAnim.unityObject.transform.forward);e.uAnim.ragdollCase = Tween.DelayedCall(2.0f, () =>{e.uAnim.ragdoll?.Disable();});}
END
,时长02:06
最后,附上"人形物理骨骼"控制的完整代码,可以直接以独立的模块运行到项目中。
public class RagdollBehavior{private List<RigidbodyCase> rbCases;public void Init(Transform ragdollParentTransform){List<Rigidbody> rigidbodies = new List<Rigidbody>();ragdollParentTransform.GetComponentsInChildren(rigidbodies);rbCases = new List<RigidbodyCase>();for (int i = 0; i < rigidbodies.Count; i++){var rigidbody = rigidbodies[i];if (rigidbody.gameObject.layer != 14)continue;var rbCase = new RigidbodyCase(rigidbodies[i]);rbCase.Disable();rbCases.Add(rbCase);}}public void Activate(){for (int i = 0; i < rbCases.Count; i++){rbCases[i].Activate();}}public void ActivateWithForce(Vector3 point, float force, float radius){for (int i = 0; i < rbCases.Count; i++){rbCases[i].Activate();rbCases[i].AddForce(point, force, radius);}}public void Disable(){if (rbCases.IsNullOrEmpty())return;for (int i = 0; i < rbCases.Count; i++){if (rbCases[i] != null && rbCases[i].rigidbody != null)rbCases[i].Disable();}}public void Reset(){if (rbCases.IsNullOrEmpty())return;for (int i = 0; i < rbCases.Count; i++){rbCases[i].Reset();}}private class RigidbodyCase{public Rigidbody rigidbody;public Collider collider;public Vector3 localPosition;public Quaternion localRotation;public Vector3 localScale;public RigidbodyCase(Rigidbody rigidbody){this.rigidbody = rigidbody;collider = rigidbody.GetComponent<Collider>();localPosition = rigidbody.transform.localPosition;localRotation = rigidbody.transform.localRotation;localScale = rigidbody.transform.localScale;}public void Disable(){rigidbody.isKinematic = true;rigidbody.useGravity = false;rigidbody.Sleep();if (collider != null)collider.enabled = false;}public void Activate(){rigidbody.isKinematic = false;rigidbody.useGravity = true;rigidbody.WakeUp();if (collider != null)collider.enabled = true;}public void AddForce(Vector3 point, float force, float radius){rigidbody.AddExplosionForce(force, point, radius);}public void Reset(){rigidbody.transform.localPosition = localPosition;rigidbody.transform.localRotation = localRotation;rigidbody.transform.localScale = localScale;}}}
更多射击类技术点【本课程将学到】:
(1):完整的第三人称射击类的"搜打撤"玩法的策划案,数值与成长体系;
(2):完整的第三人成射击类的”地图编辑器“的工具开发;
(3):学到Unity/Cocos双引擎3D第三人称射击类游戏的开发与设计;
(4):基于全免素材,如何来做商业化设计;
(5):基于Unity发布微信小游戏方案与踩坑;
(6):获得Cocos使用Unity编辑器导出数据来构建更高效的工作流;
最近《搜打撤》类的游戏已经开始上榜微小/抖小的畅玩榜了。搞起来!
248

被折叠的 条评论
为什么被折叠?



