Animation problem

edited May 2011 in Help request
I feel like some noob today, but I really got stuck with this one.

At first. I'm using many animations in my game, but have problem only with this one and have no idea why (after two hour searching)-

There's my config
[AnimSet] 
AnimationList = Appear # Loop # Disappear # Hit
LinkList = Appear2Loop # Loop2Loop # Loop2Disappear # Hit2Disappear # Loop2Hit

[Hit2Disappear]
Source = Hit
Destination = Disappear
Property = immediate

[Hit]
DefaultKeyDuration = 0.08
KeyData1 = HitAnim1
KeyData2 = HitAnim2
KeyData3 = HitAnim3
KeyData4 = HitAnim4
KeyData5 = HitAnim1
KeyData6 = HitAnim2
KeyData7 = HitAnim3
KeyData8 = HitAnim4

Disappear animation is called even when no hit animation is called and I don't have any problem with this. Same as with Hit animation, which plays well. Problem is, when I play Hit animation and call disappear animation right after it. Log just screams "Couldn't compute next animation. "

Maybe I'm just blind, but I don't see any problem there as every other animations work fine. Only this Hit2Disappear thing doesn't.

Comments

  • edited May 2011
    Now I just find out, that timer I'm creating to play Disappear animation isn't called even if it should
    void Krtek::Hit(void){	
    	this->clickable = false; // disable for click
    	
    	orxObject_RemoveSound(this->object, "LoopSound");
    	orxObject_AddSound(this->object, "HitSound");
    	
    	this->lives--;
    	
    	orxClock_RemoveGlobalTimer(Game::DeleteKrtek, -1, this->object);
    	
    //this->object stores pointer to enemy object (orxOBJECT which stores this object as user data :-) )
    
    	Game::UpdateScore(1);
    	
    	this->HitAnim(); // play Hit animation
    	
    		//if (this->lives == 0) {
    	orxClock_AddGlobalTimer(Game::DeleteKrtek, 1, 0.64f, this->object); // add timer to function which calls Disappear animation
    		//}else {
    			//orxClock_AddGlobalTimer(Game::UpdateKrtek, 1, 0.64f, this->object);
    		//}
    	
    	orxLOG("HIT"); // for testing, it appears in log every time I click enemy, but same log test in DeleteKrtek() don't
    }
    

    If I call function for disappear animation instead of timer, it plays well, so there probably won't be problem in animation
  • edited May 2011
    Hi!

    As I don't have access to all the related config/code, I'll make some assumptions. Please let me know if they're wrong. :)

    My guess is that, when your object is created, it'll go from Appear to Loop and stay there indefinitely.

    After that you probably call orxObject_SetTargetAnim() (and not orxObject_SetCurrentAnim()) with either Hit or Disappear?

    My guess is that both Loop2Hit and Loop2Disappear are immediate links.

    Now I don't see why you have Hit2Disappear as immediate. Why not setting it as a regular link and let orx go from Hit to Disappear all by itself as there is no other option? This way you don't need to call Disappear yourself after having called Hit. In order for this to work, the target needs to be reset when entering the Hit anim. For that there's a property called cleartarget. If in Loop2Hit you set Property = immediate cleartarget everything should work just fine.

    If you still have problem, would you mind sending me your code/config so that I can have a closer look? :)
  • edited May 2011
    Well, enemy goes from Appear straight to Loop. If clicked in Loop, it goes to Hit and (depends on lives) from Hit it goes back to Loop or to Disappear. It also goes to Disappear from Loop after some time automatically.

    I was trying to add Hit2Disappear without immediately param. There probably isn't problem with animations at all of them are OK. I added animation loop Hit2Hit and now it just plays Hit animation forever after enemy is clicked.

    Problem is, as I have post in second message, that timer I add after hit which have to call Disappear animation function doesn't call it and so Hit animation is playing forever.
    void orxFASTCALL Game::Create(const orxEVENT* currentEvent){
    	orxOBJECT *object = (orxOBJECT*)currentEvent->hSender; // listening to ORX_OBJECT_CREATE (spawner_create/spawn doesn't work for me)
    	
    	if (object != orxNULL) {
    		const orxCHAR *name = orxObject_GetName(object);
    			
    		if (Tools::RightName(name)) {
    			
    			Krtek *userData = new Krtek(object, speed);
    			/* save Krtek object as user data of orxOBJECT */
    			orxObject_SetUserData(object, userData);
    		}
    
    	}
    }
    
    void orxFASTCALL Game::Delete(const orxCLOCK_INFO* clockInfo, void *context){	
    	orxOBJECT *object = (orxOBJECT*)context;
    	if (object != orxNULL) {
    		
    		const orxCHAR *name = orxObject_GetName(object);
    		
    		if (Tools::RightName(name)) {
    			
    			Krtek *userData = (Krtek *)orxObject_GetUserData(object);
    			userData->Disappear();
    		}
    	}
    }
    
    Krtek::Krtek(orxOBJECT *object, float speed){
    	this->clickable = true;
    	
    	this->name = orxObject_GetName(this->object);
    	
    	while (!this->IsFreePosition()) {
    		this->SetNewPosition();
    	}
    	
    	/* this adds timer which will play Disappear animation */
    	orxClock_AddGlobalTimer(Game::DeleteKrtek, this->ComputeLifeTime(), 1, this->GetObject());
    	
    	/* timer for sound */
    	orxClock_AddGlobalTimer(Game::PlayLoopSound, 0.35f, 1, this->GetObject());
    	orxObject_AddSound(object, "AppearSound");
    }
    
    void Krtek::Disappear(void){	
    	this->DisappearAnim(); // starts Disappear anim
    	
    	orxObject_RemoveSound(this->object, "LoopSound"); 
    	orxObject_RemoveSound(this->object, "HitSound"); 
    	orxObject_AddSound(this->object, "DisappearSound"); 
    	
    	orxClock_RemoveGlobalTimer(Game::DeleteKrtek, -1, this->object);
    	orxObject_SetLifeTime(this->object, 0.35f); // remove object after animation plays
    	
    	this->clickable = false; // locks object for clicking
    }
    
    void Krtek::Hit(void){	
    	this->clickable = false; // disable for click
    	
    	orxObject_RemoveSound(this->object, "LoopSound");
    	orxObject_AddSound(this->object, "HitSound");
    	
    	this->lives--;
    	
    	orxClock_RemoveGlobalTimer(Game::DeleteKrtek, -1, this->object);
    	
    	this->HitAnim(); // plays hit animation
    
    	orxClock_AddGlobalTimer(Game::DeleteKrtek, 1, 0.64f, this->object); // add timer to function which calls Disappear animation -> this is not called
    	
    	orxLOG("HIT"); // for testing, it appears in log every time I click enemy
    }
    

    Everything works just fine, only this stupid hit animation can't call Game::DeleteKrtek where Disappear is called.
  • edited May 2011
    Hi Kenn,

    Sorry for the late reply but today's been a busy day. I'm also pretty tired so I have some trouble staying focused while reading the code. :)

    However, what I can tell you is that you can probably find alternate ways of doing a few things than using all those timers. :)

    For example, you don't need a timer for disappearing after a hit. In the same order of idea, you don't need timers for starting your loop sound for example.

    Let's tackle those cases one at a time. :)

    Concerning the start loop sound, why not using a custom event set in config on the loop anim?
    If it's the first call, then you start your sound, otherwise you ignore it. Or better you have an anim called LoopStart that will get called only once and that will lead you to your Loop anim.

    Concering your looping anim, there's a feature that you can use that will tell orx how many times a link is valid, after that it gets removed. Unfortunately this feature isn't accessible from config but you can fake it by listening to the ANIM_LOOP event and using a counter.

    Also, concerning your hit->loop / hit->disappear, I'd suggest adding both these links to your set, the hit->loop link will have a Priority set to 9 (any value above 8 is ok) and the hit->disappear will be a normal link with no specific priority nor property.

    When calling SetTarget("Hit"), we saw that you can have your target being reset. Now either you let things go by themselves and your anim will go back to loop (in the case your object isn't dead) or, if your object's dead, you can now directly call SetTarget("Disappear"), no need to wait for a timer, as the previous link was immediate, it's already has been computed and the target has been cleared.
    This now means that at the end of the hit anim, orx will take the hit->disappear link instead of the hit->loop one.

    I'm not sure who calls Krtek::Disappear() in your example above. It looks like it's Game::Delete(). Is it the same than Game::DeleteKrtek() (which code's missing) that you request with a timer?
  • edited May 2011
    I was thinking about custom events, but I wasn't able to get this working. Now I know why. There's orxANIMSET page on wiki which tells, that for custom event I have to add line into config file - EventName<n> but it's actually KeyEventName<n> (I'm not sure if there's just mistake or you made some change in newer version of ORX so I didn't change it).

    Now I got it working and "fixed" (or better walked around the problem) by custom event, but this doesn't change anything as I'm not able to run timer from my KrteK::Hit function (sorry for mistake, Game::Delete is same as Game::DeleteKrtek) and I don't know why as other timers went well (I removed all of them except one with random lifetime).

    But thank you for kicking me to use custom events instead of timers :)
  • edited May 2011
    Glad you are using custom events, they often come in handy! :)

    As for the wiki, its info are based on the latest release build, so it's sometimes outdated for svn users. However, when changes are made on the svn, especially for syntax changes like this, there's a mention in the CHANGELOG file. In this case it says to have a look at CreationTemplate.ini as the way to declare custom events have been changed. :)

    As for the hit, I don't find any obvious issues by simply reading your code. Would you mind sending me a private build for me to trace and see if it's a bug in orx or something I missed while reading your code?
  • edited May 2011
    If you wouldn't mind going through my messy code, then I don't have any problem to send it to you :)
  • edited May 2011
    Now I've just find another problem. If I don't have any log output in creation process, game just doesn't work (it does, but animations don't play, can't click them etc.) and if I do, game works almost fine but got stuck somehow sometimes (stuck in way that hit animations ends, but disappear doesn't play and there's hit sound and every new enemy got stuck too). Will work on it tomorrow, but have no idea where problem can be.
  • edited May 2011
    Hi!

    I've spent 10 mins having a look and there are a couple of things that prevent your game from working. :)

    First of all, it wasn't compiling on windows due to some minor syntax errors. However, and it's a bit more of a problem, there are parts of your code that will have an undefined behavior.
    Mostly the use of undefined variables.

    One such example is a function such as
    void Krtek::SetDisappearAnim(std::string anim){
    	orxCHAR *animation;
    	orxString_Copy(animation, anim.c_str());
    	this->disappearAnim = animation;
    }
    

    In this case, animation is a pointer that is not pointing to any part of memory that has been allocated. When calling orxString_Copy(), it'll likely do some memory corruption or even simply crash.

    If you want to duplicate your string, use orxString_Duplicate() and remember you'll be responsible for deleting the string when quiting (so as not to leak memory) with orxString_Delete().

    In the same order of idea:
    orxVECTOR *vector;
    orxVector_Set(vector, -142, -152, 0);
    

    will also either crash or corrupt the memory. You have a orxVECTOR pointer but it doesn't point to any valid memory. The way to do it is:
    orxVECTOR vector;
    
    orxVector_Set(&vector, ...);
    

    After fixing that, the game now runs till after the hit animation (which was the initial problem). I'm going to check that now or maybe tomorrow if I'm too sleepy. :)
  • edited May 2011
    Ok I found your issue. It's a simple config problem.
    For all your KeyEventValue you set a list with 2 values, such as:
    KeyEventValue7 = 3 # HitEnd
    

    That means that randomly the custom event value will be 3 or 0 as it'll fail converting "HitEnd" to a float. :)

    Also, why don't you use the KeyEventName value to know what kind of event it is? Something like:
    Config:
    
    KeyEventName7 = HitEnd
    
    Code:
    
    if(!orxString_Compare(pstEventPayload->zName, "HitEnd"))
    {
    ...
    }
    

    If you fix those config lines and the uninitialized variables I mentioned in my previous post, your game should run just fine. :)

    Let me know if you have any other problem!
  • edited May 2011
    Well, I'm using Values instead of Names just because name is string and cannot be used in switch :) Ill try to change it
  • edited May 2011
    Ah, now everything is ok. Thank you very much again :)
  • edited May 2011
    No problem! :)

    If you still want to use a switch statement, you can do it indirectly. Something like:
    Config:
    
    [HitAnim]
    ...
    KeyEventName7 = HitEnd
    
    [MyEnums]
    HitEnd = 3
    ...
    
    Code:
    
    // When getting the event
    orxConfig_PushSection("MyEnums");
    s32EnumValue = orxConfig_GetS32(pstEventPayload->zName);
    
    switch(s32EnumValue)
    {
    ...
    }
    
    orxConfig_PopSection();
    
Sign In or Register to comment.