Duck Animation Suggestion for 2D Platforms

maxman

Well-known member
I was playing Naruto awhile ago and I've known that playable characters from most mods play idle animation while releasing and after holding a duck button. We know that some characters duck with one sprite frame in an animation with pressing, holding, and releasing it, and it's no problem. The problem is that when using more than 1 frames in a duck anim like 2-4 or over, you can see that how many frame played in that anim for holding, but when you release it, it reverts back to anim idle instead of playing something like an anim unduck (for standing up for ducking; no such word for "unduck" in OpenBOR). Example, when you hold down, then frame 1 ("I'm about to get down") plays, then frame 2 ("I'm half way to get down"), and lastly frame 3 ("OK. Here I'm down here!"). But when releasing it, it's back to idle anim ("Hey that's funny. I was down here and then all of a sudden I'm back to standing up without moving up from being down here. That's probably because the engine isn't interactive enough for the duck").

anim duck

offset 23 50
delay 5
frame data/chars/mikey/duck1.png
frame data/chars/mikey/duck2.png
frame data/chars/mikey/duck3.png
frame data/chars/mikey/duck4.png #frame 4 should refer to be played all the way to frame 1 after releasing a down button from ducking and should NOT revert to anim idle after releasing it
frame data/chars/mikey/duck5.png
 
I think that's what Bloodbane's using for newer builds. BTW I discovered about the each set/number of 2 values somewhat like a binary (or on/off thing) in changeentityproperty function with animation.

changeentityproperty(self, "animation", openborconstant(Ani), value)

changeentityproperty(self, "animation", openborconstant(Ani),2);
and
changeentityproperty(self, "animation", openborconstant(Ani),3);
2 value numbers work in the changeentityproperty with animation function, but it's unnecessary for me to use 3 so I refer to stay with only value 2. Also, it's because I don't like using 3, but I know it works.

I discovered the value that goes like this in a single function of changeentityproperty for animation for newer builds:

0 and 1 = disabled
2 and 3 = enabled
4 and 5 = disabled
6 and 7 = enabled
8 and 9 = disabled
10 and 11 = enabled

and it goes ALL the way by repeating two numbers per binary. Pretty weird value turns, eh? Each 2 numbers are like disablers and enablers. (Starting with 0, cannot. 1, cannot. 2, can. 3, can. 4, cannot. 5, cannot. 6, can. 7, can. And the two numbers of binary go on.)

2 is the FIRST enabling value for the function and I think that's why it is used.

If you make a platformer style in a stage while one character has frames in anim duck and anim duckattack, you will know what I mean regarding keyint2 (if the value is indicated in changeentityproperty function for animation) in the last frame of anim duckattack.

I don't know for other animations, but I tested the values with either 0 or 1 in changeentityproperty animation, and it seems that after he performs duckattack (with keyint2 used), he switches back to anim duck but with first frame.

Now I discovered about using anim duck. If duck anim has only one frame, then there's no need a loop. But if it comes with 2 or more frames, a loop is needed with a loop start.
 
utunnels gave me that solution long time ago. I think he did something in code which messed animation change scripts. So this line:

      changeentityproperty(self, "animation", openborconstant(Ani)); // without 2
      updateframe(self, Frame);

works well in older builds but not in newer builds (animation is changed but entity starts at first frame ignoring updateframe function there)
In newer builds, you need to add 2 like this:

      changeentityproperty(self, "animation", openborconstant(Ani),2);
      updateframe(self, Frame);

for it to work
 
and it goes ALL the way by repeating two numbers per binary. Pretty weird value turns, eh? Each 2 numbers are like disablers and enablers. (Starting with 0, cannot. 1, cannot. 2, can. 3, can. 4, cannot. 5, cannot. 6, can. 7, can. And the two numbers of binary go on.)

Wow, this is ubber strange. First, why not boolean? The pattern of "2 values can, 2 values not" doesn't makes any sense at all.
I don't feel myself confortable working with something I don't understand (or even know) how to work. Sure, this is a personal opinion.

And to make it clear: I am not bashing you, I am just suprised about this. Its one of those things of OpenBOR, that nobody knows why it works that way, there is no documentation (some times, not even at source code). I hope that when DC releases the ChronoCrash engine, this would be let in consideration.

In newer builds, you need to add 2 like this:
I will test it, because I think that I can do it on my mod without that value.
BUT...this could be the reason of why the grab moves in RBMOD are weird. I remember that sometimes the enemy doesn't starts on the frame I want to.

Thanks guys.
 
Wow, this is ubber strange. First, why not boolean? The pattern of "2 values can, 2 values not" doesn't makes any sense at all.

Yeah, weird about each set of 2 values being opposite with each other.

Sorry for saying about that "can-and-cannot" statement. I meant the opposite like switching on-and-off (the 2-off (e.g. value 0 and 1; 4 and 5) and the 2-on (e.g. value 2 and 3; 6 and 7). I was referring to the value that works for keyint2 for only anim duck which I tested on. But I think for other animations, that may be a different story. I tried out with the unduck anim (my own follow6 anim) using keyint2 and it seems to work. Weird. I'm not sure if other animations work 'cause I haven't tested them out yet. (Sorry for being wordy and redundant about this.)
 
Maybe, but I don't think it has to do with animpos. :) The pattern of 2 values in each opposite set remains to be kinda unexplainable to describe how. It doesn't make sense at all. The first 2 values (0 & 1) are ones that function (some) animations (maybe the older build behavior, I think?) while the second 2 (2& 3) are ones that functions properly (like it respects behavior of function pretty well). Pretty much different. So then, they take turns in taking pattern to another all the way and pass on next by repeating the steps. I think you get it about the way of 2 values of 2 different passing to another. It's like 2 people taking turns in passing 2 bottles with each other by counting each bottle passed in one hand. (Like, how long they take many turns. It doesn't matter how many turns they take, but it will end up being infinite I think.) I think it's something like a respective procedure in taking turns infinitely.
 
O Ilusionista said:
changeentityproperty(self, "animation", openborconstant(Ani),2);
What the last value means?

Because according to the manual:

changeentityproperty(entity, propname, values)

~Change an entity's property by name.
~'entity' is the handle of that entity.
~'propname' is the property's name.
~'value' is new value you want to set.

So you use that value to go to ANI_ATTACK2?
or its something undocumented?

The last value is a flag.
Resettable Animation Flag according to source code.
 
Recently I was working on the duck a little bit and I realized that using cancel with a(attack) in freespecial can become a second duckattack and on while in duck anim when pressing attack button.

anim duck
bbox 4 0 46 95
offset 24 91
loop 1 2
delay 3
cancel 2 2 0 a freespecial30
cancel 2 2 0 a2 freespecial6
cancel 2 2 0 a3 freespecial7
cancel 2 2 0 j freespecial8
cancel 2 2 0 s freespecial9
cancel 2 2 0 a4 freespecial10
frame data/chars/ryu/0001000000.gif
bbox 3 1 49 75
offset 22 72
@cmd keyint2 "ANI_FOLLOW6" 0 "D" 1
frame data/chars/ryu/0001000001.gif
bbox 3 0 49 73
offset 23 66
delay 10
@cmd keyint2 "ANI_FOLLOW6" 0 "D" 1
frame data/chars/ryu/0001000002.gif

I got it working as expected. I should've used it long time ago.

EDIT: Since I reverted back with freespecials for attack buttons, like, a2 freespecial for mid punch, a3 freespecial2 for high punch, j freespecial4 for low kick, I am no longer using the scripted attacks that are in the code so I already removed them. I replaced anim attack2 with anim freespecial for simple stuff.

This is the scripted attacks I'm no longer using:

Code:
    if(iAttack){ //Attack button pressed?
      if(vAniID == openborconstant("ANI_DUCK") ){ //Ducking?
        performattack(vSelf, openborconstant("ANI_DUCKATTACK") ); //Duckattack anim performed? / Crouch low punch performed
      }
    }
	
	if(iAttack2){ //Attack2 button pressed?
		if(vAniID == openborconstant("ANI_DUCK")){ //Ducking?
			performattack(vSelf, openborconstant("ANI_FREESPECIAL6")); //Crouch middle punch performed
		}
	}

	//Stand middle punch
	if(iAttack2){ //Attack2 button pressed?
	  if(vAniID == openborconstant("ANI_IDLE") || vAniID == openborconstant("ANI_WALK") || vAniID == openborconstant("ANI_BACKWALK")){
	  //Perform an attack move in one of the three animations
		performattack(vSelf, openborconstant("ANI_ATTACK2")); //Perform middle punch
		changeentityproperty(vSelf, "velocity", 0, 0, 0); // Move? No, because all of the velocity is 0.
		//That's why Ryu is not moving while he's attacking!
	  }
	}

	//Stand high punch
	if(iAttack3){ //Attack3 button pressed?
	  if(vAniID == openborconstant("ANI_IDLE") || vAniID == openborconstant("ANI_WALK") || vAniID == openborconstant("ANI_BACKWALK")){
	  //Perform an attack move in one of the three animations
		performattack(vSelf, openborconstant("ANI_ATTACK3")); //Perform high punch
		changeentityproperty(vSelf, "velocity", 0, 0, 0); // Move?
	  }
	}
	
	//Stand low kick
	if(iJump){ //Jump button pressed?
	  if(vAniID == openborconstant("ANI_IDLE") || vAniID == openborconstant("ANI_WALK") || vAniID == openborconstant("ANI_BACKWALK")){
	  //Perform an attack move in one of the three animations
		performattack(vSelf, openborconstant("ANI_ATTACK4")); //Perform low kick
		changeentityproperty(vSelf, "velocity", 0, 0, 0); // Move?
	  }
	}

	//Stand middle kick
	if(iSpecial){
	  if(vAniID == openborconstant("ANI_IDLE") || vAniID == openborconstant("ANI_WALK") || vAniID == openborconstant("ANI_BACKWALK")){
	  //Perform an attack move in one of the three animations
		performattack(vSelf, openborconstant("ANI_ATTACK5")); //Perform middle kick
		changeentityproperty(vSelf, "velocity", 0, 0, 0); // Move?
	  }
	}

	//Stand high kick
	if(iAttack4){
	  if(vAniID == openborconstant("ANI_IDLE") || vAniID == openborconstant("ANI_WALK") || vAniID == openborconstant("ANI_BACKWALK")){
	  //Perform an attack move in one of the three animations
		performattack(vSelf, openborconstant("ANI_ATTACK6")); //Perform high kick
		changeentityproperty(vSelf, "velocity", 0, 0, 0); // Move?
	  }
	}

	
}
 
There seems to be a problem only doing anim duckattack once without using cancel with any freespecial. Every time I perform anim duckattack with script, I cannot do it more than once. One time and that's it unless you unduck and duck again to do duckattack. One duckattack, that's it. Cannot do it more times at all. I know using cancel works, but what will happen if anim duckattack is not going to be used instead? (Instead) It will go directly to freespecial (cancel) for doing multiple crouch attacks. Is there a script which I can make anim duckattack perform more than once instead of using cancel?
 
You didn't post your DUCKATTACK and FREESPECIAL6 so I can't check if both returns Ryu back to DUCK animation or not. So I'll just ask you then, does Ryu returns to DUCK animation after performing those 2 duckattacks?
 
Oops. Sorry. I should've included them.

Here's duckattack anim:
Code:
anim	duckattack
	delay	5
	bbox	7 1 46 68
	offset	22 65
	frame	data/chars/ryu/278.gif
	attack	43 5 46 21 3 0 1 0 0 0
	frame	data/chars/ryu/279.gif
	frame	data/chars/ryu/280.gif
	offset	23 66
	delay	2
	frame	data/chars/ryu/281.gif
	@cmd	keyint2 "ANI_DUCK" 2 "D" 0 #down held for playing for anim duck?
	@cmd	keyint2 "ANI_FOLLOW6" 0 "D" 1 #down released for play an unduck anim?
	frame	data/chars/ryu/281.gif

Freespecial6 is for crouch/duck middle punch:
Code:
anim	freespecial6
	bbox	8 1 44 69
	offset	22 65
	delay	5
	frame	data/chars/ryu/282.gif
	offset	21 65
	frame	data/chars/ryu/283.gif
	attack	43 11 47 22 7 0 1 0 0 0
	frame	data/chars/ryu/284.gif
	attack	0 0 0 0 0 0 0 0 0 0
	frame	data/chars/ryu/285.gif
	frame	data/chars/ryu/286.gif
	delay	2
	frame	data/chars/ryu/286.gif
	offset	23 66
	@cmd	keyint2 "ANI_DUCK" 2 "D" 0
	@cmd	keyint2 "ANI_FOLLOW6" 0 "D" 1
	frame	data/chars/ryu/281.gif

Freespecials work for crouch attacks several times. The example of this is Freespecial30. It has the same lines as anim duckattack.

Bloodbane said:
does Ryu returns to DUCK animation after performing those 2 duckattacks?

Yeah. But when executing with anim duckattack without cancelling by pressing only normal attack button, he only performs it once and returns to duck animation. That's it. (I am talking mainly about the attack button with ducking) You cannot perform it any more after doing it once unless you add cancel in anim duck for attack button.

EDIT: Off-topic on solved problem for unduck:
I figured out a way to make an unducking animation but be aware that without using list of calling functions for arguments on functions won't work. What I mean is calling functions of entity, animation, and keys for this.

Code:
//Unduck

if(vAniID == openborconstant("ANI_DUCK")){ //Ducking?
  if(iDownR){ //Release key of Down
	 changeentityproperty(vSelf, "aiflag", "idling", 0); //Disable idling status
	 performattack(vSelf, openborconstant("ANI_FOLLOW6")); //Perform unduck animation
	}
}
 
I was creating my own script for duckattacking several times with anim duckattack but no success of performing it more than once. Last night I tested the duckattack and kept tapping the attack button but it didn't activate till later on it activates. For example, I press attack while the char is using anim duck but it doesn't activate. I keep pressing it after performing it but then a duckattack anim gets performed once or twice later on. This is my script for anim duck, trying to activate multiple hits using anim duckattack with an attack button.

Please excuse AniID which I called for script.

Code:
anim	duck
@script
  void self = getlocalvar("self");
  void iPIndex = getentityproperty(self, "playerindex");
  void AniID = getentityproperty(self, "animationid");
  void dKey;

  if(frame == 2){
    if(dKey == playerkeys(iPIndex, 1, "attack")){
      performattack(self, openborconstant("ANI_DUCKATTACK"));
    }
  }
	@end_script
	loop	1 2
	bbox	4 0 46 95
	offset	24 91
	delay	3
	cancel	2 2 0 a2 freespecial6
	cancel	2 2 0 a3 freespecial7
	cancel	2 2 0 j freespecial8
	cancel	2 2 0 s freespecial9
	cancel	2 2 0 a4 freespecial10
	@cmd	keyint2 "ANI_FOLLOW6" 0 "D" 1
	frame	data/chars/ryu/0001000000.gif
	bbox	3 1 49 75
	offset	22 72
	@cmd	keyint2 "ANI_FOLLOW6" 0 "D" 1
	frame	data/chars/ryu/0001000001.gif
	bbox	3 0 49 73
	offset	23 66
	delay	10
	@cmd	keyint2 "ANI_FOLLOW6" 0 "D" 1
	frame	data/chars/ryu/0001000002.gif
 
Tried it with "loop 1 3" with another frame and did "frame >=2" but still the same. Thanks for trying to help. Need to figure out how to make an active duckattack.
 
Freespecial# is the EASIEST way to use for doing multiple duck attacks if you are in duck animation, but for normal duckattack anim, it will be quite useless when it comes to 'cancelling' via freespecial# ala normal attack key. Using that follow# anim for ducking/crouching will make me work my @$$ off by scripting it for crouching. Using duck anim is better for me.
 
No I mean using scripts, but using FREESPECIAL OR FOLLOW anims instead of DUCKATTACK/DUCK.  So you know the engine can't interfere by running default 'duck logic'
 
Since I found out that White Dragon uses both duck and freespecial anims for transition and returning to down frame of duck anim like I do (because of this topic), I would use freespecial for attacking multiple duck attacks rather than anim duckattack. In the future, I assume/predict anim duckattack will be useless and obsolete (only if scripted anim duckattack is not solved for multiple attacks similar to freespecial/cancel).
 
There needs to be a way for a crouch pain animation to be commanded and my thought of it is onpainscript. I haven't tried doing onpainscript before. I see it's for using pain animations and attacktypes I guess. (I might be wrong about it.) I'd wanna make that similar to X-Men Mutant Apocalypse way for having character with the use of crouch pain animation while being in duck animation.
 
Back
Top Bottom