PDA

View Full Version : Custom Enemy Attack Animation



TenaciousMB
12-02-2011, 07:56 AM
Hi,

I have made a few few threads for help with getting a working custom character into my uni project. I have a week left and for the life of me, I just can't figure out what to do to get the attack animation triggering when attacking.

Please, please, please can someone help me out :/

I just want to outline that I am not a programmer and have been forced into the deepend of this project due to a group member leaving...

Sorry, as I know it is frustrating when people come on here with no previous experience. I have recieved some help from people already but just cant find an answer...


Badguy3Controller:

class Badguy3Controller extends AIController;

var Badguy3 MyBadguy3Pawn;
var Pawn thePlayer;
var Actor theNoiseMaker;
var Vector noisePos;

var () array<NavigationPoint> MyNavigationPoints;
var NavigationPoint MyNextNavigationPoint;

var int actual_node;
var int last_node;

var float perceptionDistance;
var float hearingDistance;
var float attackDistance;
var int attackDamage;

var float distanceToPlayer;
var float distanceToTargetNodeNearPlayer;

var Name AnimSetName;

var bool AttAcking;
var bool followingPath;
var bool noiseHeard;
var Float IdleInterval;

defaultproperties
{
attackDistance = 50
attackDamage = 10
perceptionDistance = 1000

AnimSetName ="ATTACK"
actual_node = 0
last_node = 0
followingPath = true
IdleInterval = 2.5f

}

function SetPawn(Badguy3 NewPawn)
{
MyBadguy3Pawn = NewPawn;
Possess(MyBadguy3Pawn, false);
MyNavigationPoints = MyBadguy3Pawn.MyNavigationPoints;
}

function Possess(Pawn aPawn, bool bVehicleTransition)
{
if (aPawn.bDeleteMe)
{
`Warn(self @ GetHumanReadableName() @ "attempted to possess destroyed Pawn" @ aPawn);
ScriptTrace();
GotoState('Dead');
}
else
{
Super.Possess(aPawn, bVehicleTransition);
Pawn.SetMovementPhysics();

if (Pawn.Physics == PHYS_Walking)
{
Pawn.SetPhysics(PHYS_Falling);
}
}
}


state Idle
{

event SeePlayer(Pawn SeenPlayer)
{
thePlayer = SeenPlayer;
distanceToPlayer = VSize(thePlayer.Location - Pawn.Location);
if (distanceToPlayer < perceptionDistance)
{
Worldinfo.Game.Broadcast(self, "Help, I have the plague!");
GotoState('Chaseplayer');
}
}

Begin:
Worldinfo.Game.Broadcast(self, "!!!!!!! idle !!!!!!!!");

Pawn.Acceleration = vect(0,0,0);
MyBadguy3Pawn.SetAttacking(false);

Sleep(IdleInterval);

Worldinfo.Game.Broadcast(self, "!!!!!!! Going to FollowPath !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
followingPath = true;
actual_node = last_node;
GotoState('FollowPath');

}

state Chaseplayer
{
Begin:

MyBadguy3Pawn.SetAttacking(false);
Pawn.Acceleration = vect(0,0,1);

while (Pawn != none && thePlayer.Health > 0)
{
Worldinfo.Game.Broadcast(self, "I can see you!!");

if (ActorReachable(thePlayer))
{
distanceToPlayer = VSize(thePlayer.Location - Pawn.Location);
if (distanceToPlayer < attackDistance)
{
GotoState('Attack');
break;
}
else //if(distanceToPlayer < 300)
{
MoveToward(thePlayer, thePlayer, 20.0f);
if(Pawn.ReachedDestination(thePlayer))
{
GotoState('Attack');
break;
}
}
}
else
{
MoveTarget = FindPathToward(thePlayer,,perceptionDistance + (perceptionDistance/2));
if (MoveTarget != none)
{
//Worldinfo.Game.Broadcast(self, "Moving toward Player");

distanceToPlayer = VSize(MoveTarget.Location - Pawn.Location);
if (distanceToPlayer < 100)
MoveToward(MoveTarget, thePlayer, 20.0f);
else
MoveToward(MoveTarget, MoveTarget, 20.0f);

//MoveToward(MoveTarget, MoveTarget);
}
else
{
GotoState('Idle');
break;
}
}

}
}

state Attack
{
Begin:
Pawn.Acceleration = vect(0,0,0);
MyBadguy3Pawn.SetAttacking(true);
while(true && thePlayer.Health > 0)
{
Worldinfo.Game.Broadcast(self, "Attacking Player");
thePlayer.TakeDamage(10, self, Location, vect(0,0,0), class'UTDmgType_Burning');

distanceToPlayer = VSize(thePlayer.Location - Pawn.Location);
if (distanceToPlayer > attackDistance * 2)

{
MyBadguy3Pawn.SetAttacking(false);
GotoState('Chaseplayer');
break;
}
Sleep(1);
}
MyBadguy3Pawn.SetAttacking(false);
}


auto state FollowPath
{
event SeePlayer(Pawn SeenPlayer)
{
thePlayer = SeenPlayer;
distanceToPlayer = VSize(thePlayer.Location - Pawn.Location);
if (distanceToPlayer < perceptionDistance)
{
//Worldinfo.Game.Broadcast(self, "I can see you!!");
noiseHeard = true;
followingPath = false;
GotoState('Chaseplayer');
}
}

Begin:

while(followingPath)
{
MoveTarget = MyNavigationPoints[actual_node];

if(Pawn.ReachedDestination(MoveTarget))
{
WorldInfo.Game.Broadcast(self, "Oooohhh a node!");
actual_node++;

if (actual_node >= MyNavigationPoints.Length)
{
actual_node = 0;
}
last_node = actual_node;

MoveTarget = MyNavigationPoints[actual_node];
}

if (ActorReachable(MoveTarget))
{
//distanceToPlayer = VSize(MoveTarget.Location - Pawn.Location);
//if (distanceToPlayer < perceptionDistance / 3)
// MoveToward(MoveTarget, MyNavigationPoints[actual_node + 1]);
//else
MoveToward(MoveTarget, MoveTarget);
}
else
{
MoveTarget = FindPathToward(MyNavigationPoints[actual_node]);
if (MoveTarget != none)
{

//SetRotation(RInterpTo(Rotation,Rotator(MoveTarget. Location),Delta,90000,true));

MoveToward(MoveTarget, MoveTarget);
}
}

Sleep(1);
}
}

BadGuy3:

class Badguy3 extends UTPawn
placeable;

// members for the custom mesh
var SkeletalMesh defaultMesh;
//var MaterialInterface defaultMaterial0;
var AnimTree defaultAnimTree;
var array<AnimSet> defaultAnimSet;
var AnimNodeSequence defaultAnimSeq;
var PhysicsAsset defaultPhysicsAsset;
var Pawn P; // variable to hold the pawn we bump into
var BadGuyZombieBot MyController;

var float Speed;
var float hearingDistance;
var float perceptionDistance;

var SkeletalMeshComponent MyMesh;
var bool bplayed;
var Name AnimSetName;
var AnimNodeSequence MyAnimPlayControl;

var bool AttAcking;

var () array<NavigationPoint> MyNavigationPoints;

simulated event Bump( Actor Other, PrimitiveComponent OtherComp, Vector HitNormal )
{
`Log("Bump");

Super.Bump( Other, OtherComp, HitNormal );

if ( (Other == None) || Other.bStatic )
return;

P = Pawn(Other); //the pawn we might have bumped into

if ( P != None) //if we hit a pawn
{
if (P.Health >0) //as long as pawns health is more than 1

{
P.Health --; //take away the pawns health
}
}

if (P.Health <1) //as long as pawns health is more than 1

{
P.Destroy(); //kills the player
}
}





simulated function PostBeginPlay()
{
super.PostBeginPlay();
//if (Controller == none)
// SpawnDefaultController();
SetPhysics(PHYS_Walking);
if (MyController == none)
{
MyController = Spawn(class'BadGuyZombieBot', self);
//MyController.SetPawn(self);
}

}

function SetAttacking(bool atacar)
{
AttAcking = atacar;
}



simulated function SetCharacterClassFromInfo(class<UTFamilyInfo> Info)
{
Mesh.SetSkeletalMesh(defaultMesh);
//Mesh.SetMaterial(0,defaultMaterial0);
Mesh.SetPhysicsAsset(defaultPhysicsAsset);
Mesh.AnimSets=defaultAnimSet;
Mesh.SetAnimTreeTemplate(defaultAnimTree);

}

defaultproperties
{
Speed=80
GroundSpeed=80
perceptionDistance =50
hearingDistance =50
AnimSetName="ATTACK"
AttAcking=true

defaultMesh=SkeletalMesh'PLG_ENEMIES.PLG_ENIM_INFM ALE'
defaultAnimTree=AnimTree'PLG_ENEMIES.PLG_ENIM_INFM ALE_ANIMTREE'
defaultAnimSet(0)=AnimSet'PLG_ENEMIES.PLG_INFMALE_ WALK'
//defaultPhysicsAsset=PhysicsAsset'Enemies.scribble_ meshh_Physics'

SoundGroupClass=class'UTPawnSoundGroup_Liandri'

Begin Object Name=WPawnSkeletalMeshComponent

Scale=1
SkeletalMesh=SkeletalMesh'PLG_ENEMIES.PLG_ENIM_INF MALE'
AnimSets(0)=AnimSet'PLG_ENEMIES.PLG_INFMALE_WALK'
AnimTreeTemplate=AnimTree'PLG_ENEMIES.PLG_ENIM_INF MALE_ANIMTREE'
End Object

}
Thanks in advance...

danath
12-02-2011, 08:49 AM
as far as i know you need to set an animtree with a fullbodyslot , then you call the fullbodyslot variable like this :



var AnimNodeSlot FullBodyAnimSlot;
simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
{

super.PostInitAnimTree(SkelComp);

FullBodyAnimSlot = AnimNodeSlot(mesh.FindAnimNode('FullBodySlot')); // <== FullBodySlot was the name i put in the FullBodyAnimSlot Box in the animtree
}



then to play an anim do that :
FullBodyAnimSlot.PlayCustomAnim("MyAnimationName",1,0.2,0.2,false,false); <== see the parameter you like in the declaration of playcustomanim



Good luck !

TenaciousMB
12-02-2011, 09:10 AM
Hi Danath,

I have implimented code and I am getting the error that I was recieving with earlier efforts:

Error, 'FullBodyAnimSlot': Bad command or expression

I have no idea what to do to rectify this :/ any ideas?

Thanks for the help :)

TenaciousMB
12-02-2011, 10:02 AM
Anyone got any ideas? :/

meganaut
12-02-2011, 10:22 AM
Hi TenaciousMB,

Do you have the FullBodyAnimSlot in your animtree? If not, that code cannot work.

Heres a quick walktrhough:

-Open up your AnimTree
-Add an AnimNodeSlot
-In the properties of that widget, Change the Node name to FullBodySlot
-Whatever is connected to the Animation socket of your anim tree widget (the main widget), disconnect it from the main widget and connect it to the source socket on the AnimNodeSlot widget.
- now connect the output of the AnimNodeSlot widget to the animation socket on the main widget.
-save

Thats all there is to it really.

If perchance, this isnt the problem, And you already have your anim tree set up correctly, then you should post the latest code you have that is producing that error.

-Mega

TenaciousMB
12-02-2011, 11:16 AM
Thanks Mega!

Followed instructions above and I am still reciving the red error below:

Development\Src\UTGame\Classes\Badguy3Controller.u c(150) : Error, 'FullBodyAnimSlot': Bad command or expression

my code is as follows:

BadguyController3:

class Badguy3Controller extends AIController;

var Badguy3 MyBadguy3Pawn;
var Pawn thePlayer;
var Actor theNoiseMaker;
var Vector noisePos;

var () array<NavigationPoint> MyNavigationPoints;
var NavigationPoint MyNextNavigationPoint;

var int actual_node;
var int last_node;

var float perceptionDistance;
var float hearingDistance;
var float attackDistance;
var int attackDamage;

var float distanceToPlayer;
var float distanceToTargetNodeNearPlayer;

var Name AnimSetName;

var bool AttAcking;
var bool followingPath;
var bool noiseHeard;
var Float IdleInterval;

defaultproperties
{
attackDistance = 50
attackDamage = 10
perceptionDistance = 1000

AnimSetName ="ATTACK"
actual_node = 0
last_node = 0
followingPath = true
IdleInterval = 2.5f

}

function SetPawn(Badguy3 NewPawn)
{
MyBadguy3Pawn = NewPawn;
Possess(MyBadguy3Pawn, false);
MyNavigationPoints = MyBadguy3Pawn.MyNavigationPoints;
}

function Possess(Pawn aPawn, bool bVehicleTransition)
{
if (aPawn.bDeleteMe)
{
`Warn(self @ GetHumanReadableName() @ "attempted to possess destroyed Pawn" @ aPawn);
ScriptTrace();
GotoState('Dead');
}
else
{
Super.Possess(aPawn, bVehicleTransition);
Pawn.SetMovementPhysics();

if (Pawn.Physics == PHYS_Walking)
{
Pawn.SetPhysics(PHYS_Falling);
}
}
}


state Idle
{

event SeePlayer(Pawn SeenPlayer)
{
thePlayer = SeenPlayer;
distanceToPlayer = VSize(thePlayer.Location - Pawn.Location);
if (distanceToPlayer < perceptionDistance)
{
Worldinfo.Game.Broadcast(self, "Help, I have the plague!");
GotoState('Chaseplayer');
}
}

Begin:
Worldinfo.Game.Broadcast(self, "!!!!!!! idle !!!!!!!!");

Pawn.Acceleration = vect(0,0,0);
MyBadguy3Pawn.SetAttacking(false);

Sleep(IdleInterval);

Worldinfo.Game.Broadcast(self, "!!!!!!! Going to FollowPath !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
followingPath = true;
actual_node = last_node;
GotoState('FollowPath');

}

state Chaseplayer
{
Begin:

MyBadguy3Pawn.SetAttacking(false);
Pawn.Acceleration = vect(0,0,1);

while (Pawn != none && thePlayer.Health > 0)
{
Worldinfo.Game.Broadcast(self, "I can see you!!");

if (ActorReachable(thePlayer))
{
distanceToPlayer = VSize(thePlayer.Location - Pawn.Location);
if (distanceToPlayer < attackDistance)
{
GotoState('Attack');
break;
}
else //if(distanceToPlayer < 300)
{
MoveToward(thePlayer, thePlayer, 20.0f);
if(Pawn.ReachedDestination(thePlayer))
{
GotoState('Attack');
break;
}
}
}
else
{
MoveTarget = FindPathToward(thePlayer,,perceptionDistance + (perceptionDistance/2));
if (MoveTarget != none)
{
//Worldinfo.Game.Broadcast(self, "Moving toward Player");

distanceToPlayer = VSize(MoveTarget.Location - Pawn.Location);
if (distanceToPlayer < 100)
MoveToward(MoveTarget, thePlayer, 20.0f);
else
MoveToward(MoveTarget, MoveTarget, 20.0f);

//MoveToward(MoveTarget, MoveTarget);
}
else
{
GotoState('Idle');
break;
}
}

}
}

state Attack
{
Begin:
Pawn.Acceleration = vect(0,0,0);
MyBadguy3Pawn.SetAttacking(true);
while(true && thePlayer.Health > 0)
{
Worldinfo.Game.Broadcast(self, "Attacking Player");
thePlayer.TakeDamage(10, self, Location, vect(0,0,0), class'UTDmgType_Burning');
//FullBodyAnimSlot.PlayCustomAnim("Attack",1,0.2,0.2,false,false);

distanceToPlayer = VSize(thePlayer.Location - Pawn.Location);
if (distanceToPlayer > attackDistance * 2)

{
MyBadguy3Pawn.SetAttacking(false);
GotoState('Chaseplayer');
break;
}
Sleep(1);
}
MyBadguy3Pawn.SetAttacking(false);
}


auto state FollowPath
{
event SeePlayer(Pawn SeenPlayer)
{
thePlayer = SeenPlayer;
distanceToPlayer = VSize(thePlayer.Location - Pawn.Location);
if (distanceToPlayer < perceptionDistance)
{
//Worldinfo.Game.Broadcast(self, "I can see you!!");
noiseHeard = true;
followingPath = false;
GotoState('Chaseplayer');
}
}

Begin:

while(followingPath)
{
MoveTarget = MyNavigationPoints[actual_node];

if(Pawn.ReachedDestination(MoveTarget))
{
WorldInfo.Game.Broadcast(self, "Oooohhh a node!");
actual_node++;

if (actual_node >= MyNavigationPoints.Length)
{
actual_node = 0;
}
last_node = actual_node;

MoveTarget = MyNavigationPoints[actual_node];
}

if (ActorReachable(MoveTarget))
{
//distanceToPlayer = VSize(MoveTarget.Location - Pawn.Location);
//if (distanceToPlayer < perceptionDistance / 3)
// MoveToward(MoveTarget, MyNavigationPoints[actual_node + 1]);
//else
MoveToward(MoveTarget, MoveTarget);
}
else
{
MoveTarget = FindPathToward(MyNavigationPoints[actual_node]);
if (MoveTarget != none)
{

//SetRotation(RInterpTo(Rotation,Rotator(MoveTarget. Location),Delta,90000,true));

MoveToward(MoveTarget, MoveTarget);
}
}

Sleep(1);
}
}

Badguy3:

class Badguy3 extends UTPawn
placeable;

// members for the custom mesh
var SkeletalMesh defaultMesh;
//var MaterialInterface defaultMaterial0;
var AnimTree defaultAnimTree;
var array<AnimSet> defaultAnimSet;
var AnimNodeSequence defaultAnimSeq;
var PhysicsAsset defaultPhysicsAsset;
var Pawn P; // variable to hold the pawn we bump into
var BadGuyZombieBot MyController;

var float Speed;
var float hearingDistance;
var float perceptionDistance;

var SkeletalMeshComponent MyMesh;
var bool bplayed;
var Name AnimSetName;
var AnimNodeSequence MyAnimPlayControl;

var bool AttAcking;

var () array<NavigationPoint> MyNavigationPoints;

simulated event PostInitAnimTree(SkeletalMeshComponent SkelComp)
{

super.PostInitAnimTree(SkelComp);

FullBodyAnimSlot = AnimNodeSlot(mesh.FindAnimNode('FullBodySlot')); // <== FullBodySlot was the name i put in the FullBodyAnimSlot Box in the animtree
}

simulated event Bump( Actor Other, PrimitiveComponent OtherComp, Vector HitNormal )
{
`Log("Bump");

Super.Bump( Other, OtherComp, HitNormal );

if ( (Other == None) || Other.bStatic )
return;

P = Pawn(Other); //the pawn we might have bumped into

if ( P != None) //if we hit a pawn
{
if (P.Health >0) //as long as pawns health is more than 1

{
P.Health --; //take away the pawns health
}
}

if (P.Health <1) //as long as pawns health is more than 1

{
P.Destroy(); //kills the player
}
}





simulated function PostBeginPlay()
{
super.PostBeginPlay();
//if (Controller == none)
// SpawnDefaultController();
SetPhysics(PHYS_Walking);
if (MyController == none)
{
MyController = Spawn(class'BadGuyZombieBot', self);
//MyController.SetPawn(self);
}

}

function SetAttacking(bool atacar)
{
AttAcking = atacar;
}



simulated function SetCharacterClassFromInfo(class<UTFamilyInfo> Info)
{
Mesh.SetSkeletalMesh(defaultMesh);
//Mesh.SetMaterial(0,defaultMaterial0);
Mesh.SetPhysicsAsset(defaultPhysicsAsset);
Mesh.AnimSets=defaultAnimSet;
Mesh.SetAnimTreeTemplate(defaultAnimTree);

}

defaultproperties
{
Speed=80
GroundSpeed=80
perceptionDistance =50
hearingDistance =50
AnimSetName="ATTACK"
AttAcking=true

defaultMesh=SkeletalMesh'PLG_ENEMIES.PLG_ENIM_INFM ALE'
defaultAnimTree=AnimTree'PLG_ENEMIES.PLG_ENIM_INFM ALE_ANIMTREE'
defaultAnimSet(0)=AnimSet'PLG_ENEMIES.PLG_INFMALE_ WALK'
//defaultPhysicsAsset=PhysicsAsset'Enemies.scribble_ meshh_Physics'

SoundGroupClass=class'UTPawnSoundGroup_Liandri'

Begin Object Name=WPawnSkeletalMeshComponent

Scale=1
SkeletalMesh=SkeletalMesh'PLG_ENEMIES.PLG_ENIM_INF MALE'
AnimSets(0)=AnimSet'PLG_ENEMIES.PLG_INFMALE_WALK'
AnimTreeTemplate=AnimTree'PLG_ENEMIES.PLG_ENIM_INF MALE_ANIMTREE'
End Object

}

Thanks again :)

TenaciousMB
12-02-2011, 12:18 PM
Any ideas what is needed to link this animation?

thommie
12-02-2011, 12:20 PM
did you add
var AnimNodeSlot FullBodyAnimSlot;
because FullBodyAnimSlot is only once in Badguy3Controller, commented out and not line 150.

TenaciousMB
12-02-2011, 12:37 PM
Hey Thommie,

Added it to my controller and it has removed the previous error! :D I has however resulted in the following error message:

Error, Type mismatch in Call to 'PlayCustomAnim', parameter 1

I finally feel like im getting somewhere =)

Any ideas what i can do? do i maybe need to list playcustomanim in the variables?

Thanks :)

Timtek
12-02-2011, 12:40 PM
Hi TenaciousMB,
I'm very new to UDK and just starting to code so I can't offer any direct help.
But I did notice in your "BadguyController3" you have your "default properties" defined just under your "Vars".
As far as I know default properties should be the last thing in the class.

danath
12-02-2011, 12:41 PM
Hi tenacious , sorry for the late ,

You should put in your PlayCustomAnim the exact name of your animation in your animset in " " example :

FullBodyAnimSlot.PlayCustomAnim("My_Attack_Anim_Name",1,0.2,0.2,false,false); where My_Attack_Anim_Name is the name you gave of your animation in your animset

Good luck !

TenaciousMB
12-02-2011, 12:43 PM
Thanks Timtek,

Just amended that ;)

TenaciousMB
12-02-2011, 12:49 PM
Hey Danath :)

I think i have already done that, my attack animation within my animset is named 'Attack' so I have put:

FullBodyAnimSlot.PlayCustomAnim("Attack",1,0.2,0.2,false,false);

I just keep getting the following error :/

Error, Type mismatch in Call to 'PlayCustomAnim', parameter 1

I have such a respect for programmers now lol :P

Should i be listing PlayCustomAnim in vars?

thommie
12-02-2011, 12:53 PM
that would do little good :)

and at Timtek, it doesn't have to be at the bottom, it's only common and as far as i know better(don't ask me why, please).

TenaciousMB
12-02-2011, 01:05 PM
Why? No im only joking :P

I can't find anything on this particular issue on the forums :/

I hope its a simple fix :(

Any ideas on the error?

Thanks

thommie
12-02-2011, 01:51 PM
ok so i got it to work with a custom pawn class.

it extended UTPawn, and because of that the FullBodyAnimSlot should already have been set, still checked if it was possible.
in theory, you could use just the last line to make it work. i just looked up an animation from the default pawn and entered it.

please do make sure you use the correct name for the animation, and maybe just use the three lines.



if(FullBodyAnimSlot == none)
FullBodyAnimSlot = AnimNodeSlot(Mesh.FindAnimNode('FullBodySlot'));
FullBodyAnimSlot.PlayCustomAnim('run_fwd_rif',1.0, 0.1,0.1,true,true);

TenaciousMB
12-02-2011, 01:58 PM
THANKYOU!!!

I will try straight away :D

Do I just put this in the attack state?

Thanks! :)

TenaciousMB
12-02-2011, 02:22 PM
I have stuck it in the attack state but it is giving me this error:

Development\Src\UTGame\Classes\Badguy3Controller.u c(152) : Error, Bad or missing expression for token: AnimNodeSlot, in '='

:/

thommie
12-02-2011, 02:29 PM
what if, you do everything related to the animation in your pawn class?

in BadGuy3



var AnimNodeSlot FullBodyAnimSlot;

function pleaseplaytheanimation()
{
if(FullBodyAnimSlot == none)
{
FullBodyAnimSlot = AnimNodeSlot(Mesh.FindAnimNode('FullBodySlot'));
}
FullBodyAnimSlot.PlayCustomAnim('run_fwd_rif',1.0, 0.1,0.1,true,true);
}



and then in your ai controller just Pawn.pleaseplaytheanimation()

that's the only difference i can find.