import { _decorator, Collider, Component, Material, Node, PhysicsGroup, PhysicsSystem, RigidBody, SkinnedMeshRenderer, SphereCollider } from 'cc'; import { RagdollBone } from './RagdollBone'; import { RagdollConstraint } from './RagdollConstraint'; import { GameController } from '../scripts/GameController'; import { AudioMgr } from '../scripts/framework/audio/AudioMgr'; import { AssetController } from '../scripts/AssetController'; const { ccclass, property } = _decorator; @ccclass('Ragdoll') export class Ragdoll extends Component { @property(Node) rootNode: Node = null; @property(Node) centerNode: Node = null; @property(SkinnedMeshRenderer) renderer: SkinnedMeshRenderer = null; @property(Material) siwang: Material; // 新的材质 private realBones: Array = []; private simuBones: Array = []; private simuBoneJointArr: Array = []; private world: any; private isEnabled: boolean = false; start() { this.world = PhysicsSystem.instance.physicsWorld.impl; this.initRagdoll() } private initRagdoll() { // 压入真实骨骼 this.getAllRealBones(this.rootNode) // 创建模拟骨骼 this.createSimuBones(); // 创建模拟骨骼的关节 this.createSimuBoneJoints(); } createSimuBones() { for (let boneNode of this.realBones) { let node = new Node node.addComponent(SphereCollider).radius = 0.2 * node.worldScale.x node.addComponent(RigidBody) this.node.addChild(node) this.simuBones.push(node) this.syncPositionAndRotation(node, boneNode) // 同步之后将位置赋给初始位置 let ragdollBone = boneNode.getComponent(RagdollBone) ragdollBone.simuNode = node ragdollBone.initPos = boneNode.getPosition(); ragdollBone.initRot = boneNode.getRotation(); } this.scheduleOnce(() => { for (let bone of this.simuBones) { let body = bone.getComponent(RigidBody) body.sleep() } }, 0) } createSimuBoneJoints() { for (let boneNode of this.realBones) { const joint = boneNode.getComponent(RagdollConstraint) if (joint) { const simuNodeA = boneNode.getComponent(RagdollBone).simuNode const simuNodeB = joint.connectedBone.getComponent(RagdollBone).simuNode const bodyA = simuNodeA.getComponent(RigidBody).body.impl const bodyB = simuNodeB.getComponent(RigidBody).body.impl let spineJoint = new CANNON.ConeTwistConstraint(bodyA, bodyB, { pivotA: new CANNON.Vec3(joint.pivotA.x, joint.pivotA.y, joint.pivotA.z), pivotB: new CANNON.Vec3(joint.pivotB.x, joint.pivotB.y, joint.pivotB.z), axisA: new CANNON.Vec3(joint.axisA.x, joint.axisA.y, joint.axisA.z), axisB: new CANNON.Vec3(joint.axisB.x, joint.axisB.y, joint.axisB.z), angle: joint.angle, twistAngle: joint.twistAngle }) this.world.addConstraint(spineJoint) this.simuBoneJointArr.push(spineJoint) } } } getAllRealBones(node: Node) { let bones = node.children; for (let boneNode of bones) { const bone = boneNode.getComponent(RagdollBone) if (bone) { this.realBones.push(boneNode) bone.ragdoll = this } this.getAllRealBones(boneNode) } } lateUpdate(deltaTime: number) { if (this.isEnabled) { this.updateBones() } } syncPositionAndRotation(nodeA: Node, nodeB: Node) { nodeA.setWorldPosition(nodeB.worldPosition) nodeA.setWorldRotation(nodeB.worldRotation) } // 将模拟骨骼的位置和转角同步到真实骨骼 private updateBones() { for (let i = 0; i < this.realBones.length; i++) { this.syncPositionAndRotation(this.realBones[i], this.simuBones[i]) } } getEnabled() { return this.isEnabled; } setEnabled(isEnabled: boolean) { if (isEnabled && this.isDie) return isEnabled ? this.enableRagdoll() : this.disableRagdoll(); AudioMgr.inst.playOneShot(AssetController.instance.die) } isDie: boolean = false enableRagdoll() { this.isDie = true GameController.getInstance().curLevel.onEnemyDie(this) // this.renderer.setMaterialInstance(this.siwang, 0) this.renderer.material = this.siwang // 将模拟骨骼的位置和真实骨骼同步 for (let bone of this.realBones) { let ragdollBone = bone.getComponent(RagdollBone) this.syncPositionAndRotation(ragdollBone.simuNode, bone) let collider = ragdollBone.getComponent(Collider) if (collider) collider.enabled = false } for (let bone of this.simuBones) { let body = bone.getComponent(RigidBody) body.wakeUp(); } // 将关节添加至物理世界 for (let joint of this.simuBoneJointArr) { this.world.addConstraint(joint); } this.isEnabled = true; } disableRagdoll() { // 将真实骨骼移动至初始位置 for (let bone of this.realBones) { let ragdollBone = bone.getComponent(RagdollBone); bone.setPosition(ragdollBone.initPos); bone.setRotation(ragdollBone.initRot); } for (let bone of this.simuBones) { let body = bone.getComponent(RigidBody) body.sleep(); } // 从物理世界中移除关节 for (let joint of this.simuBoneJointArr) { this.world.removeConstraint(joint); } this.isEnabled = false; } }