Creative Communities of the World Forums

The peer to peer support community for media production professionals.

Activity Forums Adobe After Effects Expressions Move a layer according to its own location

  • Move a layer according to its own location

    Posted by Sam Beckett on November 23, 2020 at 11:19 pm

    Hi I would like to move a layer according to its own location.

    Here is an example with its current location :

    [transform.position[0] + 100 , transform.position[1]]

    According to time, the layer doesn’t move because I cannot read the red value of each position axis.

    Here is an example with its previous location :

    x = thisComp.layer(index).transform.position.valueAtTime(time-1/25)[0] ;
    y = thisComp.layer(index).transform.position.valueAtTime(time-1/25)[1] ;
    [x+100, y]

    Again, the thing is that After Effects seems to read the blue (manual) values instead of the red (scripted) ones.

    Is there any way to read the real position (red) instead of the blue one ?

    The reason why I need to read the location of the current layer is because I want this layer to move according to the location of some other layers so that each react independantly.

    If I want each layer to spread, I just have to make each layer move away from its closest neighboor :

    NbLayers = comp(“Repartition”).numLayers ;
    seedRandom(0, timeless = true) ;

    if (time == 0){
    X_Pos = random(1920) ;
    Y_Pos = random(1080) ;
    }else{
    X_Pos = thisComp.layer(index).transform.position.valueAtTime(time-1/25)[0] ;
    Y_Pos = thisComp.layer(index).transform.position.valueAtTime(time-1/25)[1] ;
    }

    ModuleTest = 1920 ;
    Module = 1920 ;

    // We look for the closest layer
    for (i = 1; i < NbLayers ; i++){
    if(i != index){
    // We don’t consider the current layer.
    X_Calc = thisComp.layer(i).transform.position.value[0] ;
    Y_Calc = thisComp.layer(i).transform.position.value[1] ;
    ModuleTest = Math.sqrt((X_Pos-X_Calc)*(X_Pos-X_Calc)+(Y_Pos-Y_Calc)*(Y_Pos-Y_Calc)) ;
    if(ModuleTest < Module){
    // We found a layer that is closer than the previous one
    // We keep its relative position
    Module = ModuleTest ;
    Argument = Math.atan2(Y_Pos – Y_Calc, X_Pos – X_Calc) ;
    }
    }
    }

    // Let’s move away from this layer
    ArgumentDep = Argument ;
    X_Dep = Math.cos(ArgumentDep) ;
    Y_Dep = Math.sin(ArgumentDep) ;

    [X_Pos + X_Dep , Y_Pos + Y_Dep]

    (Of course I will limit the movement of each layer to the area of the comp (1920×1080 for instance) which is not a big deal.)
    <div>

    Anyway I cannot figure this out and I have not found any clue in the forum. Please could you give me some ways to fix this ?

    </div>

    Sam Beckett replied 5 years, 5 months ago 3 Members · 5 Replies
  • 5 Replies
  • Dan Ebberts

    November 23, 2020 at 11:34 pm

    The way expressions work is that an expression can only access the pre-expression value of the property hosting the expression. That means an expression has no access to results it calculated on other frames, only the keyframed (or static) value.

    However, when an expression accesses the value of any other property, it gets the post-expression value of that property.

    Depending on what you’re trying to do, there are usually ways to work around these “limitations”. However, if what you’re trying to do involves one or more expressions that affect the results of each other (creating a feedback loop) you may be in for disappointment.

  • Sam Beckett

    November 23, 2020 at 11:56 pm

    Thanks a lot for your reply Dan.

    I don’t expect any problem because each layer at a time makes a move (of any defined value) then the next frame launches the process again.

    But without considering this, let’s imagine the comp has only one layer. How would you move it according to its current location ?

    Here is a random example :

    During this frame :
    if its “x” value is odd, then add one to its “y” value
    else, then substract one to its “y” value
    if its “y” value is a multiple of 3, then add 1 to its “x” value
    else, then substract one to its “x” value
    [x,y]

    And next frame, the script restatrs its routine and the layer moves in a certain way.

  • Stephen Dixon

    November 24, 2020 at 12:16 am

    Since expressions aren’t able to store previous values, to achieve something like this you have to calculate the results for every frame up to the current one.

    e.g.

    calculatedPos = thisProperty.valueAtTime(0); //initial (blue) value
    for (let f = 0; f < time; f += thisComp.frameDuration){
    if (calculatedPos[0] % 2 > 0){ //x is odd
    calculatedPos[1]++ //add one to y
    }
    if (calculatedPos[1] % 3 === 0){ // y is multiple of 3
    calculatedPos[0]++ //add 1 to x
    } else {
    calculatedPos[0]-- //subtract 1 from x
    }
    }
    caculatedPos
  • Dan Ebberts

    November 24, 2020 at 12:27 am

    Generally, you have to convert the calculation to be time-based. If you can’t come up with a formula based on the current time (or frame number) then you can use the brute-force method, where you start at time = 0 and loop frame-by-frame to calculate the current result. Your example would look something like this:

    val = valueAtTime(0);

    f = 1;

    while (f <= timeToFrames(time)){

    val += val[0]%2 ? [0,1] : [0,-1];

    val += val[1]%3 == 0 ? [1,0] : [-1,0];

    f++;

    }

    val

  • Sam Beckett

    November 24, 2020 at 7:06 am

    Thank you Dan.

    I tried to add two slider controls that get the value of position. Then I tried to real these values.

    I have 3 layers but only one has expressions.

    Slider Control X :

    Initialized to 1 (blue value)

    transform.position[0]


    Slider Control Y :

    Initialized to 1

    transform.position[1]


    Layer Position :

    Initialized to [1000,500]

    seedRandom(0, timeless = true) ;
    X_Pos = effect(“X“)(“Control“) ;
    Y_Pos = effect(“Y“)(“Control“) ;

    But it behaves the same. The layer doesn’t move frame by frame.

    _______________________________________________________

    As you suggest, I will have to calculate all the positions of every frames of every layers till the current time.

    Each frame, the expression will recalculate all these and place the current layer according to time.

    ?To achieve this I will need to store all these informations into a 3 dimentional array (not a 3 cells array like a 3D position). I know this exists in C/C++ but does it in javascript ?

We use anonymous cookies to give you the best experience we can.
Our Privacy policy | GDPR Policy