#155887 - sgeos - Mon May 05, 2008 7:40 am
I was speaking with a friend about scripting, and the topic of a "special effects scripting language" came up. I've implemented something like this before using time based transitions that modify a host object. That is actually how the movement in this game was done. (Card flips, dealing cards, help window, win/lose messages... everything.)
The goal this time is to come up with a general purpose special effects language. A stack based approach follows. Each controller has an update stack and a general stack. The the general stack runs until it is out of tasks. The update stack loops until the general stack has finished doing its job.
Like any good scripting language, the goal is to have something that is easy for the scripter to use. There are two end goals for such a scripting language- A) replace the special effects programmer with special effects scripters, B) make the life easier for the special effects programmer if it is decided that scripters are unnecessary afterall. I'm looking for comments and constructive criticism.
-Brendan
EDIT / NOTES TO SELF:
A) Need a way to dynamically staple one object to another VS just reading the value one time. Having an orb circle a critter as the critter moves is Good Stuff. Need to be able to both in any case. Afterall, sometimes you want to throw an object at a critter and then move the critter out of the way.
B) I didn't like how the shake was done when I was writing it, but that somehow seems correct.
C) On the return, X uses non-linear timing, and Y does two transitions in the time X does one. I don't see how to make this work without more than one controller for the same object.
The goal this time is to come up with a general purpose special effects language. A stack based approach follows. Each controller has an update stack and a general stack. The the general stack runs until it is out of tasks. The update stack loops until the general stack has finished doing its job.
Code: |
# comment
# function definition funtionName(pParamA, pParamB, pParamC) { } # global constants CONSTANT # set the object to modify controller.host = object controller.host = Object.new(params) # set effect using initial and final states controller.transition_type(frames=1).parameterA(initial_state, final_state).parameterB(initial_state, final_state) # set effect using final states (transition from current value to final value) controller.transition_type(frames=1).parameterC(final_state).parameterD(final_state) # mix the above just for kicks controller.transition_type(frames=1).parameterE(initial_state, final_state).parameterF(final_state) # transition types controller.linear(frames=1) # current_frame / max_frame controller.cos(frames=1) # 1 - cos( PI * current_frame / max_frame ); radians; reluctant controller.sin(frames=1) # sin( PI * current_frame / max_frame ); radians; eager controller.s(frames=1) # cos to midpoint, sin from midpoint; slow, fast, slow controller.z(frames=1) # sin to midpoint, cos from midpoint; fast, slow, fast # push effect list onto stack (controller stops when it reaches the end of the stack) controller.push(repeat=1) # push effects list onto update stack (controller repeats update stack from the start when it reaches the end) controller.update(repeat=1) # clear stack in question controller.clear.push controller.clear.update # do nothing for a number of frames controller.wait(frames) # repeat entire stack in question a number of times controller.repeat(times=1).push controller.repeat(times=1).update # special output # flashing, shaking and tinting the background also belong here controller.sfx(sound_effect_id) # NULL clears currently playing effect controller.bgm(background_music_id) # NULL restores previous BGM controller.value(value) # show a value at the host's location controller.text(text) # show text at the host's location controller.message(message, *params) # print to the message window # example animation # animation time ... 210 frames # source throws a blade at target, blade spins on target and # returns a little short of source, but source moves in to compensate flyingBlade(pSource, pTarget, pDamage) { # initialize effect stacks blade.host = Image.new(GFX_BLADE_SMALL) sourceX.host = pSource # doing something fancy, so two stacks are needed sourceY.host = pSource # see above target.host = pTarget # blade spin - rotate 360 degrees every 30 frames for the entire effect # slowest point is 270 degrees (facing left); spin counter clockwise blade.s(30).angle(270,-90).update # source and target wait sourceX.wait(150).push sourceY.wait(180).push target.wait(90).push # blade flies at target; makes swish sound blade.sfx(SFX_SWISH) blade.linear(90).scale(0,100).alpha(0,100) blade.cos(90).x(pSource.x, pTarget.x) blade.sin(90).y(pSource.y, pTarget.y) blade.push # blade hits target; makes grinding noise blade.sfx(SFX_GRIND).value(pDamage).wait(30).push # spinning is automatic # target shakes pTarget.clear.push pTarget.linear.x( 2).push pTarget.linear.x(-2).push pTarget.repeat(15) # blade returns to source; makes zing sound gfxA.sfx(SFX_ZING) gfxA.linear(60).scale(100,0).alpha(100,0) gfxA.cos(60).x(pTarget.x, pSource.x - 30) gfxA.sin(60).y(pTarget.y, pSource.y) gfxA.push # source moves to catch blade pSourceX.s(30).x(-30).push # blade makes a click sound when caught gfxA.sfx(SFX_CLICK).push # source returns to position pSourceX.z(30).x(30).push pSourceY.sin(15).y( 15).push # U-shape down pSourceY.cos(15).y(-15).push # U-shape up # cleanup blade.host.delete } |
Like any good scripting language, the goal is to have something that is easy for the scripter to use. There are two end goals for such a scripting language- A) replace the special effects programmer with special effects scripters, B) make the life easier for the special effects programmer if it is decided that scripters are unnecessary afterall. I'm looking for comments and constructive criticism.
-Brendan
EDIT / NOTES TO SELF:
A) Need a way to dynamically staple one object to another VS just reading the value one time. Having an orb circle a critter as the critter moves is Good Stuff. Need to be able to both in any case. Afterall, sometimes you want to throw an object at a critter and then move the critter out of the way.
B) I didn't like how the shake was done when I was writing it, but that somehow seems correct.
C) On the return, X uses non-linear timing, and Y does two transitions in the time X does one. I don't see how to make this work without more than one controller for the same object.