action table

Post your questions, suggestions and experiences regarding game design, integration of external libraries here. For irrEdit, irrXML and irrKlang, see the
ambiera forums
Post Reply
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

action table

Post by Seven »

an example of storing the animation frame data for an object.
pretty easy to store / retrieve

Code: Select all

struct CSActionTableEntry
{
public:

	char m_AnimationName[255];
	int m_AnimationStart;
	int m_AnimationEnd;
};

#define MAX_ANIMATIONS 100
class CSActionTable
{
public :

	CSActionTableEntry*	m_Animations[MAX_ANIMATIONS];

	CSActionTable::CSActionTable()			{	Initialize();	}
	virtual CSActionTable::~CSActionTable() {	Cleanup();		}

	virtual void Initialize()
	{
		for (int x=0; x<MAX_ANIMATIONS; x++) { CS_INIT(m_Animations[x]); }
	}

	virtual bool Cleanup()
	{
		for (int x=0; x<MAX_ANIMATIONS; x++) { CS_SAFE_DELETE(m_Animations[x]); }
		return false;
	}

	virtual int AddEntry(char* name, int start, int end)
	{
		for (int x=0; x<MAX_ANIMATIONS; x++)
		{
			if (!m_Animations[x])
			{
				m_Animations[x] = new CSActionTableEntry();
				strcpy(m_Animations[x]->m_AnimationName,name);
				m_Animations[x]->m_AnimationStart = start;
				m_Animations[x]->m_AnimationEnd = end;
				return x;
			}
		}
		return 0;
	}

	virtual CSActionTableEntry* GetEntry(char* name)
	{
		for (int x=0; x<MAX_ANIMATIONS; x++)
		{
			if (m_Animations[x])
			{
				if (!strcmp(m_Animations[x]->m_AnimationName,name))
					return m_Animations[x];
			}
		}
		return NULL;
	}
	virtual CSActionTableEntry* GetEntry(int index)
	{
		return m_Animations[index];
	}
};

Code: Select all

		// setup an action table
		if (GetActionTable())
		{
			GetActionTable()->AddEntry("WALK",2,14);
			GetActionTable()->AddEntry("RUN",16,26);
			GetActionTable()->AddEntry("JUMP",28,40);
			GetActionTable()->AddEntry("JUMP_IN_PLACE",42,54);
			GetActionTable()->AddEntry("CROUCH",56,59);
			GetActionTable()->AddEntry("CROUCH_IDLE",60,69);
			GetActionTable()->AddEntry("STAND_UP",70,74);
			GetActionTable()->AddEntry("BATTLE_IDLE_1",75,88);
			GetActionTable()->AddEntry("BATTLE_IDLE_2",90,110);
			GetActionTable()->AddEntry("ATTACK_1",112,126);
			GetActionTable()->AddEntry("ATTACK_2",128,142);
			GetActionTable()->AddEntry("ATTACK_3",144,160);
			GetActionTable()->AddEntry("ATTACK_4",162,180);
			GetActionTable()->AddEntry("ATTACK_5",182,192);
			GetActionTable()->AddEntry("BLOCK",194,210);
			GetActionTable()->AddEntry("DIE_FORWARD",212,227);
			GetActionTable()->AddEntry("DIE_BACKWARD",230,251);
			GetActionTable()->AddEntry("NOD_HEAD",253,272);
			GetActionTable()->AddEntry("SHAKE_HEAD",274,290);
			GetActionTable()->AddEntry("IDLE_1",292,325);
			GetActionTable()->AddEntry("iDLE_2",327,360);
		}

Code: Select all

	virtual void Stop()						{ CSObject::Stop();					SetAnimation("IDLE_1"); }
	virtual void SetMoveForward(bool d)		{ CSObject::SetMoveForward(d);		if (d) SetAnimation("WALK"); }
	virtual void SetMoveBackward(bool d)	{ CSObject::SetMoveBackward(d);		if (d) SetAnimation("WALK"); }
	virtual void SetMoveTurnLeft(bool d)	{ CSObject::SetMoveTurnLeft(d);		if (d) SetAnimation("WALK"); }
	virtual void SetMoveTurnRight(bool d)	{ CSObject::SetMoveTurnRight(d);	if (d) SetAnimation("WALK"); }
	virtual void SetMoveStrafeLeft(bool d)	{ CSObject::SetMoveStrafeLeft(d);	if (d) SetAnimation("WALK"); }
	virtual void SetMoveStrafeRight(bool d) { CSObject::SetMoveStrafeRight(d);	if (d) SetAnimation("WALK"); }
	virtual void SetMoveJump(bool d)		{ CSObject::SetMoveJump(d);			if (d) SetAnimation("JUMP"); }
	virtual void SetMoveCrouch(bool d)		{ CSObject::SetMoveCrouch(d);		if (d) SetAnimation("CROUCH"); else SetAnimation("STAND_UP"); }

Code: Select all

void CSObject::SetAnimation(char* name)
{
	// if we are already playing this animation then bail
	if (!strcmp(m_Animation,name)) return;

	strcpy(m_Animation,name);
	if (!GetActionTable()) { printf("%s - Invalid Action Table\n", m_Info->GetName()); return; }
	if (!GetAnimatedSceneNode()) { printf("%s - Set Animation Failed - no animated Node\n", m_Info->GetName()); return; }
	CSActionTableEntry* e = GetActionTable()->GetEntry(name);
	if (e)
	{
		GetAnimatedSceneNode()->setLoopMode(true);
		GetAnimatedSceneNode()->setFrameLoop(e->m_AnimationStart,e->m_AnimationEnd);
		GetAnimatedSceneNode()->setCurrentFrame(e->m_AnimationStart);
	}
}
Last edited by Seven on Wed Sep 24, 2008 12:44 am, edited 2 times in total.
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

You didn't explain anything, and it's only 25% self-explanatory. So what exactly is this for, and why does ProcessStateMachine look so...unlike C/C++.
TheQuestion = 2B || !2B
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

hmm, sorry about that. the code shows how to store the frames for an animation and then call them back.


For example, if the dwarf.x file has animations

Code: Select all

Animation sequences for the Dwarf model

use "base" bone to control the static jump animation manually in yur 3D engine

"cam" bones is behind the model and used for Torque to attach a camera to for 3rd person views


2-14	Walk
16-26	Run
28-40	Jump
42-54	Jump on the spot - for control in the 3D engine

56-59	Crouch down
60-69	Stay crouched loop
70-74	Get up

75-88	Battle idle 1
90-110	Battle idle 2

112-126	Attack 1 - Swipe axe
128-142	Attack 2 - Jump and overhead whack attack
144-160	Attack 3 - 360 spin Back hander
162-180	Attack 4 - 2 Swipes left and right
182-192	Attack 5 - Stab
194-210	Block

212-227	Die 1 - Forwards
230-251	Die 2 - Backwards

253-272	Nod YES
274-290	Shake head NO

292-325	Idle 1
327-360	Idle 2



Have fun and any probs just gimme a shout ;-)

Psionic
http://www.psionic3d.co.uk

then we can call

Code: Select all

		// setup an action table
		if (GetActionTable())
		{
			GetActionTable()->AddEntry("WALK",2,14);
			GetActionTable()->AddEntry("RUN",16,26);
			GetActionTable()->AddEntry("JUMP",28,40);
			GetActionTable()->AddEntry("JUMP_IN_PLACE",42,54);
			GetActionTable()->AddEntry("CROUCH",56,59);
			GetActionTable()->AddEntry("CROUCH_IDLE",60,69);
			GetActionTable()->AddEntry("STAND_UP",70,74);
			GetActionTable()->AddEntry("BATTLE_IDLE_1",75,88);
			GetActionTable()->AddEntry("BATTLE_IDLE_2",90,110);
			GetActionTable()->AddEntry("ATTACK_1",112,126);
			GetActionTable()->AddEntry("ATTACK_2",128,142);
			GetActionTable()->AddEntry("ATTACK_3",144,160);
			GetActionTable()->AddEntry("ATTACK_4",162,180);
			GetActionTable()->AddEntry("ATTACK_5",182,192);
			GetActionTable()->AddEntry("BLOCK",194,210);
			GetActionTable()->AddEntry("DIE_FORWARD",212,227);
			GetActionTable()->AddEntry("DIE_BACKWARD",230,251);
			GetActionTable()->AddEntry("NOD_HEAD",253,272);
			GetActionTable()->AddEntry("SHAKE_HEAD",274,290);
			GetActionTable()->AddEntry("IDLE_1",292,325);
			GetActionTable()->AddEntry("iDLE_2",327,360);
		}
then it;s pretty easy to call the animation frames by a string name later. It makes it easy to load all of the frame data from an XML file and then 'use' as necessary during the game.

Game objects 'know' which animation name to play for each action. When a chair is 'used' it will tell the using object to SetAnimation("SIT"); and when the "Long Soword of perpetual death" is used, it will SetAnimation("ATTACK_4"); which loads then cycles through animations 162 through 180, but if he is holding the "Axe of Death" then he uses the "ATTACK_2" animations which are 128 through 142.

By loading the data by name at load time, it makes it really easy to set the correct animations using a string value.

i.e. SetAnimation("USING_WAND");
i.e. SetAnimation("USING_DOOR");
i.e. SetAnimation("SIT_DOWN");
i.e. SetAnimation(WALK"");

I hope tha tmakes sense. The editor/demo is coming along very nicely and I will have many examples in the near future.
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

Yeah, it makes sense. And it's actually a good idea, especially if you are making a model editor or level editor or something like that. The user is then easily able to define the frame animations.
TheQuestion = 2B || !2B
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

I think a hash table might be good too, but I have no experience in that. This code was really designed to do just what is happening :0 people talking. I am interested in what folks think about how to implement the idea. As it progresses, I will eventually post a nice code snippet about it.
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

Just read the code, looks pretty good for for version 1 release.

Keep up the good work.

Thanks for sharing the code, that means a lot when you share code.
Image
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

dlangdev wrote:Just read the code, looks pretty good for for version 1 release.
EDIT: Nevermind.
Last edited by Halifax on Wed Sep 24, 2008 10:58 pm, edited 1 time in total.
TheQuestion = 2B || !2B
Seven
Posts: 1034
Joined: Mon Nov 14, 2005 2:03 pm

Post by Seven »

You are right, I modified the original posts and should have commented that I did, however........i think he meant that he just read the code, not that you need to :)
Halifax
Posts: 1424
Joined: Sun Apr 29, 2007 10:40 pm
Location: $9D95

Post by Halifax »

Seven wrote:You are right, I modified the original posts and should have commented that I did, however........i think he meant that he just read the code, not that you need to :)
Hmm, yes, I see that now. :lol: The english language really should revise the double definition of 'read' so that it fits the pronounciation.
TheQuestion = 2B || !2B
dlangdev
Posts: 1324
Joined: Tue Aug 07, 2007 7:28 pm
Location: Beaverton OR
Contact:

Post by dlangdev »

read --> past tense.

(I) just read (past tense) the code.

What do u think? Was it an imperative statement? I wrote that as a subjunctive, tho.

What if there was this word --> readed the code. Probably use old style like read+eth. That might work.

Plus, I drop words that I can omit so much so that it becomes cryptic. (My bad).
Image
Post Reply