[Update 8pm GMT] UDK: Model's animations aren't playing!

Started by
12 comments, last by Sammieo 11 years, 1 month ago

Very basic question, I imagine, and forgive me if I'm phrasing it wrong, but Google has not been kind to me in my search for an answer. I want to give my character in UDK a model, but I'm not quite sure how, and the amount of tiny questions I have about it only seems to grow:

- Must my model be in a specific directory? If so, which one?
- Do I need to use unrealscript to do it, or is that simply the recommended way?
- How do I play animations? Must the call to the animation be written in unrealscript as it enters a new function or state?

This is how I understand how to attach a mesh to an actor right now, by writing this in the defaultproperties section of a Pawn or Actor:


Begin Object Class=StaticMeshComponent Name=BasicMesh

        StaticMesh=StaticMesh'UN_SimpleMeshes.TexPropCube_Dup'

        Materials(0)=Material'EditorMaterials.WidgetMaterial_X'

        LightEnvironment=MyLightEnvironment

        Scale3D=(X=0.25,Y=0.25,Z=0.5)

  End Object

  Components.Add(BasicMesh)


From this I can tell that 'UN_SimpleMeshes.TexPropCube_Dup' is the actual object, and exists somewhere in the UDK folders, but that is the extent of my knowledge. If anyone could offer some wisdom to me, it'd make a world of difference!

Advertisement

- Must my model be in a specific directory? If so, which one?

Nope, you can put it anywhere you want (though the package itself should be somewhere in the Content folder). And don't worry about the file type and path... unless you're like me and you enjoy typing all of it out tongue.png

StaticMesh=TexPropCube_Dup would get you the same result as StaticMesh=StaticMesh'UN_SimpleMeshes.TexPropCube_Dup'.

- Do I need to use unrealscript to do it, or is that simply the recommended way?

If you only want the mesh attached to the player for one part of the level or for some other scripted event, it might be better to use the AttachToActor node in Kismet. If you want the mesh attached all the time though, it'd probably be better to have it in Unrealscript. Also, you can only attach to an actor in Kismet, but in Unrealscript, you can attach components to an actor or to the actor's SkeletalMeshComponents.

If you're attaching something to the player, then you'll be attaching directly to the actor (as opposed to if you were attaching something to an enemy pawn, where you'd be attaching to the actor's body mesh). One way is with the DefaultProperties like you have written out. Another way is to create and attach the components dynamically, which would look something like this:


var() SkeletalMeshComp Comp;    //Can also be a StaticMeshComponent.... or any other component type

function AttachMesh()
{
   Comp = new(self) class'SkeletalMeshComponent';
   Comp.SetSkeletalMesh( WhateverMesh );
   Comp.SetLightEnvironment( MyLightEnvironment ); 

   AttachComponent( Comp );
}

You can use a local variable instead for the component you're attaching, but if you later want to detach it from the actor, play an animation, etc, it'll be easier if you kept the variable. Now to animations... Unless you're using an AnimTree, you're going to have to call the animations using the SkeletalMeshComponent's PlayAnim(name AnimName, optional float Duration, optional bool bLoop) function (I left out the rest of the optional variables but those are the main ones you'll be using). It's not difficult, but you'll want to avoid playing an animation while an existing one is being played on the component, as the first animation will be stopped and can be pretty ugly unless the first animation is something subtle like a weapon's idle animation. Also, you're going to need to have an AnimNodeSequence to play the animations on (see code below).

Since static meshes can't play anims, I'm going to pretend that the TexPropCube_Dup is a skeletal mesh for an example.


class BreakDancingCube extends Actor
   placeable;

var() SkeletalMeshComponent CubeMesh;
var name CubeMeshAnim;

simulated function PostBeginPlay()
{
   super.PostBeginPlay();

   CubeMesh.PlayAnim( CubeMeshAnim,, True );   //Play a looping animation
}

DefaultProperties
{
Begin Object Class=AnimNodeSequence Name=MeshSequenceA    //Don't need to change any settings, but you need to create it
End Object

Begin Object Class=SkeletalMeshComponent Name=BasicMesh
        SkeletalMesh=SkeletalMesh'UN_SimpleMeshes.TexPropCube_Dup'
        AnimSets(0)=AnimSet'UN_SimpleMeshes.TexPropCube_Anims'        //Totally made-up anim set
        Animations=MeshSequenceA                                      //Animations won't play without this line
        Materials(0)=Material'EditorMaterials.WidgetMaterial_X'
        LightEnvironment=MyLightEnvironment
        Scale3D=(X=0.25,Y=0.25,Z=0.5)
End Object
CubeMesh=BasicMesh       //So that we can reference this in the code
Components.Add(BasicMesh)

CubeMeshAnim=BreakDance   //Made up anim name for the made up anim set
}

Ratrace, thanks for the great help! I've imported the model I want over to UDK and I've set up the code in the MyPawn class so far, but I've ran into a strange error:

"Error, Type mismatch in Call to 'SetSkeletalMesh', parameter 1"

From my reading on the wiki and beyond, the only mandatory argument for SetSkeletalMesh is just one Skeletal mesh. I've gotten no complaints from the way I've set up BirdMesh and MeshSequenceA in Defaultproperties, so I feel like this is the one place the problem's coming from.

Here's the code in full, with (mostly) only the relevant parts left in.


class BirdPawn extends UTPawn;

var() SkeletalMeshComponent BirdMesh;
var() SkeletalMeshComponent CurrMesh;

var name BirdWalkAnim;

simulated function PostBeginPlay()
{
    super.PostBeginPlay();
    SetMeshVisibility(true);
    `log("The player birdpawn has spawned!");
}

function AttachMesh()
{
   CurrMesh = new(self) class'SkeletalMeshComponent';
   CurrMesh.SetSkeletalMesh(BirdMesh);  //This line causes the error!
   CurrMesh.SetLightEnvironment( MyLightEnvironment );

   AttachComponent(CurrMesh);
}

defaultproperties
{
    Begin Object Class=AnimNodeSequence Name=MeshSequenceA
    End Object

    Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
      bEnabled=TRUE
      End Object
    Components.Add(MyLightEnvironment)

    Begin Object= Class=SkeletalMeshComponent Name=Boobooday
          SkeletalMesh=SkeletalMesh'BirdPackage.BooboodayPacked'
          AnimSets(0)=AnimSet'BirdPackage.Armature'
          Animations=MeshSequenceA
          Materials(0)=Material'EditorMaterials.WidgetMaterial_X'
          LightEnvironment=MyLightEnvironment
          Scale3D=(X=0.25,Y=0.25,Z=0.5)
          End Object
    BirdMesh=Boobooday
    Components.Add(Boobooday)

    BirdWalkAnim = WalkOnLand
}


I also tried setting this code up in the BirdActor class, but I encountered the same issues. I may have misunderstood something you were telling me, but I thought I'd define the mesh to be the main item and then pass that in as the Skeletal Mesh to set and attach to the pawn as a component.

I'm a little baffled myself, if I can say so. Can anyone offer any advice?

Bumping this thread up so I can give you the full code. Parts I believe to be relevant are highlighted;


class CrowPawn extends UTPawn;

var int IsoCamAngle;
var float CamOffsetDistance;

var() SkeletalMeshComponent BirdMesh;
var() SkeletalMeshComponent CurrMesh;

var name BirdWalkAnim;

simulated function PostBeginPlay()
{
    super.PostBeginPlay();
    AttachMesh();
    SetMeshVisibility(true);
    `log("The player crow pawn has spawned!");
}

function AttachMesh()
{
   CurrMesh = new(self) class'SkeletalMeshComponent';
   CurrMesh.SetSkeletalMesh(BirdMesh);
   CurrMesh.SetLightEnvironment( MyLightEnvironment );

   AttachComponent(CurrMesh);
}

simulated function SetMeshVisiblity(bool bVisible)
{
    super.SetMeshVisibility(bVisible);
    Mesh.SetOwnerNoSee(false);
}

simulated function bool CalcCamera(float DeltaTime, out vector out_CamLoc, out rotator out_CamRot, out float out_FOV)
{
    local Vector HitLocation, HitNormal;

    out_CamLoc           = Location;
    out_CamLoc.X        -= Cos(Rotation.Yaw * UnrRotToRad) * Cos(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;
    out_CamLoc.Y        -= Sin(Rotation.Yaw * UnrRotToRad) * Cos(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;
    out_CamLoc.Z        -= Sin(IsoCamAngle * UnrRotToRad) * CamOffsetDistance;

    out_CamRot.Yaw       = Rotation.Yaw;
    out_CamRot.Pitch     = IsoCamAngle;
    out_CamRot.Roll      = 0;

    if (Trace(HitLocation, HitNormal, out_CamLoc, Location, false, vect(12, 12, 12)) != none)
    {
        out_CamLoc = HitLocation;
    }

    return true;
}

defaultproperties
{
    IsoCamAngle=20
    CamOffsetDistance=190.0

    Begin Object Class=AnimNodeSequence Name=MeshSequenceA
    End Object

    /*Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
      bEnabled=TRUE
      End Object
    Components.Add(MyLightEnvironment)*/

    Begin Object= Class=SkeletalMeshComponent Name=Boobooday
          SkeletalMesh=SkeletalMesh'BirdPackage.BooboodayPacked'
          AnimSets(0)=AnimSet'BirdPackage.Armature'
          Animations=MeshSequenceA
          Materials(0)=Material'EditorMaterials.WidgetMaterial_X'
          LightEnvironment=MyLightEnvironment
          Scale3D=(X=0.25,Y=0.25,Z=0.5)
          End Object
          BirdMesh=Boobooday
          Components.Add(Boobooday)

    BirdWalkAnim = WalkOnLand
}

EDIT: Agh, sorry, the green text seems to pop up instead. :/ Ah well, you can compare with the code up above anyway. I'm wondering if something went wrong in importing the model, but I wouldn't know how; I followed the steps in these two videos:


The problem would be that you're using a SkeletalMeshComponent in the SetSkeletalMesh function, which takes a SkeletalMesh (sorry if I didn't make that clear in my post).

But if you have the component added in the DefaultProperties (like you have it), there's no need to dynamically attach it again. Dynamic attachment is meant for cases when you can't have the attachment in the DefaultProperties because you don't know what it will be (such as armor pieces for a pawn, weapon add-ons, etc).

Also, for some reason I was under the impression you were extending from a class below UTPawn... UTPawn has the WPawnSkeletalMeshComponent, whose settings you can change pretty quickly to get a visible body mesh. UTPawn also already has a DynamicLightEnvironment and two AnimNodeSequences (for the arms meshes, but we can steal them for the body mesh if you aren't using an anim tree tongue.png). The "Mesh" variable from the Pawn class is also referenced to WPawnSkeletalMeshComponent, so you can use that in your code. This will be enough to give your pawn a mesh that's capable of playing animations:


class BirdPawn extends UTPawn;

var name BirdWalkAnim;

simulated function PostBeginPlay()
{
    super.PostBeginPlay();
    SetMeshVisibility(true);
    `log("The player birdpawn has spawned!");
}

defaultproperties
{
    Begin Object Name=WPawnSkeletalMeshComponent
          SkeletalMesh=SkeletalMesh'BirdPackage.BooboodayPacked'
          AnimSets(0)=AnimSet'BirdPackage.Armature'
          Animations=MeshSequenceA
          AnimTreeTemplate=None
          Materials(0)=Material'EditorMaterials.WidgetMaterial_X'
          LightEnvironment=MyLightEnvironment
          Scale3D=(X=0.25,Y=0.25,Z=0.5)
    End Object

    BirdWalkAnim = WalkOnLand
}

Depending on the scope of your project, it may be worth it to spend the time making an animtree. They're a pain to make, but they make it very easy to change or blend animations based on pawn physics, looking direction, etc.

Thanks for the clarity.

I have an AnimSet, and truth be told my project isn't meant to be about animation or modelling, just tieing UDK together in a way as to create a functional game, so this is just to make thiings fit a 'narrative' of sorts that my mechanics have hopefully laid out. An AnimTree is something I'd like to do fundamentally, but truth be told I'd like to be able to focus on my other modules that I've long neglected (particularly with exams around the corner!), so I hope you'll forgive me if I try and make do without one. If I can get my lil' Boobooday model playing with two/three animations from the Armature set, I'll be stoked.

I've tried your method and, good news, the model has changed! Bad news, though, is that the model now hovers a few inches above the ground, and is still the same UTBot model, only with no animations. Something's clearly gone wrong along the way, as I'm supposed to be seeing a little bird right about now.
Hrghm, any ideas?

Ahh yes. For the pawn mesh, if you're extending from both UTPawn and UTBot, you have to deal with UTFamilyInfo... There are two things you can do. One would be to extend your own class from UTFamilyInfo and set that as the CurrCharClassInfo in your pawn. The other choice would be to overwrite the family info function in your pawn if you don't want to deal with family info at all, like


simulated function SetCharacterClassFromInfo(class<UTFamilyInfo> Info)
{
	//Ignoring family info
}

As for animations, I can't see if you're calling any animations. The typical way of getting the pawn to start playing animations is to, in the controller/bot class, set the player's physics to PHYS_Falling by calling Pawn.SetMovementPhysics() when the controller class has possessed a pawn (which has already been done in UTBot). However, that only gets animations playing because of the animtree. So if you wanted to play an idle animation on startup for example, you'd need to directly call the animation.


//We're in the bot class
function Possess( Pawn aPawn, bool bVehicleTransition )
{
   super.Possess( aPawn, bVehicleTransition );

   aPawn.Mesh.PlayAnim( BirdPawn(aPawn).IdleAnim, , True );     //Loops a hypothetical IdleAnim
}

Finally, for the player hovering above the ground, that would most likely be that the collision cylinder and the mesh aren't aligned. Play the level and in the console, type "show collision". What you'll probably see is the collision cylinder touching the ground and the mesh hovering somewhere above that. To fix that, you'll need to modify the WPawnSkeletalMeshComponent's Z Translation in the DefaultProperties. UTPawn has it set to 8, but you'll have to change that number to work for your mesh, depending on where its pivot point is.

Trying the second option gave an interesting and comically alarming result - I think it worked, but it's really small! This may be something I have to change in the unreal edior, but right now the model is a small dot so tiny I confused it for a crosshair at first! If I squint, I think animations are even playing, but it'd be easier to tell if it were in a larger size.

I ask since I'm uncertain where to go for this - Blender or Unreal Editor, I presume - or what tools I should use when I get there; are there any bright ideas out there on how to increase a model's size?

Yeah, that's super common. Characters smaller than bullets and guns bigger than buildings. :P

I'd just place the model in a level and scale it however much you need it to be in UDK. Take note of how much you scaled it, then go into blender or any other modeling tool, scale it to that size in there, and reimport. A trick to help with that is to have your (correctly-scaled) character model in the scene when you're modeling, to use as a reference for scale.

But yeah, definitely correct the scale in your modelling tool and reimport... Dealing with a bunch of models out of scale is way more of a headache than it's worth.

EDIT: Collision cylinder is aligned just fine now: my problem was I wasn't using extreme enough units. Lowering the unreal units into the negatives did me just fine.

I've edited the scaling and the model's now at a size that I want it! Only one problem remains - playing animations.

As for the animations, I'm getting a really strange error with PlayAnim: I know my animation names and package names are correct, but with Unrealscript


Pawn.Mesh.PlayAnim( BirdPawn(Pawn).Boobooday_Packed_WalkOnLand, , True ); //causes an error

Just gives me the error:

Unrecognised member "Boobooday_Packed_WalkOnLand" in class "BirdPawn"

(If you're wondering why I'm saying Boobooday_Packed instead of BooboodayPacked, it's because that's my re-imported package.)

I'm not sure if there's some variable I'm meant to assign for the animation or what, since I don't have anything like that in the code; I still have that BirdWalkAnim name var lying around, but I'm not sure how to it - do you mean to just call that whenever I use PlayAnim?

All the other resources I've found on the topic seem to point me to Kismet, but with only two days to learn it in, I'd love it if Unrealscript could cover me.

This topic is closed to new replies.

Advertisement