diff --git a/tests/physics/character-controller.ts b/tests/physics/character-controller.ts new file mode 100644 index 00000000000..d419a677539 --- /dev/null +++ b/tests/physics/character-controller.ts @@ -0,0 +1,95 @@ +import { Quat, Vec3 } from "../../cocos/core"; +import { director } from "../../cocos/game"; +import { Node } from "../../cocos/scene-graph"; +import { ICollisionEvent, physics } from "../../exports/physics-framework"; +import { PhysicsTestEnv } from "./physics.test"; + +/** + * This function is used to test the api of the CharacterController + */ +function testCharacterControllerAPIs(cct: physics.CharacterController){ + cct.minMoveDistance = 0.001; + expect(cct.minMoveDistance === 0.001).toBe(true); + + cct.stepOffset = 0.5; + expect(cct.stepOffset === 0.5).toBe(true); + + cct.slopeLimit = 60; + expect(cct.slopeLimit === 60).toBe(true); + + cct.skinWidth = 0.01; + expect(cct.skinWidth === 0.01).toBe(true); + + cct.center = new Vec3(0, 0.5, 0); + expect(Vec3.equals(cct.center, new Vec3(0, 0.5, 0))).toBe(true); + + let targetPos = new Vec3(0, 10, 0); + cct.centerWorldPosition = targetPos; + let newPos = new Vec3(); + newPos.set(cct.centerWorldPosition); + expect(Vec3.equals(newPos, targetPos)).toBe(true); + + { + cct.move(new Vec3(0, 0, 0)); + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + director.tick(dt); + let newPos = new Vec3(); + newPos.set(cct.centerWorldPosition); + expect(Vec3.equals(newPos, targetPos)).toBe(true); + } + { + let movement = new Vec3(0, 10, 0); + Vec3.add(targetPos, targetPos, movement); + cct.move(movement); + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + director.tick(dt); + let newPos = new Vec3(); + newPos.set(cct.centerWorldPosition); + expect(Vec3.equals(newPos, targetPos)).toBe(true); + } +} + +export default function (env: PhysicsTestEnv, _steps = 0) { + //skip builtin and cannon.js for now + if (env.backendId === 'builtin' || env.backendId === 'cannon.js') + return; + + describe(`Character controller`, () => { + test(`Box character controller`, () => { + const { rootNode: parent } = env; + + const nodeBoxCCT = new Node('BoxCharacterController'); + parent.addChild(nodeBoxCCT); + const boxCCT = nodeBoxCCT.addComponent(physics.BoxCharacterController) as physics.BoxCharacterController; + expect(boxCCT.type).toBe(physics.ECharacterControllerType.BOX); + + boxCCT.halfForwardExtent = 0.5; + expect(boxCCT.halfForwardExtent === 0.5).toBe(true); + + boxCCT.halfSideExtent = 0.5; + expect(boxCCT.halfSideExtent === 0.5).toBe(true); + + boxCCT.halfHeight = 0.5; + expect(boxCCT.halfHeight === 0.5).toBe(true); + + testCharacterControllerAPIs(boxCCT as physics.CharacterController); + }); + + test(`Capsule character, controller`, () => { + const { rootNode: parent } = env; + + const nodeCapsuleCCT = new Node('CapsuleCharacterController'); + parent.addChild(nodeCapsuleCCT); + const capsuleCCT = nodeCapsuleCCT.addComponent(physics.CapsuleCharacterController) as physics.CapsuleCharacterController; + expect(capsuleCCT.type).toBe(physics.ECharacterControllerType.CAPSULE); + + capsuleCCT.radius = 0.5; + expect(capsuleCCT.radius === 0.5).toBe(true); + + capsuleCCT.height = 1; + expect(capsuleCCT.height === 1).toBe(true); + + testCharacterControllerAPIs(capsuleCCT as physics.CharacterController); + }); + }); +} \ No newline at end of file diff --git a/tests/physics/characterController.ts b/tests/physics/characterController.ts deleted file mode 100644 index d863f5f061a..00000000000 --- a/tests/physics/characterController.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { Quat, Vec3 } from "../../cocos/core"; -import { director } from "../../cocos/game"; -import { Node } from "../../cocos/scene-graph"; -import { ICollisionEvent, physics } from "../../exports/physics-framework"; - -/** - * This function is used to test the api of the CharacterController - */ -function testCharacterControllerAPIs(cct: physics.CharacterController){ - cct.minMoveDistance = 0.001; - expect(cct.minMoveDistance === 0.001).toBe(true); - - cct.stepOffset = 0.5; - expect(cct.stepOffset === 0.5).toBe(true); - - cct.slopeLimit = 60; - expect(cct.slopeLimit === 60).toBe(true); - - cct.skinWidth = 0.01; - expect(cct.skinWidth === 0.01).toBe(true); - - cct.center = new Vec3(0, 0.5, 0); - expect(Vec3.equals(cct.center, new Vec3(0, 0.5, 0))).toBe(true); - - let targetPos = new Vec3(0, 10, 0); - cct.centerWorldPosition = targetPos; - let newPos = new Vec3(); - newPos.set(cct.centerWorldPosition); - expect(Vec3.equals(newPos, targetPos)).toBe(true); - - { - cct.move(new Vec3(0, 0, 0)); - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - director.tick(dt); - let newPos = new Vec3(); - newPos.set(cct.centerWorldPosition); - expect(Vec3.equals(newPos, targetPos)).toBe(true); - } - { - let movement = new Vec3(0, 10, 0); - Vec3.add(targetPos, targetPos, movement); - cct.move(movement); - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - director.tick(dt); - let newPos = new Vec3(); - newPos.set(cct.centerWorldPosition); - expect(Vec3.equals(newPos, targetPos)).toBe(true); - } -} - -export default function (parent: Node, _steps = 0) { - //skip builtin and cannon.js for now - if (physics.selector.id === 'builtin' || physics.selector.id === 'cannon.js') - return; - - //box character controller - { - const nodeBoxCCT = new Node('BoxCharacterController'); - parent.addChild(nodeBoxCCT); - const boxCCT = nodeBoxCCT.addComponent(physics.BoxCharacterController) as physics.BoxCharacterController; - expect(boxCCT.type).toBe(physics.ECharacterControllerType.BOX); - - boxCCT.halfForwardExtent = 0.5; - expect(boxCCT.halfForwardExtent === 0.5).toBe(true); - - boxCCT.halfSideExtent = 0.5; - expect(boxCCT.halfSideExtent === 0.5).toBe(true); - - boxCCT.halfHeight = 0.5; - expect(boxCCT.halfHeight === 0.5).toBe(true); - - testCharacterControllerAPIs(boxCCT as physics.CharacterController); - - parent.destroyAllChildren(); - parent.removeAllChildren(); - } - - //capsule character controller - { - const nodeCapsuleCCT = new Node('CapsuleCharacterController'); - parent.addChild(nodeCapsuleCCT); - const capsuleCCT = nodeCapsuleCCT.addComponent(physics.CapsuleCharacterController) as physics.CapsuleCharacterController; - expect(capsuleCCT.type).toBe(physics.ECharacterControllerType.CAPSULE); - - capsuleCCT.radius = 0.5; - expect(capsuleCCT.radius === 0.5).toBe(true); - - capsuleCCT.height = 1; - expect(capsuleCCT.height === 1).toBe(true); - - testCharacterControllerAPIs(capsuleCCT as physics.CharacterController); - - parent.destroyAllChildren(); - parent.removeAllChildren(); - } - -} \ No newline at end of file diff --git a/tests/physics/constraint.ts b/tests/physics/constraint.ts index aa48f018e64..091afd304b6 100644 --- a/tests/physics/constraint.ts +++ b/tests/physics/constraint.ts @@ -2,12 +2,9 @@ import { Quat, Vec3 } from "../../cocos/core"; import { director } from "../../cocos/game"; import { Node } from "../../cocos/scene-graph"; import { ICollisionEvent, physics } from "../../exports/physics-framework"; +import { PhysicsTestEnv } from "./physics.test"; function testConfigurableConstraintAPIs(child: Node) { - if (physics.selector.id === 'builtin' || physics.selector.id === 'cannon.js') { - return; - } - const cs = child.addComponent(physics.ConfigurableConstraint) as physics.ConfigurableConstraint; { @@ -126,6 +123,12 @@ function testConfigurableConstraintAPIs(child: Node) { child.removeComponent(cs); } -export default function (temp0: Node) { - testConfigurableConstraintAPIs(temp0); +export default function (env: PhysicsTestEnv) { + if (env.backendId === 'builtin' || env.backendId === 'cannon.js') { + return; + } + + test(`Configurable constraint`, () => { + testConfigurableConstraintAPIs(env.rootNode); + }); } \ No newline at end of file diff --git a/tests/physics/dynamic.ts b/tests/physics/dynamic.ts index 5fd70bc336c..1899b101c19 100644 --- a/tests/physics/dynamic.ts +++ b/tests/physics/dynamic.ts @@ -2,139 +2,137 @@ import { Quat, Vec3 } from "../../cocos/core"; import { director } from "../../cocos/game"; import { Node } from "../../cocos/scene-graph"; import { ICollisionEvent, physics } from "../../exports/physics-framework"; +import { PhysicsTestEnv } from "./physics.test"; /** * This function is used to test the api of the RigidBody */ -export default function (parent: Node, _steps = 0) { - // basic api - { - const nodeDynamic = new Node('Dynamic'); - parent.addChild(nodeDynamic); - const initPos = new Vec3(0, 10, 0); - nodeDynamic.worldPosition = initPos; - const body = nodeDynamic.addComponent(physics.RigidBody) as physics.RigidBody; - body.type = physics.RigidBody.Type.STATIC; - expect(body.isStatic).toBe(true); - body.type = physics.RigidBody.Type.KINEMATIC; - expect(body.isKinematic).toBe(true); - body.type = physics.RigidBody.Type.DYNAMIC; - expect(body.isDynamic).toBe(true); - const massA = 2; - body.mass = massA; - expect(body.mass).toBe(massA); - - const v3_0 = Vec3.negate(new Vec3(), physics.PhysicsSystem.instance.gravity); - v3_0.multiplyScalar(massA); - body.applyForce(v3_0); - - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - director.tick(dt); - - expect(Vec3.equals(nodeDynamic.worldPosition, initPos)).toBe(true); - - v3_0.set(1, 2, 3); const v3_1 = new Vec3(); - body.setLinearVelocity(v3_0); - body.getLinearVelocity(v3_1); - expect(Vec3.equals(v3_0, v3_1)).toBe(true); - - v3_0.set(3, 2, 1); v3_1.set(0, 0, 0); - body.setAngularVelocity(v3_0); - body.getAngularVelocity(v3_1); - expect(Vec3.equals(v3_0, v3_1)).toBe(true); - - body.linearDamping = 0.001; - expect(body.linearDamping === 0.001).toBe(true); - - body.angularDamping = 0.001; - expect(body.angularDamping === 0.001).toBe(true); - - body.clearForces(); - body.clearVelocity(); - body.clearState(); - body.getLinearVelocity(v3_0); - body.getAngularVelocity(v3_1); - expect(Vec3.equals(v3_0, Vec3.ZERO)).toBe(true); - expect(Vec3.equals(v3_1, Vec3.ZERO)).toBe(true); - parent.destroyAllChildren(); - parent.removeAllChildren(); - } - - // local inertia - { - const nodeDynamic = new Node('Dynamic'); - parent.addChild(nodeDynamic); - const body = nodeDynamic.addComponent(physics.RigidBody) as physics.RigidBody; - body.type = physics.RigidBody.Type.DYNAMIC; - const v3_0 = new Vec3(1, 1, 1); - body.setAngularVelocity(v3_0); - expect(Quat.equals(nodeDynamic.worldRotation, Quat.IDENTITY)).toBe(true); - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - director.tick(dt); - expect(!Quat.equals(nodeDynamic.worldRotation, Quat.IDENTITY)).toBe(true); - parent.destroyAllChildren(); - parent.removeAllChildren(); - } - - // use gravity - { - const nodeDynamic = new Node('Dynamic'); - parent.addChild(nodeDynamic); - const body = nodeDynamic.addComponent(physics.RigidBody) as physics.RigidBody; - body.useGravity = false; - body.type = physics.RigidBody.Type.DYNAMIC; - expect(Vec3.equals(nodeDynamic.worldPosition, Vec3.ZERO)).toBe(true); - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - for (let i = 0; i < 200; i++)director.tick(dt); - expect(Vec3.equals(nodeDynamic.worldPosition, Vec3.ZERO)).toBe(true); - expect(body.isSleeping).toBe(true); - parent.destroyAllChildren(); - parent.removeAllChildren(); - } - - // use ccd - { - const nodeDynamic = new Node('Dynamic'); - parent.addChild(nodeDynamic); - const sphere = nodeDynamic.addComponent(physics.SphereCollider) as physics.SphereCollider; - const body = nodeDynamic.addComponent(physics.RigidBody) as physics.RigidBody; - body.useCCD = true; - body.useGravity = false; - body.setLinearVelocity(new Vec3(500, 0, 0)); - let isDispatched = false; - sphere.on('onCollisionEnter', (event: ICollisionEvent) => { - isDispatched = true; - expect(event.selfCollider.uuid).toBe(sphere.uuid); - expect(event.otherCollider.uuid).toBe(box.uuid); - }) - - const nodeStatic = new Node('Static'); - parent.addChild(nodeStatic); - const box = nodeStatic.addComponent(physics.BoxCollider) as physics.BoxCollider; - nodeStatic.worldPosition = new Vec3(10, 0, 0); - nodeStatic.worldRotation = Quat.fromEuler(new Quat(), 10, 20, 30); - - // PhysX/Cannon/Bullet Not enough support currently - // const nodeTrigger = new Node('Static'); - // parent.addChild(nodeTrigger); - // const sphereTrigger = nodeTrigger.addComponent(physics.SphereCollider) as physics.SphereCollider; - // sphereTrigger.isTrigger = true; - // nodeTrigger.worldPosition = new Vec3(5, 0, 0); - // nodeTrigger.worldRotation = Quat.fromEuler(new Quat(), -10, 50, 30); - // let isTriggered = false; - // sphereTrigger.on('onTriggerEnter', (event: ITriggerEvent) => { - // isTriggered = true; - // expect(event.selfCollider.uuid).toBe(sphereTrigger.uuid); - // expect(event.otherCollider.uuid).toBe(sphere.uuid); - // }) - - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - for (let i = 0; i < 100; i++)director.tick(dt); - - expect(isDispatched).toBe(true); - // expect(isTriggered).toBe(true); - - parent.destroyAllChildren(); - parent.removeAllChildren(); - } +export default function (env: PhysicsTestEnv) { + describe(`Rigid body`, () => { + test(`Basic api`, () => { + const { rootNode: parent } = env; + + const nodeDynamic = new Node('Dynamic'); + parent.addChild(nodeDynamic); + const initPos = new Vec3(0, 10, 0); + nodeDynamic.worldPosition = initPos; + const body = nodeDynamic.addComponent(physics.RigidBody) as physics.RigidBody; + body.type = physics.RigidBody.Type.STATIC; + expect(body.isStatic).toBe(true); + body.type = physics.RigidBody.Type.KINEMATIC; + expect(body.isKinematic).toBe(true); + body.type = physics.RigidBody.Type.DYNAMIC; + expect(body.isDynamic).toBe(true); + const massA = 2; + body.mass = massA; + expect(body.mass).toBe(massA); + + const v3_0 = Vec3.negate(new Vec3(), physics.PhysicsSystem.instance.gravity); + v3_0.multiplyScalar(massA); + body.applyForce(v3_0); + + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + director.tick(dt); + + expect(Vec3.equals(nodeDynamic.worldPosition, initPos)).toBe(true); + + v3_0.set(1, 2, 3); const v3_1 = new Vec3(); + body.setLinearVelocity(v3_0); + body.getLinearVelocity(v3_1); + expect(Vec3.equals(v3_0, v3_1)).toBe(true); + + v3_0.set(3, 2, 1); v3_1.set(0, 0, 0); + body.setAngularVelocity(v3_0); + body.getAngularVelocity(v3_1); + expect(Vec3.equals(v3_0, v3_1)).toBe(true); + + body.linearDamping = 0.001; + expect(body.linearDamping === 0.001).toBe(true); + + body.angularDamping = 0.001; + expect(body.angularDamping === 0.001).toBe(true); + + body.clearForces(); + body.clearVelocity(); + body.clearState(); + body.getLinearVelocity(v3_0); + body.getAngularVelocity(v3_1); + expect(Vec3.equals(v3_0, Vec3.ZERO)).toBe(true); + expect(Vec3.equals(v3_1, Vec3.ZERO)).toBe(true); + }); + + test(`Local inertia`, () => { + const { rootNode: parent } = env; + + const nodeDynamic = new Node('Dynamic'); + parent.addChild(nodeDynamic); + const body = nodeDynamic.addComponent(physics.RigidBody) as physics.RigidBody; + body.type = physics.RigidBody.Type.DYNAMIC; + const v3_0 = new Vec3(1, 1, 1); + body.setAngularVelocity(v3_0); + expect(Quat.equals(nodeDynamic.worldRotation, Quat.IDENTITY)).toBe(true); + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + director.tick(dt); + expect(!Quat.equals(nodeDynamic.worldRotation, Quat.IDENTITY)).toBe(true); + }); + + test (`Use gravity`, () => { + const { rootNode: parent } = env; + + const nodeDynamic = new Node('Dynamic'); + parent.addChild(nodeDynamic); + const body = nodeDynamic.addComponent(physics.RigidBody) as physics.RigidBody; + body.useGravity = false; + body.type = physics.RigidBody.Type.DYNAMIC; + expect(Vec3.equals(nodeDynamic.worldPosition, Vec3.ZERO)).toBe(true); + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + for (let i = 0; i < 200; i++)director.tick(dt); + expect(Vec3.equals(nodeDynamic.worldPosition, Vec3.ZERO)).toBe(true); + expect(body.isSleeping).toBe(true); + }); + + test(`CCD`, () => { + const { rootNode: parent } = env; + + const nodeDynamic = new Node('Dynamic'); + parent.addChild(nodeDynamic); + const sphere = nodeDynamic.addComponent(physics.SphereCollider) as physics.SphereCollider; + const body = nodeDynamic.addComponent(physics.RigidBody) as physics.RigidBody; + body.useCCD = true; + body.useGravity = false; + body.setLinearVelocity(new Vec3(500, 0, 0)); + let isDispatched = false; + sphere.on('onCollisionEnter', (event: ICollisionEvent) => { + isDispatched = true; + expect(event.selfCollider.uuid).toBe(sphere.uuid); + expect(event.otherCollider.uuid).toBe(box.uuid); + }) + + const nodeStatic = new Node('Static'); + parent.addChild(nodeStatic); + const box = nodeStatic.addComponent(physics.BoxCollider) as physics.BoxCollider; + nodeStatic.worldPosition = new Vec3(10, 0, 0); + nodeStatic.worldRotation = Quat.fromEuler(new Quat(), 10, 20, 30); + + // PhysX/Cannon/Bullet Not enough support currently + // const nodeTrigger = new Node('Static'); + // parent.addChild(nodeTrigger); + // const sphereTrigger = nodeTrigger.addComponent(physics.SphereCollider) as physics.SphereCollider; + // sphereTrigger.isTrigger = true; + // nodeTrigger.worldPosition = new Vec3(5, 0, 0); + // nodeTrigger.worldRotation = Quat.fromEuler(new Quat(), -10, 50, 30); + // let isTriggered = false; + // sphereTrigger.on('onTriggerEnter', (event: ITriggerEvent) => { + // isTriggered = true; + // expect(event.selfCollider.uuid).toBe(sphereTrigger.uuid); + // expect(event.otherCollider.uuid).toBe(sphere.uuid); + // }) + + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + for (let i = 0; i < 100; i++)director.tick(dt); + + expect(isDispatched).toBe(true); + // expect(isTriggered).toBe(true); + }); + }); } \ No newline at end of file diff --git a/tests/physics/event.ts b/tests/physics/event.ts index 6cb143a6ce9..9f9317bf407 100644 --- a/tests/physics/event.ts +++ b/tests/physics/event.ts @@ -2,52 +2,55 @@ import { Vec3 } from "../../cocos/core"; import { director } from "../../cocos/game"; import { Node } from "../../cocos/scene-graph"; import { physics } from "../../exports/physics-framework"; +import { PhysicsTestEnv } from "./physics.test"; /** * This function is used to test some event callback */ -export default function (parent: Node, steps = 300) { - const nodeDynamic = new Node('DynamicA'); - parent.addChild(nodeDynamic); - nodeDynamic.worldPosition = new Vec3(0, 4, 0); - nodeDynamic.addComponent(physics.RigidBody); - const colliderDynamic: physics.SphereCollider = nodeDynamic.addComponent(physics.SphereCollider); - const colliderTrigger: physics.BoxCollider = nodeDynamic.addComponent(physics.BoxCollider); - colliderTrigger.isTrigger = true; - - const nodeStatic = new Node('StaticB'); - parent.addChild(nodeStatic); - nodeStatic.addComponent(physics.BoxCollider); - - function onCollision(event: physics.ICollisionEvent) { - expect(event.selfCollider).toBe(colliderDynamic); - } - - function onTrigger(event: physics.ITriggerEvent) { - expect(event.selfCollider).toBe(colliderTrigger); - } - - // collision event - expect(colliderDynamic.needCollisionEvent).toBe(false); - colliderDynamic.on('onCollisionEnter', onCollision); - - expect(colliderDynamic.needCollisionEvent).toBe(true); - - // trigger event - expect(colliderTrigger.needTriggerEvent).toBe(false); - colliderTrigger.on('onTriggerEnter', onTrigger); - expect(colliderTrigger.needTriggerEvent).toBe(true); - - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - for (let i = 0; i < steps; i++) { - director.tick(dt); - } - - colliderDynamic.off('onCollisionEnter', onCollision); - expect(colliderDynamic.needCollisionEvent).toBe(false); - colliderTrigger.off('onTriggerEnter', onTrigger); - expect(colliderTrigger.needTriggerEvent).toBe(false); - - parent.destroyAllChildren(); - parent.removeAllChildren(); +export default function (env: PhysicsTestEnv) { + test(`Event`, () => { + const { rootNode: parent } = env; + const steps = 300; + + const nodeDynamic = new Node('DynamicA'); + parent.addChild(nodeDynamic); + nodeDynamic.worldPosition = new Vec3(0, 4, 0); + nodeDynamic.addComponent(physics.RigidBody); + const colliderDynamic: physics.SphereCollider = nodeDynamic.addComponent(physics.SphereCollider); + const colliderTrigger: physics.BoxCollider = nodeDynamic.addComponent(physics.BoxCollider); + colliderTrigger.isTrigger = true; + + const nodeStatic = new Node('StaticB'); + parent.addChild(nodeStatic); + nodeStatic.addComponent(physics.BoxCollider); + + function onCollision(event: physics.ICollisionEvent) { + expect(event.selfCollider).toBe(colliderDynamic); + } + + function onTrigger(event: physics.ITriggerEvent) { + expect(event.selfCollider).toBe(colliderTrigger); + } + + // collision event + expect(colliderDynamic.needCollisionEvent).toBe(false); + colliderDynamic.on('onCollisionEnter', onCollision); + + expect(colliderDynamic.needCollisionEvent).toBe(true); + + // trigger event + expect(colliderTrigger.needTriggerEvent).toBe(false); + colliderTrigger.on('onTriggerEnter', onTrigger); + expect(colliderTrigger.needTriggerEvent).toBe(true); + + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + for (let i = 0; i < steps; i++) { + director.tick(dt); + } + + colliderDynamic.off('onCollisionEnter', onCollision); + expect(colliderDynamic.needCollisionEvent).toBe(false); + colliderTrigger.off('onTriggerEnter', onTrigger); + expect(colliderTrigger.needTriggerEvent).toBe(false); + }); } diff --git a/tests/physics/filtering.ts b/tests/physics/filtering.ts index 20ece4dc176..528c83581b4 100644 --- a/tests/physics/filtering.ts +++ b/tests/physics/filtering.ts @@ -1,90 +1,91 @@ import { Vec3 } from "../../cocos/core"; import { Node } from "../../cocos/scene-graph"; import { physics } from "../../exports/physics-framework"; +import { PhysicsTestEnv } from "./physics.test"; /** * This function is used to test the filtering */ -export default function (parent: Node, _steps = 0) { +export default function (env: PhysicsTestEnv) { + test(`Filtering`, () => { + const { rootNode: parent } = env; - // group mask - { - const nodeStatic = new Node('StaticB'); - parent.addChild(nodeStatic); - nodeStatic.worldScale = new Vec3(20, 0.01, 20); - nodeStatic.worldPosition = new Vec3(0, -0.005, 0); - const boxStatic = nodeStatic.addComponent(physics.BoxCollider) as physics.BoxCollider; - const bodyStatic = nodeStatic.addComponent(physics.RigidBody) as physics.RigidBody; - bodyStatic.type = physics.ERigidBodyType.STATIC; + // group mask + { + const nodeStatic = new Node('StaticB'); + parent.addChild(nodeStatic); + nodeStatic.worldScale = new Vec3(20, 0.01, 20); + nodeStatic.worldPosition = new Vec3(0, -0.005, 0); + const boxStatic = nodeStatic.addComponent(physics.BoxCollider) as physics.BoxCollider; + const bodyStatic = nodeStatic.addComponent(physics.RigidBody) as physics.RigidBody; + bodyStatic.type = physics.ERigidBodyType.STATIC; - const gA = 1 << 2; - const gB = 1 << 5; - bodyStatic.setGroup(gA); - expect(boxStatic.getGroup()).toBe(gA); - bodyStatic.addGroup(gB); - expect(boxStatic.getGroup()).toBe(gA + gB); - bodyStatic.removeGroup(gA); - expect(boxStatic.getGroup()).toBe(gB); + const gA = 1 << 2; + const gB = 1 << 5; + bodyStatic.setGroup(gA); + expect(boxStatic.getGroup()).toBe(gA); + bodyStatic.addGroup(gB); + expect(boxStatic.getGroup()).toBe(gA + gB); + bodyStatic.removeGroup(gA); + expect(boxStatic.getGroup()).toBe(gB); - bodyStatic.setMask(gA); - expect(boxStatic.getMask()).toBe(gA); - bodyStatic.addMask(gB); - expect(boxStatic.getMask()).toBe(gA + gB); - bodyStatic.removeMask(gA); - expect(boxStatic.getMask()).toBe(gB); - nodeStatic.destroy(); - nodeStatic.removeFromParent(); - } + bodyStatic.setMask(gA); + expect(boxStatic.getMask()).toBe(gA); + bodyStatic.addMask(gB); + expect(boxStatic.getMask()).toBe(gA + gB); + bodyStatic.removeMask(gA); + expect(boxStatic.getMask()).toBe(gB); + nodeStatic.destroy(); + nodeStatic.removeFromParent(); + } - // collision matrix - { - const config = { - collisionGroups: [ - { - "index": 1, - "name": "BIT_1" - }, - { - "index": 2, - "name": "BIT_2" + // collision matrix + { + const config = { + collisionGroups: [ + { + "index": 1, + "name": "BIT_1" + }, + { + "index": 2, + "name": "BIT_2" + } + ], + collisionMatrix: { + "0": 5, // can collide with Default\BIT_2 + "1": 6, // can collide with BIT_1\BIT_2 + "2": 7 // can collide with Default\BIT_1\BIT_2 } - ], - collisionMatrix: { - "0": 5, // can collide with Default\BIT_2 - "1": 6, // can collide with BIT_1\BIT_2 - "2": 7 // can collide with Default\BIT_1\BIT_2 - } - }; - physics.PhysicsSystem.instance.resetConfiguration(config); + }; + physics.PhysicsSystem.instance.resetConfiguration(config); - const node1 = new Node('1'); - const boxNode1 = node1.addComponent(physics.BoxCollider) as physics.BoxCollider; - const bodyNode1 = node1.addComponent(physics.RigidBody) as physics.RigidBody; - bodyNode1.group = physics.PhysicsGroup['BIT_1']; - parent.addChild(node1); - expect(boxNode1.getGroup()).toBe(physics.PhysicsGroup['BIT_1']); - expect(boxNode1.getGroup()).toBe(bodyNode1.getGroup()); - expect(boxNode1.getMask()).toBe(bodyNode1.getMask()); - expect(bodyNode1.getMask()).toBe( - physics.PhysicsSystem.instance.collisionMatrix[physics.PhysicsGroup['BIT_1']] - ); - node1.destroy(); - node1.removeFromParent(); + const node1 = new Node('1'); + const boxNode1 = node1.addComponent(physics.BoxCollider) as physics.BoxCollider; + const bodyNode1 = node1.addComponent(physics.RigidBody) as physics.RigidBody; + bodyNode1.group = physics.PhysicsGroup['BIT_1']; + parent.addChild(node1); + expect(boxNode1.getGroup()).toBe(physics.PhysicsGroup['BIT_1']); + expect(boxNode1.getGroup()).toBe(bodyNode1.getGroup()); + expect(boxNode1.getMask()).toBe(bodyNode1.getMask()); + expect(bodyNode1.getMask()).toBe( + physics.PhysicsSystem.instance.collisionMatrix[physics.PhysicsGroup['BIT_1']] + ); + node1.destroy(); + node1.removeFromParent(); - const node2 = new Node('2'); - parent.addChild(node2); - const boxNode2 = node2.addComponent(physics.BoxCollider) as physics.BoxCollider; - const bodyNode2 = node2.addComponent(physics.RigidBody) as physics.RigidBody; - expect(boxNode2.getGroup()).toBe(physics.PhysicsGroup.DEFAULT); - expect(boxNode2.getGroup()).toBe(bodyNode2.getGroup()); - expect(boxNode2.getMask()).toBe(bodyNode2.getMask()); - expect(bodyNode2.getMask()).toBe( - physics.PhysicsSystem.instance.collisionMatrix[physics.PhysicsGroup.DEFAULT] - ); - node2.destroy(); - node2.removeFromParent(); - - parent.destroyAllChildren(); - parent.removeAllChildren(); - } + const node2 = new Node('2'); + parent.addChild(node2); + const boxNode2 = node2.addComponent(physics.BoxCollider) as physics.BoxCollider; + const bodyNode2 = node2.addComponent(physics.RigidBody) as physics.RigidBody; + expect(boxNode2.getGroup()).toBe(physics.PhysicsGroup.DEFAULT); + expect(boxNode2.getGroup()).toBe(bodyNode2.getGroup()); + expect(boxNode2.getMask()).toBe(bodyNode2.getMask()); + expect(bodyNode2.getMask()).toBe( + physics.PhysicsSystem.instance.collisionMatrix[physics.PhysicsGroup.DEFAULT] + ); + node2.destroy(); + node2.removeFromParent(); + } + }); } \ No newline at end of file diff --git a/tests/physics/physics.test.ts b/tests/physics/physics.test.ts index 6c64dde998d..22aef25172f 100644 --- a/tests/physics/physics.test.ts +++ b/tests/physics/physics.test.ts @@ -4,11 +4,9 @@ import { physics, PhysicsMaterial, PhysicsSystem } from "../../exports/physics-f import "../../exports/physics-physx"; import "../../exports/physics-builtin"; import waitForAmmoInstantiation from "../../exports/wait-for-ammo-instantiation"; -waitForAmmoInstantiation(null); import "../../exports/physics-ammo"; import "../../exports/physics-cannon"; import { InitPhysXLibs } from '../../cocos/physics/physx/physx-adapter'; -InitPhysXLibs(); import EventTest from "./event"; import RaycastTest from "./raycast"; import SweepTest from "./sweep"; @@ -18,10 +16,13 @@ import VolumeTest from "./volume"; import FilterTest from "./filtering"; import DynamicTest from "./dynamic"; import ConstraintTest from "./constraint"; -import CharacterController from "./characterController"; +import CharacterControllerTest from "./character-controller"; import { Node, Scene } from "../../cocos/scene-graph"; import { builtinResMgr } from "../../exports/base"; +waitForAmmoInstantiation(); +InitPhysXLibs(); + game.emit(Game.EVENT_PRE_SUBSYSTEM_INIT); // Manually construct and register the system PhysicsSystem.constructAndRegister(); @@ -35,62 +36,64 @@ test(`physics test | selector`, done => { done(); }); -for (const id in physics.selector.backend) { - test(`physics test | ${id}`, done => { - // test selector +export interface PhysicsTestEnv { + rootNode: Node; + backendId: 'builtin' | 'physx' | 'bullet' | 'cannon.js'; +} + +describe.each(Object.keys(physics.selector.backend))( + `Backend: %s`, (id) => { + + let scene!: Scene; + let temp0!: Node; + const env: PhysicsTestEnv = { + backendId: id as PhysicsTestEnv['backendId'], + get rootNode() { + return temp0; + }, + }; + + beforeAll(() => { physics.selector.switchTo(id); expect(physics.selector.id).toBe(id); - - const scene = new Scene('test'); + + scene = new Scene('test'); director.runSceneImmediate(scene); - - const temp0 = new Node(); + + temp0 = new Node(); scene.addChild(temp0); + }); + + afterAll(() => { + scene.destroy(); + }); - // test events - EventTest(temp0); + afterEach(() => { + temp0.destroyAllChildren(); + temp0.removeAllChildren(); + }); - // test raycast - RaycastTest(temp0); + EventTest(env); - // test sweep - SweepTest(temp0); + RaycastTest(env); - if (physics.PhysicsSystem.PHYSICS_BUILTIN) { - temp0.destroy(); - scene.destroy(); - return done(); - } + SweepTest(env); - // test auto sleep state - SleepTest(temp0); + if (id === 'builtin') { + return; + } - // test stable - [1, 0.5].forEach((v) => { StableTest(temp0, 500, v); }); + SleepTest(env); - if (physics.PhysicsSystem.PHYSICS_PHYSX) { - // test small scale in physx - [0.25, 0.15].forEach((v) => { StableTest(temp0, 500, v); }); - } + StableTest(env); - // test volume - VolumeTest(temp0); + VolumeTest(env); - // test filter - FilterTest(temp0); + FilterTest(env); - // test rigid body - DynamicTest(temp0); + DynamicTest(env); - // test constraint - ConstraintTest(temp0); + ConstraintTest(env); - // test character controller - CharacterController(temp0); - - temp0.destroy(); - scene.destroy(); - // all works done - done(); - }); -} \ No newline at end of file + CharacterControllerTest(env); +}); diff --git a/tests/physics/raycast.ts b/tests/physics/raycast.ts index f289061e0cc..bc45a990ba2 100644 --- a/tests/physics/raycast.ts +++ b/tests/physics/raycast.ts @@ -2,87 +2,88 @@ import { geometry, Quat, Vec3 } from "../../cocos/core"; import { physics } from "../../exports/physics-framework"; import { Node } from "../../cocos/scene-graph"; import { director } from "../../cocos/game"; +import { PhysicsTestEnv } from "./physics.test"; /** * This function is used to test the raycast */ -export default function (parent: Node) { - - const node0 = new Node('0'); - const sphere = node0.addComponent(physics.SphereCollider) as physics.SphereCollider; - parent.addChild(node0); - node0.worldPosition = new Vec3(0, 0.15, 2); - sphere.setGroup(physics.PhysicsGroup.DEFAULT); - - const node1 = new Node('1'); - const box = node1.addComponent(physics.BoxCollider) as physics.BoxCollider; - parent.addChild(node1); - box.setGroup(1 << 1); - - const node2 = new Node('2'); - const capsule = node2.addComponent(physics.CapsuleCollider) as physics.CapsuleCollider; - parent.addChild(node2); - node2.worldPosition = new Vec3(0.1, -0.15, 5); - capsule.setGroup(1 << 2); - capsule.isTrigger = true; - - // test zero mask - let isHit = false; - const hits = physics.PhysicsSystem.instance.raycastResults; - const ray_t = new geometry.Ray(); - isHit = physics.PhysicsSystem.instance.raycast(ray_t, 0); - expect(isHit).toBe(false); - - // physics.PhysicsSystem.instance.syncSceneToPhysics(); - director.tick(physics.PhysicsSystem.instance.fixedTimeStep); - - // test wrong ray - ray_t.o.set(0.25, 0.25, -5); - ray_t.d.set(Vec3.UNIT_Y); - isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1); - expect(isHit).toBe(false); - - // test distance - ray_t.d.set(Vec3.UNIT_Z); - isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1, 5); - expect(isHit).toBe(true); - expect(hits.length).toBe(1); - - // query trigger false - isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1, 100, false); - expect(isHit).toBe(true); - expect(hits.length).toBe(physics.PhysicsSystem.PHYSICS_BUILTIN ? 3 : 2); - - // query trigger true - isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1, 100, true); - expect(isHit).toBe(true); - expect(hits.length).toBe(physics.PhysicsSystem.PHYSICS_CANNON ? 2 : 3); - - // default distance & query trigger - isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1); - expect(isHit).toBe(true); - expect(hits.length).toBe(physics.PhysicsSystem.PHYSICS_CANNON ? 2 : 3); - - // only detect 1 - isHit = physics.PhysicsSystem.instance.raycast(ray_t, 1); - expect(isHit).toBe(true); - expect(hits.length).toBe(1); - - // detect 2 & 4, except 1 - isHit = physics.PhysicsSystem.instance.raycast(ray_t, (1 << 1) | (1 << 0)); - expect(isHit).toBe(true); - expect(hits.length).toBe(2); - - // closest test - const hitClosest = physics.PhysicsSystem.instance.raycastClosestResult; - isHit = physics.PhysicsSystem.instance.raycastClosest(ray_t, -1); - expect(isHit).toBe(true); - expect(hitClosest.collider.uuid).toBe(box.uuid); - ray_t.o.z = box.node.worldPosition.z - box.size.z / 2; - expect(Vec3.equals(hitClosest.hitPoint, ray_t.o, 0.001)).toBe(true); - expect(Vec3.equals(hitClosest.hitNormal, physics.PhysicsSystem.PHYSICS_BUILTIN ? Vec3.ZERO : Vec3.FORWARD)).toBe(true); - - parent.destroyAllChildren(); - parent.removeAllChildren(); +export default function (env: PhysicsTestEnv) { + test(`Raycast`, () => { + const { rootNode: parent } = env; + + const node0 = new Node('0'); + const sphere = node0.addComponent(physics.SphereCollider) as physics.SphereCollider; + parent.addChild(node0); + node0.worldPosition = new Vec3(0, 0.15, 2); + sphere.setGroup(physics.PhysicsGroup.DEFAULT); + + const node1 = new Node('1'); + const box = node1.addComponent(physics.BoxCollider) as physics.BoxCollider; + parent.addChild(node1); + box.setGroup(1 << 1); + + const node2 = new Node('2'); + const capsule = node2.addComponent(physics.CapsuleCollider) as physics.CapsuleCollider; + parent.addChild(node2); + node2.worldPosition = new Vec3(0.1, -0.15, 5); + capsule.setGroup(1 << 2); + capsule.isTrigger = true; + + // test zero mask + let isHit = false; + const hits = physics.PhysicsSystem.instance.raycastResults; + const ray_t = new geometry.Ray(); + isHit = physics.PhysicsSystem.instance.raycast(ray_t, 0); + expect(isHit).toBe(false); + + // physics.PhysicsSystem.instance.syncSceneToPhysics(); + director.tick(physics.PhysicsSystem.instance.fixedTimeStep); + + // test wrong ray + ray_t.o.set(0.25, 0.25, -5); + ray_t.d.set(Vec3.UNIT_Y); + isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1); + expect(isHit).toBe(false); + + // test distance + ray_t.d.set(Vec3.UNIT_Z); + isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1, 5); + expect(isHit).toBe(true); + expect(hits.length).toBe(1); + + // query trigger false + isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1, 100, false); + expect(isHit).toBe(true); + expect(hits.length).toBe(physics.PhysicsSystem.PHYSICS_BUILTIN ? 3 : 2); + + // query trigger true + isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1, 100, true); + expect(isHit).toBe(true); + expect(hits.length).toBe(physics.PhysicsSystem.PHYSICS_CANNON ? 2 : 3); + + // default distance & query trigger + isHit = physics.PhysicsSystem.instance.raycast(ray_t, -1); + expect(isHit).toBe(true); + expect(hits.length).toBe(physics.PhysicsSystem.PHYSICS_CANNON ? 2 : 3); + + // only detect 1 + isHit = physics.PhysicsSystem.instance.raycast(ray_t, 1); + expect(isHit).toBe(true); + expect(hits.length).toBe(1); + + // detect 2 & 4, except 1 + isHit = physics.PhysicsSystem.instance.raycast(ray_t, (1 << 1) | (1 << 0)); + expect(isHit).toBe(true); + expect(hits.length).toBe(2); + + // closest test + const hitClosest = physics.PhysicsSystem.instance.raycastClosestResult; + isHit = physics.PhysicsSystem.instance.raycastClosest(ray_t, -1); + expect(isHit).toBe(true); + expect(hitClosest.collider.uuid).toBe(box.uuid); + ray_t.o.z = box.node.worldPosition.z - box.size.z / 2; + expect(Vec3.equals(hitClosest.hitPoint, ray_t.o, 0.001)).toBe(true); + expect(Vec3.equals(hitClosest.hitNormal, physics.PhysicsSystem.PHYSICS_BUILTIN ? Vec3.ZERO : Vec3.FORWARD)).toBe(true); + }); } \ No newline at end of file diff --git a/tests/physics/sleep.ts b/tests/physics/sleep.ts index 7173b8840c5..40235df0caf 100644 --- a/tests/physics/sleep.ts +++ b/tests/physics/sleep.ts @@ -2,49 +2,51 @@ import { Vec3 } from "../../cocos/core"; import { physics } from "../../exports/physics-framework"; import { Node } from "../../cocos/scene-graph"; import { director } from "../../cocos/game"; +import { PhysicsTestEnv } from "./physics.test"; /** * This function is used to test automatic sleep */ -export default function (parent: Node, steps = 300) { - const nodeDynamicA = new Node('DynamicA'); - parent.addChild(nodeDynamicA); - nodeDynamicA.worldPosition = new Vec3(0, 10, 0); - nodeDynamicA.addComponent(physics.SphereCollider); - const bodyA = nodeDynamicA.addComponent(physics.RigidBody) as physics.RigidBody; +export default function (env: PhysicsTestEnv, steps = 300) { + test(`Sleep`, () => { + const { rootNode: parent } = env; + + const nodeDynamicA = new Node('DynamicA'); + parent.addChild(nodeDynamicA); + nodeDynamicA.worldPosition = new Vec3(0, 10, 0); + nodeDynamicA.addComponent(physics.SphereCollider); + const bodyA = nodeDynamicA.addComponent(physics.RigidBody) as physics.RigidBody; - const nodeDynamicB = new Node('DynamicB'); - parent.addChild(nodeDynamicB); - nodeDynamicB.worldPosition = new Vec3(0, 5, 0); - const bodyB = nodeDynamicB.addComponent(physics.RigidBody) as physics.RigidBody; - nodeDynamicB.addComponent(physics.BoxCollider); + const nodeDynamicB = new Node('DynamicB'); + parent.addChild(nodeDynamicB); + nodeDynamicB.worldPosition = new Vec3(0, 5, 0); + const bodyB = nodeDynamicB.addComponent(physics.RigidBody) as physics.RigidBody; + nodeDynamicB.addComponent(physics.BoxCollider); - const nodeStatic = new Node('StaticB'); - parent.addChild(nodeStatic); - nodeStatic.addComponent(physics.BoxCollider); - nodeStatic.worldScale = new Vec3(10, 1, 10); + const nodeStatic = new Node('StaticB'); + parent.addChild(nodeStatic); + nodeStatic.addComponent(physics.BoxCollider); + nodeStatic.worldScale = new Vec3(10, 1, 10); - expect(bodyA.isSleeping).toBe(false); - expect(bodyB.isSleeping).toBe(false); - expect(bodyA.isAwake).toBe(true); - expect(bodyB.isAwake).toBe(true); + expect(bodyA.isSleeping).toBe(false); + expect(bodyB.isSleeping).toBe(false); + expect(bodyA.isAwake).toBe(true); + expect(bodyB.isAwake).toBe(true); - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - const middle = Math.floor(steps / 2); - for (let i = 0; i < steps; i++) { - if (i === middle) { - bodyA.wakeUp(); - expect(bodyA.isSleeping).toBe(false); - expect(bodyA.isAwake).toBe(true); + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + const middle = Math.floor(steps / 2); + for (let i = 0; i < steps; i++) { + if (i === middle) { + bodyA.wakeUp(); + expect(bodyA.isSleeping).toBe(false); + expect(bodyA.isAwake).toBe(true); + } + director.tick(dt); } - director.tick(dt); - } - expect(bodyA.isSleeping).toBe(true); - expect(bodyB.isSleeping).toBe(true); - expect(bodyA.isAwake).toBe(false); - expect(bodyB.isAwake).toBe(false); - - parent.destroyAllChildren(); - parent.removeAllChildren(); + expect(bodyA.isSleeping).toBe(true); + expect(bodyB.isSleeping).toBe(true); + expect(bodyA.isAwake).toBe(false); + expect(bodyB.isAwake).toBe(false); + }); } diff --git a/tests/physics/stability.ts b/tests/physics/stability.ts index aed35705bb7..21f7505ef4e 100644 --- a/tests/physics/stability.ts +++ b/tests/physics/stability.ts @@ -2,11 +2,28 @@ import { Vec3 } from "../../cocos/core"; import { physics } from "../../exports/physics-framework"; import { Node } from "../../cocos/scene-graph"; import { director } from "../../cocos/game"; +import { PhysicsTestEnv } from "./physics.test"; + +export default function(env: PhysicsTestEnv) { + describe(`Stability test`, () => { + test.each([1, 0.5])(`Stable %s`, (v) => { + doTest(env, 500, v); + }); + + if (env.backendId === 'physx') { + test.each([0.25, 0.15])(`Stable for small scale in PhysX %s`, (v) => { + doTest(env, 500, v); + }); + } + }); +} /** * This function is used to test stability of the physics */ -export default function (parent: Node, steps = 500, scale = 0.5) { +function doTest(env: PhysicsTestEnv, steps = 500, scale = 0.5) { + const { rootNode: parent } = env; + const nodeStatic = new Node('StaticB'); parent.addChild(nodeStatic); nodeStatic.addComponent(physics.BoxCollider); @@ -49,8 +66,5 @@ export default function (parent: Node, steps = 500, scale = 0.5) { bodies.forEach((v) => { expect(v.isSleeping).toBe(true); expect(v.isAwake).toBe(false); - }) - - parent.destroyAllChildren(); - parent.removeAllChildren(); + }); } diff --git a/tests/physics/sweep.ts b/tests/physics/sweep.ts index 7533c737a1b..8e1757ddc9f 100644 --- a/tests/physics/sweep.ts +++ b/tests/physics/sweep.ts @@ -2,52 +2,54 @@ import { geometry, Quat, Vec3 } from "../../cocos/core"; import { physics } from "../../exports/physics-framework"; import { Node } from "../../cocos/scene-graph"; import { director } from "../../cocos/game"; - +import { PhysicsTestEnv } from "./physics.test"; /** * This function is used to test the raycast */ -export default function (parent: Node) { - //skip builtin and cannon.js for now - if (physics.selector.id === 'builtin' || physics.selector.id === 'cannon.js') +export default function (env: PhysicsTestEnv) { + if (env.backendId === 'builtin' || env.backendId === 'cannon.js') { return; - - const nodeSphere = new Node('sphere'); - const sphere = nodeSphere.addComponent(physics.SphereCollider) as physics.SphereCollider; - parent.addChild(nodeSphere); - nodeSphere.worldPosition = new Vec3(10, 0, 0); - sphere.setGroup(physics.PhysicsGroup.DEFAULT); + } - const nodeBox = new Node('box'); - const box = nodeBox.addComponent(physics.BoxCollider) as physics.BoxCollider; - parent.addChild(nodeBox); - nodeBox.worldPosition = new Vec3(5, 0, 0); - box.setGroup(physics.PhysicsGroup.DEFAULT); + test(`Sweep`, () => { + const { rootNode: parent } = env; + + const nodeSphere = new Node('sphere'); + const sphere = nodeSphere.addComponent(physics.SphereCollider) as physics.SphereCollider; + parent.addChild(nodeSphere); + nodeSphere.worldPosition = new Vec3(10, 0, 0); + sphere.setGroup(physics.PhysicsGroup.DEFAULT); - let isHit = false; - const ray_t = new geometry.Ray(0,0,0,1,0,0); + const nodeBox = new Node('box'); + const box = nodeBox.addComponent(physics.BoxCollider) as physics.BoxCollider; + parent.addChild(nodeBox); + nodeBox.worldPosition = new Vec3(5, 0, 0); + box.setGroup(physics.PhysicsGroup.DEFAULT); - director.tick(physics.PhysicsSystem.instance.fixedTimeStep); - - // all test - { - const hits = physics.PhysicsSystem.instance.sweepCastResults; - const boxHalfExtents = new Vec3(0.5, 0.5, 0.5); - const orientation = new Quat(); - isHit = physics.PhysicsSystem.instance.sweepBox(ray_t, boxHalfExtents, orientation); - expect(isHit).toBe(true); - expect(hits.length).toBe(2); - } + let isHit = false; + const ray_t = new geometry.Ray(0,0,0,1,0,0); - // closest test - { - const hitClosest = physics.PhysicsSystem.instance.sweepCastClosestResult; - const boxHalfExtents = new Vec3(0.5, 0.5, 0.5); - const orientation = new Quat(); - isHit = physics.PhysicsSystem.instance.sweepBoxClosest(ray_t, boxHalfExtents, orientation); - expect(isHit).toBe(true); - expect(hitClosest.collider.uuid).toBe(box.uuid); - } - parent.destroyAllChildren(); - parent.removeAllChildren(); + director.tick(physics.PhysicsSystem.instance.fixedTimeStep); + + // all test + { + const hits = physics.PhysicsSystem.instance.sweepCastResults; + const boxHalfExtents = new Vec3(0.5, 0.5, 0.5); + const orientation = new Quat(); + isHit = physics.PhysicsSystem.instance.sweepBox(ray_t, boxHalfExtents, orientation); + expect(isHit).toBe(true); + expect(hits.length).toBe(2); + } + + // closest test + { + const hitClosest = physics.PhysicsSystem.instance.sweepCastClosestResult; + const boxHalfExtents = new Vec3(0.5, 0.5, 0.5); + const orientation = new Quat(); + isHit = physics.PhysicsSystem.instance.sweepBoxClosest(ray_t, boxHalfExtents, orientation); + expect(isHit).toBe(true); + expect(hitClosest.collider.uuid).toBe(box.uuid); + } + }); } \ No newline at end of file diff --git a/tests/physics/volume.ts b/tests/physics/volume.ts index 6c813e8b998..45a8d80001e 100644 --- a/tests/physics/volume.ts +++ b/tests/physics/volume.ts @@ -2,38 +2,42 @@ import { Vec3 } from "../../cocos/core"; import { physics } from "../../exports/physics-framework"; import { Node } from "../../cocos/scene-graph"; import { director } from "../../cocos/game"; +import { PhysicsTestEnv } from "./physics.test"; /** * This function is used to test the behavior of different volume ratios */ -export default function (parent: Node, steps = 120, ratios = 0.2) { - const nodeStatic = new Node('StaticB'); - parent.addChild(nodeStatic); - nodeStatic.addComponent(physics.BoxCollider); - nodeStatic.worldScale = new Vec3(20, 0.01, 20); - nodeStatic.worldPosition = new Vec3(0, -0.005, 0); +export default function (env: PhysicsTestEnv) { + test(`Volume`, () => { + const { rootNode: parent } = env; - const high = new Node('high'); - parent.addChild(high); - const highBody = high.addComponent(physics.RigidBody) as physics.RigidBody; - high.addComponent(physics.BoxCollider); - const initPos = new Vec3(0, 0.5 + ratios, 0); - high.worldPosition = initPos; + const steps = 120, ratios = 0.2; + + const nodeStatic = new Node('StaticB'); + parent.addChild(nodeStatic); + nodeStatic.addComponent(physics.BoxCollider); + nodeStatic.worldScale = new Vec3(20, 0.01, 20); + nodeStatic.worldPosition = new Vec3(0, -0.005, 0); - const low = new Node('low'); - parent.addChild(low); - low.addComponent(physics.RigidBody); - low.addComponent(physics.BoxCollider); - low.worldScale = new Vec3(ratios, ratios, ratios); - low.worldPosition = new Vec3(0, ratios / 2, 0); + const high = new Node('high'); + parent.addChild(high); + const highBody = high.addComponent(physics.RigidBody) as physics.RigidBody; + high.addComponent(physics.BoxCollider); + const initPos = new Vec3(0, 0.5 + ratios, 0); + high.worldPosition = initPos; - const dt = physics.PhysicsSystem.instance.fixedTimeStep; - for (let i = 0; i < steps; i++) { - director.tick(dt); - } + const low = new Node('low'); + parent.addChild(low); + low.addComponent(physics.RigidBody); + low.addComponent(physics.BoxCollider); + low.worldScale = new Vec3(ratios, ratios, ratios); + low.worldPosition = new Vec3(0, ratios / 2, 0); - expect(high.worldPosition.equals(initPos, 0.01)).toBe(true); + const dt = physics.PhysicsSystem.instance.fixedTimeStep; + for (let i = 0; i < steps; i++) { + director.tick(dt); + } - parent.destroyAllChildren(); - parent.removeAllChildren(); + expect(high.worldPosition.equals(initPos, 0.01)).toBe(true); + }); }