UNPKG

ecspresso

Version:

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

5 lines (3 loc) 10.3 kB
var kz=((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 Vz}from"ecspresso";function s(z){let J=new Map,K=new WeakMap,G=1;function j($){let Q=J.get($);if(Q!==void 0)return Q;if(G===0)throw Error(`[ecspresso] ${z} layer bitmask overflow: more than 32 distinct layers registered`);let D=G;return J.set($,D),G<<=1,D}function O($){let Q=K.get($);if(Q!==void 0)return Q;let D=0;for(let N=0;N<$.length;N++)D|=j($[N]);return K.set($,D),D}return{getLayerBit:j,getCollidesWithMask:O}}var f={normalX:0,normalY:0,depth:0},S=0,v=1,a=s("Collision"),Qz=a.getLayerBit,Zz=a.getCollidesWithMask;function g(z,J,K,G,j,O,$,Q){if(z.entityId=J,z.layer=j,z.collidesWith=O,z.layerBit=Qz(j),z.collidesWithMask=Zz(O),$)return z.x=K+($.offsetX??0),z.y=G+($.offsetY??0),z.shape=S,z.halfWidth=$.width/2,z.halfHeight=$.height/2,z.radius=0,!0;if(Q)return z.x=K+(Q.offsetX??0),z.y=G+(Q.offsetY??0),z.shape=v,z.halfWidth=0,z.halfHeight=0,z.radius=Q.radius,!0;return!1}function $z(z,J,K,G,j,O,$,Q,D){let N=j-z,Z=O-J,U=K+$-Math.abs(N),V=G+Q-Math.abs(Z);if(U<=0||V<=0)return!1;if(U<V)return D.normalX=N>=0?1:-1,D.normalY=0,D.depth=U,!0;return D.normalX=0,D.normalY=Z>=0?1:-1,D.depth=V,!0}function jz(z,J,K,G,j,O,$){let Q=G-z,D=j-J,N=Q*Q+D*D,Z=K+O;if(N>=Z*Z)return!1;let U=Math.sqrt(N);if(U===0)return $.normalX=1,$.normalY=0,$.depth=Z,!0;return $.normalX=Q/U,$.normalY=D/U,$.depth=Z-U,!0}function c(z,J,K,G,j,O,$,Q){let D=Math.max(z-K,Math.min(j,z+K)),N=Math.max(J-G,Math.min(O,J+G)),Z=j-D,U=O-N,V=Z*Z+U*U;if(V>=$*$)return!1;if(V===0){let k=j-(z-K),T=z+K-j,L=O-(J-G),H=J+G-O,M=Math.min(k,T,L,H);if(M===T)return Q.normalX=1,Q.normalY=0,Q.depth=T+$,!0;if(M===k)return Q.normalX=-1,Q.normalY=0,Q.depth=k+$,!0;if(M===H)return Q.normalX=0,Q.normalY=1,Q.depth=H+$,!0;return Q.normalX=0,Q.normalY=-1,Q.depth=L+$,!0}let F=Math.sqrt(V);return Q.normalX=Z/F,Q.normalY=U/F,Q.depth=$-F,!0}function e(z,J,K){if(z.shape===S&&J.shape===S)return $z(z.x,z.y,z.halfWidth,z.halfHeight,J.x,J.y,J.halfWidth,J.halfHeight,K);if(z.shape===v&&J.shape===v)return jz(z.x,z.y,z.radius,J.x,J.y,J.radius,K);if(z.shape===S&&J.shape===v)return c(z.x,z.y,z.halfWidth,z.halfHeight,J.x,J.y,J.radius,K);if(!c(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 u=[];function t(){return{arr:[],gen:[],current:0}}var i=!1,Uz=50;function o(z,J,K,G,j,O){if(G)Gz(z,J,K,G,j,O);else Oz(z,J,j,O)}function Oz(z,J,K,G){if(!i&&J>=Uz)i=!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 j=0;j<J;j++){let O=z[j];if(!O)continue;for(let $=j+1;$<J;$++){let Q=z[$];if(!Q)continue;if((O.collidesWithMask&Q.layerBit|Q.collidesWithMask&O.layerBit)===0)continue;if(!e(O,Q,f))continue;K(O,Q,f,G)}}}function Gz(z,J,K,G,j,O){let{arr:$,gen:Q}=K,D=++K.current;for(let N=0;N<J;N++){let Z=z[N];if(!Z)continue;let U=Z.entityId;$[U]=Z,Q[U]=D}for(let N=0;N<J;N++){let Z=z[N];if(!Z)continue;let U=Z.shape===S?Z.halfWidth:Z.radius,V=Z.shape===S?Z.halfHeight:Z.radius;u.length=0,G.queryRectInto(Z.x-U,Z.y-V,Z.x+U,Z.y+V,u,Z.entityId);for(let F of u){if(Q[F]!==D)continue;let k=$[F];if(!k)continue;if((Z.collidesWithMask&k.layerBit|k.collidesWithMask&Z.layerBit)===0)continue;if(!e(Z,k,f))continue;j(Z,k,f,O)}}}function Mz(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 Wz(z,J){return{force:{x:z,y:J}}}function zz(z,J,K,G){let j=z.getComponent(J,"force");if(!j)return;j.x+=K,j.y+=G}function Pz(z,J,K,G){let j=z.getComponent(J,"velocity"),O=z.getComponent(J,"rigidBody");if(!j||!O)return;if(O.mass===1/0||O.mass===0)return;j.x+=K/O.mass,j.y+=G/O.mass}function Ez(z,J,K,G){let j=z.getComponent(J,"velocity");if(!j)return;j.x=K,j.y=G}var B={entityA:0,entityB:0,normalX:0,normalY:0,depth:0};function Dz(z,J,K,G){let j=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,$=j+O;if($>0){let Q=K.depth/$;if(j>0){let U=G.getComponent(z.entityId,"localTransform");if(!U)return;let V=Q*j;U.x-=V*K.normalX,U.y-=V*K.normalY,z.x=U.x,z.y=U.y,G.markChanged(z.entityId,"localTransform")}if(O>0){let U=G.getComponent(J.entityId,"localTransform");if(!U)return;let V=Q*O;U.x+=V*K.normalX,U.y+=V*K.normalY,J.x=U.x,J.y=U.y,G.markChanged(J.entityId,"localTransform")}let D=J.velocity.x-z.velocity.x,N=J.velocity.y-z.velocity.y,Z=D*K.normalX+N*K.normalY;if(Z<0){let V=-(1+Math.min(z.rigidBody.restitution,J.rigidBody.restitution))*Z/$;z.velocity.x-=V*j*K.normalX,z.velocity.y-=V*j*K.normalY,J.velocity.x+=V*O*K.normalX,J.velocity.y+=V*O*K.normalY;let F=D-Z*K.normalX,k=N-Z*K.normalY,T=Math.sqrt(F*F+k*k);if(T>0.000001){let L=F/T,H=k/T,P=Math.sqrt(z.rigidBody.friction*J.rigidBody.friction)*Math.abs(V),R=Math.min(T/$,P);z.velocity.x+=R*j*L,z.velocity.y+=R*j*H,J.velocity.x-=R*O*L,J.velocity.y-=R*O*H}}G.markChanged(z.entityId,"velocity"),G.markChanged(J.entityId,"velocity")}B.entityA=z.entityId,B.entityB=J.entityId,B.normalX=K.normalX,B.normalY=K.normalY,B.depth=K.depth,G.eventBus.publish("physicsCollision",B)}function Xz(z){let{gravity:J={x:0,y:0},systemGroup:K="physics2D",collisionSystemGroup:G,integrationPriority:j=1000,collisionPriority:O=900,phase:$="fixedUpdate"}=z??{};return Vz("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(j).inPhase($).inGroup(K).addQuery("bodies",{with:["localTransform","velocity","rigidBody","force"]}).setProcess(({queries:k,dt:T,ecs:L})=>{let{gravity:H}=L.getResource("physicsConfig"),M=H.x,P=H.y;for(let R of k.bodies){let{localTransform:q,velocity:W,rigidBody:E,force:X}=R.components;if(E.type==="static")continue;if(E.type==="dynamic"){let x=E.gravityScale*T;W.x+=M*x,W.y+=P*x;let A=E.mass;if(A>0&&A!==1/0){let _=T/A;W.x+=X.x*_,W.y+=X.y*_}if(E.drag>0){let _=Math.max(0,1-E.drag*T);W.x*=_,W.y*=_}}q.x+=W.x*T,q.y+=W.y*T,X.x=0,X.y=0,L.markChanged(R.id,"localTransform")}});let D=Q.addSystem("physics2D-collision").setPriority(O).inPhase($).inGroup(K);if(G)D.inGroup(G);let N=[],Z=t(),U,V=!1,F=(k,T,L,H,M,P)=>{let R=N[k];if(!R)R={entityId:T,x:0,y:0,layer:L,collidesWith:H,layerBit:0,collidesWithMask:0,shape:S,halfWidth:0,halfHeight:0,radius:0,rigidBody:M,velocity:P},N[k]=R;else R.rigidBody=M,R.velocity=P;return R};D.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:T})=>{let L=0;for(let H of k.aabbOnly){let{localTransform:M,rigidBody:P,velocity:R,collisionLayer:q,aabbCollider:W}=H.components,E=F(L,H.id,q.layer,q.collidesWith,P,R);if(!g(E,H.id,M.x,M.y,q.layer,q.collidesWith,W,void 0))continue;L++}for(let H of k.circleOnly){let{localTransform:M,rigidBody:P,velocity:R,collisionLayer:q,circleCollider:W}=H.components,E=F(L,H.id,q.layer,q.collidesWith,P,R);if(!g(E,H.id,M.x,M.y,q.layer,q.collidesWith,void 0,W))continue;L++}for(let H of k.both){let{localTransform:M,rigidBody:P,velocity:R,collisionLayer:q,aabbCollider:W,circleCollider:E}=H.components,X=F(L,H.id,q.layer,q.collidesWith,P,R);if(!g(X,H.id,M.x,M.y,q.layer,q.collidesWith,W,E))continue;L++}if(!V)U=T.tryGetResource("spatialIndex"),V=!0;o(N,L,Z,U,Dz,T)})})}import{definePlugin as Nz}from"ecspresso";function Iz(z){return{flockingAgent:{perceptionRadius:z?.perceptionRadius??100,separationWeight:z?.separationWeight??1.5,alignmentWeight:z?.alignmentWeight??1,cohesionWeight:z?.cohesionWeight??1,maxForce:z?.maxForce??400,maxSpeed:z?.maxSpeed??200,flockGroup:z?.flockGroup??0}}}var d=[],Jz=0.01;function Sz(z){let{systemGroup:J="ai",priority:K=500,phase:G="update",headingPriority:j=200}=z??{};return Nz("flocking").withComponentTypes().withLabels().withGroups().requires().install((O)=>{O.addSystem("flocking-forces").setPriority(K).inPhase(G).inGroup(J).addQuery("boids",{with:["flockingAgent","worldTransform","velocity","force"]}).setProcess(({queries:$,ecs:Q})=>{let D=Q.getResource("spatialIndex");for(let N of $.boids){let{flockingAgent:Z,worldTransform:U,velocity:V}=N.components,{perceptionRadius:F,separationWeight:k,alignmentWeight:T,cohesionWeight:L,maxForce:H,flockGroup:M}=Z;d.length=0,D.queryRadiusInto(U.x,U.y,F,d);let P=0,R=0,q=0,W=0,E=0,X=0,x=0,A=0,_=0,r=F*0.5,Kz=r*r;for(let Y of d){if(Y===N.id)continue;let C=Q.getComponent(Y,"flockingAgent");if(!C)continue;if(C.flockGroup!==M)continue;let m=Q.getComponent(Y,"worldTransform");if(!m)continue;let p=U.x-m.x,h=U.y-m.y,b=p*p+h*h;if(b>0&&b<Kz){let n=Math.sqrt(b);P+=p/n,R+=h/n,q++}let y=Q.getComponent(Y,"velocity");if(y)W+=y.x,E+=y.y,X++;x+=m.x,A+=m.y,_++}let w=0,I=0;if(q>0)w+=P/q*k,I+=R/q*k;if(X>0){let Y=W/X,C=E/X;w+=(Y-V.x)*T,I+=(C-V.y)*T}if(_>0){let Y=x/_,C=A/_;w+=(Y-U.x-V.x)*L,I+=(C-U.y-V.y)*L}let l=w*w+I*I;if(l>H*H){let Y=Math.sqrt(l);w=w/Y*H,I=I/Y*H}zz(Q,N.id,w,I)}}),O.addSystem("flocking-heading").setPriority(j).inPhase(G).inGroup(J).addQuery("boids",{with:["flockingAgent","velocity","localTransform"]}).setProcess(({queries:$,ecs:Q})=>{for(let D of $.boids){let{flockingAgent:N,velocity:Z,localTransform:U}=D.components,{maxSpeed:V}=N,F=Z.x*Z.x+Z.y*Z.y;if(F>V*V){let k=Math.sqrt(F);Z.x=Z.x/k*V,Z.y=Z.y/k*V,Q.markChanged(D.id,"velocity")}if(F>Jz*Jz){let k=Math.atan2(Z.y,Z.x);if(k!==U.rotation)U.rotation=k,Q.markChanged(D.id,"localTransform")}}})})}export{Sz as createFlockingPlugin,Iz as createFlockingAgent}; //# debugId=3BF6BCC8003D861864756E2164756E21 //# sourceMappingURL=flocking.js.map