Animated Textures Using Controller ScriptsThe not as hard way of doing it the hard way

Hello folks, here's a controller script for animating textures within the scene editor. Please read the information below on how to use it, download the .7z file containing the examples, and/or watch the video tutorial. (Note: the images in the .7z file had to be reduced in quality in order to upload correctly).

What it doesThis controller script takes an Anim8or texture and swaps the file name on command, using a main controller script that reads the data of an animation controller for a sprite object. This script will animate any texture on any material that is applied to any mesh.

Applications

Particle effects

Animating facial expressions when the face or parts of the face uses textures instead of geometry (like for example, Mii characters)

Videos in the scene, like television screens, computer monitors, or sci-fi projections

Entirely 2D animated character sprites

Etc.

How to use the controller scriptDownload the .zip file attached to this forum post and extract it. The contents of the zip file should be:

sprite_controller.txt - This is the controller script with the default configuration. Use copies of this, change the parameters inside it, and apply the changed copies to your animated textures in Anim8or following the instructions further down.

Example 1 - Video and Fire.an8 - This is the same file that was made in the first part of the video tutorial. It has animated fire and an animated computer screen.

Example 2 - Character Sprite.an8 - This is the same file that was made in the second part of the video tutorial. It has an animated character sprite that runs and jumps.

Sprites folder - Contains the sprite image sequences used in the two example .an8 files

Step 1: Setting up the sprite object

A unique object, material, and texture for each unique sprite you wish to animate

The sprite object, in the object editor, needs to contain a mesh with a material applied to it. This material needs to have a texture loaded into it. The important thing is the name of this texture object (circled in red in the image above). The controller script will be swapping the filename of this texture, and to do so it needs this name.

If you want to have multiple unique sprites in the scene that use the same sequence of images (just animated differently), you need to create a new object, a new material, and a new texture for each sprite instance you want to use. You don't have to make these copies if you only want to use one instance of the sprite in multiple scenes, or if you want to use duplicates of the sprite that all animate identical to each other in the same scene.

Step 2: Setting up the sceneThe first thing you need to do is create a "sprites_enabled" boolean controller in the scene, applied to the "world" element. This is an on/off switch which enables or disables all of the animated textures in the scene. This is handy because sometimes Anim8or will randomly crash if you click on the sprite element while the controller script is active (the setFileName() in the script function seems to cause this random-seeming crash).

Add a "sprites_enabled" boolean controller

Do this by going to Edit->Controllers..., select the world element in the top drop down menu, and then clicking on the "New" button. A boolean controller can only have a value of 0 or 1. In the timeline on the first frame, set its value to 1 to enable it ahead of time.

Add and name your sprite object to the scene

Next, add your sprite object to the scene and give it a suitable name. For example in the image above, I named it "fire1_sprite". The reason for the "1" in the name is in case I wanted multiple unique instances of the sprite in that scene. This name is important since the controller script will be referencing it.

Mouthe needs both an anim_controller and a swap_controller

Now create two float-type controllers for that sprite element. The first one will be the animation controller, so name it something sensible like "anim_controller". The second one will be the swap controller (I usually name it "swap_controller", and is optional and only required if you want to animate two different sets of sprites on the same sprite element (like in the second .an8 file where the mouthe sprite has a run and jump animation that it swaps between).

What you just created were the controllers that tell the controller script which frames to animate for what set of textures. Next you'll have to create the element that holds the controller script itself. There is some flexibility in how you do this, but you can follow the next bit of instructions for an easy, organized way to manage your controller scripts.

Creating the containers for the controller scripts

First, add a target and name it "sprites_scripts" (or something similar). This will be the "container" that holds all of the controller scripts.

Next, add another target and name it based on the sprite you wish to control. For example in the image above, I named it "fire1_script". This target is what will hold the controller script. Then parent the "sprites_scripts" target to this target you just created. In the timeline, it should look something like in the image above.

Step 3: Configuring the controller scriptIn a text editor, open up the "sprite_controller.txt" file. There is a set of parameters that you need to configure in order for the script to know what textures to work with. Unless you are intentionally modifying the controller script to change its core programming, only modify the parameters that are between "/* FILL OUT ANIMATION DATA HERE */" and "/* EVERYTHING PAST HERE, LEAVE ALONE */"

Below is a description of each parameter. Please change any or all that are required for your specific sprites.

Enable/Disable

$enabled=1;

Required. Enables or disables the animation of that sprite. Handy if you have large amounts of sprites and just want to have a single one active while you work with it.

Texture Name

$texName="";

Required. This is the name of the texture that you made (circled in red in the image in Step 1).

Required. Change "Sprite_Element_Name" to the name of the sprite element it's controlling. For example, it was "fire1_sprite" in Step 2. Change "Anim_Controller_Name" to the name of the animation controller you created for that sprite element. This was named "anim_controller" in the Step 2 example.

Animation Controller Type

$controllerAnimType="multiplier";

Required. There are two options to specify for how the controller script handles the values passed in the animation controller you specified above. The default option, "multiplier", interprets the values as the percentage of the animation cycle you want to play. For example, a value of 0 means it's the first frame of the animation cycle. A value of 1 means it's the last frame of the animation cycle. A value of 0.5 means it's the middle frame. A value of 2.5 means it's the middle frame, except in the second animation loop.

The second option is "frame". This allows you to specify the exact frame of the animation cycle (starts at 0). So a value of 0 means it's the first frame. A value of 1 means it's the second frame. A value of 51 means it's the 50th frame. If the animation cycle has only 25 images in its sequence, then a value of 51 would mean that it's at the start of the second loop.

Swap Controller Details

$controllerSwapFloat= GetAttributeFloat("","");

Optional. Leave blank if you don't need to swap the animation cycle with a different one for that particular sprite object. Fill the first string with the name of the sprite element it's controlling. For example, it was "fire1_sprite" in Step 2. Fill the second string with the name of the swap controller you created for that sprite element. This was named "swap_controller" in the Step 2 example.

Texture File Name - Prefix

$texPrefix.push("");

Required. Fill in the quotation marks with the prefix of the texture file the animation cycle is using. For example, if a texture file is named "file_0001.png", then "file_" is the prefix.

If you are using a swap controller, then for each set of textures you need to animate, you have to add another '$texPrefix.push()' line. This is also required for all of the .push() parameters. The first .push() parameter corresponds to the value 0 in the swap controller. The second .push() parameter corresponds to value 1 in the swap controller. Etc, etc. Don't mix up the order of the .push() parameters.

Texture File Name - Number of digits

$texDigits.push();

Required. The texture files in the animation sequence must be numbered sequentially with the same number of digits. "file_1.png" will not be considered in the same sequence as "file_0002.png". It must be named "file_0001.png". The parameter above specifies this number of digits. For example, "file_0001.png" has 4 digits, so you would place the number 4 inside the parenthesis with no quotation marks (it would look like '$texDigits.push(4);')

Texture File Name - Type

$texType.push("");

Required. Set the file type. It'll be either png, bmp, gif, or jpg. For example, if the sequence of files were png files, it would look like '$texType.push("png");'

Texture File Name - Path

$texPath.push("");

Required. Set the path to the sequence of files for that sprite. If you want to set a path relative to the .an8 file, and the files are in subfolders of that .an8 file, you would use something like '$texPath.push("./Path/To/Files/");'. Otherwise if you want to specify the absolute path to it, set it like '$texPath.push("C:/Path/To/Files/");' Make sure a forward slash is at the end for whichever of these options you choose.

If you placed all of the textures in the same path as what you specified for the texture directory in File->Configure, you can leave it as just '$texPath.push("");'. Note however that the script does not and can not look through subfolders.

Texture File Name - Starting Number

$texStartingFrame.push();

Required. Use the same number as the first file in the sequence. For example, if the first file was named "file_0001.png", the parameter would look like '$texStartingFrame.push(1);'. If the first file was named "file_0024.png", it would look like '$texStartingFrame.push(24);'.

Texture File Name - Ending Number

$texEndingFrame.push();

Required. Use the same number as the last file in the sequence. For example, if the last file was named "file_0036.png", the parameter would look like '$texEndingFrame.push(36);'. If the last file was named "file_0125.png", it would look like '$texEndingFrame.push(125);'.

-----

If you want to make it easier to read which set of .push() parameters applies to which set of file sequences, you can re-order it to look like this:

Alternative way to set multiple swap parameters

// Swap value 0

$texPrefix.push("");

$texDigits.push();

$texType.push("");

$texPath.push("");

$texStartingFrame.push();

$texEndingFrame.push();

// Swap value 1

$texPrefix.push("");

$texDigits.push();

$texType.push("");

$texPath.push("");

$texStartingFrame.push();

$texEndingFrame.push();

// Swap value 2

$texPrefix.push("");

$texDigits.push();

$texType.push("");

$texPath.push("");

$texStartingFrame.push();

$texEndingFrame.push();

Step 4: Applying the controller scriptAssuming you completed Step 3, copy the entire controller script to your clipboard (Ctrl+C). Next, double-click on the controller script target you had made in Step 2. Click on the '...' button next to the Location details, set the Expressions to 'On', and click the 'Edit' button. Select everything in the text field that pops up and press Ctrl+V to replace it with the controller script.

Copy the controller script into the script target's position controller

The reason we're using a controller script target and applying the controller script to its 'position' controller is so that we can bypass a bug in Anim8or, in which after setting a controller as an Expression, you can no longer access it via the timeline (or any other means aside from editing the .an8 file in a text editor). The only way you can access a controller is through the element's dialog box and clicking on the buttons corresponding to its preset controllers. Until this bug is fixed, you'll have to do it this way. Otherwise you don't have to create controller script 'targets' and instead just add controllers directly to the controller script container target you had first created. Then you'd apply the controller scripts to these controllers.

Step 5: AnimatingIf you want to animate the textures, you have to keyframe the animation controller and (optionally) the swap controller assigned to that sprite element. For example, in Step 2, this was "anim_controller" and "swap_controller".

Animation ControllerThis is the main meat of the animation and tells the controller script which frame of the animation cycle corresponds to which frame in the timeline. Keyframe this on the timeline to any values you need, based on the animation controller type parameter you specified in Step 3. Anim8or will interpolate between these values on the timeline. Anim8or will interpolate between these values on the timeline and the controller script will round this value to the nearest integer, thus picking which frame of the animation cycle to use.

Anim8or currently doesn't have a means to create linear keyframes (that I know of, anyway). Meaning if you look in the graph editor, the paths connecting the keyframes will all look like curves until you manually change the path nodes. If you want to slow down or speed up the animations then having curves is fine. Otherwise adjust the node handles so that these paths are as linear (straight) as possible. You may have to set the keyframe type to "corner" or "step" in order to accomplish this.

Swap ControllerThis controller swaps between the sets of animation sequences you had specified in Step 3 (using the .push() parameters). The first set corresponds to the value 0. The second set corresponds to the value 1, etc etc. Keyframe this on the timeline to any values you need. Anim8or will interpolate between these values on the timeline and the controller script will round this value to the nearest integer, thus picking which set to use. I recommend using "step" type keyframes for the swap controller.

Important things to know or remember

Always create and use the "sprites_enabled" boolean controller in each scene that you use this controller script. A value of 1 is enabled, 0 is disabled.

Crashing happens much more often thanks to this script. Save often.

If crashing occurs as soon as you open the Anim8or project and click on one of the sprites or controllers, set "sprites_enabled" to 0 first, then click on them. It *shouldn't* crash after you enable it again during the same session, though sometimes it will anyway. Again, save often.

If you have a non-syntax-related error in your controller script parameters, you'll have to manually troubleshoot the problem and figure out what parameters are missing or incorrect. So double-check that each parameter has the right value.

Sometimes if you make major changes to the scripts or add new controller scripts, the textures will no longer swap in the workspace. This usually happens if it looks for a file that's not there (usually caused by an incorrect parameter), and almost always during the first time you set up the scene for controller scripts. To avoid frustration, once you're sure that the parameters are correct and you've set up the scene as described in the steps above, save the project and restart Anim8or. Then try moving through the frames to see if it works.

If you can't get it to work no matter what, look through the two provided .an8 examples for reference and/or post in this topic and attach the .an8 file and associated textures (put it all in one .zip file). If you don't want to have your project available to the public, PM me and we can work it out

Only tested to work with Anim8or development release 1210. I recommend using this version or higher

It's located at the bottom of the first post as an attachment, under where the video tutorial is located. You'll need 7-zip or a modern file archiver/extractor program to extract the contents of the .7z file.

Talked about duh moment wasn't logged in before asking question, thank you for the locale and your hard work on this most awesome method keep up the good work, we appreciate it greatly. After actually attempting to view both an8 files I realized that all picture files are PNG and can't load them might use gimp to export to jpg unless im missing some awesome feature of an8 that i havent figured out yet

Hi dancingshoes, I gave it a shot and it doesn't crash when I go into scene mode. I suppose it's due to some ghostly reason that it crashes for you, I've never really figured it out and I think it's something only Steve can address.

I created a new set of files with the sprites_enabled controller set to 0, effectively disabling it so that it *shouldn't* crash when you enter the scene editor. Just set the controller back to 1 in the time track when you get in. Click this link to download it.

As for the amount of memory it uses, theoretically it shouldn't use any more or less than with normal non-animated textures. What it'll do is increase the CPU cycles and harddrive activity when switching between frames since it's swapping out the files in the material.

I have a project now where I really need animated textures. The problem: it won't work for me at all. When I open your projects, they crash every time in scene mode.

I tried following your tutorial step by step, and it doesn't animate my textures. I can't understand what the problem is. Please help. Mine doesn't crash in scene mode, but it doesn't work either. The texture is w001.jpg to w120.jpg, 800/800

Can you share your project, or a lesser example of with your step by step approach? Also, attached is a modified version of the first post's an8 files. These don't have the sprites_enabled controller, so it shouldn't crash when you go to the scene editor.

You'll have to add the boolean sprites_enabled controller to these files via Edit->Controllers and give it a boolean value of 1 in the timeline in order to see the animation(s) play.

These didn't crash. I've added sprites enable controller and they animate. Although I don't totally understand how this script works yet, it seems. For my material, I need the normal map. So I tried to add the same fire texture to a normal map as well and now it crashed. So, if I make any changes to the material after the script is in place, it supposed to crash? I kept saving over my project, and delete it after a few tries.But mine is simple. I'd appreciate if you'll find the time to create a new project, and I'll add my textures in the ./sprites" folder afterward. You can use any images named "w001.jpg to "w150.jpg'. Size is 800x800. It's gonna be a sandy terrain, where the wind kinda blows the sand slightly, and that's why I use only the normal map for it. I'm sure I'm doing somethin' wrong, but I haven't figured out what...yet!