UNPKG

ecspresso

Version:

A minimal Entity-Component-System library for typescript and javascript.

5 lines (3 loc) 8.3 kB
var e=((z)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(z,{get:(J,K)=>(typeof require<"u"?require:J)[K]}):z)(function(z){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+z+'" is not supported')});import{definePlugin as c}from"ecspresso";function B(z){let J=new Map,K=new WeakMap,j=1;function Z($){let Q=J.get($);if(Q!==void 0)return Q;if(j===0)throw Error(`[ecspresso] ${z} layer bitmask overflow: more than 32 distinct layers registered`);let V=j;return J.set($,V),j<<=1,V}function O($){let Q=K.get($);if(Q!==void 0)return Q;let V=0;for(let G=0;G<$.length;G++)V|=Z($[G]);return K.set($,V),V}return{getLayerBit:Z,getCollidesWithMask:O}}var I={normalX:0,normalY:0,depth:0},X=0,S=1,f=B("Collision"),b=f.getLayerBit,u=f.getCollidesWithMask;function C(z,J,K,j,Z,O,$,Q){if(z.entityId=J,z.layer=Z,z.collidesWith=O,z.layerBit=b(Z),z.collidesWithMask=u(O),$)return z.x=K+($.offsetX??0),z.y=j+($.offsetY??0),z.shape=X,z.halfWidth=$.width/2,z.halfHeight=$.height/2,z.radius=0,!0;if(Q)return z.x=K+(Q.offsetX??0),z.y=j+(Q.offsetY??0),z.shape=S,z.halfWidth=0,z.halfHeight=0,z.radius=Q.radius,!0;return!1}function d(z,J,K,j,Z,O,$,Q,V){let G=Z-z,U=O-J,F=K+$-Math.abs(G),D=j+Q-Math.abs(U);if(F<=0||D<=0)return!1;if(F<D)return V.normalX=G>=0?1:-1,V.normalY=0,V.depth=F,!0;return V.normalX=0,V.normalY=U>=0?1:-1,V.depth=D,!0}function r(z,J,K,j,Z,O,$){let Q=j-z,V=Z-J,G=Q*Q+V*V,U=K+O;if(G>=U*U)return!1;let F=Math.sqrt(G);if(F===0)return $.normalX=1,$.normalY=0,$.depth=U,!0;return $.normalX=Q/F,$.normalY=V/F,$.depth=U-F,!0}function g(z,J,K,j,Z,O,$,Q){let V=Math.max(z-K,Math.min(Z,z+K)),G=Math.max(J-j,Math.min(O,J+j)),U=Z-V,F=O-G,D=U*U+F*F;if(D>=$*$)return!1;if(D===0){let k=Z-(z-K),q=z+K-Z,R=O-(J-j),N=J+j-O,H=Math.min(k,q,R,N);if(H===q)return Q.normalX=1,Q.normalY=0,Q.depth=q+$,!0;if(H===k)return Q.normalX=-1,Q.normalY=0,Q.depth=k+$,!0;if(H===N)return Q.normalX=0,Q.normalY=1,Q.depth=N+$,!0;return Q.normalX=0,Q.normalY=-1,Q.depth=R+$,!0}let W=Math.sqrt(D);return Q.normalX=U/W,Q.normalY=F/W,Q.depth=$-W,!0}function p(z,J,K){if(z.shape===X&&J.shape===X)return d(z.x,z.y,z.halfWidth,z.halfHeight,J.x,J.y,J.halfWidth,J.halfHeight,K);if(z.shape===S&&J.shape===S)return r(z.x,z.y,z.radius,J.x,J.y,J.radius,K);if(z.shape===X&&J.shape===S)return g(z.x,z.y,z.halfWidth,z.halfHeight,J.x,J.y,J.radius,K);if(!g(J.x,J.y,J.halfWidth,J.halfHeight,z.x,z.y,z.radius,K))return!1;return K.normalX=-K.normalX,K.normalY=-K.normalY,!0}var x=[];function h(){return{arr:[],gen:[],current:0}}var v=!1,n=50;function y(z,J,K,j,Z,O){if(j)l(z,J,K,j,Z,O);else s(z,J,Z,O)}function s(z,J,K,j){if(!v&&J>=n)v=!0,console.warn(`[ecspresso] Collision detection is using O(n²) brute force with ${J} colliders. For better performance, install createSpatialIndexPlugin() alongside your collision or physics2D plugin.`);for(let Z=0;Z<J;Z++){let O=z[Z];if(!O)continue;for(let $=Z+1;$<J;$++){let Q=z[$];if(!Q)continue;if((O.collidesWithMask&Q.layerBit|Q.collidesWithMask&O.layerBit)===0)continue;if(!p(O,Q,I))continue;K(O,Q,I,j)}}}function l(z,J,K,j,Z,O){let{arr:$,gen:Q}=K,V=++K.current;for(let G=0;G<J;G++){let U=z[G];if(!U)continue;let F=U.entityId;$[F]=U,Q[F]=V}for(let G=0;G<J;G++){let U=z[G];if(!U)continue;let F=U.shape===X?U.halfWidth:U.radius,D=U.shape===X?U.halfHeight:U.radius;x.length=0,j.queryRectInto(U.x-F,U.y-D,U.x+F,U.y+D,x,U.entityId);for(let W of x){if(Q[W]!==V)continue;let k=$[W];if(!k)continue;if((U.collidesWithMask&k.layerBit|k.collidesWithMask&U.layerBit)===0)continue;if(!p(U,k,I))continue;Z(U,k,I,O)}}}function Qz(z,J){return{rigidBody:{type:z,mass:z==="static"?1/0:J?.mass??1,drag:J?.drag??0,restitution:J?.restitution??0,friction:J?.friction??0,gravityScale:J?.gravityScale??1},force:{x:0,y:0}}}function Zz(z,J){return{force:{x:z,y:J}}}function $z(z,J,K,j){let Z=z.getComponent(J,"force");if(!Z)return;Z.x+=K,Z.y+=j}function Oz(z,J,K,j){let Z=z.getComponent(J,"velocity"),O=z.getComponent(J,"rigidBody");if(!Z||!O)return;if(O.mass===1/0||O.mass===0)return;Z.x+=K/O.mass,Z.y+=j/O.mass}function jz(z,J,K,j){let Z=z.getComponent(J,"velocity");if(!Z)return;Z.x=K,Z.y=j}var _={entityA:0,entityB:0,normalX:0,normalY:0,depth:0};function i(z,J,K,j){let Z=z.rigidBody.type==="dynamic"&&z.rigidBody.mass>0&&z.rigidBody.mass!==1/0?1/z.rigidBody.mass:0,O=J.rigidBody.type==="dynamic"&&J.rigidBody.mass>0&&J.rigidBody.mass!==1/0?1/J.rigidBody.mass:0,$=Z+O;if($>0){let Q=K.depth/$;if(Z>0){let F=j.getComponent(z.entityId,"localTransform");if(!F)return;let D=Q*Z;F.x-=D*K.normalX,F.y-=D*K.normalY,z.x=F.x,z.y=F.y,j.markChanged(z.entityId,"localTransform")}if(O>0){let F=j.getComponent(J.entityId,"localTransform");if(!F)return;let D=Q*O;F.x+=D*K.normalX,F.y+=D*K.normalY,J.x=F.x,J.y=F.y,j.markChanged(J.entityId,"localTransform")}let V=J.velocity.x-z.velocity.x,G=J.velocity.y-z.velocity.y,U=V*K.normalX+G*K.normalY;if(U<0){let D=-(1+Math.min(z.rigidBody.restitution,J.rigidBody.restitution))*U/$;z.velocity.x-=D*Z*K.normalX,z.velocity.y-=D*Z*K.normalY,J.velocity.x+=D*O*K.normalX,J.velocity.y+=D*O*K.normalY;let W=V-U*K.normalX,k=G-U*K.normalY,q=Math.sqrt(W*W+k*k);if(q>0.000001){let R=W/q,N=k/q,E=Math.sqrt(z.rigidBody.friction*J.rigidBody.friction)*Math.abs(D),T=Math.min(q/$,E);z.velocity.x+=T*Z*R,z.velocity.y+=T*Z*N,J.velocity.x-=T*O*R,J.velocity.y-=T*O*N}}j.markChanged(z.entityId,"velocity"),j.markChanged(J.entityId,"velocity")}_.entityA=z.entityId,_.entityB=J.entityId,_.normalX=K.normalX,_.normalY=K.normalY,_.depth=K.depth,j.eventBus.publish("physicsCollision",_)}function Uz(z){let{gravity:J={x:0,y:0},systemGroup:K="physics2D",collisionSystemGroup:j,integrationPriority:Z=1000,collisionPriority:O=900,phase:$="fixedUpdate"}=z??{};return c("physics2D").withComponentTypes().withEventTypes().withResourceTypes().withLabels().withGroups().requires().install((Q)=>{Q.registerRequired("rigidBody","velocity",()=>({x:0,y:0})),Q.registerRequired("rigidBody","force",()=>({x:0,y:0})),Q.addResource("physicsConfig",{gravity:{x:J.x,y:J.y}}),Q.addSystem("physics2D-integration").setPriority(Z).inPhase($).inGroup(K).addQuery("bodies",{with:["localTransform","velocity","rigidBody","force"]}).setProcess(({queries:k,dt:q,ecs:R})=>{let{gravity:N}=R.getResource("physicsConfig"),H=N.x,E=N.y;for(let T of k.bodies){let{localTransform:P,velocity:M,rigidBody:L,force:Y}=T.components;if(L.type==="static")continue;if(L.type==="dynamic"){let m=L.gravityScale*q;M.x+=H*m,M.y+=E*m;let A=L.mass;if(A>0&&A!==1/0){let w=q/A;M.x+=Y.x*w,M.y+=Y.y*w}if(L.drag>0){let w=Math.max(0,1-L.drag*q);M.x*=w,M.y*=w}}P.x+=M.x*q,P.y+=M.y*q,Y.x=0,Y.y=0,R.markChanged(T.id,"localTransform")}});let V=Q.addSystem("physics2D-collision").setPriority(O).inPhase($).inGroup(K);if(j)V.inGroup(j);let G=[],U=h(),F,D=!1,W=(k,q,R,N,H,E)=>{let T=G[k];if(!T)T={entityId:q,x:0,y:0,layer:R,collidesWith:N,layerBit:0,collidesWithMask:0,shape:X,halfWidth:0,halfHeight:0,radius:0,rigidBody:H,velocity:E},G[k]=T;else T.rigidBody=H,T.velocity=E;return T};V.addQuery("aabbOnly",{with:["localTransform","rigidBody","velocity","collisionLayer","aabbCollider"],without:["circleCollider"]}).addQuery("circleOnly",{with:["localTransform","rigidBody","velocity","collisionLayer","circleCollider"],without:["aabbCollider"]}).addQuery("both",{with:["localTransform","rigidBody","velocity","collisionLayer","aabbCollider","circleCollider"]}).setProcess(({queries:k,ecs:q})=>{let R=0;for(let N of k.aabbOnly){let{localTransform:H,rigidBody:E,velocity:T,collisionLayer:P,aabbCollider:M}=N.components,L=W(R,N.id,P.layer,P.collidesWith,E,T);if(!C(L,N.id,H.x,H.y,P.layer,P.collidesWith,M,void 0))continue;R++}for(let N of k.circleOnly){let{localTransform:H,rigidBody:E,velocity:T,collisionLayer:P,circleCollider:M}=N.components,L=W(R,N.id,P.layer,P.collidesWith,E,T);if(!C(L,N.id,H.x,H.y,P.layer,P.collidesWith,void 0,M))continue;R++}for(let N of k.both){let{localTransform:H,rigidBody:E,velocity:T,collisionLayer:P,aabbCollider:M,circleCollider:L}=N.components,Y=W(R,N.id,P.layer,P.collidesWith,E,T);if(!C(Y,N.id,H.x,H.y,P.layer,P.collidesWith,M,L))continue;R++}if(!D)F=q.tryGetResource("spatialIndex"),D=!0;y(G,R,U,F,i,q)})})}export{jz as setVelocity,Qz as createRigidBody,Uz as createPhysics2DPlugin,Zz as createForce,Oz as applyImpulse,$z as applyForce}; //# debugId=C7B6730AA14E017664756E2164756E21 //# sourceMappingURL=physics2D.js.map