ecspresso
Version:
A minimal Entity-Component-System library for typescript and javascript.
5 lines (3 loc) • 9.39 kB
JavaScript
var e=((J)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(J,{get:(K,Q)=>(typeof require<"u"?require:K)[Q]}):J)(function(J){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+J+'" is not supported')});import{definePlugin as s}from"ecspresso";function v(J){let K=new Map,Q=new WeakMap,G=1;function V(j){let $=K.get(j);if($!==void 0)return $;if(G===0)throw Error(`[ecspresso] ${J} layer bitmask overflow: more than 32 distinct layers registered`);let N=G;return K.set(j,N),G<<=1,N}function O(j){let $=Q.get(j);if($!==void 0)return $;let N=0;for(let k=0;k<j.length;k++)N|=V(j[k]);return Q.set(j,N),N}return{getLayerBit:V,getCollidesWithMask:O}}var m={normalX:0,normalY:0,normalZ:0,depth:0},w=0,A=1,y=v("3D collision"),b=y.getLayerBit,u=y.getCollidesWithMask;function B(J,K,Q,G,V,O,j,$,N){if(J.entityId=K,J.layer=O,J.collidesWith=j,J.layerBit=b(O),J.collidesWithMask=u(j),$)return J.x=Q+($.offsetX??0),J.y=G+($.offsetY??0),J.z=V+($.offsetZ??0),J.shape=w,J.halfWidth=$.width/2,J.halfHeight=$.height/2,J.halfDepth=$.depth/2,J.radius=0,!0;if(N)return J.x=Q+(N.offsetX??0),J.y=G+(N.offsetY??0),J.z=V+(N.offsetZ??0),J.shape=A,J.halfWidth=0,J.halfHeight=0,J.halfDepth=0,J.radius=N.radius,!0;return!1}function d(J,K,Q,G,V,O,j,$,N,k,F,z,U){let R=j-J,L=$-K,P=N-Q,W=G+k-Math.abs(R),q=V+F-Math.abs(L),T=O+z-Math.abs(P);if(W<=0||q<=0||T<=0)return!1;if(W<=q&&W<=T)return U.normalX=R>=0?1:-1,U.normalY=0,U.normalZ=0,U.depth=W,!0;if(q<=T)return U.normalX=0,U.normalY=L>=0?1:-1,U.normalZ=0,U.depth=q,!0;return U.normalX=0,U.normalY=0,U.normalZ=P>=0?1:-1,U.depth=T,!0}function r(J,K,Q,G,V,O,j,$,N){let k=V-J,F=O-K,z=j-Q,U=k*k+F*F+z*z,R=G+$;if(U>=R*R)return!1;let L=Math.sqrt(U);if(L===0)return N.normalX=1,N.normalY=0,N.normalZ=0,N.depth=R,!0;return N.normalX=k/L,N.normalY=F/L,N.normalZ=z/L,N.depth=R-L,!0}function D(J,K,Q,G,V,O,j,$,N,k,F){let z=Math.max(J-G,Math.min(j,J+G)),U=Math.max(K-V,Math.min($,K+V)),R=Math.max(Q-O,Math.min(N,Q+O)),L=j-z,P=$-U,W=N-R,q=L*L+P*P+W*W;if(q>=k*k)return!1;if(q===0){let Z=j-(J-G),Y=J+G-j,H=$-(K-V),E=K+V-$,X=N-(Q-O),_=Q+O-N,M=Math.min(Z,Y,H,E,X,_);if(M===Y)return F.normalX=1,F.normalY=0,F.normalZ=0,F.depth=Y+k,!0;if(M===Z)return F.normalX=-1,F.normalY=0,F.normalZ=0,F.depth=Z+k,!0;if(M===E)return F.normalX=0,F.normalY=1,F.normalZ=0,F.depth=E+k,!0;if(M===H)return F.normalX=0,F.normalY=-1,F.normalZ=0,F.depth=H+k,!0;if(M===_)return F.normalX=0,F.normalY=0,F.normalZ=1,F.depth=_+k,!0;return F.normalX=0,F.normalY=0,F.normalZ=-1,F.depth=X+k,!0}let T=Math.sqrt(q);return F.normalX=L/T,F.normalY=P/T,F.normalZ=W/T,F.depth=k-T,!0}function p(J,K,Q){if(J.shape===w&&K.shape===w)return d(J.x,J.y,J.z,J.halfWidth,J.halfHeight,J.halfDepth,K.x,K.y,K.z,K.halfWidth,K.halfHeight,K.halfDepth,Q);if(J.shape===A&&K.shape===A)return r(J.x,J.y,J.z,J.radius,K.x,K.y,K.z,K.radius,Q);if(J.shape===w&&K.shape===A)return D(J.x,J.y,J.z,J.halfWidth,J.halfHeight,J.halfDepth,K.x,K.y,K.z,K.radius,Q);if(!D(K.x,K.y,K.z,K.halfWidth,K.halfHeight,K.halfDepth,J.x,J.y,J.z,J.radius,Q))return!1;return Q.normalX=-Q.normalX,Q.normalY=-Q.normalY,Q.normalZ=-Q.normalZ,!0}var g=[],f=!1,c=50;function h(J,K,Q,G,V,O){if(G)n(J,K,Q,G,V,O);else l(J,K,V,O)}function l(J,K,Q,G){if(!f&&K>=c)f=!0,console.warn(`[ecspresso] 3D collision detection is using O(n²) brute force with ${K} colliders. For better performance, install createSpatialIndex3DPlugin() alongside your collision or physics3D plugin.`);for(let V=0;V<K;V++){let O=J[V];if(!O)continue;for(let j=V+1;j<K;j++){let $=J[j];if(!$)continue;if((O.collidesWithMask&$.layerBit|$.collidesWithMask&O.layerBit)===0)continue;if(!p(O,$,m))continue;Q(O,$,m,G)}}}function n(J,K,Q,G,V,O){Q.clear();for(let j=0;j<K;j++){let $=J[j];if(!$)continue;Q.set($.entityId,$)}for(let j=0;j<K;j++){let $=J[j];if(!$)continue;let N=$.shape===w?$.halfWidth:$.radius,k=$.shape===w?$.halfHeight:$.radius,F=$.shape===w?$.halfDepth:$.radius;g.length=0,G.queryBoxInto($.x-N,$.y-k,$.z-F,$.x+N,$.y+k,$.z+F,g,$.entityId);for(let z of g){let U=Q.get(z);if(!U)continue;if(($.collidesWithMask&U.layerBit|U.collidesWithMask&$.layerBit)===0)continue;if(!p($,U,m))continue;V($,U,m,O)}}}function $J(J,K){return{rigidBody3D:{type:J,mass:J==="static"?1/0:K?.mass??1,drag:K?.drag??0,restitution:K?.restitution??0,friction:K?.friction??0,gravityScale:K?.gravityScale??1},force3D:{x:0,y:0,z:0}}}function OJ(J,K,Q){return{force3D:{x:J,y:K,z:Q}}}function jJ(J,K,Q,G,V){let O=J.getComponent(K,"force3D");if(!O)return;O.x+=Q,O.y+=G,O.z+=V}function UJ(J,K,Q,G,V){let O=J.getComponent(K,"velocity3D"),j=J.getComponent(K,"rigidBody3D");if(!O||!j)return;if(j.mass===1/0||j.mass===0)return;O.x+=Q/j.mass,O.y+=G/j.mass,O.z+=V/j.mass}function FJ(J,K,Q,G,V){let O=J.getComponent(K,"velocity3D");if(!O)return;O.x=Q,O.y=G,O.z=V}var x={entityA:0,entityB:0,normalX:0,normalY:0,normalZ:0,depth:0};function i(J,K,Q,G){let V=J.rigidBody.type==="dynamic"&&J.rigidBody.mass>0&&J.rigidBody.mass!==1/0?1/J.rigidBody.mass:0,O=K.rigidBody.type==="dynamic"&&K.rigidBody.mass>0&&K.rigidBody.mass!==1/0?1/K.rigidBody.mass:0,j=V+O;if(j>0){let $=Q.depth/j;if(V>0){let U=G.getComponent(J.entityId,"localTransform3D");if(!U)return;let R=$*V;U.x-=R*Q.normalX,U.y-=R*Q.normalY,U.z-=R*Q.normalZ,J.x=U.x,J.y=U.y,J.z=U.z,G.markChanged(J.entityId,"localTransform3D")}if(O>0){let U=G.getComponent(K.entityId,"localTransform3D");if(!U)return;let R=$*O;U.x+=R*Q.normalX,U.y+=R*Q.normalY,U.z+=R*Q.normalZ,K.x=U.x,K.y=U.y,K.z=U.z,G.markChanged(K.entityId,"localTransform3D")}let N=K.velocity.x-J.velocity.x,k=K.velocity.y-J.velocity.y,F=K.velocity.z-J.velocity.z,z=N*Q.normalX+k*Q.normalY+F*Q.normalZ;if(z<0){let R=-(1+Math.min(J.rigidBody.restitution,K.rigidBody.restitution))*z/j,L=R*V,P=R*O;J.velocity.x-=L*Q.normalX,J.velocity.y-=L*Q.normalY,J.velocity.z-=L*Q.normalZ,K.velocity.x+=P*Q.normalX,K.velocity.y+=P*Q.normalY,K.velocity.z+=P*Q.normalZ;let W=N-z*Q.normalX,q=k-z*Q.normalY,T=F-z*Q.normalZ,Z=Math.sqrt(W*W+q*q+T*T);if(Z>0.000001){let Y=W/Z,H=q/Z,E=T/Z,_=Math.sqrt(J.rigidBody.friction*K.rigidBody.friction)*Math.abs(R),M=Math.min(Z/j,_),I=M*V,C=M*O;J.velocity.x+=I*Y,J.velocity.y+=I*H,J.velocity.z+=I*E,K.velocity.x-=C*Y,K.velocity.y-=C*H,K.velocity.z-=C*E}}G.markChanged(J.entityId,"velocity3D"),G.markChanged(K.entityId,"velocity3D")}x.entityA=J.entityId,x.entityB=K.entityId,x.normalX=Q.normalX,x.normalY=Q.normalY,x.normalZ=Q.normalZ,x.depth=Q.depth,G.eventBus.publish("physics3DCollision",x)}function GJ(J){let{gravity:K={x:0,y:0,z:0},systemGroup:Q="physics3D",collisionSystemGroup:G,integrationPriority:V=1000,collisionPriority:O=900,phase:j="fixedUpdate"}=J??{};return s("physics3D").withComponentTypes().withEventTypes().withResourceTypes().withLabels().withGroups().requires().install(($)=>{$.registerRequired("rigidBody3D","velocity3D",()=>({x:0,y:0,z:0})),$.registerRequired("rigidBody3D","force3D",()=>({x:0,y:0,z:0})),$.addResource("physics3DConfig",{gravity:{x:K.x,y:K.y,z:K.z}}),$.addSystem("physics3D-integration").setPriority(V).inPhase(j).inGroup(Q).addQuery("bodies",{with:["localTransform3D","velocity3D","rigidBody3D","force3D"]}).setProcess(({queries:L,dt:P,ecs:W})=>{let{gravity:q}=W.getResource("physics3DConfig"),T=q.x,Z=q.y,Y=q.z;for(let H of L.bodies){let{localTransform3D:E,velocity3D:X,rigidBody3D:_,force3D:M}=H.components;if(_.type==="static")continue;if(_.type==="dynamic"){let I=_.gravityScale*P;X.x+=T*I,X.y+=Z*I,X.z+=Y*I;let C=_.mass;if(C>0&&C!==1/0){let S=P/C;X.x+=M.x*S,X.y+=M.y*S,X.z+=M.z*S}if(_.drag>0){let S=Math.max(0,1-_.drag*P);X.x*=S,X.y*=S,X.z*=S}}E.x+=X.x*P,E.y+=X.y*P,E.z+=X.z*P,M.x=0,M.y=0,M.z=0,W.markChanged(H.id,"localTransform3D")}});let N=$.addSystem("physics3D-collision").setPriority(O).inPhase(j).inGroup(Q);if(G)N.inGroup(G);let k=[],F=new Map,z,U=!1,R=(L,P,W,q,T,Z)=>{let Y=k[L];if(!Y)Y={entityId:P,x:0,y:0,z:0,layer:W,collidesWith:q,layerBit:0,collidesWithMask:0,shape:w,halfWidth:0,halfHeight:0,halfDepth:0,radius:0,rigidBody:T,velocity:Z},k[L]=Y;else Y.rigidBody=T,Y.velocity=Z;return Y};N.addQuery("aabbOnly",{with:["localTransform3D","rigidBody3D","velocity3D","collisionLayer","aabb3DCollider"],without:["sphereCollider"]}).addQuery("sphereOnly",{with:["localTransform3D","rigidBody3D","velocity3D","collisionLayer","sphereCollider"],without:["aabb3DCollider"]}).addQuery("both",{with:["localTransform3D","rigidBody3D","velocity3D","collisionLayer","aabb3DCollider","sphereCollider"]}).setProcess(({queries:L,ecs:P})=>{let W=0;for(let q of L.aabbOnly){let{localTransform3D:T,rigidBody3D:Z,velocity3D:Y,collisionLayer:H,aabb3DCollider:E}=q.components,X=R(W,q.id,H.layer,H.collidesWith,Z,Y);if(!B(X,q.id,T.x,T.y,T.z,H.layer,H.collidesWith,E,void 0))continue;W++}for(let q of L.sphereOnly){let{localTransform3D:T,rigidBody3D:Z,velocity3D:Y,collisionLayer:H,sphereCollider:E}=q.components,X=R(W,q.id,H.layer,H.collidesWith,Z,Y);if(!B(X,q.id,T.x,T.y,T.z,H.layer,H.collidesWith,void 0,E))continue;W++}for(let q of L.both){let{localTransform3D:T,rigidBody3D:Z,velocity3D:Y,collisionLayer:H,aabb3DCollider:E,sphereCollider:X}=q.components,_=R(W,q.id,H.layer,H.collidesWith,Z,Y);if(!B(_,q.id,T.x,T.y,T.z,H.layer,H.collidesWith,E,X))continue;W++}if(!U)z=P.tryGetResource("spatialIndex3D"),U=!0;h(k,W,F,z,i,P)})})}export{FJ as setVelocity3D,$J as createRigidBody3D,GJ as createPhysics3DPlugin,OJ as createForce3D,UJ as applyImpulse3D,jJ as applyForce3D};
//# debugId=FABAD286A305821E64756E2164756E21
//# sourceMappingURL=physics3D.js.map