News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_freemac

Blood and haduken

Started by freemac, 11:45, 28 May 18

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

freemac

Hi,

For Mortal Kombat, I want to implement blood splash and haduken fireballs without using sprites, but using instead basic effects that could be randomize a few (or not)

For performance, I think that I'll draw only one effect, in less than 1/2 vsync.
For blood, I can have 3 points of start, where player is hurt : top, middle, bottom.
I think that model could be a vector (two points : start and direction (length for importance))

Any suggestion of effect ?

Targhan

Unless you draw simple points, generated effects will probably be slower than displaying sprites.
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

freemac

#2
Here a 8Bytes hadouken  :)

PS : I'm in mode 1, 1 color.

freemac

Source : point of impact, enter one per one ( max 8 )
At each step : ones from left go to right, more and more slowly. All gone from top to bottom at same speed.
Still 8 Bytes.

Targhan

You can do this with small sprites, but you can also code your own specialized sprite code, like this:
ld (hl),<byte>
inc hl
ld (hl),<byte>
<move to the next line>
ld (hl),<byte>
dec hl
ld (hl),<byte>


etc.


This is as fast as you can get. I don't know how you manage your background, it should probably be stored/restored too.
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

freemac


https://www.youtube.com/watch?v=15Mb19-YrTg


Using algo, I can enter more or less blood...

Targhan

In my humble opinion, it doesn't look very good. I would:
- either use blood sprites.
- use "particules". You could stick to the point (be pixel-accurate please), with a little X-speed (may be negative) and Y-speed, both would be initialized so that they all look a bit different. You could add more points according to the power of the hit. Use fixed-point number to manage accurate speeds. If you don't know how to do that, ask.
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

freemac

Quote from: Targhan on 22:10, 02 June 18
- use "particules". You could stick to the point (be pixel-accurate please), with a little X-speed (may be negative) and Y-speed, both would be initialized so that they all look a bit different. You could add more points according to the power of the hit. Use fixed-point number to manage accurate speeds. If you don't know how to do that, ask.

That's what I want, "particules" :)

My algorithm at this step is :
- insert pixel in algorithm one per one
- apply BLOOD_X_SPEED
- apply BLOOD_Y_SPEED
- resolve X pixels having same coordinates, pushing them X++

I added also :
- gravity (acceleration blood_g++ at each frame, started at 1)
- g (glitch - something stupid that accelerate new pixels more that old ones (g is local))

#define BLOOD_SIZE 14
//#define BLOOD_B_SPEED 0 - vitesse d'entrée des gouttes dans l'algo : déjà au maximum (en entrer plusieurs ?)
#define BLOOD_X_SPEED 8
#define BLOOD_Y_SPEED 4
unsigned char current_blood[BLOOD_SIZE][2];
char blood_depth=0;
char blood_n=0;
unsigned char blood_x_slow=0;
unsigned char blood_y_slow=0;
char blood_x;
char blood_y; // tete ou ventre ou pied
char blood_d; // direction
char blood_g; // gravite

/**
* Controler : propagation du sang (lancé à chaque frame)
*/
void blood() {
   char i;char sx;char sy;char g;
   if (blood_y==0) return;
   g=0; // glitch (formule capturée lors de tests en échecs, car c'est jolie)

   // ==> ou <== : on s'en fou, le tableau on le retournera à l'affichage !
   blood_x_slow++;
   if (blood_x_slow == BLOOD_X_SPEED) { // x
      blood_x_slow=0;
   }
   if (blood_x_slow==0) {
      for (i=0;i<blood_depth;i++)  {
         // se poussent en x
         if (current_blood[i][0]<BLOOD_SIZE) { // x
            current_blood[i][0]=current_blood[i][0]+1;
         }
      }
      return;
   }
   blood_y_slow++;
   if (blood_y_slow == BLOOD_Y_SPEED) { // y
      blood_y_slow=0;
   }
   if (blood_y_slow==0) {
      for (i=0;i<blood_depth;i++)  {
         if (current_blood[i][1]>0) { // y
            // descend à vitesse constante.
            current_blood[i][1]=current_blood[i][1]-1;
         }
      }
      return;
   }
   // BLOOD_B_SPEED/blood_b_slow
   if (blood_depth<blood_n) {
      // insertion
      current_blood[blood_depth][0]=0;
      current_blood[blood_depth][1]=blood_y;
      blood_depth++;
      blood_g=1;
   } else {
      // gravité
      for (i=1;i<blood_depth;i++)  {
         if (current_blood[i][1]>blood_g + g) {
            // descend à vitesse non constante
            current_blood[i][1]=current_blood[i][1]-g-blood_g;
            g++;
         } else {
            // touche le sol
            current_blood[i][1]=0;
         }
      }
      blood_g++;
      if (blood_g>7) {
         // on coupe l'animation sang (car c'est moche sinon : une goutte reste bizarrement suspendue...)
         blood_y=0;
         blood_depth=0;
      }
   }
   // solve superpositions X
   sx=current_blood[0][0];sy=current_blood[0][1];
   for (i=1;i<blood_depth;i++)  {
      if (current_blood[i][1] != sy) {
         // nouvelle ligne, pas de problème de gouttes
         sx=current_blood[i][0];
         sy=current_blood[i][1];
      } else if (current_blood[i][0] <= sx) {
         // goutte génante, je la pousse, puis je la garde de côté
         sx=sx+1;
         current_blood[i][0]= sx;
      } else {
         // goutte pas génante, je la garde de côté
         sx=current_blood[i][0];
      }
   }
}

/**
* Controler : lancé à la place de blood() lors d'un nouveau dégat - ça déclanche une nouvelle animation
* @param d : direction (plutôt aléatoire)
* @param n : dégats (entre 1 et BLOOD_SIZE)
* @param x,y : coordonnées du coup reçu
*/
void bloodDegats(char d, char n,char x, char y) {
   blood_d = d;
   blood_n = n;
   blood_x = x;
   blood_y = y;
   blood_depth=0;
   blood();
}

/**
* Renderer : Affiche le sang
*/
void bloodRender() {
   char i;
   for (i=0;i<blood_depth;i++)  {
      if (blood_d==0) {
         if (blood_x+current_blood[i][0]>6*8+3+2) continue;
         put_byte(blood_x+current_blood[i][0],120+50-1-current_blood[i][1],0xF0);
      } else {
         if (blood_x-current_blood[i][0]<3) continue;
         put_byte(blood_x-current_blood[i][0],120+50-1-current_blood[i][1],0xF0);
      }
   }
}

/**
* Renderer : Efface le sang
*/
void bloodDerender() {
   char i;
   for (i=0;i<blood_depth;i++)  {
      if (blood_d==0) {
         if (blood_x+current_blood[i][0]>6*8+3+2) continue;
         put_byteC000(blood_x+current_blood[i][0],120+50-1-current_blood[i][1],0x00);
      } else {
         if (blood_x-current_blood[i][0]<3) continue;
         put_byteC000(blood_x-current_blood[i][0],120+50-1-current_blood[i][1],0x00);
      }
   }
}

Targhan

Well yes, it seems you already manages this somehow. But it doesn't look great, in my opinion. Be pixel-accurate, not byte-accurate.
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

freemac


https://www.youtube.com/watch?v=71QmiD5EvGg

I corrected the first launch of algorithm in order to enter more pixels at first step.

I do now launch several times blood() algorithm during first step :
#define BLOOD_SIZE 14
// 1 + 2 + 3 + 4 < 14
#define BLOOD_SIZE_INIT 5
(...)

void bloodDegats(char d, char n,char x, char y) {
(...)
while (blood_depth<blood_n && blood_depth<BLOOD_SIZE_INIT) {
blood();
}


and also enter pixels two per two :
if (blood_depth<blood_n) {
// insertion
current_blood[blood_depth][0]=0;
current_blood[blood_depth][1]=blood_y;
blood_depth++;
if (blood_depth<blood_n) {
current_blood[blood_depth][0]=1;
current_blood[blood_depth][1]=blood_y+1;
blood_depth++;
}


So normaly with BLOOD_SIZE_INIT == 5 relaunch of blood(), full blood does enter at first step of algorithm : 1 + 2 + 3 + 4 < BLOOD_SIZE/2

Quote#define BLOOD_SIZE 14
// 1 + 2 + 3 + 4 < 14
#define BLOOD_SIZE_INIT 5
//#define BLOOD_B_SPEED 0 - vitesse d'entrée des gouttes dans l'algo : déjà au maximum (en entrer plusieurs ?)
#define BLOOD_X_SPEED 8
#define BLOOD_Y_SPEED 4
unsigned char current_blood[BLOOD_SIZE][2];
char blood_depth=0;
char blood_n=0;
unsigned char blood_x_slow=0;
unsigned char blood_y_slow=0;
char blood_x;
char blood_y; // tete ou ventre ou pied
char blood_d; // direction
char blood_g; // gravite

/**
* Controler : propagation du sang (lancé à chaque frame)
*/
void blood() {
   char i;char sx;char sy;char g;
   if (blood_y==0) return;
   g=0; // glitch (formule capturée lors de tests en échecs, car c'est jolie)

   // ==> ou <== : on s'en fou, le tableau on le retournera à l'affichage !
   blood_x_slow++;
   if (blood_x_slow == BLOOD_X_SPEED) { // x
      blood_x_slow=0;
   }
   if (blood_x_slow==0) {
      for (i=0;i<blood_depth;i++)  {
         // se poussent en x
         if (current_blood
  • <BLOOD_SIZE) { // x
                current_blood
    • =current_blood
      • +1;
                 }
              }
              return;
           }
           blood_y_slow++;
           if (blood_y_slow == BLOOD_Y_SPEED) { // y
              blood_y_slow=0;
           }
           if (blood_y_slow==0) {
              for (i=0;i<blood_depth;i++)  {
                 if (current_blood[1]>0) { // y
                    // descend à vitesse constante.
                    current_blood[1]=current_blood[1]-1;
                 }
              }
              return;
           }
           // BLOOD_B_SPEED/blood_b_slow
           if (blood_depth<blood_n) {
              // insertion
              current_blood[blood_depth][0]=0;
              current_blood[blood_depth][1]=blood_y;
              blood_depth++;
              if (blood_depth<blood_n) {
                 current_blood[blood_depth][0]=1;
                 current_blood[blood_depth][1]=blood_y+1;
                 blood_depth++;
              }
              blood_g=1;
           } else {
              // gravité
              for (i=1;i<blood_depth;i++)  {
                 if (current_blood[1]>blood_g + g) {
                    // descend à vitesse non constante
                    current_blood[1]=current_blood[1]-g-blood_g;
                    g++;
                 } else {
                    // touche le sol
                    current_blood[1]=0;
                 }
              }
              blood_g++;
              if (blood_g>7) {
                 // on coupe l'animation sang (car c'est moche sinon : une goutte reste bizarrement suspendue...)
                 blood_y=0;
                 blood_depth=0;
              }
           }
           // solve superpositions X
           sx=current_blood[0][0];sy=current_blood[0][1];
           for (i=1;i<blood_depth;i++)  {
              if (current_blood[1] != sy) {
                 // nouvelle ligne, pas de problème de gouttes
                 sx=current_blood
        • ;
                   sy=current_blood[1];
                } else if (current_blood
          • <= sx) {
                     // goutte génante, je la pousse, puis je la garde de côté
                     sx=sx+1;
                     current_blood
            • = sx;
                    } else {
                       // goutte pas génante, je la garde de côté
                       sx=current_blood
              • ;
                      }
                   }
                }

                /**
                * Controler : lancé à la place de blood() lors d'un nouveau dégat - ça déclanche une nouvelle animation
                * @param d : direction (plutôt aléatoire)
                * @param n : dégats (entre 1 et BLOOD_SIZE)
                * @param x,y : coordonnées du coup reçu
                */
                void bloodDegats(char d, char n,char x, char y) {
                   blood_d = d;
                   blood_n = n;
                   blood_x = x;
                   blood_y = y;
                   blood_depth=0;
                   while (blood_depth<blood_n && blood_depth<BLOOD_SIZE_INIT) {
                      blood();
                   }
                }

                /**
                * Renderer : Affiche le sang
                */
                void bloodRender() {
                   char i;
                   for (i=0;i<blood_depth;i++)  {
                      if (blood_d==0) {
                         if (blood_x+current_blood
                • >6*8+3+2) continue;
                           put_byte(blood_x+current_blood
                  • ,120+50-1-current_blood[1],0xF0);
                          } else {
                             if (blood_x-current_blood
                    • <3) continue;
                               put_byte(blood_x-current_blood
                      • ,120+50-1-current_blood[1],0xF0);
                              }
                           }
                        }

                        /**
                        * Renderer : Efface le sang
                        */
                        void bloodDerender() {
                           char i;
                           for (i=0;i<blood_depth;i++)  {
                              if (blood_d==0) {
                                 if (blood_x+current_blood
                        • >6*8+3+2) continue;
                                   put_byteC000(blood_x+current_blood
                          • ,120+50-1-current_blood[1],0x00);
                                  } else {
                                     if (blood_x-current_blood
                            • <3) continue;
                                       put_byteC000(blood_x-current_blood
                              • ,120+50-1-current_blood[1],0x00);
                                      }
                                   }
                                }

Targhan

Better, but still not great. Make your blood Speed Y be faster maybe, so that it can move instead of "flying" at remaining at the same height before disappearing. Sorry I won't have time to check your code.
Targhan/Arkos

Arkos Tracker 2.0.1 now released! - Follow the news on Twitter!
Disark - A cross-platform Z80 disassembler/source converter
FDC Tool 1.1 - Read Amsdos files without the system

Imperial Mahjong
Orion Prime

freemac

I take note of that.

I started implementing also Hadouken (but without damages), and start export/import of player parameters.

I think I'll do a second pass on my code. I've got a lot of small things to calibrate/finish.

freemac


ThomH

Quote from: Targhan on 14:26, 28 May 18
You can do this with small sprites, but you can also code your own specialized sprite code, like this:
ld (hl),<byte>
inc hl
ld (hl),<byte>
<move to the next line>
ld (hl),<byte>
dec hl
ld (hl),<byte>


etc.


This is as fast as you can get. I don't know how you manage your background, it should probably be stored/restored too.
Re: this is as fast as you can get; if you suitably aligned and sized your display surely you could get away with just inc/dec l?

sigh

Very interesting thread. May I suggest that you use pixel dots instead of the lines? Also - a lesser amount too?Have you tried changing the colour of the lines while they are animating? If you cycle from Pink - Red - Dark Red - Black, that could give a better interpretation of the blood disappearing.

freemac


freemac

#16
Quote from: sigh on 13:49, 27 June 18
Very interesting thread. May I suggest that you use pixel dots instead of the lines? Also - a lesser amount too?Have you tried changing the colour of the lines while they are animating? If you cycle from Pink - Red - Dark Red - Black, that could give a better interpretation of the blood disappearing.
I'm using here mode 1, so only 4 colors : blood, player1, background, player2.

Powered by SMFPacks Menu Editor Mod