Continuously Animating a Button (repeatedly_execute_always) SOLVED

Started by deadsuperhero, Sun 15/11/2020 23:45:08

Previous topic - Next topic

deadsuperhero

I have this game mechanic that I want to try.
In a nutshell, the player character has anxiety. Various interactions cause the character's anxiety level to increase, and I want to render that anxiety on a graph, like this one:



Effectively, the graph is just a button with a view set. If a character property is set to a certain level, a specific loop gets loaded and played continuously.

Code: ags

    function getAnxiety() {
      int anxiety_level = cEgo.GetProperty("anxiety_level");
          // Animate the anxiety meter independent of blocking
          if (anxiety_level == 0) {
        checkMeter.Animate(6, 0, 0, eRepeat);
      }
        else if (anxiety_level == 1) {
        checkMeter.Animate(6, 2, 3, eRepeat);
        }
    }


Unfortunately, we have the problem of blocking...I want this "graph" to render while things such as dialog are happening, as it gives the player and idea of what things trigger the player character.

I tried calling this function from inside of repeatedly_execute_always, and unfortunately this seems to cause some pretty big problems. A separate thread here suggested that the animation is being called 40 times a second or something.
I'm basically stuck in a situation where I can either:
1. Have a working function that gets blocked every time a message is rendered (since those pause the game)
2. Leave the function inside of repeatedly_execute_always and try to figure out some other way to do the rendering (if possible)

Initially, I went down the rabbit hole of simply using views because I wasn't sure whether I could just get the game engine to draw the line on top of the button using DynamicSprite.

So...I guess this all boils down to two questions:

1. Is there a way to animate buttons inside of repeatedly_execute_always?
2. If no, is there a way to render Dynamic Sprites inside of repeatedly_execute_always instead?
The fediverse needs great indie game developers! Find me there!

morganw

You could just check the loop and not change it if it is the correct one:
https://adventuregamestudio.github.io/ags-manual/Button.html#buttonloop

...but it is probably better to write a function that sets your custom property and then also checks/changes the loop. There isn't much point in checking it continuously when you know the value won't be changing.

deadsuperhero

Quote from: morganw on Mon 16/11/2020 00:49:15
You could just check the loop and not change it if it is the correct one:
https://adventuregamestudio.github.io/ags-manual/Button.html#buttonloop

...but it is probably better to write a function that sets your custom property and then also checks/changes the loop. There isn't much point in checking it continuously when you know the value won't be changing.

Yeah, I guess part of my problem is that I'm trying to check which loop it needs to be based on the custom property, and also continuously run the animation in the background.
It probably wouldn't be too hard to split it out into two functions so that one function is doing the check, and another is passing the output of that check into a continuous animation function.

I guess the crux of the problem, though, is that button animation itself can't run in a non-blocking fashion, and the frames cannot be manually advanced due to the button's frame property being read-only.

The alternative might be to use something like the Spline module to draw the line on top of the button, and make it go through generated points at a certain speed and magnitude...though, the line would have to give the illusion of continuously moving.
The fediverse needs great indie game developers! Find me there!

CrashPL

Unless there's a specific reason to put that code in repeatedly_execute_always (like changing it during cutscenes etc.), I would suggest putting it to repeatedly_execute instead. ;)

As for the question - you can either check the Button.Loop property, just like morganw mentioned, or the Button.Animating property (it will prevent firing up the animation constantly when the button's already animated. And on the anxiety value change, you can stop the old animation and run the new one).

deadsuperhero

Quote from: CrashPL on Mon 16/11/2020 00:56:05
Unless there's a specific reason to put that code in repeatedly_execute_always (like changing it during cutscenes etc.), I would suggest putting it to repeatedly_execute instead. ;)

The purpose is for it to run while dialog is happening. While it's more of an aesthetic idea than anything else, it gives a quick indication to the player what their character's state of mind is, and when to mitigate that anxiety back down to acceptable levels.

Unfortunately, doing it in repeatedly_execute means that the animation will pause every time somebody is talking.
The fediverse needs great indie game developers! Find me there!

deadsuperhero

Okay, so I'm happy to report that this ended up working really well!

Code: ags

    function getAnxiety() {
      int anxiety_level = cEgo.GetProperty("anxiety_level");
          // Animate the anxiety meter independent of blocking
          if (anxiety_level == 0) {
            if (checkMeter.Animating == false) {
              checkMeter.Animate(6, 0, 0, eOnce);
            }
      }
        else if (anxiety_level == 1) {
          if (checkMeter.Animating == false) {
            checkMeter.Animate(6, 2, 3, eOnce);
          }
        }
    }


Basically, all I have to do now is call getAnxiety() from inside of repeatedly_execute_always!

THANK YOU SO MUCH!  :-D
The fediverse needs great indie game developers! Find me there!

CrashPL

Quote from: DeadSuperHero on Mon 16/11/2020 00:58:56
The purpose is for it to run while dialog is happening.

Somehow I totally missed that from the original post, even though I read it twice. Guess that's what happens when you're replying at 2AM. :-D

Glad to see the 'Animating' approach is working well for you!

morganw

An (untested) example of what I mean:
Code: ags
function SetAnxiety(int anxiety_level)
{
    if (cEgo.SetProperty("anxiety_level", anxiety_level))
    {
        if (anxiety_level == 1)
        {
            checkMeter.Animate(6, 2, 3, eRepeat);
        }
        else
        {
            checkMeter.Animate(6, 0, 0, eRepeat);
        }
    }
}

Khris

Quote from: DeadSuperHero on Sun 15/11/2020 23:45:08I tried calling this function from inside of repeatedly_execute_always, and unfortunately this seems to cause some pretty big problems. A separate thread here suggested that the animation is being called 40 times a second or something.

Exactly; you're starting the animation from the beginning every frame, which means it'll never reach its 2nd frame.

One solution that will definitely work is simply setting the buttons  .NormalGraphic  manually.

Code: ags
// above repeatedly_execute_always
int btnAnxietyFrame = -1;

  // inside repeatedly_execute_always
  btnAnxietyFrame = (btnAnxietyFrame + 1) % 5; // 5 frames per animation
  btnAnxiety.NormalGraphic = btnAnxietyFrame + anxietyLevel * 5 + 30;


This code assumes that anxiety level 0 uses sprites 30 - 34, anxiety level 1 uses sprites 35-39, etc.

SMF spam blocked by CleanTalk