Journal of a young adventurer 06/Jan/08
by Nerrad Weil · 01/06/2008 (8:23 am) · 5 comments
I bought TGE + AFX few months back together with 2 torque reference books. but only recently i have time to fool around with TGE.
my TGE project goal is to create a multiplayer online dancing game, something similar to Audition Online, but much smaller scale, but even that it's quite a undertaking for me. i guess this would be a long and tough journey, but i hope unleast it won't be a lonely journey. i would like to use this space to note down the changes i have made to TGE and hope that some TGE veterans could give some guidance to me.
#1 problem
my project required "multi threaded" animations, e.g. a dance sequence consists of a set of head, body and legs animations. i find that Player::setActionThread() alone is very difficult to achieve the desired result and i have no confidence to hack player class without broken things
#1 problem's solution
my solution is ShapeBase::playThread() function, shapebase's animation functions are more primitive and easier to hack. i also noted that sequence priority play a big role here, for my case legs should has highest priority and head should has the least priority.
#2 problem
shapebase can't play the same animation consecutively
#2 problem's solution
after spamming breakpoints, i discovered this problem was caused by animation sequence didn't rewind properly at end and the sequence did't marked as Thread::Stop. therefore ShapeBase::advanceThreads() always prohibit the same animation sequence being played consecutively.
to solve this problem i added
to ensure the thread was rewind properly at the end, add these lines to ShapeBase::updateThread() under Thread::Play case, where st.atEnd != true
#3 problem
shapebase doesn't support animation transition but this is a must have feature for my project
#3 problem's solution
the solution is simple, expose the TSShapeinstance::transitionToSequence to script. one thing to take note is the transitionToSequence() must called after timeScale being set properly. for my case, i do it in this order
#4 problem
after all these changes, now the avatar lost full body animation such as root and walk animation, this due to shapebase's animations have higher piority than player's animation
#4 problem's solution
to solve this problem we need to "disable" shapebase's animation thread when player's animations are needed. for my case, i added in a bool variable called disabled into TSThread class in tsShapeInstance.h
and then in S32 TSThread::operator<(const TSThread & th2) const add in these lines
one last point is don't forget to modify your ShapeBase::packUpdate() and ShapeBase::unpackUpdate() methods. for my case, they become these at the end
my TGE project goal is to create a multiplayer online dancing game, something similar to Audition Online, but much smaller scale, but even that it's quite a undertaking for me. i guess this would be a long and tough journey, but i hope unleast it won't be a lonely journey. i would like to use this space to note down the changes i have made to TGE and hope that some TGE veterans could give some guidance to me.
#1 problem
my project required "multi threaded" animations, e.g. a dance sequence consists of a set of head, body and legs animations. i find that Player::setActionThread() alone is very difficult to achieve the desired result and i have no confidence to hack player class without broken things
#1 problem's solution
my solution is ShapeBase::playThread() function, shapebase's animation functions are more primitive and easier to hack. i also noted that sequence priority play a big role here, for my case legs should has highest priority and head should has the least priority.
#2 problem
shapebase can't play the same animation consecutively
#2 problem's solution
after spamming breakpoints, i discovered this problem was caused by animation sequence didn't rewind properly at end and the sequence did't marked as Thread::Stop. therefore ShapeBase::advanceThreads() always prohibit the same animation sequence being played consecutively.
to solve this problem i added
if (!mShapeInstance->getShape()->sequences[st.sequence].isCyclic() && !st.atEnd &&
(st.forward? mShapeInstance->getPos(st.thread) >= 1.0:
mShapeInstance->getPos(st.thread) <= 0)) {
st.atEnd = true;
updateThread(st);
st.state = Thread::Stop; // new line
if (!isGhost()) {
char slot[16];
dSprintf(slot,sizeof(slot),"%d",i);
Con::executef(mDataBlock,3,"onEndSequence",scriptThis(),slot);
}
}after ShapeBase::advanceThreads() marked the thread as atEnd and updated the thread's state.to ensure the thread was rewind properly at the end, add these lines to ShapeBase::updateThread() under Thread::Play case, where st.atEnd != true
TSShape::Sequence seq = mShapeInstance->getShape()->sequences[st.sequence];
if (!seq.isCyclic() && !st.transit &&
(st.forward? mShapeInstance->getPos(st.thread) >= 1.0 : mShapeInstance->getPos(st.thread) <= 0)) {
mShapeInstance->setPos(st.thread,st.forward? 0: 1);
}#3 problem
shapebase doesn't support animation transition but this is a must have feature for my project
#3 problem's solution
the solution is simple, expose the TSShapeinstance::transitionToSequence to script. one thing to take note is the transitionToSequence() must called after timeScale being set properly. for my case, i do it in this order
updateThread(st); mShapeInstance->transitionToSequence(st.thread,seq,0, duration, continuePlay); // must call after setTimeScale(), updateThread() contains setTimeScale()
#4 problem
after all these changes, now the avatar lost full body animation such as root and walk animation, this due to shapebase's animations have higher piority than player's animation
#4 problem's solution
to solve this problem we need to "disable" shapebase's animation thread when player's animations are needed. for my case, i added in a bool variable called disabled into TSThread class in tsShapeInstance.h
and then in S32 TSThread::operator<(const TSThread & th2) const add in these lines
if (disabled && !th2.disabled) return 1; if (th2.disabled && !disabled) return -1;and also expose a method in shapebase class to script, to do that add in these few lines into shapeBase.cc
bool ShapeBase::disableThread(U32 slot,bool disable)
{
if (mShapeInstance) {
Thread& st = mScriptThread[slot];
if (st.thread)
{
TSThread * th = st.thread;
if (th->isDisable() == disable) return disable;
setMaskBits(ThreadMaskN << slot);
return th->disableThread(disable);
}
}
return false;
}
ConsoleMethod( ShapeBase, disableThread, bool, 4, 4, "(int slot, bool disable)")
{
int slot = dAtoi(argv[2]);
if (slot >= 0 && slot < ShapeBase::MaxScriptThreads) {
if (object->disableThread(slot,dAtob(argv[3])))
return true;
}
return false;
}btw, TSShapeInstance::animate(S32 dl) is a great place to study the threads' order, just put some breakpoints after sortThreads(mThreadList);one last point is don't forget to modify your ShapeBase::packUpdate() and ShapeBase::unpackUpdate() methods. for my case, they become these at the end
// packData
if (stream->writeFlag(mask & ThreadMask)) {
for (int i = 0; i < MaxScriptThreads; i++) {
Thread& st = mScriptThread[i];
if (stream->writeFlag(st.sequence != -1 && (mask & (ThreadMaskN << i)))) {
stream->writeInt(st.sequence,ThreadSequenceBits);
stream->writeInt(st.state,2);
stream->writeFlag(st.forward);
stream->writeFlag(st.atEnd);
stream->writeInt (st.speed*1000, 11);
stream->writeFlag(st.transit);
stream->writeInt(st.duration*100, 10);
stream->writeFlag(st.simulPlay);
stream->writeFlag(st.thread ? st.thread->isDisable() : false);
}
}
// unpackData
if (stream->readFlag()) {
for (S32 i = 0; i < MaxScriptThreads; i++) {
if (stream->readFlag()) {
Thread& st = mScriptThread[i];
U32 seq = stream->readInt(ThreadSequenceBits);
st.state = stream->readInt(2);
st.forward = stream->readFlag();
st.atEnd = stream->readFlag();
st.speed = stream->readInt(11)*0.001f;
st.transit = stream->readFlag();
st.duration = stream->readInt(10)*0.01f;
st.simulPlay = stream->readFlag();
bool disable = stream->readFlag();
if (st.sequence != seq)
{
if (st.transit)
setThreadTransitSequence(i,seq,st.duration,st.simulPlay,false);
else
setThreadSequence(i,seq,false);
}
else
updateThread(st);
disableThread(i, disable);
}
}
#2
01/06/2008 (5:43 pm)
by judging the codes which involved many packdata and unpackdata methods modification, i believe playthread should works under multiplayer mode too
#3
shapebase doesn't support animation transition but this is a must have feature for my project
Thanks a ton! for exposing this!. Wondered why when I tried to override the transition, I got bad animation....
01/07/2008 (7:48 am)
#3 problemshapebase doesn't support animation transition but this is a must have feature for my project
Thanks a ton! for exposing this!. Wondered why when I tried to override the transition, I got bad animation....
#4
01/08/2008 (6:40 am)
if can tell me more about your problem and the changes you have made, maybe i could help you...
#5
I only ask because I'm making a game in which I need to have the player model remain in the last position of the playthread animation. In otherwords, if a player jumps or dances to the right during the animation, have him or her remain to the right instead of snapping back to the original position from which they started the animation.
if that makes sense :)
02/14/2008 (1:02 pm)
When you say that you are exposing the shapebase to support animation transition, do you mean that the player is now capable of animation-based movement?I only ask because I'm making a game in which I need to have the player model remain in the last position of the playthread animation. In otherwords, if a player jumps or dances to the right during the animation, have him or her remain to the right instead of snapping back to the original position from which they started the animation.
if that makes sense :)
Torque Owner Cinder Games