UNPKG

ecspresso

Version:

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

5 lines (3 loc) 7.52 kB
var t=(($)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy($,{get:(z,R)=>(typeof require<"u"?require:z)[R]}):$)(function($){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+$+'" is not supported')});import{definePlugin as r}from"ecspresso";var v={traumaDecay:1,maxOffsetX:10,maxOffsetY:10,maxRotation:0.05},X={smoothing:5,deadzoneX:0,deadzoneY:0,offsetX:0,offsetY:0};function jj($,z,R){let H=$-(R.x+R.shakeOffsetX),B=z-(R.y+R.shakeOffsetY),b=-(R.rotation+R.shakeRotation),E=Math.cos(b),W=Math.sin(b),L=H*E-B*W,U=H*W+B*E;return{x:L*R.zoom+R.viewportWidth/2,y:U*R.zoom+R.viewportHeight/2}}function c($,z,R){let H=($-R.viewportWidth/2)/R.zoom,B=(z-R.viewportHeight/2)/R.zoom,b=R.rotation+R.shakeRotation,E=Math.cos(b),W=Math.sin(b),L=H*E-B*W,U=H*W+B*E;return{x:L+R.x+R.shakeOffsetX,y:U+R.y+R.shakeOffsetY}}function o($){return typeof $==="number"?$:$.id}function w($){let z=$===!0?{}:$;return{trauma:0,traumaDecay:z.traumaDecay??v.traumaDecay,maxOffsetX:z.maxOffsetX??v.maxOffsetX,maxOffsetY:z.maxOffsetY??v.maxOffsetY,maxRotation:z.maxRotation??v.maxRotation}}function s($){if(Array.isArray($))return{minX:$[0],minY:$[1],maxX:$[2],maxY:$[3]};return{...$}}function u($){return{smoothing:$?.smoothing??X.smoothing,deadzoneX:$?.deadzoneX??X.deadzoneX,deadzoneY:$?.deadzoneY??X.deadzoneY,offsetX:$?.offsetX??X.offsetX,offsetY:$?.offsetY??X.offsetY}}function Jj($){let{viewportWidth:z=800,viewportHeight:R=600,initial:H,follow:B,shake:b,bounds:E,zoom:W,pan:L,systemGroup:U="camera",phase:Y="postUpdate",randomFn:F=Math.random}=$??{};return r("camera").withComponentTypes().withResourceTypes().withLabels().withGroups().requires().install((D)=>{let j={x:H?.x??0,y:H?.y??0,zoom:H?.zoom??1,rotation:H?.rotation??0,shakeOffsetX:0,shakeOffsetY:0,shakeRotation:0,viewportWidth:z,viewportHeight:R,entityId:-1,follow:()=>{},unfollow:()=>{},setPosition:()=>{},setZoom:()=>{},setRotation:()=>{},setBounds:()=>{},clearBounds:()=>{},addTrauma:()=>{}};if(D.addResource("cameraState",j),D.addSystem("camera-init").inGroup(U).setOnInitialize((V)=>{let I=V.spawn({camera:{x:H?.x??0,y:H?.y??0,zoom:H?.zoom??1,rotation:H?.rotation??0}});if(B)V.addComponent(I.id,"cameraFollow",{target:-1,...u(B)});if(b)V.addComponent(I.id,"cameraShake",w(b));if(E)V.addComponent(I.id,"cameraBounds",s(E));j.entityId=I.id,j.follow=(Q,J)=>{let P={target:o(Q),...u(J)},N=V.getComponent(j.entityId,"cameraFollow");if(N)N.target=P.target,N.smoothing=P.smoothing,N.deadzoneX=P.deadzoneX,N.deadzoneY=P.deadzoneY,N.offsetX=P.offsetX,N.offsetY=P.offsetY;else V.addComponent(j.entityId,"cameraFollow",P)},j.unfollow=()=>{if(V.getComponent(j.entityId,"cameraFollow"))V.removeComponent(j.entityId,"cameraFollow")},j.setPosition=(Q,J)=>{let G=V.getComponent(j.entityId,"camera");if(!G)return;G.x=Q,G.y=J},j.setZoom=(Q)=>{let J=V.getComponent(j.entityId,"camera");if(!J)return;J.zoom=Q},j.setRotation=(Q)=>{let J=V.getComponent(j.entityId,"camera");if(!J)return;J.rotation=Q},j.setBounds=(Q,J,G,P)=>{let N=V.getComponent(j.entityId,"cameraBounds");if(N)N.minX=Q,N.minY=J,N.maxX=G,N.maxY=P;else V.addComponent(j.entityId,"cameraBounds",{minX:Q,minY:J,maxX:G,maxY:P})},j.clearBounds=()=>{if(V.getComponent(j.entityId,"cameraBounds"))V.removeComponent(j.entityId,"cameraBounds")},j.addTrauma=(Q)=>{let J=V.getComponent(j.entityId,"cameraShake");if(J)J.trauma=Math.min(1,Math.max(0,J.trauma+Q));else V.addComponent(j.entityId,"cameraShake",{...w(!0),trauma:Math.min(1,Math.max(0,Q))})}}),D.addSystem("camera-follow").setPriority(400).inPhase(Y).inGroup(U).addQuery("cameras",{with:["camera","cameraFollow"]}).setProcess(({queries:V,dt:I,ecs:Q})=>{let J=Math.min(1,I);for(let G of V.cameras){let{camera:P,cameraFollow:N}=G.components;if(N.target<0)continue;let Z=Q.getComponent(N.target,"worldTransform");if(!Z)continue;let q=Z.x+N.offsetX,M=Z.y+N.offsetY,_=q-P.x,C=M-P.y;if(Math.abs(_)>N.deadzoneX){let K=_>0?1:-1,T=_-K*N.deadzoneX,A=Math.min(1,N.smoothing*J);P.x+=T*A}if(Math.abs(C)>N.deadzoneY){let K=C>0?1:-1,T=C-K*N.deadzoneY,A=Math.min(1,N.smoothing*J);P.y+=T*A}}}),D.addSystem("camera-shake-update").setPriority(390).inPhase(Y).inGroup(U).addQuery("shakeCameras",{with:["camera","cameraShake"]}).setProcess(({queries:V,dt:I})=>{for(let Q of V.shakeCameras){let{cameraShake:J}=Q.components;J.trauma=Math.max(0,J.trauma-J.traumaDecay*I)}}),D.addSystem("camera-bounds").setPriority(380).inPhase(Y).inGroup(U).addQuery("boundedCameras",{with:["camera","cameraBounds"]}).setProcess(({queries:V})=>{for(let I of V.boundedCameras){let{camera:Q,cameraBounds:J}=I.components,G=j.viewportWidth/(2*Q.zoom),P=j.viewportHeight/(2*Q.zoom),N=J.minX+G,Z=J.maxX-G,q=J.minY+P,M=J.maxY-P;if(N>Z)Q.x=(J.minX+J.maxX)/2;else Q.x=Math.max(N,Math.min(Z,Q.x));if(q>M)Q.y=(J.minY+J.maxY)/2;else Q.y=Math.max(q,Math.min(M,Q.y))}}),D.addSystem("camera-state-sync").setPriority(370).inPhase(Y).inGroup(U).setProcess(({ecs:V})=>{let I=V.getComponent(j.entityId,"camera");if(!I){j.x=0,j.y=0,j.zoom=1,j.rotation=0,j.shakeOffsetX=0,j.shakeOffsetY=0,j.shakeRotation=0;return}j.x=I.x,j.y=I.y,j.zoom=I.zoom,j.rotation=I.rotation;let Q=V.getComponent(j.entityId,"cameraShake");if(Q&&Q.trauma>0){let J=Q.trauma*Q.trauma;j.shakeOffsetX=Q.maxOffsetX*J*(F()*2-1),j.shakeOffsetY=Q.maxOffsetY*J*(F()*2-1),j.shakeRotation=Q.maxRotation*J*(F()*2-1)}else j.shakeOffsetX=0,j.shakeOffsetY=0,j.shakeRotation=0}),W){let Z=function(q){q.preventDefault(),J+=Math.sign(q.deltaY)},{zoomStep:V=0.1,minZoom:I=0.1,maxZoom:Q=10}=W,J=0,G=!1,P,N;D.addSystem("camera-zoom").setPriority(410).inPhase("preUpdate").inGroup(U).addQuery("cameras",{with:["camera"]}).setOnInitialize((q)=>{let M=q.tryGetResource("inputState"),_=q.tryGetResource("pixiApp");if(!M||!_){console.error("[camera] zoom requires the input plugin and renderer2D plugin. Zoom will be disabled.");return}P=_.canvas,P.addEventListener("wheel",Z,{passive:!1}),N=q.tryGetResource("isoProjection"),G=!0}).setOnDetach(()=>{if(!G||!P)return;P.removeEventListener("wheel",Z)}).setProcess(({queries:q,ecs:M})=>{if(!G||J===0)return;let _=J;J=0;let[C]=q.cameras;if(!C)return;let K=C.components.camera,T=M.tryGetResource("inputState");if(!T)return;let A=_>0?1-V:1+V,k=Math.max(I,Math.min(Q,K.zoom*Math.pow(A,Math.abs(_))));if(N&&P){let O=P.getBoundingClientRect(),y=T.pointer.position.x-(O.left+O.width/2),h=T.pointer.position.y-(O.top+O.height/2),f=N.tileWidth/2,p=N.tileHeight/2,d=(K.x-K.y)*f+N.originX,S=(K.x+K.y)*p+N.originY,l=d+y/K.zoom,m=S+h/K.zoom;K.zoom=k;let i=l-y/k,n=m-h/k,x=i-N.originX,g=n-N.originY;K.x=x/N.tileWidth+g/N.tileHeight,K.y=-x/N.tileWidth+g/N.tileHeight}else{let O=c(T.pointer.position.x,T.pointer.position.y,j);K.zoom=k,K.x=O.x-(T.pointer.position.x-j.viewportWidth/2)/k,K.y=O.y-(T.pointer.position.y-j.viewportHeight/2)/k}})}if(L){let{speed:V,actions:I}=L,Q=I?.up??"panUp",J=I?.down??"panDown",G=I?.left??"panLeft",P=I?.right??"panRight",N=!1;D.addSystem("camera-pan").setPriority(420).inPhase("preUpdate").inGroup(U).setOnInitialize((Z)=>{if(!Z.tryGetResource("inputState")){console.error("[camera] pan requires the input plugin. Pan will be disabled.");return}N=!0}).setProcess(({ecs:Z,dt:q})=>{if(!N)return;let M=Z.tryGetResource("inputState");if(!M)return;let _=V/j.zoom*q,C=(M.actions.isActive(P)?1:0)-(M.actions.isActive(G)?1:0),K=(M.actions.isActive(J)?1:0)-(M.actions.isActive(Q)?1:0);if(C!==0||K!==0)j.setPosition(j.x+C*_,j.y+K*_)})}})}export{jj as worldToScreen,c as screenToWorld,Jj as createCameraPlugin}; //# debugId=25B2568457374CA064756E2164756E21 //# sourceMappingURL=camera.js.map