How do I get this sine wave to move?

Started by Scavenger, Sat 10/10/2015 14:54:23

Previous topic - Next topic

Scavenger

I'm currently working on a text renderer so I can do fancy text effects and coloured text and all that, and I'm currently trying to do a flowing sine wave for the text. The good news is, I can draw the text in a sine wave. The bad news is, I can't seem to get it to move. It remains a static sine wave no matter where I put the sinetimer, or what values I give it. I need it to shift right with time.

My full code is:

Code: AGS
// room script file

DynamicSprite *textarea;
Overlay *ov;
String targettxt;
int targettxtlength;
String txt;
int counter;
int delay;
int targetindex;
int length;
int sinetimer;

bool renderingtext;
bool renderingcomplete;

function DisplayRenderedText (String text, int textdelay)
{
  targettxt = text.Copy ();
  targetindex = 0;
  delay = textdelay;
  counter = 0;
  renderingtext = true;
  txt = String.Format("");
  while (targettxt.Substring (targetindex, 1) == "@") //if the current character is the escape code.
        {
            targetindex++;
            if (targettxt.Substring (targetindex, 1) == "j") // if the escape code is "jitter"
            {
              targetindex+=2;
            }
            else if (targettxt.Substring (targetindex, 1) == "t") //if escape code is "tremor", for really tiny jitters.
            {
              targetindex++;
            }
            else if (targettxt.Substring (targetindex, 1) == "n") // if the escape code is "normal"
            {
              targetindex++;
            }
            else if (targettxt.Substring (targetindex, 1) == "c") // if the escape code is "colour"
            {
              targetindex+=4;
            }
            else if (targettxt.Substring (targetindex, 1) == "f") // if the escape code is "font"
            {
              targetindex+=3;
            }
            else if (targettxt.Substring (targetindex, 1) == "s") // if the escape code is "sine"
            {
              targetindex+=3;
            }
            else if (targettxt.Substring (targetindex, 1) == "p") // if the escape code is "pause"
            {
              targetindex+=2;
            }
            else if (targettxt.Substring (targetindex, 1) == "[") // if the escape code is "carriage return"
            {
              targetindex+=1;
            }
        }
}

String ProgressCurrentText ()
{
  if (counter == delay)
  {
  if (targetindex < targettxt.Length)
  {
    targetindex++;
      while (targettxt.Substring (targetindex, 1) == "@") //if the current character is the escape code.
        {
            targetindex++;
            if (targettxt.Substring (targetindex, 1) == "j") // if the escape code is "jitter"
            {
              targetindex+=2;
            }
            else if (targettxt.Substring (targetindex, 1) == "t") //if escape code is "tremor", for really tiny jitters.
            {
              targetindex++;
            }
            else if (targettxt.Substring (targetindex, 1) == "n") // if the escape code is "normal"
            {
              targetindex++;
            }
            else if (targettxt.Substring (targetindex, 1) == "c") // if the escape code is "colour"
            {
              targetindex+=4;
            }
            else if (targettxt.Substring (targetindex, 1) == "s") // if the escape code is "sine"
            {
              targetindex+=3;
            }
            else if (targettxt.Substring (targetindex, 1) == "f") // if the escape code is "font"
            {
              targetindex+=3;
            }
            else if (targettxt.Substring (targetindex, 1) == "p") //If the escape code is pause.
            {
              targetindex++;
              String s_amount = targettxt.Substring (targetindex, 1);
              if (s_amount.AsInt > 0) counter = (s_amount.AsInt * delay) * (-1);
              else AbortGame ("Invalid pause amount (1-9)");
            }
            else if (targettxt.Substring (targetindex, 1) == "[") //If the escape code is pause.
            {
              targetindex++;
            }
        }
  }
  }
  else counter++;
  return targettxt.Substring (0, targetindex);
}

function RenderText (String text, int x, int y)
{
  int curry;
  int mode;
  int modedata;
  int modedata2;
  int color;
  int font;
  int prog;
  DrawingSurface *surf = textarea.GetDrawingSurface ();
  surf.Clear ();
  surf.DrawingColor = color;
  int i;
  curry = y;
  prog=0;
  while (i < text.Length)
  {
    surf.DrawingColor = color;
    if (text.Substring (i, 1) == "@") //if the current character is the escape code.
        {
          i++;
          if (text.Substring (i, 1) == "j") // if the escape code is "jitter"
          {
            mode = 1;
            i++;
            String s_amount = text.Substring (i, 1);
            if (s_amount.AsInt > 0) modedata = s_amount.AsInt;
            else AbortGame ("Invalid Jitter amount (1-9)");
            i++;
          }
          else if (text.Substring (i, 1) == "t") //if escape code is "tremor", for really tiny jitters.
          {
            mode = 2;
            i++;
          }
          else if (text.Substring (i, 1) == "n") // if the escape code is "normal"
          {
            mode = 0;
            i++;
          }
          else if (text.Substring (i, 1) == "s") // if the escape code is "sine"
          {
            mode = 3;
            i++;
           String h_amount = text.Substring (i, 1);
           if (h_amount.AsInt > 0) modedata = h_amount.AsInt;
           else AbortGame ("Invalid sine height amount (1-9)");
           i++;
           String w_amount = text.Substring (i, 1);
           if (w_amount.AsInt > 0) modedata2 = w_amount.AsInt;
           else AbortGame ("Invalid sine period amount (1-9)");
           i++;
          }
          else if (text.Substring (i, 1) == "c") // if the escape code is "colour"
          {
            i++;
            String colordata = text.Substring (i, 3);
            if (colordata.AsInt > 0) color = colordata.AsInt;
            else AbortGame ("Invalid color number.");
            i+=3;
          }
          else if (text.Substring (i, 1) == "f") // if the escape code is "font"
          {
            i++;
            String fontdata = text.Substring (i, 2);
            if (fontdata.AsInt > 0 || fontdata.CompareTo ("00") == 0) font = fontdata.AsInt;
            else AbortGame ("Invalid font number.");
            i+=2;
          }
          else if (text.Substring (i, 1) == "[") // if the escape code is the AGS carriage return
          {
            prog = 0;
            curry+= GetTextHeight ("Quick brown fox jumped over the Lazy dog",font, 320) + 1;
            i++;
          }
          else if (text.Substring (i, 1) == "p") //If the escape code is pause.
          {
            i+=2; //This escape code is not for this part of the renderer.
          }
          else AbortGame ("Invalid text escape code.");
        }
    else 
    {
      if (mode == 0) // normal mode
      {
        surf.DrawString (x+prog, curry, font, text.Substring (i, 1));
      }
      else if (mode == 1) //jitter mode
      {
        surf.DrawString (x+prog+Random(1), curry+(Random(modedata*2)-modedata), font, text.Substring (i, 1));
      }
      else if (mode == 2) //tremor mode
      {
        surf.DrawString (x+prog+Random(1), curry+Random(1), font, text.Substring (i, 1));
      }
      else if (mode == 3) //sine mode
      {
        if (sinetimer < modedata2) sinetimer++;
        else sinetimer = 0;
        float period = (2.0*Maths.Pi)/(IntToFloat (modedata2));
        float offset = IntToFloat(modedata) * Maths.Sin ((period * IntToFloat (sinetimer)) - IntToFloat(i));
        surf.DrawString (x+prog, curry+FloatToInt (offset, eRoundNearest), font, text.Substring (i, 1));
      }
    prog += GetTextWidth (text.Substring (i, 1), font);
    i++;
    }
  }
  surf.Release ();
  ov = Overlay.CreateGraphical (0, 0, textarea.Graphic, true);
}

function GetRenderTextWidth (String text)
{
  int font;
  int currfont;
  int totallength;
  int i;
  while (i < text.Length)
  {
    if (text.Substring (i, 1) == "@") //if the current character is the escape code.
    {
      i++;
      if (text.Substring (i, 1) == "j") // if the escape code is "jitter"
      {
        i+=2;
      }
      else if (text.Substring (i, 1) == "t") //if escape code is "tremor", for really tiny jitters.
      {
        i++;
      }
      else if (text.Substring (i, 1) == "n") // if the escape code is "normal"
      {
        i++;
      }
      else if (text.Substring (i, 1) == "c") // if the escape code is "colour"
      {
        i+=4;
      }
      else if (text.Substring (i, 1) == "f") // if the escape code is "font"
      {
        i++;
        String fontdata = text.Substring (i, 2);
        if (fontdata.AsInt > 0 || fontdata.CompareTo ("00") == 0) currfont = fontdata.AsInt;
        else AbortGame ("Invalid font number.");
        i+=2;
      }
      else if (text.Substring (i, 1) == "p") //If the escape code is pause.
      {
        i+=2; //This escape code is not for this part of the renderer.
      }
      else if (text.Substring (i, 1) == "s") //If the escape code is sine.
      {
        i+=3; 
      }
      else if (text.Substring (i, 1) == "[") //If the escape code is pause.
      {
        i++;
        totallength = 0;
      }
      else AbortGame ("Invalid text escape code.");
    }
    else 
    {
    totallength += GetTextWidth (text.Substring (i, 1), font);
    i++;
    }
  }
    return totallength;
}

function room_AfterFadeIn()
{
textarea = DynamicSprite.Create (320, 200);
DisplayRenderedText ("@c015@s21 This is a test string.",5);
}


function room_RepExec()
{
  String newtext = ProgressCurrentText ();
  RenderText (newtext, 30, 20);
}


And the actual drawing code is:

Code: AGS
      else if (mode == 3) //sine mode
      {
        if (sinetimer < modedata2) sinetimer++;
        else sinetimer = 0;
        float period = (2.0*Maths.Pi)/(IntToFloat (modedata2));
        float offset = IntToFloat(modedata) * Maths.Sin ((period * IntToFloat (sinetimer)) - IntToFloat(i));
        surf.DrawString (x+prog, curry+FloatToInt (offset, eRoundNearest), font, text.Substring (i, 1));
      }


I'm really stumped as to how to get it to move with time. There must be something obvious that I'm missing, but for the life of me I can't see what it is. Can anyone help?

Snarky

Jesus! I think since you know what all those variables are for and are supposed to do, it'll be easier for you to debug this than for others to make sense of it.

Well, one thing I noticed... I think the variable that's meant to make the wave move is sinetimer, right? I would expect it to increment once per cycle, but you're incrementing it inside a "while (i < text.Length)" loop. That looks wrong to me, without digging through all your logic and calculations.

If that's not it, just break it down step by step. Put the value of sinetimer on-screen to check that it actually updates as you expect (if it updates too quicky, you can change the repexec code to only run the method calls every 10 cycles or whatever; or you can write to a log file). Maybe change the text string to a single letter to simplify tracking the value. Then check period * IntToFloat (sinetimer) and the final value of offset. Once you find where exactly is breaks down, it should be easy to fix.

Scavenger

Ah, OK, I seperated the sinetimer into it's own thing, made it run on it's own timer (0-65536), and it works fine now! I really should comment my own code better. Thankyou!

Monsieur OUXX

 

Khris

I just want to point out that this code is extremely wasteful of system resources.
Assuming that the first x checks fail, AGS will call the exact same substring function x + 1 times. Multiple times, every single frame.

All you need is
Code: ags
char c = targettxt.Chars[targetindex]; // once

if (c == '@') ...
else if (c == 'j')
// etc.

Scavenger

I didn't know Substring was resource intensive, it didn't seem to slow anything down.

Is String.Chars also doing anything other than acting as an array of chars, though? Why would I need to put the contents in c when I could just reference the array directly (instead of the silly 1 length substrings I've been using)?

Monsieur OUXX

Quote from: Scavenger on Tue 13/10/2015 15:08:25
I didn't know Substring was resource intensive, it didn't seem to slow anything down.
Well it's not THAT resource intensive, but still, don't forget that AGS langage is still a script langage, so each time you call a function that works on arrays of characters, it calls a ton of layers of code to eventually reach the simple character processing. But you already know that.

PS: Did I thank you enough for the module you wrote for Indy? I didn't thank you enough for that. I'm doing it right now. Eternal thank you.
 

Crimson Wizard

#7
Quote from: Scavenger on Tue 13/10/2015 15:08:25
I didn't know Substring was resource intensive, it didn't seem to slow anything down.

Is String.Chars also doing anything other than acting as an array of chars, though? Why would I need to put the contents in c when I could just reference the array directly (instead of the silly 1 length substrings I've been using)?
In both cases the difference in speed may be relatively large, but negligible in absolute measurement (from human perspective).
Regardless, as I use to say, even if not causing any immediate problems, bad coding style produces bad habits that may cause problems in the future.

Also, the code in Khris's example is plain shorter and easier to read :).

E: Kidding aside, though, here is another reason to assign a variable once and use it later on instead of calling same operation over and over again (would be that substring, or taking a character by index): with single assignment you may be certain that you are using precisely same value in every condition. When you retype same operation for each condition, you may do typos and mistakes, therefore ending with comparing different values.

Snarky

Quote from: Scavenger on Tue 13/10/2015 15:08:25
Is String.Chars also doing anything other than acting as an array of chars, though? Why would I need to put the contents in c when I could just reference the array directly (instead of the silly 1 length substrings I've been using)?

1. Saves on typing.
1.b As CW says, this reduces the risk of typos or other mistakes.
2. If for whatever reason you need to change it at some point in the future, you only have to do it in one place.

SMF spam blocked by CleanTalk