Note: To begin with, install the following plugins to allow you to export X files from your respective modelling application. X files are the intermediate file format that you'll use to import your characters into Reality Builder.
Note: Your model can actually consist -only- of keyframe animated rigid meshes if you so desire. That enables you to animate rigid objects such as machinery via this standard system. Simply follow the tutorial the same way, minus the bits specific to character skinning.
Note: Modifying the values mentioned on following lines from Player.cs will effectively replace the character model and basic movement animations of the Player in the Eval Kit. However, adjusting these particular values will not affect the rest of the Player's animations that are not listed here (of which there are quite a few), or the Player's ragdoll, so be prepared to see visual incongruities there unless you replace (or remove) the rest of the animations and ragdoll setup.
static private MModel StaticModel = MPrecacher.PrecacheModel(ClassName, "Alien.xml"); //Ln 36, replace this with your XML model name StaticAnimIdle = StaticModel.LoadAnimation("alien_idle.x", true, LowerBodyFrameNames); //Ln 150, replace with your X idle anim StaticAnimRunForward = StaticModel.LoadAnimation("alien_runforward.x", true, LowerBodyFrameNames); //Ln 152, replace with your X run-f anim StaticAnimRunBackward = StaticModel.LoadAnimation("alien_runbackward.x", true, LowerBodyFrameNames); //Ln 153, replace with your X run-b anim StaticAnimStrafeLeft = StaticModel.LoadAnimation("alien_strafeleft.x", true, LowerBodyFrameNames); //Ln 154, replace with your X strafe-l anim StaticAnimStrafeRight = StaticModel.LoadAnimation("alien_straferight.x", true, LowerBodyFrameNames); //Ln 155, replace with your X strafe-r anim // (plays on upper body) StaticAnimHurt = StaticModel.LoadAnimation("alien_hurt.x", false, UpperBodyFrameNames); //Ln 155, replace with your X generic hurt anim // (plays on upper body) StaticAnimIdleUpper = StaticModel.LoadAnimation("alien_idle.x", true, UpperBodyFrameNames); //Ln 161, replace with your X idle anim
Note: In the Eval Kit, you can press Z to enter the Player's Third Person View, or type "spawn Player" into the console to add an idle Player in front of your view.
StaticAnimIdle = StaticModel.LoadAnimation("alien_idle.x", true); // loads an animation track as looping StaticAnimIdle = StaticModel.LoadAnimation("alien_idle.x", false); // loads an animation track as non-looping bool playing = StaticModel.IsPlaying(StaticAnimIdle); //returns whether a looping or non-looping track is currently playing bool looping = StaticModel.IsLooping(StaticAnimIdle); //returns whether a track is a looping track float duration = StaticModel.GetDuration(StaticAnimIdle); //returns the length in seconds of a specified track float remaining = StaticModel.GetRemaining(StaticAnimIdle); //returns the remaining playback time in seconds, if any, of a non-looping track
// get the handles of a couple important bones, // the spine bone to bend at the waist and the gun bone to put the TPV gun at gunBone = MyModel.GetModelFrame("Weapon_bone"); // sets to the absolute transformation of the ModelFrame in the World, including animation transform weaponActor.Location = gunBone.CombinedTransformationMatrix.m3; weaponActor.Rotation = gunBone.CombinedTransformationMatrix.GetRotationMatrix(); // sets the relative transformation of the ModelFrame in the Model's hierarchy (this can be overriden by Animation) gunBone.TransformationMatrix = new MMatrix();
In the Player ctor: MModelFrame spinBone; // get the handles of a couple important bones, // the spine bone to bend at the waist and the gun bone to put the TPV gun at spineBone = MyModel.GetModelFrame("Bip01_Spine2"); ---- ---- Then in the Player PreRender override (done there to allow us to alter the Player's Model transformation immediately before rendering): // get the direction that the player is looking on the XZ plane MVector dir = Rotation.GetDir(); MVector noYdir = new MVector(); dir.Copy(noYdir); noYdir.y = 0; // force the Player's Model base transformation to rotate only on the XZ plane. // The Y-look will come from bending at the waist with SetFrameInfluence below MyModel.RootTransform = MMatrix.LookTowards(noYdir.Normalized()) // calculate the angle between the player's Y-look direction and the World's XZ plane float pitchAngle = dir.RadAngle(MHelpers.VectorDown) - (float)Math.PI / 2; // limit max and min bone bend pitch if (pitchAngle > 1.1f) pitchAngle = 1.1f; else if (pitchAngle < -1.3f) pitchAngle = -1.3f; // bend the Player's Model at the waist according to the Pitch Angle MMatrix spineBoneInfluence = new MMatrix(); spineBoneInfluence.SetRotations(0, pitchAngle, 0); MyModel.SetFrameInfluence(spineBone, spineBoneInfluence);
In the Player ctor: // store two sets of model frame lists -- one for lower body, one for upper body, // which can be used to alter which animations affect which list for differentation between upper // and lower body animations ArrayList meshes = StaticModelTPose.GetModelFrame("Bip01_L_Thigh").EnumerateFrames(); foreach (MModelFrame mesh in meshes) { LowerBodyFrameNames.Add(mesh.Name); } LowerBodyFrameNames.Add("Bip01_Pelvis"); meshes = StaticModelTPose.GetModelFrame("Bip01_Spine").EnumerateFrames(); foreach (MModelFrame mesh in meshes) { bool found = false; foreach (String s in LowerBodyFrameNames) { if (s == mesh.Name) { found = true; break; } } if (!found) UpperBodyFrameNames.Add(mesh.Name); } UpperBodyFrameNames.Add("Bip01"); StaticAnimRunForward = StaticModel.LoadAnimation("alien_runforward.x", true, LowerBodyFrameNames); StaticAnimRunBackward = StaticModel.LoadAnimation("alien_runbackward.x", true, LowerBodyFrameNames); StaticAnimStrafeLeft = StaticModel.LoadAnimation("alien_strafeleft.x", true, LowerBodyFrameNames); StaticAnimStrafeRight = StaticModel.LoadAnimation("alien_straferight.x", true, LowerBodyFrameNames); StaticAnimShoot = StaticModel.LoadAnimation("alien_shoot.x", false, UpperBodyFrameNames); StaticAnimReload = StaticModel.LoadAnimation("alien_reload.x", false, UpperBodyFrameNames);
In the Player Tick, for Lower-body animations: if (CurrentLowerBodyAnim != DesiredLowerBodyAnim) { // transition to the new animation track at .5 weighting over a transitionTime MyModel.TransitionToAnimation(DesiredLowerBodyAnim, transitionTime, .5f, DesiredAnimSpeed); // and stop the old animation track (transition its weighting to 0) MyModel.SetAnimationWeight(CurrentLowerBodyAnim, 0, transitionTime); CurrentLowerBodyAnim = DesiredLowerBodyAnim; } ---- Wherever we want to play an Upper-body animation: // play the event animation if we're not currently playing it, or it's stopped if (CurrentUpperBodyAnim != AnimationIndex || !MyModel.IsPlaying(CurrentUpperBodyAnim)) { // transition to the new animation track at .5 weighting over a transitionTime MyModel.TransitionToAnimation(AnimationIndex, transitionTime, .5f, Speed); // and stop the old animation track (ramp down its weighting to 0) // but only if the previous track is NOT the current track that we're starting to play now if(CurrentUpperBodyAnim != AnimationIndex) MyModel.SetAnimationWeight(CurrentUpperBodyAnim, 0, transitionTime); CurrentUpperBodyAnim = AnimationIndex; }