From c27d11502ef73f09b76d066591f69234163ab015 Mon Sep 17 00:00:00 2001 From: yangfengzzz <yangfengzzz@hotmail.com> Date: Sat, 28 Jan 2023 12:19:59 +0800 Subject: [PATCH] feat: add spherical joint --- .../core/src/physics/joint/SphericalJoint.ts | 86 ++++++++++++++++ packages/core/src/physics/joint/index.ts | 1 + packages/design/src/physics/IPhysics.ts | 8 +- .../src/physics/joints/ISphericalJoint.ts | 24 +++++ packages/design/src/physics/joints/index.ts | 1 + packages/physics-lite/src/LitePhysics.ts | 14 ++- packages/physics-physx/src/PhysXPhysics.ts | 9 ++ .../src/joint/PhysXSphericalJoint.ts | 97 +++++++++++++++++++ 8 files changed, 236 insertions(+), 4 deletions(-) create mode 100644 packages/core/src/physics/joint/SphericalJoint.ts create mode 100644 packages/design/src/physics/joints/ISphericalJoint.ts create mode 100644 packages/physics-physx/src/joint/PhysXSphericalJoint.ts diff --git a/packages/core/src/physics/joint/SphericalJoint.ts b/packages/core/src/physics/joint/SphericalJoint.ts new file mode 100644 index 0000000000..9a0baca25c --- /dev/null +++ b/packages/core/src/physics/joint/SphericalJoint.ts @@ -0,0 +1,86 @@ +import { Joint } from "./Joint"; +import { ISphericalJoint } from "@oasis-engine/design"; +import { Collider } from "../Collider"; +import { PhysicsManager } from "../PhysicsManager"; + +/** + * A joint which behaves in a similar way to a ball and socket. + */ +export class SphericalJoint extends Joint { + private _yLimit = Math.PI / 2; + private _zLimit = Math.PI / 2; + private _contactDistance = -1; + private _stiffness = 0; + private _damping = 0; + private _enableSpring = false; + + /** Whether enable spring limit */ + get enableSpring(): boolean { + return this._enableSpring; + } + + set enableSpring(value: boolean) { + this._enableSpring = value; + (<ISphericalJoint>this._nativeJoint).enableSpring(value); + } + + /** The limit angle from the Y-axis of the constraint frame. */ + get yLimit(): number { + return this._yLimit; + } + + set yLimit(value: number) { + this._yLimit = value; + (<ISphericalJoint>this._nativeJoint).setYLimit(value); + } + + /** The limit angle from the Z-axis of the constraint frame. */ + get zLimit(): number { + return this._zLimit; + } + + set zLimit(value: number) { + this._zLimit = value; + (<ISphericalJoint>this._nativeJoint).setZLimit(value); + } + + /** Distance inside the limit value at which the limit will be considered to be active by the solver. */ + get contactDistance(): number { + return this._contactDistance; + } + + set contactDistance(value: number) { + this._contactDistance = value; + (<ISphericalJoint>this._nativeJoint).setContactDistance(value); + } + + /** The spring forces used to reach the target position. */ + get stiffness(): number { + return this._stiffness; + } + + set stiffness(value: number) { + this._stiffness = value; + (<ISphericalJoint>this._nativeJoint).setStiffness(value); + } + + /** The damper force uses to dampen the spring. */ + get damping(): number { + return this._damping; + } + + set damping(value: number) { + this._damping = value; + (<ISphericalJoint>this._nativeJoint).setDamping(value); + } + + /** + * @override + * @internal + */ + _onAwake() { + const collider = this._collider; + collider.collider = this.entity.getComponent(Collider); + this._nativeJoint = PhysicsManager._nativePhysics.createSphericalJoint(collider.collider._nativeCollider); + } +} diff --git a/packages/core/src/physics/joint/index.ts b/packages/core/src/physics/joint/index.ts index 2ffd2e3cb2..b643d06dd5 100644 --- a/packages/core/src/physics/joint/index.ts +++ b/packages/core/src/physics/joint/index.ts @@ -2,6 +2,7 @@ export { Joint } from "./Joint"; export { FixedJoint } from "./FixedJoint"; export { HingeJoint } from "./HingeJoint"; export { SpringJoint } from "./SpringJoint"; +export { SphericalJoint } from "./SphericalJoint"; export { JointLimits } from "./JointLimits"; export { JointMotor } from "./JointMotor"; diff --git a/packages/design/src/physics/IPhysics.ts b/packages/design/src/physics/IPhysics.ts index ad90d00da2..ad0d08b17d 100644 --- a/packages/design/src/physics/IPhysics.ts +++ b/packages/design/src/physics/IPhysics.ts @@ -6,7 +6,7 @@ import { IStaticCollider } from "./IStaticCollider"; import { Quaternion, Vector3 } from "@oasis-engine/math"; import { ICollider } from "./ICollider"; import { ICharacterController } from "./ICharacterController"; -import { IFixedJoint, IHingeJoint, ISpringJoint } from "./joints"; +import { IFixedJoint, IHingeJoint, ISpringJoint, ISphericalJoint } from "./joints"; /** * The interface of physics creation. @@ -119,4 +119,10 @@ export interface IPhysics { * @param collider - Affector of joint */ createSpringJoint(collider: ICollider): ISpringJoint; + + /** + * Create spherical joint + * @param collider - Affector of joint + */ + createSphericalJoint(collider: ICollider): ISphericalJoint; } diff --git a/packages/design/src/physics/joints/ISphericalJoint.ts b/packages/design/src/physics/joints/ISphericalJoint.ts new file mode 100644 index 0000000000..9be2e17a95 --- /dev/null +++ b/packages/design/src/physics/joints/ISphericalJoint.ts @@ -0,0 +1,24 @@ +import { IJoint } from "./IJoint"; + +/** + * A joint which behaves in a similar way to a ball and socket. + */ +export interface ISphericalJoint extends IJoint { + /** Whether enable spring limit */ + enableSpring(value: boolean); + + /** The limit angle from the Y-axis of the constraint frame. */ + setYLimit(value: number); + + /** The limit angle from the Z-axis of the constraint frame. */ + setZLimit(value: number); + + /** Distance inside the limit value at which the limit will be considered to be active by the solver. */ + setContactDistance(value: number); + + /** The spring forces used to reach the target position. */ + setStiffness(value: number); + + /** The damper force uses to dampen the spring. */ + setDamping(value: number); +} diff --git a/packages/design/src/physics/joints/index.ts b/packages/design/src/physics/joints/index.ts index 6a0b39f4e6..7f278b23ad 100644 --- a/packages/design/src/physics/joints/index.ts +++ b/packages/design/src/physics/joints/index.ts @@ -2,3 +2,4 @@ export type { IJoint } from "./IJoint"; export type { IFixedJoint } from "./IFixedJoint"; export type { IHingeJoint } from "./IHingeJoint"; export type { ISpringJoint } from "./ISpringJoint"; +export type { ISphericalJoint } from "./ISphericalJoint"; diff --git a/packages/physics-lite/src/LitePhysics.ts b/packages/physics-lite/src/LitePhysics.ts index 6cc92369b3..48b00e70ed 100644 --- a/packages/physics-lite/src/LitePhysics.ts +++ b/packages/physics-lite/src/LitePhysics.ts @@ -12,6 +12,7 @@ import { IFixedJoint, IHingeJoint, ISpringJoint, + ISphericalJoint } from "@oasis-engine/design"; import { Quaternion, Vector3 } from "oasis-engine"; import { LiteDynamicCollider } from "./LiteDynamicCollider"; @@ -121,20 +122,27 @@ export class LitePhysics { * {@inheritDoc IPhysics.createFixedJoint } */ static createFixedJoint(collider: LiteCollider): IFixedJoint { - throw "Physics-lite don't support CapsuleColliderShape. Use Physics-PhysX instead!"; + throw "Physics-lite don't support FixedJoint. Use Physics-PhysX instead!"; } /** * {@inheritDoc IPhysics.createHingeJoint } */ static createHingeJoint(collider: LiteCollider): IHingeJoint { - throw "Physics-lite don't support CapsuleColliderShape. Use Physics-PhysX instead!"; + throw "Physics-lite don't support HingeJoint. Use Physics-PhysX instead!"; } /** * {@inheritDoc IPhysics.createSpringJoint } */ static createSpringJoint(collider: LiteCollider): ISpringJoint { - throw "Physics-lite don't support CapsuleColliderShape. Use Physics-PhysX instead!"; + throw "Physics-lite don't support SpringJoint. Use Physics-PhysX instead!"; + } + + /** + * {@inheritDoc IPhysics.createSphericalJoint } + */ + static createSphericalJoint(collider: LiteCollider): ISphericalJoint { + throw "Physics-lite don't support SphericalJoint. Use Physics-PhysX instead!"; } } diff --git a/packages/physics-physx/src/PhysXPhysics.ts b/packages/physics-physx/src/PhysXPhysics.ts index d5569dcebb..1456f00f33 100644 --- a/packages/physics-physx/src/PhysXPhysics.ts +++ b/packages/physics-physx/src/PhysXPhysics.ts @@ -10,6 +10,7 @@ import { IPhysicsMaterial, IPlaneColliderShape, ISphereColliderShape, + ISphericalJoint, ISpringJoint, IStaticCollider } from "@oasis-engine/design"; @@ -18,6 +19,7 @@ import { PhysXRuntimeMode } from "./enum/PhysXRuntimeMode"; import { PhysXFixedJoint } from "./joint/PhysXFixedJoint"; import { PhysXHingeJoint } from "./joint/PhysXHingeJoint"; import { PhysXSpringJoint } from "./joint/PhysXSpringJoint"; +import { PhysXSphericalJoint } from "./joint/PhysXSphericalJoint"; import { PhysXCharacterController } from "./PhysXCharacterController"; import { PhysXCollider } from "./PhysXCollider"; import { PhysXDynamicCollider } from "./PhysXDynamicCollider"; @@ -220,6 +222,13 @@ export class PhysXPhysics { return new PhysXSpringJoint(collider); } + /** + * {@inheritDoc IPhysics.createSpringJoint } + */ + static createSphericalJoint(collider: PhysXCollider): ISphericalJoint { + return new PhysXSphericalJoint(collider); + } + private static _init(physX: any): void { const version = physX.PX_PHYSICS_VERSION; const defaultErrorCallback = new physX.PxDefaultErrorCallback(); diff --git a/packages/physics-physx/src/joint/PhysXSphericalJoint.ts b/packages/physics-physx/src/joint/PhysXSphericalJoint.ts new file mode 100644 index 0000000000..2844126f0e --- /dev/null +++ b/packages/physics-physx/src/joint/PhysXSphericalJoint.ts @@ -0,0 +1,97 @@ +import { ISphericalJoint } from "@oasis-engine/design"; +import { PhysXJoint } from "./PhysXJoint"; +import { PhysXCollider } from "../PhysXCollider"; +import { PhysXPhysics } from "../PhysXPhysics"; + +/** + * A joint which behaves in a similar way to a ball and socket. + */ +export class PhysXSphericalJoint extends PhysXJoint implements ISphericalJoint { + private _yLimit = Math.PI / 2; + private _zLimit = Math.PI / 2; + private _contactDistance = -1; + private _stiffness = 0; + private _damping = 0; + private _enableSpring = false; + + constructor(collider: PhysXCollider) { + super(); + this._collider = collider; + this._pxJoint = PhysXPhysics._pxPhysics.createSphericalJoint( + null, + PhysXJoint._defaultVec, + PhysXJoint._defaultQuat, + collider._pxActor, + PhysXJoint._defaultVec, + PhysXJoint._defaultQuat + ); + } + + /** + * {@inheritDoc ISphericalJoint.enableSpring } + */ + enableSpring(value: boolean) { + if (this._enableSpring !== value) { + this._enableSpring = value; + this._setLimitCone(); + } + } + + /** + * {@inheritDoc ISphericalJoint.setYLimit } + */ + setYLimit(value: number) { + if (this._yLimit !== value) { + this._yLimit = value; + this._setLimitCone(); + } + } + + /** + * {@inheritDoc ISphericalJoint.setZLimit } + */ + setZLimit(value: number) { + if (this._zLimit !== value) { + this._zLimit = value; + this._setLimitCone(); + } + } + + /** + * {@inheritDoc ISphericalJoint.setContactDistance } + */ + setContactDistance(value: number) { + if (this._contactDistance !== value) { + this._contactDistance = value; + this._setLimitCone(); + } + } + + /** + * {@inheritDoc ISphericalJoint.setStiffness } + */ + setStiffness(value: number) { + if (this._stiffness !== value) { + this._stiffness = value; + this._setLimitCone(); + } + } + + /** + * {@inheritDoc ISphericalJoint.setDamping } + */ + setDamping(value: number) { + if (this._damping !== value) { + this._damping = value; + this._setLimitCone(); + } + } + + private _setLimitCone() { + if (this._enableSpring) { + this._pxJoint.setSoftLimitCone(this._yLimit, this._zLimit, this._stiffness, this._damping); + } else { + this._pxJoint.setHardLimitCone(this._yLimit, this._zLimit, this._contactDistance); + } + } +}