Scripting For Loop Issue

Hello,

I am trying to create a small script that does the following:

On Key Press:

  1. Look at a particular framebuffer.
  2. Get the takeID of items on layers -99 to 99.
  3. Execute for layers that have something on them.

The script I wrote is as follows:

Sub OnKeyPress (Engine as xpEngine)
dim takeitem as xpBaseTakeItem
dim fb as xpOutputFrameBuffer
dim layer as integer

engine.GetOutputFrameBuffer(0,fb)
for layer = -99 to 99
fb.GetTakeItemOnLayer(layer,takeitem)
if takeitem.IsOnline() then
takeitem.Execute
end if
next​

The script does not do anything if the for loop is active. When I comment out the for loop, it works perfectly for anything on layer 0. Any help on this would be appreciated.

Thanks!

Surely if you are finding them online then execute doesn’t do anything as they are already online?

Sorry, I should have clarified. In this project, execute once to take on, execute again to take off. We do not use any take offline or separate functions to animate off.

Originally posted by ****

The script is failing when it tries to get a take item on an empty layer – in this case, once it fails to find a take item on layer -99, it stops running, so an item on any other layer in the loop won’t be evaluated.

This can be easily fixed by nesting another if-then statement to evaluate if an item was found on the layer or not. The xpOutputFrameBuffer.getTakeItemOnLayer method, like most of the other “get” methods, returns true/false values. So the fix would be:

if fb.GetTakeItemOnLayer(layer,takeitem) then
	if takeitem.IsOnline() then
		takeitem.Execute
	end if
end if​

You may also be interested in xpOutputFrameBuffer.getTakeItem, added in version 10, which simply gets online take items by index rather than layer. That way you don’t have to loop through 200 layers, and it will never fail because it’s always getting items that are already online. For example:

dim fb as xpOutputFrameBuffer
engine.getOutputFrameBuffer(0,fb)

dim take as xpTakeItem

'UsedLayerCount returns how many items are online (-1 because the index starts at 0)
for i as integer = 0 to fb.usedLayerCount - 1
fb.getTakeItem(i,take)
if take.isOnline then
take.execute
end if
next​

Ah that makes perfect sense as to why it was failing out, didn’t realize the test ended if no value was found on the first loop. Thanks so much! When we update to v10, I will take a look at that other method.

Thanks again!

I like that second option, didn’t know that was a thing, thanks Greg!

Thank you again for your help. While working with this script I have noticed that if there is a pause in the scene, then I have to keep running the script to make it completely work (which is exactly how it is written to work). For example:

Execute to effect online
Execute to push the pause (to highlight a line or morph the graphic, etc)
Execute to effect offline

I have been able to partially remedy this with a for loop that sends an execute command a bunch of times, but I do not like the inconsistency of how it works. Therefore, I want it to do a loop to continue pressing execute while the take item is online.

dim takeitem as xpBaseTakeItem
dim fb as xpOutputFrameBuffer
dim layer as integer

'FB4
engine.GetOutputFrameBuffer(3,fb)
for layer = -99 to 99
if fb.GetTakeItemOnLayer(layer,takeitem) then
while takeitem.IsOnline()
takeitem.Execute
end while
end if
next​
As currently written, it does continue to push through a graphic until it is off, however it seemingly never exits the while loop and crashes XPression. I’ve tried some different variations of it and cannot get it to work. Any ideas what is wrong with my logic?

Thank you!!

Originally posted by ****

Scripts run instantaneously, which means that your while loop is always going to find that the take item is still online. From the perspective of the script, no time is passing, so it just runs forever and causes the crash.

If the goal is to have a keyboard shortcut that always animates off everything on the channel no matter what, you’ll probably need to use transition logic and separate your offline animations into their own scene directors. When using pauses, XPression doesn’t distinguish the difference between a pause waiting for a highlight animation vs a pause waiting for an offline animation. With transition logic, you could make uses of xpTakeItem.setOffline to reliably animate off regardless of where the graphic is within a sequence of pauses, whereas xpTakeItem.execute can only advance the pauses.

That said, I typically use a script like the below to “resume” channels – if items are paused, it advances them, but if they’re finished, it takes them offline. An actual “Resume Channel” function is available in the regular keyboard shortcuts menu under “Channel Functions” in the Available Global Functions list – that one only advances pauses.

dim fb as xpOutputFrameBuffer
engine.getOutputFrameBuffer(0,fb)

for i as integer = -99 to 99
dim take as xpTakeItem
if fb.getTakeItemOnLayer(i,take) then
'4 means paused
if take.state = 4 then
take.execute
else
take.setOffline
end if
end if
next​

Hi Greg,

I appreciate that response. I agree that the take offline function is the solution to this issue. Unfortunately, this graphics package is a hot mess of inconsistencies, with only certain graphics having proper transition logic in them. I appreciate your help nonetheless, and that script does definitely work on the graphics with transition logic in them. For now though, given the state of this project, I think it is safer to use the earlier script that you helped with, and just have the operator spam the key until it pushes fully through.

Thank you nonetheless for your help!