Skip to main content
Inspiring
December 18, 2021
Question

Shape layer expression query.

  • December 18, 2021
  • 3 replies
  • 1038 views

Hello.

I am still trying to learn expressions in after effects. So I was stuck with something and I thought might as well ask. So I've uploaded a screenshot. My requirement is the small red shape layers should wiggle inside the big circle shape layer and should not go out of it. If it tries to go out it should like collide with the shape layer and stay inside. Is there an expression or script that allows me to wiggle but also like clamps the region of the small red shape layer to the region of the circle. 

This topic has been closed for replies.

3 replies

Dan Ebberts
Community Expert
Community Expert
December 18, 2021

If you make some assumptions, like the shape layers are centered (so thier shape transform anchor points and positions are [0,0], you can probably get away with something like this for the red dots shape position expression:

r = thisComp.layer("Shape Layer 1").content("Ellipse 1").content("Ellipse Path 1").size[0]/2;
w = wiggle(2,r);
if (length(w) > r){
  normalize(w)*r;
}else
  w
Community Expert
December 18, 2021

I knew that Dan would come up with something brilliant.

Community Expert
December 18, 2021

I would start with Dan Ebbert's Collision Detection from motionscript.com

 

In the example, Dan is controlling opacity, but you could use the same basic math to control the position and force another move. I'm not saying that it would be simple, but it could be done.

 

Here's Dan's basic code:

function getMin(a, b, c, d){
  return Math.min(Math.min(a,b),Math.min(c,d));
}

function getMax(a, b, c, d){
  return Math.max(Math.max(a,b),Math.max(c,d));
}

function getBoundingBox(theLayer){
  bb = [];
  c1 = theLayer.toWorld([0,0]);
  c2 = theLayer.toWorld([theLayer.width,0]);
  c3 = theLayer.toWorld([theLayer.width,theLayer.height]);
  c4 = theLayer.toWorld([0,theLayer.height]);
  bb[0] = getMin(c1[0],c2[0],c3[0],c4[0]);
  bb[1] = getMin(c1[1],c2[1],c3[1],c4[1]);
  bb[2] = getMax(c1[0],c2[0],c3[0],c4[0]);
  bb[3] = getMax(c1[1],c2[1],c3[1],c4[1]);
  return bb;
}

function checkLayers(){
  cUL = [];
  cLR = [];
  for ( idx = 1; idx <= thisComp.numLayers; idx++){
    if (index == idx) continue;
    L = thisComp.layer(idx);
    if (! L.active) continue;
    BB = getBoundingBox(L);
    UL = [BB[0],BB[1]];
    LR = [BB[2],BB[3]];

    if (!(myLR[1] < UL[1] || LR[1] < myUL[1] ||
          myLR[0] < UL[0] || LR[0] < myUL[0])){

      cUL[1] = (myUL[1] < UL[1]) ? UL[1] : myUL[1];
      cUL[0] = (myUL[0] < UL[0]) ? UL[0] : myUL[0];
      cLR[1] = (myLR[1] < LR[1]) ? myLR[1] : LR[1];
      cLR[0] = (myLR[0] < LR[0]) ? myLR[0] : LR[0];

      for(i = cUL[0]; i <= cLR[0]; i++){
        for (j = cUL[1]; j <= cLR[1]; j++){
          if (sampleImage(fromWorld([i,j]))[3] > 0 &&
              L.sampleImage(L.fromWorld([i,j]))[3] > 0){

            return true;
          }
        }
      }
    }
  }
  return false;
}

myBB = getBoundingBox(thisLayer);
myUL = [myBB[0],myBB[1]];
myLR = [myBB[2],myBB[3]];

if (checkLayers()){ 100 }else{ 30 }

As I said, this is controlling opacity, but it could be set to trigger a change in direction.

 

The other option: Newton. If your time is worth $50/hr and it takes you 4 hours to figure out the code you have more than paid for Newton.

Mylenium
Legend
December 18, 2021

Is it doable? Yes, just not with a "dumb" wiggle. Since there is no simple collision function in the expression engine, you'd have to check the position against the parametric definition of a circle with sinus and cosinus and then it turns into quite some math. A simplification of this might be to wiggle along the radius of the circle, but then of course the motion looks different. So there you have it. It would take soem time to sit down and craft the code. Other than that if you really just want some round blobs to bounce off a mask in 2D give good old Particle Playground a try.

 

Mylenium