Character Animation
Using keyframePlayer
This tutorial assumes you have completed my others in the series. You'll need to start with characteranim.dir, which has the shockwave 3D cast member with animation in the form of movement in the legs and arms. I've also included another model, a hat, which you can see in the pic on the left.
At the top, you'll see:
global gWearHat
property pTofuBB, pHatBB
property pCamera, pFlip
I have a global variable, gWearHat, which will define when the character is wearing the hat. Properties pTofuBB and pHatBB are the bounding boxes for the tofu character and hat models respectively. The pFlip variable is one that will flip the movement depending on which camera angle you' re using.
Scroll down the behavior. In the beginSprite handler, we have:
hat = pMember.model("hat")
Here we set the hat local variable to the related model.
tofuBB_MR = pMember.newModelResource("tofuBox
The above numbers relate to the proportions of the tofu. If you were doing this with your own model, you' d need to keep track of the units in your 3D application. In my case, it was 3DS Max. You could create the bounding box in your 3D application to avoid the need to do it via Lingo as I have.
pTofuBB.worldPosition = tofu.worldPosition
invisShader = pMember.newShader("invisShader",#standard)
The above creates a new shader that is meant to be invisible. I have set the blend to 50 so that we can see the bounding box (as seen in the pic). We'll change it to 0 later. The pic shows the bounding box (sphere) for the hat, which we'll create later.
The primary benefit of these parent-child relationships is that they make it easier to move complex models around in the 3D world and to have the component parts of those models move together in the proper way.
Hopefully that will make sense in the context of this tutorial. After the line:
-- create parent child relationships
ptofuBB.addChild(tofu, #preserveworld)
In the above code, we made the character bounding box the parent of a number of child models. In a parent child relationship, you can link multiple child objects to a parent but each child can only have one parent. The child objects are the tofu character, and the arms and legs.
3. Let's inspect some other code I have.
-- create hat bounding box
By
4. You can scroll through the more code which should all be clear. Finally, you'll get to:
-- set starting motion speed
Follow this statement with:
The keyframePlayer registers 2 events - #animationStarted and #animationEnded.
And these can be used by handlers declared in registerforEvent()
5. Scroll down to the keyDown handler and look though the code, which should all make sense. Note the statement:
if keypressed(8) then changeCamera
This means that if the character c is pressed, the changeCamera custom message will be executed.
6. Scroll down to the changeCamera handler.
See the code:
pCamera.rotate(0,0,180,pTofuBB)
7. Scroll up to the keyUp handler. After the pDownArrow statement, add:
pMember.model("armR").keyframePlayer.playRate = 0
This sets the leg and arm movement to a paused state when the any key is released.
8. Scroll back up to the exitFrame handler,
and at the start you'll see SetMoving. This is
the custom message to define the movement of the character when a key is
pressed. Now scroll down to the SetMoving handler.
At the start, insert the following code:
if pRightArrow then pTofuBB.rotate(0,0,-5*pFlip)
pMember.model("legL").keyframePlayer.playRate = 1
When the up or down arrows are pressed, the playRate is set to 1 (normal speed). We also have a variable, pFlip, in the equation, which switches between positive and negative, as we saw earlier.
9. The code that you'll see in the rest of the SetMoving
handler just moves the character up and down the terrain using the modelUnderRay
technique. It is explained in the Terrain
following tutorial.
10. Scroll down to the SetCollision handler.
In here, I have code that uses the modelUnderRay technique to test when the character collides with objects. But I have included 2 bits of collision scripting.
One collision detect will activate checkObjectFoundDistance, the other checkForCollision
1
if gWearHat = TRUE then
ptofuBB.addChild(pHatBB,#preserveParent)
Following the result of step 11, we now have gWearHat being TRUE and so we make changes accordingly.
The hat bounding box is made a child of the character bounding box so that when the character walks, the hat will not be left behind.
We change the world position of the hat to correspond to the bounding box of the tofu character. Then we move the hat up 87 along the z axis so it sits on the character' s head.
13. Now it's time to play the movie and see how it all
works. Notice the bounding boxes. To make them completely invisible, change
the blend to 0. This was referred to at the end of step 1 just before step
2.
Another thing to note is that when you press c, you can toggle between a camera looking from behind and in front. But, no matter what camera view you're using, the up arrow will always move the character up the screen, down arrow will move it down.
You can download the completed movie
from here.
If you're wondering why I used a global variable for gWearHat (it could have worked as a property variable like the others used), you can email me or check back this page in the near future as there is a planned addition.
How the legs and arms were set up in 3DS Max
In Max, the arms and legs were animated as individual objects in a keyframed manner. Lingo made them a child to the body. Often, character animation is created using mesh deformation using a skelteton or bones hierachy. For more info on biped and bones animation setup in Max, look at the Preparing 3D content for Shockwave 3D technote (for general info) and the Character Animation for Shockwave 3D article (detailed info).