• All, Gmail is currently rejecting messages from my host. I have a ticket in process, but it may take some time to resolve. Until further notice, do NOT use Gmail for your accounts. You will be unable to receive confirmations and two factor messages to login.

Different anims for walking left/walking right

aL BeasTie

Well-known member
I've been wondering a while how difficult it would be to try make it so a character can have different animation for walking left and right.

so default anim WALK would be WALK RIGHT, I want a different one for WALK LEFT. (Ultimately I would want it for all directions, UP LEFT, UP RIGHT, DOWN LEFT, DOWN RIGHT)


My guess was trying with keyscript, but I thought I'd ask and see what others had to say first.
 
Last edited:
Let me see, if you are using the newest build, I have a solution.

Put this function in your animation script.

void walk6d()
{
  /*
  2  1
  3    0
  4  5
  */
  void self = getlocalvar("self");
  int pli = getentityproperty(self, "playerindex");
  int dir = getentityproperty(self, "direction");
  int walkmode =0;
  if(dir==1)
  {
    if(playerkeys(pli, 0, "moveup"))
      walkmode = 1;
    else if(playerkeys(pli, 0, "movedown"))
      walkmode = 5;
    else
      walkmode = 0;
  }
  else
  {
    if(playerkeys(pli, 0, "moveup"))
      walkmode = 2;
    else if(playerkeys(pli, 0, "movedown"))
      walkmode = 4;
    else
      walkmode = 3;
  }

  changeentityproperty(self, "walkmode", !dir);
  switch(walkmode)
  {
  case 0:
    changeentityproperty(self, "animation", openborconstant("ANI_WALK"), 2);
    break;
  case 1:
    changeentityproperty(self, "animation", openborconstant("ANI_UP"), 2);
    break;
  case 2:
    changeentityproperty(self, "animation", openborconstant("ANI_UP2"), 2);
    break;
  case 3:
    changeentityproperty(self, "animation", openborconstant("ANI_WALK2"), 2);
    break;
  case 4:
    changeentityproperty(self, "animation", openborconstant("ANI_DOWN2"), 2);
    break;
  case 5:
    changeentityproperty(self, "animation", openborconstant("ANI_DOWN"), 2);
    break;
  }
}



Then create your animations, don't forget to set maxwalks, maxups and maxdowns in models.txt


anim walk
@script walk6d(); @end_script
delay 16
offset 100 100
frame data/chars/a/right0
frame data/chars/a/right1
frame data/chars/a/right2
frame data/chars/a/right3

anim walk2
@script walk6d(); @end_script
delay 16
offset 100 100
frame data/chars/a/left0
frame data/chars/a/left1
frame data/chars/a/left2
frame data/chars/a/left3



anim up
@script walk6d(); @end_script
delay 16
offset 100 100
frame data/chars/a/ul0
frame data/chars/a/ul1
frame data/chars/a/ul2
frame data/chars/a/ul3

anim up2
@script walk6d(); @end_script
delay 16
offset 100 100
frame data/chars/a/ur0
frame data/chars/a/ur1
frame data/chars/a/ur2
frame data/chars/a/ur3



anim down
@script walk6d(); @end_script
delay 16
offset 100 100
frame data/chars/a/dl0
frame data/chars/a/dl1
frame data/chars/a/dl2
frame data/chars/a/dl3

anim down2
@script walk6d(); @end_script
delay 16
offset 100 100
frame data/chars/a/dr0
frame data/chars/a/dr1
frame data/chars/a/dr2
frame data/chars/a/dr3




=====================================

P.S.

If animations don't work, you can set range and rangez to something like -10000 10000 to see if it is solved.

The solution has not been tested, so cross your fingers.

===========================

P.P.S.

Well I just recalled there must be targets on screen to make extra walk animations work.
Let me see if I can let walkmode script take control of that instead next time. 
 
That's awesome, thank you very much!

I plan to get my mods working with the latest build, but still using an older build for some mods thou, until I can get my scripts updated to work newer builds.  I'll try this out with the latest build thou.

Cheers
 
I had tried this, but I think I muddled some script cause it was crashing.  I will try again shortly.

Well I just recalled there must be targets on screen to make extra walk animations work.
Let me see if I can let walkmode script take control of that instead next time.
might not be a huge problem, I always have exit doors which are enemies to the engine.

The other thing i diddn't mention thou, I'd also like a way to give enemies the extra walks too somehow. Instead of checking player keys we would check enemy direction?
 
Yeah, you are right. The target problem is removed though.

As for enemies, it depends on the velocity. Consider openbor automatically half speed in z direction for players to make a semi-sideview effect, the 8-direction map looks like this:



[attachment deleted by admin]
 
Sorry it took me a while to be able to try this again.  I had to redo my sprites for doom mod to suit it.

Doom mod is updated to latest version now thanks to MatMan,  I've also tried this with a fresh mod with no other chars or scripts added and I still can't get it working.  :-\

Property name 'walkmode' is not supported by function getentityproperty.

Script compile error in 'animationscript': changeentityproperty line 32, column 2

Just wanted to try and get this working before I redo the mod/demo.  Otherwise I'll just  use the LEFT sprites flipped instead of the right ones like I did before (looks better for shooting etc.)

Maybe it's too much hassle, because will also need different facing directions for pain and attack anims.
 
Did anoyone succesfully tried to do diagonal walk and change to different walk animations when pressing up+right for example?
This script provided by utunnels has "walkmode" property which isnt supported by newest version of the engine which is weird cause his script is quite old.
 
OK i managed to do it by using bloodbane's contra script for his custom walks with weapon and modified it a bit.
Now i have 8 directions but i think i will modify it for 12 to be more smooth.
If anyone tried to do custom walks then please post here because your method might be better.
 
So I'm looking at trying to get this working again for something else. I still would like to use it for doom mod but that's probably just never happening...

Has anyone else tried something like this in more recent times?
 
You can take a look at Bloodbane's SoKoBoR mod for walking in different directions. He uses follow animations instead of anims up, down, and such. Also, DemonSluga mod has the walking directions, but I'm just gonna leave the link of SoKoBoR for now.

 
thanks for the suggestion, I saw BB had some exhibition mods but I haven't really had time to check it out yet. :)

EDIT: I'm looking to do a complete system now, different directions for nearly every animation. PAIN, ATTACKS, DEATH etc.
 
You can make your pain animation to look like it has more than one pain animations according to the hit detection, if you don't like wasting pain animations for another attack or any animation. For instance, you have both onpainscript and ondoattack scripts for playing specific pain animations in one pain animation. Ryu has a single pain animation, but with two looking pain animations for idle and duck anims.

Code:
onpainscript data/scripts/painscript.c
ondoattackscript data/scripts/ondoattack.c

Code:
anim    pain #LP pain
    delay    4 #Pain from both close and far ranges of light punch
    offset    25 99
    platform 4 99 0 0 46 46 1 55
    frame    data/chars/ryu/0500000000.gif # 0
    @cmd    velo001 -2 0 0
    delay    7
    platform 4 99 0 0 46 46 1 55
    frame    data/chars/ryu/0500000000.gif # 1
    offset    35 100
    delay    5
    platform 12 100 0 0 46 46 1 55
    frame    data/chars/ryu/0500000010.gif # 2
    offset    25 99
    @cmd    velo001 0 0 0
    platform 4 99 0 0 46 46 1 55
    frame    data/chars/ryu/0500000000.gif # 3
    @cmd beidle # Switch to idle.
    frame    data/chars/ryu/0500000000.gif # 4
    #Crouch pain activated via onpainscript and ondoattackscript
    offset 26 67
    frame data/CHARS/Ryu/0502000000.gif #5
    offset 38 68
    frame data/CHARS/Ryu/0502000010.gif #6
    frame data/CHARS/Ryu/0502000010.gif #7
    frame data/CHARS/Ryu/0502000010.gif
    #offset 45 67
    #frame data/CHARS/Ryu/0502000020.gif
    #offset 57 67
    #frame data/CHARS/Ryu/0502000030.gif
    @cmd    keyint "ANI_DUCK" 2 "D" 0 # Switch to ducking?
    @cmd    keyint "ANI_FOLLOW6" 0 "D" 1 # Switch to standing up?
    #frame data/CHARS/Ryu/0502000030.gif
    offset 26 67
    frame data/CHARS/Ryu/0502000000.gif #5

Code:
anim    duck #Stand-to-crouch
@script
  void self = getlocalvar("self");
  void Fighter1 = getglobalvar("Fighter1");
  void Fighter2 = getglobalvar("Fighter2");

  void Fighter; float Fx; float x; int Dir;


  if(Fighter1 && Fighter2){
    if(Fighter1 == self){
      Fighter = Fighter2;
    } else {
      Fighter = Fighter1;
    }

    Fx = getentityproperty(Fighter, "x");
    x = getentityproperty(self, "x");
    Dir = getentityproperty(self, "direction");


    if(Fx >= x){
       if(Dir == 0){
    performattack(self, openborconstant("ANI_FOLLOW7")); //Crouch turning
       }
    } else {
       if(Dir == 1){
    performattack(self, openborconstant("ANI_FOLLOW7")); //Crouch turning
       }
    }

 }
    @end_script    
    loop    1 2
    bbox    4 0 46 95
    offset    24 91
    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
    frame    data/chars/ryu/0001000001.gif
    bbox    3 0 49 73
    offset    23 66
    delay    3
    @cmd    keyint "ANI_FOLLOW6" 0 "D" 1
    @cmd    stop
    frame    data/chars/ryu/0001000002.gif

Code:
anim    follow6 #Crouch to stand
    offset    23 66
    delay    3
    frame    data/chars/ryu/0001000002.gif
    bbox    3 1 49 75
    offset    22 72
    frame    data/chars/ryu/0001000001.gif
    bbox    4 0 46 95
    offset    24 91
    frame    data/chars/ryu/0001000000.gif

Code:
anim    follow7 #Crouch turn

    offset    22 66
    delay    4
    flipframe    4
    @cmd    stop
    frame    data/chars/ryu/25.gif
    offset    26 68
    frame    data/chars/ryu/24.gif
    offset    31 67
    frame    data/chars/ryu/23.gif
    delay    2
    frame    data/chars/ryu/23.gif
    offset    23 66
    delay    2
    frame    data/chars/ryu/0001000002.gif
    @cmd    keyint "ANI_FOLLOW6" 0 "D" 1
    frame    data/chars/ryu/0001000002.gif

Animation script:
Code:
void keyint(void Ani, int Frame, void Key, int Hflag)
{// Change current animation if proper key is pressed or released
// Animation is changed without attacking

    void self = getlocalvar("self");
    int Dir = getentityproperty(self, "direction");
    int iPIndex = getentityproperty(self,"playerindex"); //Get player index
    void iRKey;

      if (Key=="U"){ //Up Required?
        iRKey = playerkeys(iPIndex, 0, "moveup"); // "Up"
      } else if (Key=="D"){ //Down Required?
        iRKey = playerkeys(iPIndex, 0, "movedown"); // "Down"
      } else if (Key=="L"){ //Left Required?
        iRKey = playerkeys(iPIndex, 0, "moveleft"); // "Left"
      } else if (Key=="R"){ //Right Required?
        iRKey = playerkeys(iPIndex, 0, "moveright"); // "Right"
      } else if (Key=="F"){ //Forward Required?
        if (Dir == 0){ // Facing Left?
          iRKey = playerkeys(iPIndex, 0, "moveleft"); // "Left"
        } else { // Facing Right
          iRKey = playerkeys(iPIndex, 0, "moveright"); // "Right"
        }
      } else if (Key=="B"){ //Backward Required?
        if (Dir == 1){ // Facing Right?
          iRKey = playerkeys(iPIndex, 0, "moveleft"); // "Left"
        } else { // Facing Left
          iRKey = playerkeys(iPIndex, 0, "moveright"); // "Right"
        }
      } else if (Key=="A"){ //Attack Required?
        iRKey = playerkeys(iPIndex, 0, "attack"); // "Attack"
      }

      if (Hflag==1){ //Not holding the button case?
        iRKey = !iRKey; //Take the opposite condition
      }

      if (iRKey){
        if (Ani=="ANI_IDLE"){ // Going idle?
          setidle(self, openborconstant("ANI_IDLE")); //Be idle!
        } else {
          changeentityproperty(self, "animation", openborconstant(Ani),2);
        }
        changeentityproperty(self, "animpos", Frame); //Change frame
      }
}

painscript.c:
C:
void main(){
    forcePain();
}

void forcePain(){
    void vEnt = getlocalvar("self");
    int forcePain = getentityvar(vEnt, "forcePain");
   
    int DuckForcePain = getentityvar(vEnt, "DuckForcePain");
    int damage = getentityvar(vEnt, "damage");
    void vAniID = getentityproperty(vEnt, "animationid");
    void vTarget = getentityproperty(vEnt, "opponent");
    int hResolution = openborvariant("hResolution");
    int xPos = openborvariant("xpos");
    int x = getentityproperty(vEnt, "x");
    int Tx = getentityproperty(vTarget, "x");
   
    if(forcePain != NULL()){
        setentityvar(vEnt, "forcePain", NULL());
        changeentityproperty(vEnt, "animation", openborconstant("ANI_pain" + forcePain));
        if( x >= xPos+hResolution-1){
            changeentityproperty(vTarget, "velocity", -1.5, 0, 0);
        }else if(x <= xPos+1){
            changeentityproperty(vTarget, "velocity", 1.5, 0, 0);
        }
    }
   
    if(damage != NULL()){
        setentityvar(vEnt, "damage", NULL());
        changeentityproperty(vEnt, "attacking", openborconstant("ATK_NORMAL" + damage));
    }
   
   
    if(vAniID = openborconstant("ANI_DUCK")){
        if(DuckForcePain != NULL()){
            setentityvar(vEnt, "DuckForcePain", NULL()); //For anim pain
            updateframe(vEnt, DuckForcePain); // Change frame under the same pain animation
            if( x >= xPos+hResolution-1){
                changeentityproperty(vTarget, "velocity", -1.5, 0, 0);
            }else if(x <= xPos+1){
                changeentityproperty(vTarget, "velocity", 1.5, 0, 0);
            }
        }
    }
   
   
}

ondoattack.c:
C:
void main(){
    DuckPain();
}

void DuckPain(){
   
    void vEnt = getlocalvar("self"); //Calling entity
   
    if(getlocalvar("which") == 0){ // Defending
        void vAniID = getentityproperty(vEnt, "animationid"); // Calling animation ID
        int lastHitY = openborvariant("lasthity"); // Confirming or getting hit last from bottom as top (like from character's feet to head)
       
        if(vAniID == openborconstant("ANI_DUCK")){ // Is the player ducking?
            if(lastHitY >= 0){ // Detecting on the player for getting attacked last in Y
                setentityvar(vEnt, "DuckForcePain", 5); // Check the onpain script part for "DuckForcePain" that exists there and is set as entityvar. The value is a frame number for certain anim pain
            }
        }
    }
}

For attacks, I don't know, but you can use keyscript to trigger with attack button on other "idle" animations (maybe with entityvars?). What I mean with "idle" is the follow animations based on the different walking directions.

EDIT: I forgot to show animation script for changing animations.
 
Last edited:
Not sure. The only ones I know are SokoBoR and Demon Sluga, but you have to use follow animations instead of using anim up, anim down, and anim walk. For anim idle, you reserve it for skipping to any follow animation that have idle frames with different directions. You can try something different.

The good thing is that @DCurrent made the "direction" property with general directions such as openborconstant("DIRECTION_RIGHT"), openborconstant("DIRECTION_LEFT"), etc., so that you don't need magic numbers for left and right directions.

C:
void direction = getentityproperty(self, "direction");

if(direction == openborconstant("DIRECTION_RIGHT") || direction == openborconstant("DIRECTION_LEFT") ){
    //Make an argument.
}

Ninja'd
 
Last edited:
Yes please I wouldn't mind to take a look when you can.
The code basically will detect the velocity and change the frame to a proper one, and the looper function will hold the animation until the velocity changes again.
I don't know how it would work in the walk animation once I'm using idle.

Entity
C:
name                Robotx_Missile
type                none
subtype                chase
health                1
nolife                1
lifespan            4
offscreenkill        50
death                1
remove                0
nomove                1 0
gfxshadow            1 1
antigravity            100
ondrawscript        data/scripts/ondraw/robotx_missile.c
animationscript        data/scripts/animation/default.c

anim idle
    fastattack 0
    jugglecost 16
    forcedirection 0
    otg 1
    hitflash Burn
    loop    0
    delay    4
    offset    36 27
    @cmd sound "data/sounds/sor3_shot2.wav"
    @cmd sound "data/sounds/sor3_jet.wav"
    burn 24 25 12 3 12 2 1 0 0 18
    dropv 4 4 0
    frame    data/chars/bosses/robotx/missile/missile00.png #LEFT-RIGHT
    frame    data/chars/bosses/robotx/missile/missile01.png
    frame    data/chars/bosses/robotx/missile/missile00.png
    frame    data/chars/bosses/robotx/missile/missile01.png
    @cmd looper 2 9999
    burn 27 18 9 9 12 2 1 0 0 18
    dropv 4 4 0
    frame    data/chars/bosses/robotx/missile/missile02.png #DIAGONAL DOWN
    frame    data/chars/bosses/robotx/missile/missile03.png
    frame    data/chars/bosses/robotx/missile/missile02.png
    frame    data/chars/bosses/robotx/missile/missile03.png
    @cmd looper 6 9999
    burn 27 26 9 9 12 2 1 0 0 18
    dropv 4 4 0
    frame    data/chars/bosses/robotx/missile/missile04.png #DIAGONAL UP
    frame    data/chars/bosses/robotx/missile/missile05.png
    frame    data/chars/bosses/robotx/missile/missile04.png
    frame    data/chars/bosses/robotx/missile/missile05.png
    @cmd looper 10 9999
    burn 34 16 3 11 12 2 1 0 0 18
    dropv 4 4 0
    frame    data/chars/bosses/robotx/missile/missile06.png #DOWN
    frame    data/chars/bosses/robotx/missile/missile07.png
    frame    data/chars/bosses/robotx/missile/missile06.png
    frame    data/chars/bosses/robotx/missile/missile07.png
    @cmd looper 14 9999
    burn 34 26 3 11 12 2 1 0 0 18
    dropv 4 4 0
    frame    data/chars/bosses/robotx/missile/missile08.png #UP
    frame    data/chars/bosses/robotx/missile/missile09.png
    frame    data/chars/bosses/robotx/missile/missile08.png
    frame    data/chars/bosses/robotx/missile/missile09.png
    @cmd looper 18 9999
    frame    data/chars/bosses/robotx/missile/empty.png

And this is the base script, I still need to improve once I created it a long time ago for the old SOR2X, but it does the job.
If the entity already is in the proper frame, nothing will be changed. It runs in the ondrawscript event.
C:
void main()
{
    frameVel();
}

void frameVel()
{//Update frame with velocity check
    void self = getlocalvar("self");
    void anim = getentityproperty(self, "animationID");
    
    if(anim == openborconstant("ANI_IDLE")){
        int dir        = getentityproperty(self, "direction");
        int xVel    = getentityproperty(self, "xdir");
        int zVel    = getentityproperty(self, "zdir");
        int frame    = getentityproperty(self, "animpos");
        float max    = 0.6;
        float min    = 0.3;

        //RIGHT DIRECTION
        if(xVel > max && dir == 1){
            if(frame != 0 && frame != 1 && frame != 2 && frame != 3){updateframe(self, 2);}
        }else

        //LEFT DIRECTION
        if(xVel < -max && dir == 0){
            if(frame != 0 && frame != 1 && frame != 2 && frame != 3){updateframe(self, 2);}
        }else
        
        //DIAGONAL RIGHT DIRECTION
        if(xVel <= max && xVel >= min && dir == 1){
            
            //DIAGONAL DOWN
            if(zVel > 0){
                if(frame != 4 && frame != 5 && frame != 6 && frame != 7){updateframe(self, 6);}
            }else
            
            //DIAGONAL UP
            if(zVel < 0){
                if(frame != 8 && frame != 9 && frame != 10 && frame != 11){updateframe(self, 10);}
            }
        }else

        //DIAGONAL LEFT DIRECTION
        if(xVel >= -max && xVel <= -min && dir == 0){
            
            //DIAGONAL DOWN
            if(zVel > 0){
                if(frame != 4 && frame != 5 && frame != 6 && frame != 7){updateframe(self, 6);}
            }else
            
            //DIAGONAL UP
            if(zVel < 0){
                if(frame != 8 && frame != 9 && frame != 10 && frame != 11){updateframe(self, 10);}
            }
        }else
        
        //UP-DOWN DIRECTION
        if(xVel < min && xVel > -min){
            
            //DOWN
            if(zVel > 0){
                if(frame != 12 && frame != 13 && frame != 14 && frame != 15){updateframe(self, 14);}
            }else
            
            //UP
            if(zVel < 0){
                if(frame != 16 && frame != 17 && frame != 18 && frame != 19){updateframe(self, 18);}
            }
        }
    }
}

C:
void looper(int frame, int limit)
{//Loops current animation
    void self    = getlocalvar("self");
    void anim    = getentityproperty(self, "animationID");
    int loop    = getlocalvar("loop"+self+anim);

    //LOCALVAR EMPTY?
    if(loop == NULL()){
        setlocalvar("loop"+self+anim, 0);
        loop = 0;
    }

    //LOOPS BELOW LIMIT?
    if(loop < limit){
        setlocalvar("loop"+self+anim, loop+1); //INCREMENT NUMBER OF LOOPS
        updateframe(self, frame); //CHANGE FRAME
    }else

    //LOOPS REACH LIMIT?
    if(loop == limit){
        setlocalvar("loop"+self+anim, NULL()); //CLEAR THE LOOPER VARIABLE
    }
}
 
Back
Top Bottom