Motion AfterImage Effect??
by Kevin Epps · in Torque Game Builder · 03/09/2008 (11:49 am) · 38 replies
I don't really know what anyone else would call this to do a proper search, but I'm trying to figure out how achieve an afterimage motion effect.
Meaning, I want copies of a sprite to trail the main sprite and fade out. I really hope you know what I'm talking about because I don't know how to put it into words without just calling it a motion afterimage effect.
Does anyone know how to achieve this in TGB? Maybe use particles for this or something?
Meaning, I want copies of a sprite to trail the main sprite and fade out. I really hope you know what I'm talking about because I don't know how to put it into words without just calling it a motion afterimage effect.
Does anyone know how to achieve this in TGB? Maybe use particles for this or something?
About the author
#2
03/09/2008 (4:03 pm)
You'd just have to create copies of the static sprite that just have the same dimensions and picture. Set them at a lower alpha then fade them out and delete them. If the object is moving, the images will be copied in a row and have different blend alphas then fade out.
#3
You can easily adapt this for different objects, but I'll be posting a much more refined method later. (After I write it.)
03/09/2008 (4:48 pm)
Here's some quick code for an after image effect for an animated sprite:// after image motion blur effect
function t2dAnimatedSprite::doAfterImageEffect(%this)
{
%this.createAfterImageClone();
%this.schedule(50, "createAfterImageClone");
%this.schedule(100, "createAfterImageClone");
%this.schedule(150, "createAfterImageClone");
%this.schedule(200, "createAfterImageClone");
%this.schedule(250, "createAfterImageClone");
%this.schedule(300, "createAfterImageClone");
%this.schedule(350, "createAfterImageClone");
%this.schedule(400, "createAfterImageClone");
%this.schedule(450, "createAfterImageClone");
%this.schedule(500, "createAfterImageClone");
}
function t2dAnimatedSprite::createAfterImageClone(%this)
{
%clone = new t2dAnimatedSprite()
{
scenegraph = %this.getSceneGraph();
class = "afterImageObject";
size = %this.getSize();
position = %this.getPosition();
layer = (%this.getLayer() + 1);
flipX = %this.FlipX;
rotation = %this.getRotation();
animationName = %this.getAnimation();
};
%clone.setFrameChangeCallback(true);
%clone.setAnimationFrame(%this.getAnimationFrame());
%clone.fadeOut(0.14, 50, 0);
%clone.schedule(1500, "safeDelete");
}
function afterImageObject::onFrameChange(%this, %frameIndex)
{
%this.setAnimationFrame(%frameIndex - 1);
}You can easily adapt this for different objects, but I'll be posting a much more refined method later. (After I write it.)
#4
03/09/2008 (5:00 pm)
Oh yeah, this function would probably be helpful://This function makes the object gradually disappear.
function t2dSceneObject::fadeOut(%this, %increment, %speed, %goal)
{
if(isEventPending(%this.fadeInSchedule))
cancel(%this.fadeInSchedule);
%curAlpha = %this.getBlendAlpha();
%this.setBlendAlpha(%curAlpha - %increment);
if(%this.getBlendAlpha() >= %goal)
%this.fadeOutSchedule = %this.schedule(%speed, "fadeOut", %increment, %speed, %goal);
else
{
%this.setBlendAlpha(%goal);
cancel(%this.fadeOutSchedule);
}
}
#5
03/09/2008 (7:55 pm)
Thanks so much, Kevin!
#7
03/12/2008 (1:33 pm)
No problem Kevin. I'm still going to post some more refined code, but I've been pretty busy. ;)
#8
03/21/2008 (4:25 pm)
Finally got around to working on the after image effect some more. Now you can pass in parameters that distinctly change how the effect plays out. Recommended defaults:object.doSimpleAfterImageEffect(100, 1500, false, true, 0.14, 50, 0);
//**simple after image motion blur effect for animated sprites**
//frequency - how often to make after image clones (copies of object that fade out)
//duration - how long the effect will last
//owner visible - if true, the owner stays visible during the entire effect
// if false, the owner disappears during the effect, and reappears
// at the end.
//still frames - if true, then the copies are forced to render the same exact frame
// as the owner had when the particular copy was made. Bit of a hacked
// solution. Changes the frame back to previous one on an onFrameChange
// callback.
//increment, speed, goal - all of these parameters are used soly for the fadeOut
// function. Increment is the number by which to reduce
// the alpha each speed interval which is in milliseconds.
// Goal tells the function when to stop fading.
function t2dAnimatedSprite::doSimpleAfterImageEffect(%this, %frequency, %duration, %ownerVisible, %stillFrames, %increment, %speed, %goal)
{
for(%i = 0; %i < %duration; %i += %frequency)
{
%this.schedule(%i, "createAfterImageClone", %stillFrames, %increment, %speed, %goal);
}
if(!%ownerVisible)
{
%this.visible = false;
%this.schedule(%duration, "setVisible", true);
}
}
//used by the after image effects to produce copy images.
function t2dAnimatedSprite::createAfterImageClone(%this, %stillFrames, %increment, %speed, %goal)
{
%clone = new t2dAnimatedSprite()
{
scenegraph = %this.getSceneGraph();
class = "afterImageObject";
size = %this.getSize();
position = %this.getPosition();
layer = (%this.getLayer() + 1);
flipX = %this.FlipX;
rotation = %this.getRotation();
animationName = %this.getAnimation();
};
%clone.setAnimationFrame(%this.getAnimationFrame());
%clone.fadeOut(%increment, %speed, %goal);
//the next line assumes that your goal is 0. It just automatically computes a safe waiting
//time for the deletion of the clone. Use the commented line after it to manually control
//the deletion. Make sure to comment the automated line.
%clone.schedule(((((1 - %increment) * %speed)/43) * 1500), "safeDelete");
//%clone.schedule([int in milliseconds] "safeDelete");
if(%stillFrames)
%clone.setFrameChangeCallback(true);
}
//hacked solution to freeze an animation
function afterImageObject::onFrameChange(%this, %frameIndex)
{
%this.setAnimationFrame(%frameIndex - 1);
}
function t2dStaticSprite::doSimpleAfterImageEffect(%this, %frequency, %duration, %ownerVisible, %increment, %speed, %goal)
{
for(%i = 0; %i < %duration; %i += %frequency)
{
%this.schedule(%i, "createAfterImageClone", %increment, %speed, %goal);
}
if(!%ownerVisible)
{
%this.visible = false;
%this.schedule(%duration, "setVisible", true);
}
}
function t2dStaticSprite::createAfterImageClone(%this, %increment, %speed, %goal)
{
%clone = new t2dStaticSprite()
{
scenegraph = %this.getSceneGraph();
class = "afterImageObject";
size = %this.getSize();
position = %this.getPosition();
layer = (%this.getLayer() + 1);
flipX = %this.FlipX;
rotation = %this.getRotation();
imageMap = %this.getImageMap();
};
%clone.fadeOut(%increment, %speed, %goal);
//the next line assumes that your goal is 0. It just automatically computes a safe waiting
//time for the deletion of the clone. Use the commented line after it to manually control
//the deletion. Make sure to comment the automated line.
%clone.schedule(((((1 - %increment) * %speed)/43) * 1500), "safeDelete");
//%clone.schedule([int in milliseconds] "safeDelete");
}
#9
03/29/2008 (1:13 pm)
Now to make this into a behavior :)
#11
newbie question.
Where exactly do I place/call this function? -
for these remaining functions, do I dump them into a new .cs file?
What do I do with this function?
Should I set the afterimage effect as a behavior? any way you can include step by step instructions for newbs like me?
Thank you so much for your time!
11/06/2012 (3:18 pm)
Hello Kevin,newbie question.
Where exactly do I place/call this function? -
object.doSimpleAfterImageEffect(100, 1500, false, true, 0.14, 50, 0);
for these remaining functions, do I dump them into a new .cs file?
function t2dStaticSprite::createAfterImageClone(%this, %increment, %speed, %goal) function t2dStaticSprite::doSimpleAfterImageEffect(%this, %frequency, %duration, %ownerVisible, %increment, %speed, %goal) function afterImageObject::onFrameChange(%this, %frameIndex) function t2dAnimatedSprite::createAfterImageClone(%this, %stillFrames, %increment, %speed, %goal) function t2dAnimatedSprite::doSimpleAfterImageEffect(%this, %frequency, %duration, %ownerVisible, %stillFrames, %increment, %speed, %goal)
What do I do with this function?
function t2dSceneObject::fadeOut(%this, %increment, %speed, %goal)
Should I set the afterimage effect as a behavior? any way you can include step by step instructions for newbs like me?
Thank you so much for your time!
#12
Yeah, I'm not sure how one would use this in a behavior - there's certainly possibilities, but it doesn't *have* to be in a behavior.
There aren't step-by-step instructions because, well, the possibilities are endless, basically. Maybe you have a platform jumper where you want the player animated sprite to have an after image effect when he hits a boost platform. Maybe you have a scroller shooter where you can go into slow motion and you want the player static sprite to have an after image effect during this time.
To answer your questions:
1.) Where exactly do I place/call this function?
Call this function where you want the effect to start.
2.) Do I dump them into a new .cs file?
Yes
3.) What do I do with this function?
Put it in the same .cs file as the functions above
4.) Should I set the afterimage effect as a behavior?
No
11/06/2012 (9:26 pm)
@Matt, you're lucky I saw this, I just recently started paying attention to these forums again!Yeah, I'm not sure how one would use this in a behavior - there's certainly possibilities, but it doesn't *have* to be in a behavior.
There aren't step-by-step instructions because, well, the possibilities are endless, basically. Maybe you have a platform jumper where you want the player animated sprite to have an after image effect when he hits a boost platform. Maybe you have a scroller shooter where you can go into slow motion and you want the player static sprite to have an after image effect during this time.
To answer your questions:
1.) Where exactly do I place/call this function?
Call this function where you want the effect to start.
2.) Do I dump them into a new .cs file?
Yes
3.) What do I do with this function?
Put it in the same .cs file as the functions above
4.) Should I set the afterimage effect as a behavior?
No
#13
I'm using the PSK. I made a file called "AfterImage.cs" and put the following code in the file:
I call the function:
11/09/2012 (11:29 am)
Hello,I'm using the PSK. I made a file called "AfterImage.cs" and put the following code in the file:
//object.doSimpleAfterImageEffect(100, 1500, false, true, 0.14, 50, 0);
//**simple after image motion blur effect for animated sprites**
//frequency - how often to make after image clones (copies of object that fade out)
//duration - how long the effect will last
//owner visible - if true, the owner stays visible during the entire effect
// if false, the owner disappears during the effect, and reappears
// at the end.
//still frames - if true, then the copies are forced to render the same exact frame
// as the owner had when the particular copy was made. Bit of a hacked
// solution. Changes the frame back to previous one on an onFrameChange
// callback.
//increment, speed, goal - all of these parameters are used soly for the fadeOut
// function. Increment is the number by which to reduce
// the alpha each speed interval which is in milliseconds.
// Goal tells the function when to stop fading.
function t2dAnimatedSprite::doSimpleAfterImageEffect(%this, %frequency, %duration, %ownerVisible, %stillFrames, %increment, %speed, %goal)
{
for(%i = 0; %i < %duration; %i += %frequency)
{
%this.schedule(%i, "createAfterImageClone", %stillFrames, %increment, %speed, %goal);
}
if(!%ownerVisible)
{
%this.visible = false;
%this.schedule(%duration, "setVisible", true);
}
}
//used by the after image effects to produce copy images.
function t2dAnimatedSprite::createAfterImageClone(%this, %stillFrames, %increment, %speed, %goal)
{
%clone = new t2dAnimatedSprite()
{
scenegraph = %this.getSceneGraph();
class = "afterImageObject";
size = %this.getSize();
position = %this.getPosition();
layer = (%this.getLayer() + 1);
flipX = %this.FlipX;
rotation = %this.getRotation();
animationName = %this.getAnimation();
};
%clone.setAnimationFrame(%this.getAnimationFrame());
%clone.fadeOut(%increment, %speed, %goal);
//the next line assumes that your goal is 0. It just automatically computes a safe waiting
//time for the deletion of the clone. Use the commented line after it to manually control
//the deletion. Make sure to comment the automated line.
%clone.schedule(((((1 - %increment) * %speed)/43) * 1500), "safeDelete");
//%clone.schedule([int in milliseconds] "safeDelete");
if(%stillFrames)
%clone.setFrameChangeCallback(true);
}
//hacked solution to freeze an animation
function afterImageObject::onFrameChange(%this, %frameIndex)
{
%this.setAnimationFrame(%frameIndex - 1);
}
function t2dStaticSprite::doSimpleAfterImageEffect(%this, %frequency, %duration, %ownerVisible, %increment, %speed, %goal)
{
for(%i = 0; %i < %duration; %i += %frequency)
{
%this.schedule(%i, "createAfterImageClone", %increment, %speed, %goal);
}
if(!%ownerVisible)
{
%this.visible = false;
%this.schedule(%duration, "setVisible", true);
}
}
function t2dStaticSprite::createAfterImageClone(%this, %increment, %speed, %goal)
{
%clone = new t2dStaticSprite()
{
scenegraph = %this.getSceneGraph();
class = "afterImageObject";
size = %this.getSize();
position = %this.getPosition();
layer = (%this.getLayer() + 1);
flipX = %this.FlipX;
rotation = %this.getRotation();
imageMap = %this.getImageMap();
};
%clone.fadeOut(%increment, %speed, %goal);
//the next line assumes that your goal is 0. It just automatically computes a safe waiting
//time for the deletion of the clone. Use the commented line after it to manually control
//the deletion. Make sure to comment the automated line.
%clone.schedule(((((1 - %increment) * %speed)/43) * 1500), "safeDelete");
//%clone.schedule([int in milliseconds] "safeDelete");
}
//This function makes the object gradually disappear.
function t2dSceneObject::fadeOut(%this, %increment, %speed, %goal)
{
if(isEventPending(%this.fadeInSchedule))
cancel(%this.fadeInSchedule);
%curAlpha = %this.getBlendAlpha();
%this.setBlendAlpha(%curAlpha - %increment);
if(%this.getBlendAlpha() >= %goal)
%this.fadeOutSchedule = %this.schedule(%speed, "fadeOut", %increment, %speed, %goal);
else
{
%this.setBlendAlpha(%goal);
cancel(%this.fadeOutSchedule);
}
}I call the function:
%theirObject.doSimpleAfterImageEffect(100, 1500, false, true, 0.14, 50, 0);p that should make this work but it doesn't work... Help?
#14
1) The afterimage.cs file is located in your /gamescripts/ folder, correct ?
2) Did you add an EXEC command in main.cs to run this script ?
3) Do you have an object in your scene named "theirObject" ?
4) You might try %theirObject.owner.doSimple....... I am unclear when you should, and should not use .owner., but if i recall correctly mine did not work until i used .owner.
5) If you only have this called once, the effect will instantly play on level loaded and only for 1500ms, so it's possible you may not even be seeing it unless you move your object around fairly quickly after the scene loads.
6) What does the console (~) say when you load the game ? Any errors ?
7) I turned mine into a behavior with a keybind to play the effect that you can attach to any object I can post the code for that if you like .... speaking of ...
8) As far as I can tell this ONLY works on animated sprites, if your object is a static sprite it will not play. If you Need it for a static sprite, simply turn that imageMap into a 1-frame animated sprite.
11/09/2012 (5:00 pm)
Warning: I'm a complete noob, so take everything I say with a grain of salt. That being said, here's a couple questions for you Jackrabbit.1) The afterimage.cs file is located in your /gamescripts/ folder, correct ?
2) Did you add an EXEC command in main.cs to run this script ?
3) Do you have an object in your scene named "theirObject" ?
4) You might try %theirObject.owner.doSimple....... I am unclear when you should, and should not use .owner., but if i recall correctly mine did not work until i used .owner.
5) If you only have this called once, the effect will instantly play on level loaded and only for 1500ms, so it's possible you may not even be seeing it unless you move your object around fairly quickly after the scene loads.
6) What does the console (~) say when you load the game ? Any errors ?
7) I turned mine into a behavior with a keybind to play the effect that you can attach to any object I can post the code for that if you like .... speaking of ...
8) As far as I can tell this ONLY works on animated sprites, if your object is a static sprite it will not play. If you Need it for a static sprite, simply turn that imageMap into a 1-frame animated sprite.
#15
All of those check off except 6. When I call the function, I get "Unknown command doSimpleAfterImageEffect."
It's called when you jump. I checked thoroughly through but I found no errors in the EXEC process. It just seems like there is something wrong with the code... Could you post the file as a behavior? It might change things a bit. ;)
11/10/2012 (9:58 am)
Hello,All of those check off except 6. When I call the function, I get "Unknown command doSimpleAfterImageEffect."
It's called when you jump. I checked thoroughly through but I found no errors in the EXEC process. It just seems like there is something wrong with the code... Could you post the file as a behavior? It might change things a bit. ;)
#16
@all, it should be noted that it was more than 4 years ago that I wrote this code, so I'm mostly going off what it *should* be doing.
@Jackrabbit, do you get that error *before* you try and jump?
11/10/2012 (10:13 am)
d00d, dunno why everyone is talking about a behavior with this code. Perhaps I'm missing something big, and if I am, I would appreciate illumination. :D@all, it should be noted that it was more than 4 years ago that I wrote this code, so I'm mostly going off what it *should* be doing.
@Jackrabbit, do you get that error *before* you try and jump?
#17
11/10/2012 (2:06 pm)
Nope. It tells me it can't find the function every time I jump. :-\
#18
Add this to "AfterImage.cs":
Then run your project, open the console. Type: "testDerp()" and see what happens. You should see "Here!"
Also note that if there's even one error in a script file, none of the functions in that script file will be loaded.
11/10/2012 (5:00 pm)
You def. need to debug if AfterImage.cs is getting loaded.Add this to "AfterImage.cs":
function testDerp()
{
echo("Here!");
}Then run your project, open the console. Type: "testDerp()" and see what happens. You should see "Here!"
Also note that if there's even one error in a script file, none of the functions in that script file will be loaded.
#19
11/11/2012 (3:36 pm)
@Matt, did you get everything figured out?
#20
11/12/2012 (9:07 am)
Here is my code. I tried your test thingy and it worked. :-?//doSimpleAfterImageEffect(100, 1500, false, true, 0.14, 50, 0);
//**simple after image motion blur effect for animated sprites**
//frequency - how often to make after image clones (copies of object that fade out)
//duration - how long the effect will last
//owner visible - if true, the owner stays visible during the entire effect
// if false, the owner disappears during the effect, and reappears
// at the end.
//still frames - if true, then the copies are forced to render the same exact frame
// as the owner had when the particular copy was made. Bit of a hacked
// solution. Changes the frame back to previous one on an onFrameChange
// callback.
//increment, speed, goal - all of these parameters are used soly for the fadeOut
// function. Increment is the number by which to reduce
// the alpha each speed interval which is in milliseconds.
// Goal tells the function when to stop fading.
function t2dAnimatedSprite::doSimpleAfterImageEffect(%this, %frequency, %duration, %ownerVisible, %stillFrames, %increment, %speed, %goal)
{
for(%i = 0; %i < %duration; %i += %frequency)
{
%this.schedule(%i, "createAfterImageClone", %stillFrames, %increment, %speed, %goal);
}
if(!%ownerVisible)
{
%this.visible = false;
%this.schedule(%duration, "setVisible", true);
}
}
//used by the after image effects to produce copy images.
function t2dAnimatedSprite::createAfterImageClone(%this, %stillFrames, %increment, %speed, %goal)
{
%clone = new t2dAnimatedSprite()
{
scenegraph = %this.getSceneGraph();
class = "afterImageObject";
size = %this.getSize();
position = %this.getPosition();
layer = (%this.getLayer() + 1);
flipX = %this.FlipX;
rotation = %this.getRotation();
animationName = %this.getAnimation();
};
%clone.setAnimationFrame(%this.getAnimationFrame());
%clone.fadeOut(%increment, %speed, %goal);
//the next line assumes that your goal is 0. It just automatically computes a safe waiting
//time for the deletion of the clone. Use the commented line after it to manually control
//the deletion. Make sure to comment the automated line.
%clone.schedule(((((1 - %increment) * %speed)/43) * 1500), "safeDelete");
//%clone.schedule([int in milliseconds] "safeDelete");
if(%stillFrames)
%clone.setFrameChangeCallback(true);
}
//hacked solution to freeze an animation
function afterImageObject::onFrameChange(%this, %frameIndex)
{
%this.setAnimationFrame(%frameIndex - 1);
}
function t2dStaticSprite::doSimpleAfterImageEffect(%this, %frequency, %duration, %ownerVisible, %increment, %speed, %goal)
{
for(%i = 0; %i < %duration; %i += %frequency)
{
%this.schedule(%i, "createAfterImageClone", %increment, %speed, %goal);
}
if(!%ownerVisible)
{
%this.visible = false;
%this.schedule(%duration, "setVisible", true);
}
}
function t2dStaticSprite::createAfterImageClone(%this, %increment, %speed, %goal)
{
%clone = new t2dStaticSprite()
{
scenegraph = %this.getSceneGraph();
class = "afterImageObject";
size = %this.getSize();
position = %this.getPosition();
layer = (%this.getLayer() + 1);
flipX = %this.FlipX;
rotation = %this.getRotation();
imageMap = %this.getImageMap();
};
%clone.fadeOut(%increment, %speed, %goal);
//the next line assumes that your goal is 0. It just automatically computes a safe waiting
//time for the deletion of the clone. Use the commented line after it to manually control
//the deletion. Make sure to comment the automated line.
%clone.schedule(((((1 - %increment) * %speed)/43) * 1500), "safeDelete");
//%clone.schedule([int in milliseconds] "safeDelete");
}
//This function makes the object gradually disappear.
function t2dSceneObject::fadeOut(%this, %increment, %speed, %goal)
{
if(isEventPending(%this.fadeInSchedule))
cancel(%this.fadeInSchedule);
%curAlpha = %this.getBlendAlpha();
%this.setBlendAlpha(%curAlpha - %increment);
if(%this.getBlendAlpha() >= %goal)
%this.fadeOutSchedule = %this.schedule(%speed, "fadeOut", %increment, %speed, %goal);
else
{
%this.setBlendAlpha(%goal);
cancel(%this.fadeOutSchedule);
}
}
function testderp()
{
echo("after image reporting.");
}
Torque Owner Brian Carter