Difference between revisions of "Animating Props"
() |
|||
(13 intermediate revisions by the same user not shown) | |||
Line 6: | Line 6: | ||
[[The First Room|2]] | | [[The First Room|2]] | | ||
[[Interacting with Objects|3]] | | [[Interacting with Objects|3]] | | ||
− | [[The Priority Screen| | + | [[Adding a Background and Static Objects|4]] | |
− | [[Animating Props| | + | [[The Priority Screen|5]] | |
− | [[Managing the Player’s Inventory| | + | [[Animating Props|6]] | |
− | [[Actors| | + | [[Managing the Player’s Inventory|7]] | |
− | [[Dying| | + | [[Actors|8]] | |
− | [[Using Inventory Items| | + | [[Dying|9]] | |
− | [[Scoring and Flags| | + | [[Using Inventory Items|10]] | |
− | [[Adding a Second Room| | + | [[Scoring and Flags|11]] | |
+ | [[Adding a Second Room|12]] | ||
</div><br /> | </div><br /> | ||
− | <div align="center"><span style="font-size: 22pt"></span><br /> | + | <div align="center"><span style="font-size: 22pt">Animating Props</span><br /> |
''Author: [[Phil Fortier]]''</div> | ''Author: [[Phil Fortier]]''</div> | ||
− | + | This will show you how to use [[scicompdoc:Classes/Cycle.html#Cycle|<span class="Reference">Cycle</span>]] objects to create animations. | |
− | ==<br /> | + | ==<br /> A simple animation == |
+ | Remember that blue box? Go back to the box view, and add a third cel. Color shift it so it’s yellow (or do whatever you want). | ||
+ | Go to your script file, and add at a setCycle method call to the box’s initialization: | ||
+ | |||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (theBox | ||
+ | approachVerbs: V_DO | ||
+ | setCycle: Forward | ||
+ | init: | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | This uses the [[scicompdoc:Classes/Forward.html#Forward|<span class="Reference">Forward</span>]] cycler to cycle forward through the loops cels. So when you run the game, the blue box will now cycle between blue, red and yellow. Easy! | ||
+ | |||
+ | To adjust the speed, you can set a different cycleSpeed on the object: | ||
+ | |||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (instance theBox of Prop | ||
+ | (properties | ||
+ | view 123 | ||
+ | x 150 | ||
+ | y 100 | ||
+ | signal ignAct | ||
+ | loop 0 | ||
+ | cel 0 | ||
+ | noun N_BOX | ||
+ | priority 0 | ||
+ | approachX 130 | ||
+ | approachY 110 | ||
+ | cycleSpeed 15 ; Large numbers are slower. | ||
+ | ) | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ==<br /> Triggering Off Animation Events == | ||
+ | |||
+ | Let’s do something a little more complicated. Let’s make the box shrink when the player touches it. Go back to view 123, and create a new loop. When you create a new loop, by default it should contain the first cel of the previous loop (it has to contain something). That’s great, it’s our blue box. | ||
+ | |||
+ | Add three more cels to the loop. They should all have blue boxes in them by default. | ||
+ | |||
+ | Click on the second cel and resize the borders while holding down the SHIFT key (this makes resizing the borders grow or shrink the view inside). Make the box a ''little'' smaller. Click on the third cel and make it even smaller, and so on. You should end up with something like this: | ||
+ | |||
+ | <div align="center">[[File:ShrinkingBox.png]]<br /> | ||
+ | </div> | ||
+ | |||
+ | Now we’ll write code that triggers off the ego performing the V_DO verb on the N_BOX. In that, we’ll make the box cels cycle from beginning to end. To do that, we’ll need to do a few things: | ||
+ | |||
+ | * Remove the (theBox:setCycle(Forward)) we added in the previous section (in the room’s init()). | ||
+ | * Make ''theBox'' use loop 1 by default (since that’s where our shrinking box is). | ||
+ | * Add a doVerb method to ''theBox'', and tell the box to cycle from beginning to end.<br /> | ||
+ | | ||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (instance theBox of Prop | ||
+ | (properties | ||
+ | view 123 | ||
+ | x 150 | ||
+ | y 100 | ||
+ | signal ignAct | ||
+ | loop 1 | ||
+ | cel 0 | ||
+ | noun N_BOX | ||
+ | priority 0 | ||
+ | approachX 130 | ||
+ | approachY 110 | ||
+ | cycleSpeed 15 | ||
+ | ) | ||
+ | |||
+ | (method (doVerb theVerb) | ||
+ | (switch theVerb | ||
+ | (V_DO | ||
+ | (self setCycle: EndLoop) | ||
+ | ) | ||
+ | (else | ||
+ | (super doVerb: theVerb &rest) | ||
+ | ) | ||
+ | ) | ||
+ | ) | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Compile and run the game to test it. | ||
+ | |||
+ | That’s nice, but what if we want to display a message after the box has shrunk? This is where [[scicompdoc:Classes/Script.html#Script|<span class="Reference">Script</span>]] objects come in (not to be confused with script files). With a Script we can choreograph a sequence of events. We’ll make a Script that has a state for shrinking the box, followed by a state for displaying a message. We’ll attach this Script to ''theBox''. | ||
+ | |||
+ | First, create a new Script object (you can use ''Insert Object->Script'' for convenience): | ||
+ | |||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (instance shrinkBoxScript of Script | ||
+ | (properties) | ||
+ | |||
+ | (method (changeState newState) | ||
+ | (= state newState) | ||
+ | (switch state | ||
+ | (0) | ||
+ | ) | ||
+ | ) | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Then, replace our previous handling of ''theBox'' doVerb with a call to set the Script on the box: | ||
+ | |||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (method (doVerb theVerb) | ||
+ | (switch theVerb | ||
+ | (V_DO | ||
+ | (self setScript: shrinkBoxScript) | ||
+ | ) | ||
+ | (else | ||
+ | (super doVerb: theVerb &rest) | ||
+ | ) | ||
+ | ) | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Now add some meat to the shrinkBoxScript. | ||
+ | |||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (instance shrinkBoxScript of Script | ||
+ | (properties) | ||
+ | |||
+ | (method (changeState newState) | ||
+ | (= state newState) | ||
+ | (switch state | ||
+ | (0 | ||
+ | (gGame handsOff:) | ||
+ | ; We could also say (theBox setCycle: EndLoop self) | ||
+ | (client setCycle: EndLoop self) | ||
+ | ) | ||
+ | (1 | ||
+ | (= seconds 2) | ||
+ | ) | ||
+ | (2 | ||
+ | (Prints {The box shrunk!}) | ||
+ | (gGame handsOn:) | ||
+ | ) | ||
+ | ) | ||
+ | ) | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Ok, what is all that? First of all, ''case 0'' will be executed as soon as the Script is set on the box. So that will start the cycle to shrink the box. Note that we added a '''self''' parameter to the setCycle call. This is a common thing for setCycle (and setMotion). It means that '''self''' will be ''cued()'' when the cycle is finished. And what happenes when a Script is cued()? It’s changeState() is called with an incremented ''newState''. So basically this is saying: “when we reach the End of the cycle, go to the next state”. | ||
+ | |||
+ | The next state sets the Script’s seconds to 2. So after 2 seconds, changeState will be called again with an incremented newState. In this final case, we print some text to notify the player what happened (of course, we should probably use a message here). | ||
+ | |||
+ | We also put calls to handsOff and handsOn so that the player can’t go and do something else while this short Script is executing (for instance, to prevent them from touching the box again and re-triggering the Script). | ||
+ | |||
+ | Now, the player can keep touching ''theBox'' and it will appear large again and shrink down. Because that’s what the <span class="Reference">End</span> cycle does: Starts from cel 0 and goes to the end. So maybe we should handle that case. | ||
+ | |||
+ | Go to the top of the script and add a local variable: | ||
+ | |||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (local | ||
+ | hasBoxShrunk = FALSE | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Then modify theBox:doVerb() like so: | ||
+ | |||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (method (doVerb theVerb) | ||
+ | (switch theVerb | ||
+ | (V_DO | ||
+ | (if (not hasBoxShrunk) | ||
+ | (= hasBoxShrunk TRUE) | ||
+ | (self setScript: shrinkBoxScript) | ||
+ | else | ||
+ | (Prints {What a small box!}) | ||
+ | ) | ||
+ | ) | ||
+ | (else | ||
+ | (super doVerb: theVerb &rest) | ||
+ | ) | ||
+ | ) | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Now the box can only shrink once, and we can respond to V_DO with something else when the box is already shrunk. | ||
+ | |||
+ | ==<br /> switchto == | ||
+ | |||
+ | This might be a good time to introduce the switchto statement. It’s just like a switch statement, except the cases are implicitly number from 0 upwards. This can be useful if you’re adding and removing lots of cases as you create your room scripts. | ||
+ | |||
+ | This is what shrinkBoxScript’s changeState method looks like if we use a switchto: | ||
+ | |||
+ | <div class="CodeBlockHeader">Code:</div> | ||
+ | <syntaxhighlight lang="sci"> | ||
+ | (method (changeState newState) | ||
+ | (= state newState) | ||
+ | (switchto state | ||
+ | ( | ||
+ | (gGame handsOff:) | ||
+ | ; We could also say (theBox setCycle: EndLoop self) | ||
+ | (client setCycle: EndLoop self) | ||
+ | ) | ||
+ | ( | ||
+ | (= seconds 2) | ||
+ | ) | ||
+ | ( | ||
+ | (Prints {The box shrunk!}) | ||
+ | (gGame handsOn:) | ||
+ | ) | ||
+ | ) | ||
+ | ) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | It doesn’t look much different, but there’s no chance we miss a state number when we’re adding and removing states. | ||
| | ||
<span style="float: left">[[The Priority Screen|< Previous: The Priority Screen]]</span> | <span style="float: left">[[The Priority Screen|< Previous: The Priority Screen]]</span> | ||
− | <span style="float: right">[[Next: | + | <span style="float: right">[[Managing the Player’s Inventory|Next: Managing the Player’s Inventory >]]</span> |
Latest revision as of 22:59, 30 July 2016
This will show you how to use Cycle objects to create animations.
A simple animation
Remember that blue box? Go back to the box view, and add a third cel. Color shift it so it’s yellow (or do whatever you want).
Go to your script file, and add at a setCycle method call to the box’s initialization:
(theBox
approachVerbs: V_DO
setCycle: Forward
init:
)
This uses the Forward cycler to cycle forward through the loops cels. So when you run the game, the blue box will now cycle between blue, red and yellow. Easy!
To adjust the speed, you can set a different cycleSpeed on the object:
(instance theBox of Prop
(properties
view 123
x 150
y 100
signal ignAct
loop 0
cel 0
noun N_BOX
priority 0
approachX 130
approachY 110
cycleSpeed 15 ; Large numbers are slower.
)
)
Triggering Off Animation Events
Let’s do something a little more complicated. Let’s make the box shrink when the player touches it. Go back to view 123, and create a new loop. When you create a new loop, by default it should contain the first cel of the previous loop (it has to contain something). That’s great, it’s our blue box.
Add three more cels to the loop. They should all have blue boxes in them by default.
Click on the second cel and resize the borders while holding down the SHIFT key (this makes resizing the borders grow or shrink the view inside). Make the box a little smaller. Click on the third cel and make it even smaller, and so on. You should end up with something like this:
Now we’ll write code that triggers off the ego performing the V_DO verb on the N_BOX. In that, we’ll make the box cels cycle from beginning to end. To do that, we’ll need to do a few things:
- Remove the (theBox:setCycle(Forward)) we added in the previous section (in the room’s init()).
- Make theBox use loop 1 by default (since that’s where our shrinking box is).
- Add a doVerb method to theBox, and tell the box to cycle from beginning to end.
(instance theBox of Prop
(properties
view 123
x 150
y 100
signal ignAct
loop 1
cel 0
noun N_BOX
priority 0
approachX 130
approachY 110
cycleSpeed 15
)
(method (doVerb theVerb)
(switch theVerb
(V_DO
(self setCycle: EndLoop)
)
(else
(super doVerb: theVerb &rest)
)
)
)
)
Compile and run the game to test it.
That’s nice, but what if we want to display a message after the box has shrunk? This is where Script objects come in (not to be confused with script files). With a Script we can choreograph a sequence of events. We’ll make a Script that has a state for shrinking the box, followed by a state for displaying a message. We’ll attach this Script to theBox.
First, create a new Script object (you can use Insert Object->Script for convenience):
(instance shrinkBoxScript of Script
(properties)
(method (changeState newState)
(= state newState)
(switch state
(0)
)
)
)
Then, replace our previous handling of theBox doVerb with a call to set the Script on the box:
(method (doVerb theVerb)
(switch theVerb
(V_DO
(self setScript: shrinkBoxScript)
)
(else
(super doVerb: theVerb &rest)
)
)
)
Now add some meat to the shrinkBoxScript.
(instance shrinkBoxScript of Script
(properties)
(method (changeState newState)
(= state newState)
(switch state
(0
(gGame handsOff:)
; We could also say (theBox setCycle: EndLoop self)
(client setCycle: EndLoop self)
)
(1
(= seconds 2)
)
(2
(Prints {The box shrunk!})
(gGame handsOn:)
)
)
)
)
Ok, what is all that? First of all, case 0 will be executed as soon as the Script is set on the box. So that will start the cycle to shrink the box. Note that we added a self parameter to the setCycle call. This is a common thing for setCycle (and setMotion). It means that self will be cued() when the cycle is finished. And what happenes when a Script is cued()? It’s changeState() is called with an incremented newState. So basically this is saying: “when we reach the End of the cycle, go to the next state”.
The next state sets the Script’s seconds to 2. So after 2 seconds, changeState will be called again with an incremented newState. In this final case, we print some text to notify the player what happened (of course, we should probably use a message here).
We also put calls to handsOff and handsOn so that the player can’t go and do something else while this short Script is executing (for instance, to prevent them from touching the box again and re-triggering the Script).
Now, the player can keep touching theBox and it will appear large again and shrink down. Because that’s what the End cycle does: Starts from cel 0 and goes to the end. So maybe we should handle that case.
Go to the top of the script and add a local variable:
(local
hasBoxShrunk = FALSE
)
Then modify theBox:doVerb() like so:
(method (doVerb theVerb)
(switch theVerb
(V_DO
(if (not hasBoxShrunk)
(= hasBoxShrunk TRUE)
(self setScript: shrinkBoxScript)
else
(Prints {What a small box!})
)
)
(else
(super doVerb: theVerb &rest)
)
)
)
Now the box can only shrink once, and we can respond to V_DO with something else when the box is already shrunk.
switchto
This might be a good time to introduce the switchto statement. It’s just like a switch statement, except the cases are implicitly number from 0 upwards. This can be useful if you’re adding and removing lots of cases as you create your room scripts.
This is what shrinkBoxScript’s changeState method looks like if we use a switchto:
(method (changeState newState)
(= state newState)
(switchto state
(
(gGame handsOff:)
; We could also say (theBox setCycle: EndLoop self)
(client setCycle: EndLoop self)
)
(
(= seconds 2)
)
(
(Prints {The box shrunk!})
(gGame handsOn:)
)
)
)
It doesn’t look much different, but there’s no chance we miss a state number when we’re adding and removing states.
< Previous: The Priority Screen Next: Managing the Player’s Inventory >